multimodars 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. {multimodars-0.3.0 → multimodars-0.3.2}/.github/workflows/CI.yml +46 -16
  2. {multimodars-0.3.0 → multimodars-0.3.2}/.gitignore +13 -1
  3. multimodars-0.3.2/.readthedocs.yaml +19 -0
  4. {multimodars-0.3.0 → multimodars-0.3.2}/CHANGELOG.md +50 -0
  5. {multimodars-0.3.0 → multimodars-0.3.2}/Cargo.lock +139 -1
  6. {multimodars-0.3.0 → multimodars-0.3.2}/Cargo.toml +2 -1
  7. multimodars-0.3.2/PKG-INFO +156 -0
  8. multimodars-0.3.2/README.md +131 -0
  9. {multimodars-0.3.0 → multimodars-0.3.2}/ROADMAP.MD +26 -23
  10. multimodars-0.3.2/benchmarks/BENCHMARK_PLAN.md +143 -0
  11. multimodars-0.3.2/benchmarks/benchmark_bruteforce_stepsize.py +196 -0
  12. multimodars-0.3.2/benchmarks/benchmark_cpu_scaling.py +258 -0
  13. multimodars-0.3.2/benchmarks/results/bruteforce_stepsize.png +0 -0
  14. multimodars-0.3.2/benchmarks/results/cpu_scaling.png +0 -0
  15. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/__init__.py +1 -1
  16. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/ccta/labeling.py +15 -5
  17. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/ccta/manipulating.py +13 -15
  18. {multimodars-0.3.0 → multimodars-0.3.2}/paper/paper.md +6 -2
  19. {multimodars-0.3.0 → multimodars-0.3.2}/pyproject.toml +16 -4
  20. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/adjust_mesh/scale_coronary.rs +31 -41
  21. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/binding/mod.rs +8 -8
  22. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/centerline_align/align_algorithms.rs +3 -3
  23. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/centerline_align/mod.rs +7 -13
  24. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/io/input.rs +4 -2
  25. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/io/mod.rs +1 -1
  26. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/align_between.rs +21 -19
  27. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/align_within.rs +55 -10
  28. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/preprocessing.rs +14 -9
  29. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/process_utils.rs +12 -20
  30. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/to_object/mod.rs +1 -2
  31. multimodars-0.3.0/.readthedocs.yaml +0 -36
  32. multimodars-0.3.0/PKG-INFO +0 -286
  33. multimodars-0.3.0/README.md +0 -249
  34. multimodars-0.3.0/docs/Makefile +0 -20
  35. multimodars-0.3.0/docs/_static/.gitkeep +0 -0
  36. multimodars-0.3.0/docs/api/adjust_ccta.rst +0 -9
  37. multimodars-0.3.0/docs/api/centerline.rst +0 -6
  38. multimodars-0.3.0/docs/api/classes/PyCenterline.rst +0 -12
  39. multimodars-0.3.0/docs/api/classes/PyCenterlinePoint.rst +0 -12
  40. multimodars-0.3.0/docs/api/classes/PyContour.rst +0 -12
  41. multimodars-0.3.0/docs/api/classes/PyContourPoint.rst +0 -12
  42. multimodars-0.3.0/docs/api/classes/PyFrame.rst +0 -12
  43. multimodars-0.3.0/docs/api/classes/PyGeometry.rst +0 -12
  44. multimodars-0.3.0/docs/api/classes/PyGeometryPair.rst +0 -12
  45. multimodars-0.3.0/docs/api/classes/PyInputData.rst +0 -12
  46. multimodars-0.3.0/docs/api/classes/PyRecord.rst +0 -11
  47. multimodars-0.3.0/docs/api/classes/index.rst +0 -16
  48. multimodars-0.3.0/docs/api/converters_and_wrappers.rst +0 -9
  49. multimodars-0.3.0/docs/api/core.rst +0 -8
  50. multimodars-0.3.0/docs/api/index.rst +0 -14
  51. multimodars-0.3.0/docs/api/processing.rst +0 -11
  52. multimodars-0.3.0/docs/api/utilities.rst +0 -4
  53. multimodars-0.3.0/docs/build.sh +0 -13
  54. multimodars-0.3.0/docs/changelog.md +0 -2
  55. multimodars-0.3.0/docs/conf.py +0 -67
  56. multimodars-0.3.0/docs/figures/Alignment3p.png +0 -0
  57. multimodars-0.3.0/docs/figures/animation_stress_induced_systolic_deformation.gif +0 -0
  58. multimodars-0.3.0/docs/figures/anomalous_labeling.jpg +0 -0
  59. multimodars-0.3.0/docs/figures/dataprep.jpg +0 -0
  60. multimodars-0.3.0/docs/figures/initial_labeling.jpg +0 -0
  61. multimodars-0.3.0/docs/figures/scaling.jpg +0 -0
  62. multimodars-0.3.0/docs/index.rst +0 -82
  63. multimodars-0.3.0/docs/installation.rst +0 -53
  64. multimodars-0.3.0/docs/make.bat +0 -35
  65. multimodars-0.3.0/docs/tutorial_ccta.rst +0 -485
  66. multimodars-0.3.0/docs/tutorial_intravascular.rst +0 -621
  67. {multimodars-0.3.0 → multimodars-0.3.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  68. {multimodars-0.3.0 → multimodars-0.3.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  69. {multimodars-0.3.0 → multimodars-0.3.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  70. {multimodars-0.3.0 → multimodars-0.3.2}/.github/workflows/draft-pdf.yml +0 -0
  71. {multimodars-0.3.0 → multimodars-0.3.2}/.pre-commit-config.yaml +0 -0
  72. {multimodars-0.3.0 → multimodars-0.3.2}/CONTRIBUTING.md +0 -0
  73. {multimodars-0.3.0 → multimodars-0.3.2}/LICENSE +0 -0
  74. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/branch_diastolic_contours.csv +0 -0
  75. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/branch_systolic_contours.csv +0 -0
  76. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/calcium_diastolic_contours.csv +0 -0
  77. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/calcium_systolic_contours.csv +0 -0
  78. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/diastolic_contours.csv +0 -0
  79. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/diastolic_reference_points.csv +0 -0
  80. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/eem_diastolic_contours.csv +0 -0
  81. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/eem_systolic_contours.csv +0 -0
  82. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/systolic_contours.csv +0 -0
  83. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/idealized_geometry/systolic_reference_points.csv +0 -0
  84. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/branch_diastolic_contours.csv +0 -0
  85. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/branch_systolic_contours.csv +0 -0
  86. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/calcium_diastolic_contours.csv +0 -0
  87. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/calcium_systolic_contours.csv +0 -0
  88. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/diastolic_contours.csv +0 -0
  89. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/diastolic_reference_points.csv +0 -0
  90. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/eem_diastolic_contours.csv +0 -0
  91. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/eem_systolic_contours.csv +0 -0
  92. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/systolic_contours.csv +0 -0
  93. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_full/systolic_reference_points.csv +0 -0
  94. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_rest/combined_sorted_manual.csv +0 -0
  95. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_rest/diastolic_contours.csv +0 -0
  96. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_rest/diastolic_reference_points.csv +0 -0
  97. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_rest/systolic_contours.csv +0 -0
  98. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_rest/systolic_reference_points.csv +0 -0
  99. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_stress/combined_sorted_manual.csv +0 -0
  100. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_stress/diastolic_contours.csv +0 -0
  101. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_stress/diastolic_reference_points.csv +0 -0
  102. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_stress/systolic_contours.csv +0 -0
  103. {multimodars-0.3.0 → multimodars-0.3.2}/data/fixtures/ivus_stress/systolic_reference_points.csv +0 -0
  104. {multimodars-0.3.0 → multimodars-0.3.2}/media/coronary_artery_disease.jpg +0 -0
  105. {multimodars-0.3.0 → multimodars-0.3.2}/media/dynamic_lumen_changes.png +0 -0
  106. {multimodars-0.3.0 → multimodars-0.3.2}/media/multimoda-rs.jpg +0 -0
  107. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/_converters.py +0 -0
  108. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/_processing.py +0 -0
  109. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/ccta/__init__.py +0 -0
  110. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/ccta/debug_plots.py +0 -0
  111. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/ccta/fixing_functions.py +0 -0
  112. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/io/__init__.py +0 -0
  113. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/io/read_geometrical.py +0 -0
  114. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/io/write_geometries.py +0 -0
  115. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/multimodars.pyi +0 -0
  116. {multimodars-0.3.0 → multimodars-0.3.2}/multimodars/py.typed +0 -0
  117. {multimodars-0.3.0 → multimodars-0.3.2}/paper/REVIEWER1.md +0 -0
  118. {multimodars-0.3.0 → multimodars-0.3.2}/paper/bibliography.bib +0 -0
  119. {multimodars-0.3.0 → multimodars-0.3.2}/paper/figures/Figure1.jpg +0 -0
  120. {multimodars-0.3.0 → multimodars-0.3.2}/paper/figures/Figure2.jpg +0 -0
  121. {multimodars-0.3.0 → multimodars-0.3.2}/paper/figures/Figure3.png +0 -0
  122. {multimodars-0.3.0 → multimodars-0.3.2}/paper/figures/Figure4.jpg +0 -0
  123. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/adjust_mesh/label_coronary.rs +0 -0
  124. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/adjust_mesh/mod.rs +0 -0
  125. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/binding/ccta_py.rs +0 -0
  126. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/binding/mod.rs +0 -0
  127. {multimodars-0.3.0 → multimodars-0.3.2}/src/ccta/mod.rs +0 -0
  128. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/binding/align.rs +0 -0
  129. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/binding/classes.rs +0 -0
  130. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/binding/entry.rs +0 -0
  131. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/centerline_align/preprocessing.rs +0 -0
  132. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/io/geometry.rs +0 -0
  133. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/io/integrity_check.rs +0 -0
  134. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/io/output.rs +0 -0
  135. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/mod.rs +0 -0
  136. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/mod.rs +0 -0
  137. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/postprocessing.rs +0 -0
  138. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/processing/wall.rs +0 -0
  139. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/to_object/interpolation.rs +0 -0
  140. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/to_object/texture.rs +0 -0
  141. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/to_object/write_mtl.rs +0 -0
  142. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/utils/general_utils.rs +0 -0
  143. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/utils/mod.rs +0 -0
  144. {multimodars-0.3.0 → multimodars-0.3.2}/src/intravascular/utils/test_utils.rs +0 -0
  145. {multimodars-0.3.0 → multimodars-0.3.2}/src/lib.rs +0 -0
  146. {multimodars-0.3.0 → multimodars-0.3.2}/tests/conftest.py +0 -0
  147. {multimodars-0.3.0 → multimodars-0.3.2}/tests/test_ccta.py +0 -0
  148. {multimodars-0.3.0 → multimodars-0.3.2}/tests/test_converters.py +0 -0
  149. {multimodars-0.3.0 → multimodars-0.3.2}/tests/test_core.py +0 -0
  150. {multimodars-0.3.0 → multimodars-0.3.2}/tests/test_wrappers.py +0 -0
  151. {multimodars-0.3.0 → multimodars-0.3.2}/tests/tests_todo.md +0 -0
@@ -19,6 +19,31 @@ permissions:
19
19
  contents: read
20
20
 
21
21
  jobs:
22
+ notebook-tests:
23
+ name: Notebook tests
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+ - uses: actions/setup-python@v6
28
+ with:
29
+ python-version: 3.12.x
30
+ - name: Install Rust
31
+ uses: dtolnay/rust-toolchain@stable
32
+ - name: Install system dependencies
33
+ # pymeshlab loads MeshLab filter plugins as shared libraries at import time via
34
+ # load_default_plugins(). On bare Linux runners this requires libopengl0 to be
35
+ # present; without it the call silently fails (PyMeshLabException is caught in
36
+ # pymeshlab's __init__.py) and MeshSet is left with no filter methods, causing
37
+ # AttributeError on any filter call such as meshing_close_holes().
38
+ run: sudo apt-get install -y libopengl0
39
+ - name: Install dependencies
40
+ run: |
41
+ python -m pip install --upgrade pip
42
+ pip install -e '.[meshlab]'
43
+ pip install --group dev
44
+ - name: Run notebook tests
45
+ run: pytest --nbmake docs/notebooks/
46
+
22
47
  python-compat:
23
48
  name: Python ${{ matrix.python-version }} compatibility
24
49
  runs-on: ubuntu-latest
@@ -27,8 +52,8 @@ jobs:
27
52
  matrix:
28
53
  python-version: ['3.10', '3.11', '3.12', '3.13']
29
54
  steps:
30
- - uses: actions/checkout@v4
31
- - uses: actions/setup-python@v5
55
+ - uses: actions/checkout@v6
56
+ - uses: actions/setup-python@v6
32
57
  with:
33
58
  python-version: ${{ matrix.python-version }}
34
59
  - name: Install Rust
@@ -36,7 +61,8 @@ jobs:
36
61
  - name: Install Python deps
37
62
  run: |
38
63
  python -m pip install --upgrade pip
39
- pip install -e .[test]
64
+ pip install -e .
65
+ pip install --group test
40
66
  - name: Run Python tests
41
67
  run: pytest
42
68
 
@@ -50,16 +76,17 @@ jobs:
50
76
  - runner: ubuntu-latest
51
77
  target: aarch64
52
78
  steps:
53
- - uses: actions/checkout@v4
79
+ - uses: actions/checkout@v6
54
80
 
55
- - uses: actions/setup-python@v5
81
+ - uses: actions/setup-python@v6
56
82
  with:
57
83
  python-version: 3.12.x
58
84
 
59
85
  - name: Install Python deps
60
86
  run: |
61
87
  python -m pip install --upgrade pip
62
- pip install -e .[test,docs,maturin]
88
+ pip install -e .
89
+ pip install --group test
63
90
 
64
91
  - name: run Python tests
65
92
  run: pytest
@@ -102,14 +129,15 @@ jobs:
102
129
  - runner: ubuntu-latest
103
130
  target: armv7
104
131
  steps:
105
- - uses: actions/checkout@v4
106
- - uses: actions/setup-python@v5
132
+ - uses: actions/checkout@v6
133
+ - uses: actions/setup-python@v6
107
134
  with:
108
135
  python-version: 3.12.x
109
136
  - name: Install Python deps
110
137
  run: |
111
138
  python -m pip install --upgrade pip
112
- pip install -e .[test,docs,maturin]
139
+ pip install -e .
140
+ pip install --group test
113
141
  - name: run Python tests
114
142
  run: pytest
115
143
  - name: Format Python code
@@ -139,15 +167,16 @@ jobs:
139
167
  - runner: windows-latest
140
168
  target: x64
141
169
  steps:
142
- - uses: actions/checkout@v4
143
- - uses: actions/setup-python@v5
170
+ - uses: actions/checkout@v6
171
+ - uses: actions/setup-python@v6
144
172
  with:
145
173
  python-version: 3.12.x
146
174
  architecture: ${{ matrix.platform.target }}
147
175
  - name: Install Python deps
148
176
  run: |
149
177
  python -m pip install --upgrade pip
150
- pip install -e .[test,docs,maturin]
178
+ pip install -e .
179
+ pip install --group test
151
180
  - name: run Python tests
152
181
  run: pytest
153
182
  - name: Format Python code
@@ -179,14 +208,15 @@ jobs:
179
208
  target: aarch64
180
209
  arch: arm64
181
210
  steps:
182
- - uses: actions/checkout@v4
183
- - uses: actions/setup-python@v5
211
+ - uses: actions/checkout@v6
212
+ - uses: actions/setup-python@v6
184
213
  with:
185
214
  python-version: 3.12.x
186
215
  - name: Install Python deps
187
216
  run: |
188
217
  python -m pip install --upgrade pip
189
- pip install -e .[test,docs,maturin]
218
+ pip install -e .
219
+ pip install --group test
190
220
  - name: run Python tests
191
221
  run: pytest
192
222
  - name: Format Python code
@@ -210,7 +240,7 @@ jobs:
210
240
  sdist:
211
241
  runs-on: ubuntu-latest
212
242
  steps:
213
- - uses: actions/checkout@v4
243
+ - uses: actions/checkout@v6
214
244
  - name: Build sdist
215
245
  uses: PyO3/maturin-action@v1
216
246
  with:
@@ -5,7 +5,19 @@
5
5
  /paper/old
6
6
  .VSCodeCounter
7
7
  /test
8
- /examples
8
+ examples/__pycache__/
9
+ examples/logs/
10
+ examples/data/output/
11
+ examples/data/test/
12
+ examples/data/logs/
13
+ # generated/intermediate STL outputs in data root
14
+ examples/data/all.stl
15
+ examples/data/all_wall.stl
16
+ examples/data/fixed_mesh.stl
17
+ examples/data/prefixed_mesh.stl
18
+ examples/data/lca.stl
19
+ examples/data/rca.stl
20
+ examples/data/aorta.stl
9
21
 
10
22
  # Byte-compiled / optimized / DLL files
11
23
  __pycache__/
@@ -0,0 +1,19 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-22.04
5
+ tools:
6
+ python: "3.12"
7
+ rust: "latest"
8
+ jobs:
9
+ post_create_environment:
10
+ - "$READTHEDOCS_VIRTUALENV_PATH/bin/pip install maturin sphinx sphinx-rtd-theme sphinx-autodoc-typehints myst-nb plotly furo"
11
+
12
+ sphinx:
13
+ configuration: docs/conf.py
14
+ fail_on_warning: true
15
+
16
+ python:
17
+ install:
18
+ - method: pip
19
+ path: .
@@ -3,6 +3,56 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.3.2] - 2026-05-05
7
+
8
+ ### Added
9
+ - Benchmark suite (`benchmarks/`) with two scripts: `benchmark_bruteforce_stepsize.py`
10
+ (step-size scaling, `from_file_full`) and `benchmark_cpu_scaling.py` (core-count
11
+ scaling, `from_array_single`). Results saved to `benchmarks/results/`.
12
+ - Benchmark documentation page (`docs/benchmark.rst`) with result figures and table,
13
+ linked in the ReadTheDocs table of contents.
14
+
15
+ ### Changed
16
+ - `paper/paper.md` Performance section updated with quantified benchmark results and
17
+ corrected parallelisation description.
18
+
19
+ ### Performance
20
+ - Intra-pullback alignment (`search_range`) now parallelises over candidate rotation
21
+ angles via `par_iter` instead of the point-rotation loop. The inner cost-function
22
+ loop is now sequential. This provides enough rayon tasks per frame step to saturate
23
+ all cores: bruteforce scales 6.5× and optimised 4.2× from 2 to 16 cores (previously
24
+ ~1.4× for both). Combined algorithmic + parallelisation gain reaches **38.5×** vs.
25
+ brute-force at 2 cores.
26
+
27
+ ## [0.3.1] - 2026-05-04
28
+
29
+ ### Added
30
+ - Example data and Jupyter notebooks are now included directly in the repository under
31
+ `examples/` — no longer distributed as a release attachment. Both tutorials link to
32
+ the `examples/` directory and cross-reference the rendered notebook pages.
33
+ - CCTA and intravascular Jupyter notebooks (`docs/notebooks/`) are now rendered and served
34
+ in the documentation via `myst-nb`, accessible as `:doc:` references from the tutorials.
35
+ - Detailed explanation of the rolling-sphere and ray-casting labeling algorithms added to
36
+ the CCTA tutorial, including annotated figures.
37
+
38
+ ### Changed
39
+ - README condensed: developer-setup section added, key workflow images included, installation
40
+ and quickstart sections tightened.
41
+ - `plotly` added as a documentation dependency for interactive notebook figures.
42
+ - Improved all print statements in the whole package.
43
+
44
+ ### Fixed
45
+ - CI pipeline now correctly installs optional dependency groups required for the full test
46
+ suite.
47
+ - Notebook tests no longer fail with `AttributeError: MeshSet has no attribute
48
+ 'meshing_close_holes'` on bare Linux runners. pymeshlab silently skips plugin loading when
49
+ `libopengl0` is absent, leaving `MeshSet` with no filter methods; the CI now installs
50
+ `libopengl0` before the notebook test job runs.
51
+
52
+ ### Performance
53
+ - Rust labeling step migrated to `par_iter()` for parallel vertex classification, reducing
54
+ wall time on large meshes.
55
+
6
56
  ## [0.3.0] - 2026-04-30
7
57
 
8
58
  ### Added
@@ -191,6 +191,19 @@ version = "1.1.0"
191
191
  source = "registry+https://github.com/rust-lang/crates.io-index"
192
192
  checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
193
193
 
194
+ [[package]]
195
+ name = "console"
196
+ version = "0.15.11"
197
+ source = "registry+https://github.com/rust-lang/crates.io-index"
198
+ checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
199
+ dependencies = [
200
+ "encode_unicode",
201
+ "libc",
202
+ "once_cell",
203
+ "unicode-width",
204
+ "windows-sys",
205
+ ]
206
+
194
207
  [[package]]
195
208
  name = "core2"
196
209
  version = "0.4.0"
@@ -298,6 +311,12 @@ version = "1.15.0"
298
311
  source = "registry+https://github.com/rust-lang/crates.io-index"
299
312
  checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
300
313
 
314
+ [[package]]
315
+ name = "encode_unicode"
316
+ version = "1.0.0"
317
+ source = "registry+https://github.com/rust-lang/crates.io-index"
318
+ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
319
+
301
320
  [[package]]
302
321
  name = "equator"
303
322
  version = "0.4.2"
@@ -575,6 +594,19 @@ dependencies = [
575
594
  "hashbrown",
576
595
  ]
577
596
 
597
+ [[package]]
598
+ name = "indicatif"
599
+ version = "0.17.11"
600
+ source = "registry+https://github.com/rust-lang/crates.io-index"
601
+ checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
602
+ dependencies = [
603
+ "console",
604
+ "number_prefix",
605
+ "portable-atomic",
606
+ "unicode-width",
607
+ "web-time",
608
+ ]
609
+
578
610
  [[package]]
579
611
  name = "indoc"
580
612
  version = "2.0.6"
@@ -617,6 +649,16 @@ dependencies = [
617
649
  "libc",
618
650
  ]
619
651
 
652
+ [[package]]
653
+ name = "js-sys"
654
+ version = "0.3.82"
655
+ source = "registry+https://github.com/rust-lang/crates.io-index"
656
+ checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
657
+ dependencies = [
658
+ "once_cell",
659
+ "wasm-bindgen",
660
+ ]
661
+
620
662
  [[package]]
621
663
  name = "lebe"
622
664
  version = "0.5.3"
@@ -711,13 +753,14 @@ dependencies = [
711
753
 
712
754
  [[package]]
713
755
  name = "multimodars"
714
- version = "0.3.0"
756
+ version = "0.3.2"
715
757
  dependencies = [
716
758
  "anyhow",
717
759
  "approx",
718
760
  "crossbeam",
719
761
  "csv",
720
762
  "image",
763
+ "indicatif",
721
764
  "nalgebra",
722
765
  "pyo3",
723
766
  "rayon",
@@ -848,6 +891,12 @@ dependencies = [
848
891
  "autocfg",
849
892
  ]
850
893
 
894
+ [[package]]
895
+ name = "number_prefix"
896
+ version = "0.4.0"
897
+ source = "registry+https://github.com/rust-lang/crates.io-index"
898
+ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
899
+
851
900
  [[package]]
852
901
  name = "once_cell"
853
902
  version = "1.21.3"
@@ -1341,6 +1390,12 @@ version = "1.0.18"
1341
1390
  source = "registry+https://github.com/rust-lang/crates.io-index"
1342
1391
  checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
1343
1392
 
1393
+ [[package]]
1394
+ name = "unicode-width"
1395
+ version = "0.2.2"
1396
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1397
+ checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
1398
+
1344
1399
  [[package]]
1345
1400
  name = "unindent"
1346
1401
  version = "0.2.4"
@@ -1412,6 +1467,16 @@ dependencies = [
1412
1467
  "unicode-ident",
1413
1468
  ]
1414
1469
 
1470
+ [[package]]
1471
+ name = "web-time"
1472
+ version = "1.1.0"
1473
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1474
+ checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
1475
+ dependencies = [
1476
+ "js-sys",
1477
+ "wasm-bindgen",
1478
+ ]
1479
+
1415
1480
  [[package]]
1416
1481
  name = "weezl"
1417
1482
  version = "0.1.11"
@@ -1428,6 +1493,79 @@ dependencies = [
1428
1493
  "safe_arch",
1429
1494
  ]
1430
1495
 
1496
+ [[package]]
1497
+ name = "windows-sys"
1498
+ version = "0.59.0"
1499
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1500
+ checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
1501
+ dependencies = [
1502
+ "windows-targets",
1503
+ ]
1504
+
1505
+ [[package]]
1506
+ name = "windows-targets"
1507
+ version = "0.52.6"
1508
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1509
+ checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
1510
+ dependencies = [
1511
+ "windows_aarch64_gnullvm",
1512
+ "windows_aarch64_msvc",
1513
+ "windows_i686_gnu",
1514
+ "windows_i686_gnullvm",
1515
+ "windows_i686_msvc",
1516
+ "windows_x86_64_gnu",
1517
+ "windows_x86_64_gnullvm",
1518
+ "windows_x86_64_msvc",
1519
+ ]
1520
+
1521
+ [[package]]
1522
+ name = "windows_aarch64_gnullvm"
1523
+ version = "0.52.6"
1524
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1525
+ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
1526
+
1527
+ [[package]]
1528
+ name = "windows_aarch64_msvc"
1529
+ version = "0.52.6"
1530
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1531
+ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
1532
+
1533
+ [[package]]
1534
+ name = "windows_i686_gnu"
1535
+ version = "0.52.6"
1536
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1537
+ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
1538
+
1539
+ [[package]]
1540
+ name = "windows_i686_gnullvm"
1541
+ version = "0.52.6"
1542
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1543
+ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
1544
+
1545
+ [[package]]
1546
+ name = "windows_i686_msvc"
1547
+ version = "0.52.6"
1548
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1549
+ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
1550
+
1551
+ [[package]]
1552
+ name = "windows_x86_64_gnu"
1553
+ version = "0.52.6"
1554
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1555
+ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
1556
+
1557
+ [[package]]
1558
+ name = "windows_x86_64_gnullvm"
1559
+ version = "0.52.6"
1560
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1561
+ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
1562
+
1563
+ [[package]]
1564
+ name = "windows_x86_64_msvc"
1565
+ version = "0.52.6"
1566
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1567
+ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1568
+
1431
1569
  [[package]]
1432
1570
  name = "winnow"
1433
1571
  version = "0.7.13"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "multimodars"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  edition = "2021"
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -20,3 +20,4 @@ rayon = "1.7.1"
20
20
  crossbeam = "0.8.4"
21
21
  anyhow = "1.0.100"
22
22
  approx = "0.5"
23
+ indicatif = "0.17"
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: multimodars
3
+ Version: 0.3.2
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Requires-Dist: numpy>=2.0.0,<3.0.0
9
+ Requires-Dist: trimesh>=4.8.0
10
+ Requires-Dist: scipy>=1.15.0
11
+ Requires-Dist: networkx>=3.0
12
+ Requires-Dist: pymeshlab>=2023.12 ; extra == 'meshlab'
13
+ Requires-Dist: pyglet<2 ; extra == 'viz'
14
+ Provides-Extra: meshlab
15
+ Provides-Extra: viz
16
+ License-File: LICENSE
17
+ Summary: A Rust-powered cardiac multi-image modality fusion package
18
+ Author: Anselm W. Stark
19
+ License-Expression: MIT
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
22
+ Project-URL: Homepage, https://github.com/yungselm/multimoda-rs
23
+ Project-URL: Issues, https://github.com/yungselm/multimoda-rs/issues
24
+
25
+ <p align="center">
26
+ <a href="https://github.com/yungselm/multimoda-rs">
27
+ <img
28
+ src="https://raw.githubusercontent.com/yungselm/multimoda-rs/main/media/multimoda-rs.jpg"
29
+ alt="multimoda-rs logo"
30
+ >
31
+ </a>
32
+ </p>
33
+
34
+ [![PyPI](https://img.shields.io/pypi/v/multimodars.svg)](https://pypi.org/project/multimodars)
35
+ [![License](https://img.shields.io/pypi/l/multimodars.svg)](LICENSE)
36
+ [![Docs](https://img.shields.io/readthedocs/multimoda-rs)](https://multimoda-rs.readthedocs.io)
37
+ [![Tests and Build](https://github.com/yungselm/multimoda-rs/actions/workflows/CI.yml/badge.svg)](https://github.com/yungselm/multimoda-rs/actions/workflows/CI.yml)
38
+ [![status](https://joss.theoj.org/papers/24992cb138d85b0bf08f01bc2b384a80/status.svg)](https://joss.theoj.org/papers/24992cb138d85b0bf08f01bc2b384a80)
39
+
40
+
41
+ <figure class="epigraph" style="text-align: center; font-style: italic;">
42
+ <blockquote>
43
+ "One package to fuse them all."
44
+ </blockquote>
45
+ <figcaption>— <cite>The Lord of the Rings (probably)</cite></figcaption>
46
+ </figure>
47
+
48
+ ---
49
+
50
+ > A high‑performance, Rust‑accelerated toolkit for multi‑modality cardiac image fusion and registration ﮩ٨ـﮩﮩ٨ـ♡ﮩ٨ـﮩﮩ٨ـ.
51
+
52
+ ---
53
+
54
+ ## Overview
55
+
56
+ `multimoda-rs` aligns and fuses diverse cardiac imaging modalities — IVUS, OCT and CCTA — into unified high-resolution 3D models. Originally developed to quantify dynamic lumen deformation in coronary artery anomalies (CAAs), it is equally applicable to longitudinal studies (e.g., pre/post-stenting) and general coronary artery disease workflows. The Rust backend parallelizes computationally intensive registration steps for speeds well beyond pure Python.
57
+
58
+ ## Key Features
59
+
60
+ - **Intravascular Registration**: align pullback sequences (rest/stress, diastole/systole) using Hausdorff distance on vessel contours and catheter centroids; four modes: *full*, *double-pair*, *single-pair*, *single*.
61
+ - **Centerline Alignment**: register intravascular geometries onto a CCTA-derived centerline via three-point landmark or manual rotation.
62
+ - **CCTA Fusion**: automatically label CCTA geometries by vessel region and morph them to match intravascular measurements.
63
+ - **Flexible Input**: accepts CSV files ([AIVUS](https://github.com/AI-in-Cardiovascular-Medicine/AIVUS-CAA) format) or raw NumPy arrays.
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pip install multimodars
69
+ ```
70
+
71
+ Optional extras:
72
+
73
+ ```bash
74
+ pip install "multimodars[viz]" # mesh visualisation (pyglet)
75
+ pip install "multimodars[meshlab]" # MeshLab integration
76
+ ```
77
+
78
+ For building from source or the full developer setup (tests, linting, docs), see the [Installation guide](https://multimoda-rs.readthedocs.io/en/latest/installation.html).
79
+
80
+ ## Quick Example
81
+
82
+ Checkout our **[Documentation](https://multimod-rs.readthedocs.io/en/latest)** for in-depth explanations of the functionality and preloaded notebooks including 3D plots. Otherwise clone the repo to follow along the different examples:
83
+
84
+ ```python
85
+ import multimodars as mm
86
+ import numpy as np
87
+
88
+ # Align four intravascular phases (rest-dia, rest-sys, stress-dia, stress-sys)
89
+ rest, stress, dia, sys, _ = mm.from_file_full(
90
+ "examples/data/ivus_rest", # input_path_ab
91
+ "examples/data/ivus_stress", # input_path_cd
92
+ write_obj=True,
93
+ output_path_ab="output/rest",
94
+ output_path_cd="output/stress",
95
+ output_path_ac="output/diastole",
96
+ output_path_bd="output/systole",
97
+ )
98
+
99
+ # Align geometry onto a CCTA-derived centerline
100
+ cl_raw = np.genfromtxt("examples/data/centerline_raw.csv", delimiter=",")
101
+ centerline = mm.numpy_to_centerline(cl_raw)
102
+ aligned_pair, cl_resampled = mm.align_three_point(
103
+ centerline, rest,
104
+ aortic_ref_pt=(12.2605, -201.3643, 1751.0554),
105
+ upper_ref_pt=(11.7567, -202.1920, 1754.7975),
106
+ lower_ref_pt=(15.6605, -202.1920, 1749.9655),
107
+ write=True,
108
+ output_dir="output/aligned",
109
+ )
110
+ ```
111
+
112
+ ## Pipeline
113
+
114
+ **1. Intrapullback alignment** — frames within each pullback are co-registered to remove cardiac-motion artefacts, yielding clean diastolic and systolic geometries:
115
+
116
+ ![Dynamic lumen changes](https://raw.githubusercontent.com/yungselm/multimoda-rs/main/media/dynamic_lumen_changes.png)
117
+
118
+ **2. Inter-pullback alignment** — registered pullbacks (rest vs. stress, diastole vs. systole) are aligned against each other to reveal stress-induced and pulsatile deformation:
119
+
120
+ ![Stress-induced diastolic lumen deformation](https://raw.githubusercontent.com/yungselm/multimoda-rs/main/docs/figures/animation_stress_induced_systolic_deformation.gif)
121
+
122
+ **3. CCTA labeling** — the CCTA-derived geometry is automatically segmented by vessel region (aorta, RCA, LCA, intramural) to prepare it for fusion:
123
+
124
+ ![Initial CCTA labeling](https://raw.githubusercontent.com/yungselm/multimoda-rs/main/docs/figures/initial_labeling.jpg)
125
+
126
+ **4. CCTA–morphing** — the labeled CCTA geometry is morphed along the centerline to match the high-resolution intravascular geometry:
127
+
128
+ ![CCTA scaling](https://raw.githubusercontent.com/yungselm/multimoda-rs/main/docs/figures/scaling.jpg)
129
+
130
+ **5. CCTA/intravascular fusio** — the morphed CCTA geometry is stitched to the intravascular geometry, replacing a section with a high resolution verison:
131
+
132
+ ![CCTA fusion](https://raw.githubusercontent.com/yungselm/multimoda-rs/main/docs/figures/concept.jpg)
133
+
134
+ ## Documentation
135
+
136
+ Full documentation — installation, step-by-step tutorials, interactive (preloaded) Jupyter notebooks, and API reference — is available at **[multimoda-rs.readthedocs.io](https://multimoda-rs.readthedocs.io)**.
137
+
138
+ ## License
139
+
140
+ Distributed under the MIT License. See [LICENSE](LICENSE) for details.
141
+
142
+ ## Citation
143
+
144
+ Please kindly cite the following paper if you use this repository.
145
+
146
+ ```
147
+ @article{stark2025multimodars,
148
+ title = {multimodars: A Rust-powered toolkit for multi-modality cardiac image fusion and registration},
149
+ author = {Stark, Anselm W. and Ilic, Marc and Mokhtari, Ali and Mohammadi Kazaj, Pooya and Graeni, Christoph and Shiri, Isaac},
150
+ journal = {arXiv preprint arXiv:2510.06241},
151
+ year = {2025}
152
+ }
153
+ ```
154
+
155
+ Stark, Anselm W., Marc Ilic, Ali Mokhtari, Pooya Mohammadi Kazaj, Christoph Graeni, and Isaac Shiri. "multimodars: A Rust-powered toolkit for multi-modality cardiac image fusion and registration." arXiv preprint arXiv:2510.06241 (2025).
156
+