.. _changelog: Changelog ========= All notable changes to this project are documented in this file. The format is based on `Keep a Changelog `_, and this project adheres to `Semantic Versioning `_. 1.0.1 - 2026-04-16 ------------------ Fixed ~~~~~ - Corrected installation documentation to lead with the PyPI package install path instead of editable development installs. - Clarified that SIMIND is an external runtime dependency and must be available as ``simind`` on ``PATH`` for local connector runs. - Updated contributing and testing documentation to use Ruff for linting, import sorting, and formatting checks. - Updated examples documentation to include the DICOM-driven adaptor examples. - Fixed the GitHub Actions coverage target after the import package rename. - Fixed README links and release metadata for the patch release. 1.0.0 - 2026-04-16 ------------------ **Breaking Changes** ~~~~~~~~~~~~~~~~~~~~ **Connector-first public API** The legacy simulator-oriented surface has been removed in favor of connector/adaptor entry points: - Removed ``SimindSimulator`` from top-level exports. - Removed ``NativeBackendConnector`` from connector exports. - Removed legacy core runtime modules (``core.simulator``, ``core.backend_adapter``, ``core.components``, ``core.file_managers``, ``core.output_processor``). **PyTomography adaptor boundary tightening** ``PyTomographySimindAdaptor`` no longer wraps reconstruction-package helper methods: - Removed ``build_system_matrix()`` - Removed ``get_pytomography_metadata()`` System-matrix creation is now performed directly with PyTomography APIs in user code/examples. Added ~~~~~ - ``core.executor.SimindExecutor`` as a minimal subprocess runner for SIMIND. - Expanded unit coverage for connector/adaptor behavior: - native STIR/SIRF adaptor validation and forwarding behavior - PyTomography adaptor connector wiring and axis-order forwarding - additional ``configure_voxel_phantom`` edge cases in Python connector tests - Geometry documentation note for STIR/SIRF voxel-size extraction fallback behavior. Changed ~~~~~~~ - Renamed the PyPI distribution to ``simind-python-connector``. - Renamed the import package to ``simind_python_connector``. - Updated user-facing branding to ``simind-python-connector`` and added explicit non-affiliation and external-SIMIND-install disclaimers in README/docs. - ``SimindPythonConnector`` is now the central execution path for adaptor workflows. - ``StirSimindAdaptor`` and ``SirfSimindAdaptor`` now delegate SIMIND setup/run through ``SimindPythonConnector`` and return native backend projection types. - ``PyTomographySimindAdaptor`` remains focused on SIMIND I/O adaptation and tensor conversion only. - README and docs pages were rewritten with user-facing guidance for connector and adaptor workflows. Fixed ~~~~~ - STIR/SIRF voxel-size extraction fallback now supports both 4-element and 3-element ``get_grid_spacing()`` outputs, plus non-iterable coordinate objects (for example, STIR ``Float3BasicCoordinate``) for z-spacing extraction. - ``SimindExecutor`` command invocation hardened with explicit token validation and ``shell=False`` execution. [0.4.0] - 2026-02-26 -------------------- **Breaking Changes** ~~~~~~~~~~~~~~~~~~~~ **Example suite renumbering and adaptor split** The old monolithic OSEM examples were replaced with backend-specific adaptor examples: - ``07A_stir_adaptor_osem.py`` - ``07B_sirf_adaptor_osem.py`` - ``07C_pytomography_adaptor_osem.py`` - ``08A/08B/08C`` DICOM-driven adaptor examples Legacy numbering and naming references should be updated to the new files. **Connector/adaptor naming normalization** Public docs and examples now consistently use: - ``SimindPythonConnector`` for backend-agnostic NumPy workflows - ``StirSimindAdaptor`` / ``SirfSimindAdaptor`` / ``PyTomographySimindAdaptor`` for backend-native workflows Added ~~~~~ - Geometry documentation for SIMIND/STIR/SIRF/PyTomography axis conventions (``docs/geometry.rst``). - Container scripts for split validation and examples: ``scripts/run_container_validation.sh`` and ``scripts/run_container_examples.sh``. - Backend-isolation and connector/adaptor unit tests (markers + import gating). - Example profile config (``configs/Example.yaml``) and Python-connector helper flow for lightweight deterministic runs. Changed ~~~~~~~ - Core examples 01-06 now use the pure Python connector path. - OSEM examples now use dedicated adaptor paths and backend-specific outputs. - Documentation updated for new example numbering, runtime flags, and testing entry points. - Versioning aligned across package metadata and docs. Fixed ~~~~~ - PENETRATE component header parsing via ``.bXX`` outputs in the Python connector. - SIMIND optional-availability handling in container scripts (fail-fast option plus skip-by-default behavior when binary is absent). - Quantization scaling docs and naming consistency (``quantization_scale``). [0.3.0] - 2025-01-23 -------------------- **Breaking Changes** ~~~~~~~~~~~~~~~~~~~~ **Backend-Agnostic Public API** All public methods now return wrapped backend-agnostic objects instead of native SIRF/STIR objects: - ``SimindSimulator.get_total_output()`` → Returns ``AcquisitionDataInterface`` - ``SimindSimulator.get_scatter_output()`` → Returns ``AcquisitionDataInterface`` - ``SimindSimulator.get_primary_output()`` → Returns ``AcquisitionDataInterface`` - ``SimindSimulator.get_penetrate_output()`` → Returns ``AcquisitionDataInterface`` - ``SimindToStirConverter.convert(return_object=True)`` → Returns ``AcquisitionDataInterface`` - ``convert_simind_to_stir()`` → Returns ``AcquisitionDataInterface`` **Migration**: Use ``.native_object`` property to access underlying SIRF/STIR objects if needed for backend-specific operations. Wrapper objects support common operations (``.write()``, ``.sum()``, ``.as_array()``, etc.). **Backend-Agnostic extract_attributes_from_stir()** Function now only accepts filepath (string), not acquisition data objects: - **Before**: ``extract_attributes_from_stir(acq_obj)`` or ``extract_attributes_from_stir(filepath)`` - **After**: ``extract_attributes_from_stir(filepath)`` only - **Migration**: If you have an acquisition object, write it to a file first: ``acq_obj.write(temp_path); extract_attributes_from_stir(temp_path)`` Changed ~~~~~~~ **Enhanced Factory Functions** Factory functions now accept multiple input types: - String filepath → Loads and wraps - Already wrapped object → Returns as-is (idempotent) - Native SIRF/STIR object → Wraps it - ``None`` → Creates empty object (SIRF only) **Internal Template Storage** ``SimindSimulator`` now stores both template filepath (backend-agnostic) and wrapped object for efficient operations. Fixed ~~~~~ **Critical: Coordinator Update Timing Fix** Fixed off-by-one error in coordinator update scheduling: - **Issue**: Coordinator updates were occurring at iteration N, but callbacks (UpdateEtaCallback, ArmijoTriggerCallback) ran AFTER the step was taken, causing Armijo line search to run one iteration late with a mismatched objective function - **Fix**: Modified ``SimindCoordinator.should_update()`` and ``StirPsfCoordinator.should_update()`` to trigger updates ONE iteration early (at ``correction_update_interval - 1`` instead of ``correction_update_interval``) - **Impact**: Ensures proper callback ordering for convergent optimization - **Result**: Eliminates divergence caused by taking steps with wrong objective, ensures convexity is maintained Added ~~~~~ **Backend Abstraction Layer** New backend system supporting both SIRF and STIR Python: - Factory functions: ``create_image_data()``, ``create_acquisition_data()`` - Utility functions: ``get_backend()``, ``set_backend()``, ``is_sirf_backend()`` - Wrapper classes: ``SirfImageData``, ``SirfAcquisitionData``, ``StirImageData``, ``StirAcquisitionData`` - See :doc:`backends` for complete documentation **Utility Functions for STIR Compatibility** - ``to_projdata_in_memory()``: Convert ProjData to ProjDataInMemory for arithmetic operations (STIR Python compatibility) - Fixes arithmetic operations (``+``, ``-``, ``*``) on STIR ProjData objects - Works transparently with both SIRF and STIR backends **Example Updates** - Updated examples 01-06 to support both SIRF and STIR Python backends - Added ``--backend`` command-line option to force specific backend - Fixed arithmetic operations in example 03 (TEW correction) **ShiftedKullbackLeibler Support** - Added conditional support for SETR's ``ShiftedKullbackLeibler`` in data partitioning - New ``use_shifted_kl`` parameter in ``partition_data_with_cil_objectives()`` function - Automatic fallback to standard ``KullbackLeibler`` when SETR is not available **ResidualCorrectedKullbackLeibler Jordan Split** - Residual-aware KL now decomposes residuals into positive/negative parts - Keeps the objective convex and allows arbitrary residual signs Changed ~~~~~~~ **Documentation Organization** - Moved BACKENDS.md to docs/backends.rst (reStructuredText format) - Updated docs/changelog.rst with comprehensive change history - Added backends page to documentation index Version 0.2.1 ------------- New Features ~~~~~~~~~~~~ **Schneider2000 Density Conversion** Advanced 44-segment piecewise model for HU-to-density conversion: - ``hu_to_density_schneider()``: Interpolated conversion using all 44 tissue segments - ``hu_to_density_schneider_piecewise()``: Exact piecewise conversion matching lookup table - ``get_schneider_tissue_info()``: Lookup tissue information for specific HU values - ``compare_density_methods()``: Compare bilinear vs Schneider methods - Enhanced Accuracy: ~0.17-0.19 g/cm³ improved accuracy over bilinear model - Comprehensive Tissue Support: Covers air, lung variations, soft tissues, bones, and metal implants - New Example: ``06_schneider_density_conversion.py`` demonstrates advanced density conversion **Coordinator Architecture** Efficient subset reconstruction with shared Monte Carlo corrections: - ``SimindCoordinator``: Manages single SIMIND simulation for all subsets - ``SimindSubsetProjector``: Projector for individual subsets - CIL partitioner utilities for subset-based reconstruction - 12× faster for 12-subset reconstruction - See coordinator-related API/docs sections for implementation details **SimindProjector AcquisitionModel Interface** Drop-in replacement for SIRF AcquisitionModel with Monte Carlo corrections: - Complete AcquisitionModel API compatibility - Three correction modes (residual only, additive only, both) - Automatic iteration tracking - Intelligent scaling strategy - CIL framework compatibility Improvements ~~~~~~~~~~~~ - Extended documentation with density conversion methods comparison - Comprehensive test suite for Schneider functionality (16 new tests) - Enhanced attenuation conversion utilities with clinical-grade accuracy - MPI parallel execution support for SIMIND simulations - STIR CUDARelativeDifferencePrior integration Fixed ~~~~~ **Critical: Non-Circular Orbit Support** Multiple fixes for proper orbit file handling: - Issue 1: Missing orbit file creation (AcquisitionData.get_info() doesn't include orbit/radii) - Issue 2: Missing unit conversion (radii in mm instead of cm) - Issue 3: File naming collision (input orbit file overwritten) - Issue 4: Incorrect command argument order - Issue 5: Full path instead of filename **Critical: Subset View Index Out of Range** - Fixed coordinator receiving subset acquisition models but attempting to extract using full-data indices - Coordinator now requires full-data acquisition models passed to ``__init__()`` **Module Import Issues** - Fixed RecursionError in lazy imports (``converters``, ``utils``, ``builders`` modules) - Wrapped SIRF imports in try/except blocks for better fallback behavior Version 0.2.0 ------------- Breaking Changes ~~~~~~~~~~~~~~~~ - Modified config file loading mechanism in SimulationConfig class - Updated API for configuration initialization New Features ~~~~~~~~~~~~ - Comprehensive test suite with unit and integration tests - Enhanced documentation with ReadTheDocs support - GitHub Actions CI/CD pipeline - Auto-generated API documentation - Professional documentation structure Improvements ~~~~~~~~~~~~ - Better test coverage for all components - Improved code quality with automated checks - Streamlined README for better user experience Version 0.1.1 ------------- - Bug fixes and minor improvements from initial release Version 0.1.0 ------------- - Initial release with core functionalities and examples