simind-python-connector 1.0.0__py3-none-any.whl
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.
- simind_python_connector/__init__.py +72 -0
- simind_python_connector/backends/__init__.py +480 -0
- simind_python_connector/backends/base.py +387 -0
- simind_python_connector/backends/sirf_backend.py +309 -0
- simind_python_connector/backends/stir_backend.py +395 -0
- simind_python_connector/builders/__init__.py +19 -0
- simind_python_connector/builders/acquisition_builder.py +526 -0
- simind_python_connector/builders/image_builder.py +217 -0
- simind_python_connector/configs/AnyScan.yaml +420 -0
- simind_python_connector/configs/Discovery670.yaml +412 -0
- simind_python_connector/configs/Example.yaml +420 -0
- simind_python_connector/configs/MLD001_SCAN0.yaml +426 -0
- simind_python_connector/configs/__init__.py +41 -0
- simind_python_connector/configs/input.smc +51 -0
- simind_python_connector/connectors/__init__.py +24 -0
- simind_python_connector/connectors/_spacing.py +69 -0
- simind_python_connector/connectors/base.py +40 -0
- simind_python_connector/connectors/python_connector.py +355 -0
- simind_python_connector/connectors/pytomography_adaptor.py +263 -0
- simind_python_connector/connectors/sirf_adaptor.py +164 -0
- simind_python_connector/connectors/stir_adaptor.py +164 -0
- simind_python_connector/converters/__init__.py +16 -0
- simind_python_connector/converters/attenuation.py +367 -0
- simind_python_connector/converters/dicom_to_stir.py +3 -0
- simind_python_connector/converters/simind_to_stir.py +769 -0
- simind_python_connector/core/__init__.py +7 -0
- simind_python_connector/core/config.py +939 -0
- simind_python_connector/core/executor.py +96 -0
- simind_python_connector/core/types.py +203 -0
- simind_python_connector/data/Schneider2000.json +222 -0
- simind_python_connector/data/__init__.py +25 -0
- simind_python_connector/data/bone.atn +187 -0
- simind_python_connector/data/h2o.atn +92 -0
- simind_python_connector/utils/__init__.py +120 -0
- simind_python_connector/utils/backend_access.py +121 -0
- simind_python_connector/utils/import_helpers.py +74 -0
- simind_python_connector/utils/interfile_numpy.py +195 -0
- simind_python_connector/utils/interfile_parser.py +175 -0
- simind_python_connector/utils/io_utils.py +14 -0
- simind_python_connector/utils/simind_utils.py +70 -0
- simind_python_connector/utils/sirf_stir_utils.py +194 -0
- simind_python_connector/utils/stir_utils.py +485 -0
- simind_python_connector-1.0.0.dist-info/METADATA +274 -0
- simind_python_connector-1.0.0.dist-info/RECORD +47 -0
- simind_python_connector-1.0.0.dist-info/WHEEL +5 -0
- simind_python_connector-1.0.0.dist-info/licenses/LICENSE +195 -0
- simind_python_connector-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
metadata:
|
|
2
|
+
comment: MLD001_SCAN0
|
|
3
|
+
source_file: MLD001_SCAN0.smc
|
|
4
|
+
parameters:
|
|
5
|
+
source:
|
|
6
|
+
photon_energy:
|
|
7
|
+
index: 1
|
|
8
|
+
value: 208.0
|
|
9
|
+
description: Photon energy in keV (e.g., 140 for 99mTc, 208 for 177Lu)
|
|
10
|
+
source_half_length:
|
|
11
|
+
index: 2
|
|
12
|
+
value: 28.267
|
|
13
|
+
description: Source half-length in cm
|
|
14
|
+
source_half_width:
|
|
15
|
+
index: 3
|
|
16
|
+
value: 28.267
|
|
17
|
+
description: Source half-width in cm
|
|
18
|
+
source_half_height:
|
|
19
|
+
index: 4
|
|
20
|
+
value: 28.267
|
|
21
|
+
description: Source half-height in cm
|
|
22
|
+
source_type:
|
|
23
|
+
index: 15
|
|
24
|
+
value: -1.0
|
|
25
|
+
description: Source type code (0=sphere, 1=cylinder, etc.) - check SIMIND manual
|
|
26
|
+
shift_source_x:
|
|
27
|
+
index: 16
|
|
28
|
+
value: 0.0
|
|
29
|
+
description: Shift of source in x-direction (cm)
|
|
30
|
+
shift_source_y:
|
|
31
|
+
index: 17
|
|
32
|
+
value: 0.0
|
|
33
|
+
description: Shift of source in y-direction (cm)
|
|
34
|
+
shift_source_z:
|
|
35
|
+
index: 18
|
|
36
|
+
value: 0.0
|
|
37
|
+
description: Shift of source in z-direction (cm)
|
|
38
|
+
photon_direction:
|
|
39
|
+
index: 19
|
|
40
|
+
value: 2.0
|
|
41
|
+
description: Photon direction code (2=isotropic typical)
|
|
42
|
+
emitted_photons_per_decay:
|
|
43
|
+
index: 24
|
|
44
|
+
value: 0.879
|
|
45
|
+
description: Number of photons emitted per decay
|
|
46
|
+
source_activity:
|
|
47
|
+
index: 25
|
|
48
|
+
value: 21238.0
|
|
49
|
+
description: Source activity in MBq
|
|
50
|
+
number_photon_histories:
|
|
51
|
+
index: 26
|
|
52
|
+
value: 1.0
|
|
53
|
+
description: Number of photon histories to simulate (10^6 typical minimum)
|
|
54
|
+
matrix_size_source_map_i:
|
|
55
|
+
index: 79
|
|
56
|
+
value: 128.0
|
|
57
|
+
description: Matrix size for source map (i-direction) - 128x128 standard
|
|
58
|
+
matrix_size_source_map_j:
|
|
59
|
+
index: 82
|
|
60
|
+
value: 0.0
|
|
61
|
+
description: Matrix size for source map (j-direction) - 128x128 standard
|
|
62
|
+
phantom:
|
|
63
|
+
phantom_half_length:
|
|
64
|
+
index: 5
|
|
65
|
+
value: 28.267
|
|
66
|
+
description: Phantom half-length in cm
|
|
67
|
+
phantom_half_width:
|
|
68
|
+
index: 6
|
|
69
|
+
value: 28.267
|
|
70
|
+
description: Phantom half-width in cm
|
|
71
|
+
phantom_half_height:
|
|
72
|
+
index: 7
|
|
73
|
+
value: 28.267
|
|
74
|
+
description: Phantom half-height in cm
|
|
75
|
+
phantom_type:
|
|
76
|
+
index: 14
|
|
77
|
+
value: -1.0
|
|
78
|
+
description: Phantom type code
|
|
79
|
+
pixel_size_density_images:
|
|
80
|
+
index: 31
|
|
81
|
+
value: 0.44167
|
|
82
|
+
description: Pixel size for density images (cm)
|
|
83
|
+
orientation_density_images:
|
|
84
|
+
index: 32
|
|
85
|
+
value: 0.0
|
|
86
|
+
description: Orientation of density images
|
|
87
|
+
first_image_density_images:
|
|
88
|
+
index: 33
|
|
89
|
+
value: 1.0
|
|
90
|
+
description: First image number for density images
|
|
91
|
+
number_density_images:
|
|
92
|
+
index: 34
|
|
93
|
+
value: 128.0
|
|
94
|
+
description: Number of density images
|
|
95
|
+
density_limit_border:
|
|
96
|
+
index: 35
|
|
97
|
+
value: 0.01
|
|
98
|
+
description: Density limit at border
|
|
99
|
+
shift_density_images_y:
|
|
100
|
+
index: 36
|
|
101
|
+
value: 0.0
|
|
102
|
+
description: Shift of density images in y-direction (cm)
|
|
103
|
+
shift_density_images_z:
|
|
104
|
+
index: 37
|
|
105
|
+
value: 0.0
|
|
106
|
+
description: Shift of density images in z-direction (cm)
|
|
107
|
+
shift_density_images_x:
|
|
108
|
+
index: 39
|
|
109
|
+
value: 0.0
|
|
110
|
+
description: Shift of density images in x-direction (cm)
|
|
111
|
+
density_threshold_soft_bone:
|
|
112
|
+
index: 40
|
|
113
|
+
value: 0.0
|
|
114
|
+
description: Density threshold for soft bone
|
|
115
|
+
code_definitions_zubal_phantom:
|
|
116
|
+
index: 45
|
|
117
|
+
value: 1.0
|
|
118
|
+
description: Code definitions for Zubal phantom
|
|
119
|
+
matrix_size_density_map_i:
|
|
120
|
+
index: 78
|
|
121
|
+
value: 128.0
|
|
122
|
+
description: Matrix size for density map (i-direction)
|
|
123
|
+
matrix_size_density_map_j:
|
|
124
|
+
index: 81
|
|
125
|
+
value: 0.0
|
|
126
|
+
description: Matrix size for density map (j-direction)
|
|
127
|
+
detector_crystal:
|
|
128
|
+
crystal_half_length_radius:
|
|
129
|
+
index: 8
|
|
130
|
+
value: 20.0
|
|
131
|
+
description: Crystal half-length/radius in cm (circular detectors use radius)
|
|
132
|
+
crystal_thickness:
|
|
133
|
+
index: 9
|
|
134
|
+
value: 0.9525
|
|
135
|
+
description: 'Crystal thickness in cm (NaI(Tl) typical: 0.95cm)'
|
|
136
|
+
crystal_half_width:
|
|
137
|
+
index: 10
|
|
138
|
+
value: 27.0
|
|
139
|
+
description: Crystal half-width in cm (for rectangular crystals)
|
|
140
|
+
height_to_detector_surface:
|
|
141
|
+
index: 12
|
|
142
|
+
value: 20.0
|
|
143
|
+
description: Height from collimator to detector surface (cm)
|
|
144
|
+
cover_thickness:
|
|
145
|
+
index: 13
|
|
146
|
+
value: 0.1
|
|
147
|
+
description: Cover thickness in cm (typically Al or Be window)
|
|
148
|
+
energy_resolution:
|
|
149
|
+
index: 22
|
|
150
|
+
value: 12.0
|
|
151
|
+
description: Energy resolution FWHM (%) at reference energy (9-12% typical at
|
|
152
|
+
140keV)
|
|
153
|
+
intrinsic_resolution:
|
|
154
|
+
index: 23
|
|
155
|
+
value: 0.55
|
|
156
|
+
description: Intrinsic spatial resolution FWHM (cm) (3-4mm typical)
|
|
157
|
+
voltage:
|
|
158
|
+
index: 91
|
|
159
|
+
value: 0.0
|
|
160
|
+
description: Applied voltage (V) for semiconductor detectors
|
|
161
|
+
mobility_life_electrons:
|
|
162
|
+
index: 92
|
|
163
|
+
value: 0.0
|
|
164
|
+
description: Mobility-life product for electrons (semiconductor detectors)
|
|
165
|
+
mobility_life_holes:
|
|
166
|
+
index: 93
|
|
167
|
+
value: 0.0
|
|
168
|
+
description: Mobility-life product for holes (semiconductor detectors)
|
|
169
|
+
contact_pad_size:
|
|
170
|
+
index: 94
|
|
171
|
+
value: 0.0
|
|
172
|
+
description: Contact pad size (cm) for pixelated detectors
|
|
173
|
+
anode_element_pitch:
|
|
174
|
+
index: 95
|
|
175
|
+
value: 0.0
|
|
176
|
+
description: Anode element pitch (cm) for pixelated detectors
|
|
177
|
+
exponential_decay_constant_tau:
|
|
178
|
+
index: 96
|
|
179
|
+
value: 0.0
|
|
180
|
+
description: Exponential decay constant tau for charge collection
|
|
181
|
+
components_hecht_formula:
|
|
182
|
+
index: 97
|
|
183
|
+
value: 0.0
|
|
184
|
+
description: Components for Hecht formula (charge collection efficiency)
|
|
185
|
+
energy_resolution_model:
|
|
186
|
+
index: 98
|
|
187
|
+
value: 0.0
|
|
188
|
+
description: Energy resolution model code (check SIMIND manual for options)
|
|
189
|
+
cloud_mobility:
|
|
190
|
+
index: 99
|
|
191
|
+
value: 0.0
|
|
192
|
+
description: Cloud mobility parameter for charge collection
|
|
193
|
+
detector_array_size_i:
|
|
194
|
+
index: 100
|
|
195
|
+
value: 0.0
|
|
196
|
+
description: Detector array size (i-direction) for pixelated systems
|
|
197
|
+
detector_array_size_j:
|
|
198
|
+
index: 101
|
|
199
|
+
value: 0.0
|
|
200
|
+
description: Detector array size (j-direction) for pixelated systems
|
|
201
|
+
collimator:
|
|
202
|
+
hole_size_x:
|
|
203
|
+
index: 46
|
|
204
|
+
value: 0.25
|
|
205
|
+
description: 'Collimator hole diameter (cm) - LEHR: 0.111cm, HEGP: 0.24cm'
|
|
206
|
+
hole_size_y:
|
|
207
|
+
index: 47
|
|
208
|
+
value: 0.28868
|
|
209
|
+
description: Collimator hole diameter (cm) - should match hole_size_x for round
|
|
210
|
+
holes
|
|
211
|
+
distance_between_holes_x:
|
|
212
|
+
index: 48
|
|
213
|
+
value: 0.03
|
|
214
|
+
description: 'Distance between hole centers (cm) - LEHR: 0.16cm septal thickness'
|
|
215
|
+
distance_between_holes_y:
|
|
216
|
+
index: 49
|
|
217
|
+
value: 0.1963
|
|
218
|
+
description: Distance between hole centers (cm) - hexagonal pattern spacing
|
|
219
|
+
shift_center_hole_x:
|
|
220
|
+
index: 50
|
|
221
|
+
value: 0.14
|
|
222
|
+
description: Shift of center hole in x-direction (cm) for alignment
|
|
223
|
+
shift_center_hole_y:
|
|
224
|
+
index: 51
|
|
225
|
+
value: 0.24249
|
|
226
|
+
description: Shift of center hole in y-direction (cm) for alignment
|
|
227
|
+
collimator_thickness:
|
|
228
|
+
index: 52
|
|
229
|
+
value: 4.1
|
|
230
|
+
description: 'Collimator thickness (cm) - LEHR: 2.405cm, HEGP: 5.9cm'
|
|
231
|
+
collimator_routine:
|
|
232
|
+
index: 53
|
|
233
|
+
value: 0.0
|
|
234
|
+
description: Collimator routine code (0=no collimator, 1=parallel holes, etc.)
|
|
235
|
+
hole_shape:
|
|
236
|
+
index: 54
|
|
237
|
+
value: 3.0
|
|
238
|
+
description: Hole shape code (0=round, 1=square, 2=hexagonal)
|
|
239
|
+
distance_collimator_detector:
|
|
240
|
+
index: 56
|
|
241
|
+
value: 0.0
|
|
242
|
+
description: Distance from collimator face to detector surface (cm)
|
|
243
|
+
random_collimator_movement:
|
|
244
|
+
index: 59
|
|
245
|
+
value: 0.0
|
|
246
|
+
description: Random collimator movement parameter (for manufacturing variations)
|
|
247
|
+
energy_analysis:
|
|
248
|
+
upper_window_threshold:
|
|
249
|
+
index: 20
|
|
250
|
+
value: -100.0
|
|
251
|
+
description: Upper energy window threshold (keV) - set to -100 for automatic
|
|
252
|
+
lower_window_threshold:
|
|
253
|
+
index: 21
|
|
254
|
+
value: -100.0
|
|
255
|
+
description: Lower energy window threshold (keV) - set to -100 for automatic
|
|
256
|
+
kev_per_channel:
|
|
257
|
+
index: 27
|
|
258
|
+
value: 0.5
|
|
259
|
+
description: keV per channel for energy spectrum binning
|
|
260
|
+
energy_spectra_channels:
|
|
261
|
+
index: 80
|
|
262
|
+
value: 512.0
|
|
263
|
+
description: Number of energy spectra channels (512 typical)
|
|
264
|
+
cutoff_energy_terminate_photon_history:
|
|
265
|
+
index: 83
|
|
266
|
+
value: 0.0
|
|
267
|
+
description: Cutoff energy to terminate photon history (keV)
|
|
268
|
+
spect_imaging:
|
|
269
|
+
pixel_size_simulated_image:
|
|
270
|
+
index: 28
|
|
271
|
+
value: 0.44167
|
|
272
|
+
description: Pixel size for simulated images (cm) - affects resolution vs FOV
|
|
273
|
+
spect_no_projections:
|
|
274
|
+
index: 29
|
|
275
|
+
value: 120.0
|
|
276
|
+
description: Number of SPECT projections (64, 120, 128 typical)
|
|
277
|
+
spect_rotation:
|
|
278
|
+
index: 30
|
|
279
|
+
value: 2.0
|
|
280
|
+
description: "SPECT rotation parameter (2=360\xB0 typical)"
|
|
281
|
+
spect_starting_angle:
|
|
282
|
+
index: 41
|
|
283
|
+
value: 0.0
|
|
284
|
+
description: "SPECT starting angle (degrees) - 0\xB0 = anterior"
|
|
285
|
+
spect_orbital_rotation_fraction:
|
|
286
|
+
index: 42
|
|
287
|
+
value: -1.0
|
|
288
|
+
description: SPECT orbital rotation fraction (1.0 = full orbit)
|
|
289
|
+
camera_offset_x:
|
|
290
|
+
index: 43
|
|
291
|
+
value: 0.0
|
|
292
|
+
description: Camera offset in x-direction (cm) from rotation center
|
|
293
|
+
camera_offset_y:
|
|
294
|
+
index: 44
|
|
295
|
+
value: 0.0
|
|
296
|
+
description: Camera offset in y-direction (cm) from rotation center
|
|
297
|
+
matrix_size_image_i:
|
|
298
|
+
index: 76
|
|
299
|
+
value: 128.0
|
|
300
|
+
description: Matrix size for images (i-direction) - 128x128 standard
|
|
301
|
+
matrix_size_image_j:
|
|
302
|
+
index: 77
|
|
303
|
+
value: 128.0
|
|
304
|
+
description: Matrix size for images (j-direction) - 128x128 standard
|
|
305
|
+
simulation_control:
|
|
306
|
+
step_size_photon_path_simulation:
|
|
307
|
+
index: 38
|
|
308
|
+
value: 0.44167
|
|
309
|
+
description: Step size for photon path simulation (cm) - smaller = more accurate
|
|
310
|
+
type:
|
|
311
|
+
index: 55
|
|
312
|
+
value: 0.0
|
|
313
|
+
description: General type parameter - check SIMIND manual for current meaning
|
|
314
|
+
scoring_routine:
|
|
315
|
+
index: 84
|
|
316
|
+
value: 1.0
|
|
317
|
+
description: Scoring routine code - affects output data collection
|
|
318
|
+
csv_file_content:
|
|
319
|
+
index: 85
|
|
320
|
+
value: 0.0
|
|
321
|
+
description: CSV file content parameter - for custom data output
|
|
322
|
+
unused_parameters:
|
|
323
|
+
unused_parameter_1:
|
|
324
|
+
index: 57
|
|
325
|
+
value: 0.0
|
|
326
|
+
description: Unused parameter 1 - reserved for future use
|
|
327
|
+
unused_parameter_2:
|
|
328
|
+
index: 58
|
|
329
|
+
value: 0.0
|
|
330
|
+
description: Unused parameter 2 - reserved for future use
|
|
331
|
+
unused_parameter_3:
|
|
332
|
+
index: 60
|
|
333
|
+
value: 0.0
|
|
334
|
+
description: Unused parameter 3 - reserved for future use
|
|
335
|
+
simulation_flags:
|
|
336
|
+
write_results_to_screen:
|
|
337
|
+
index: 1
|
|
338
|
+
enabled: true
|
|
339
|
+
write_images_to_files:
|
|
340
|
+
index: 2
|
|
341
|
+
enabled: false
|
|
342
|
+
write_pulse_height_distribution_to_file:
|
|
343
|
+
index: 3
|
|
344
|
+
enabled: true
|
|
345
|
+
include_collimator:
|
|
346
|
+
index: 4
|
|
347
|
+
enabled: true
|
|
348
|
+
simulate_spect_study:
|
|
349
|
+
index: 5
|
|
350
|
+
enabled: true
|
|
351
|
+
include_characteristic_xray_emissions:
|
|
352
|
+
index: 6
|
|
353
|
+
enabled: true
|
|
354
|
+
include_backscattering_material:
|
|
355
|
+
index: 7
|
|
356
|
+
enabled: true
|
|
357
|
+
use_random_seed_value:
|
|
358
|
+
index: 8
|
|
359
|
+
enabled: true
|
|
360
|
+
currently_not_in_use:
|
|
361
|
+
index: 9
|
|
362
|
+
enabled: false
|
|
363
|
+
include_interactions_in_cover:
|
|
364
|
+
index: 10
|
|
365
|
+
enabled: true
|
|
366
|
+
include_interactions_in_phantom:
|
|
367
|
+
index: 11
|
|
368
|
+
enabled: true
|
|
369
|
+
include_energy_resolution_in_crystal:
|
|
370
|
+
index: 12
|
|
371
|
+
enabled: true
|
|
372
|
+
include_forced_interactions_in_crystal:
|
|
373
|
+
index: 13
|
|
374
|
+
enabled: false
|
|
375
|
+
write_interfile_header_files:
|
|
376
|
+
index: 14
|
|
377
|
+
enabled: true
|
|
378
|
+
save_aligned_phantom_images:
|
|
379
|
+
index: 15
|
|
380
|
+
enabled: false
|
|
381
|
+
text_variables:
|
|
382
|
+
1: ge-legp
|
|
383
|
+
2: none
|
|
384
|
+
3: none
|
|
385
|
+
4: none
|
|
386
|
+
5: none
|
|
387
|
+
6: none
|
|
388
|
+
7: none
|
|
389
|
+
8: none
|
|
390
|
+
data_files:
|
|
391
|
+
phantom_soft_tissue:
|
|
392
|
+
index: 1
|
|
393
|
+
filepath: h2o
|
|
394
|
+
phantom_bone:
|
|
395
|
+
index: 2
|
|
396
|
+
filepath: bone
|
|
397
|
+
cover_material:
|
|
398
|
+
index: 3
|
|
399
|
+
filepath: al
|
|
400
|
+
crystal_material:
|
|
401
|
+
index: 4
|
|
402
|
+
filepath: nai
|
|
403
|
+
image_file_phantom:
|
|
404
|
+
index: 5
|
|
405
|
+
filepath: tmp_density
|
|
406
|
+
image_file_source:
|
|
407
|
+
index: 6
|
|
408
|
+
filepath: tmp_source
|
|
409
|
+
backscatter_material:
|
|
410
|
+
index: 7
|
|
411
|
+
filepath: pmt
|
|
412
|
+
energy_resolution_file:
|
|
413
|
+
index: 8
|
|
414
|
+
filepath: none
|
|
415
|
+
unknown_file_1:
|
|
416
|
+
index: 9
|
|
417
|
+
filepath: none
|
|
418
|
+
unknown_file_2:
|
|
419
|
+
index: 10
|
|
420
|
+
filepath: none
|
|
421
|
+
unknown_file_3:
|
|
422
|
+
index: 11
|
|
423
|
+
filepath: none
|
|
424
|
+
unknown_file_4:
|
|
425
|
+
index: 12
|
|
426
|
+
filepath: none
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Packaged scanner presets (YAML or SMC).
|
|
3
|
+
|
|
4
|
+
Example
|
|
5
|
+
-------
|
|
6
|
+
>>> from simind_python_connector.configs import get
|
|
7
|
+
>>> cfg = get("AnyScan.yaml") # Path object
|
|
8
|
+
|
|
9
|
+
>>> from simind_python_connector.core import SimulationConfig
|
|
10
|
+
>>> sim_cfg = SimulationConfig(cfg) # load file
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from importlib import resources as _res
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Union
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["get", "list"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get(name: str) -> Path:
|
|
22
|
+
"""
|
|
23
|
+
Return a **Path** to a bundled config file.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
name : str
|
|
28
|
+
Filename, e.g. ``"AnyScan.yaml"`` or ``"input.smc"``.
|
|
29
|
+
"""
|
|
30
|
+
return _res.files(__package__).joinpath(name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def list(ext: Union[str, tuple[str, ...]] = (".yaml", ".smc")) -> list[str]:
|
|
34
|
+
"""
|
|
35
|
+
List files in this package (default: *.yaml / *.smc).
|
|
36
|
+
"""
|
|
37
|
+
return [
|
|
38
|
+
p.name
|
|
39
|
+
for p in _res.files(__package__).iterdir()
|
|
40
|
+
if p.suffix in (ext if isinstance(ext, tuple) else (ext,))
|
|
41
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
SMCV2
|
|
2
|
+
Test simulation as a benchmark
|
|
3
|
+
120 # Basic Change data
|
|
4
|
+
0.14000E+03 0.10000E+00 0.10000E+00 0.10000E+00 0.83200E+01
|
|
5
|
+
0.11000E+02 0.11000E+02 0.25000E+02 0.95300E+00 0.00000E+00
|
|
6
|
+
0.10000E+02 0.25000E+02 0.10000E+00 0.40000E+01 0.50000E+01
|
|
7
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.20000E+01-0.20000E+02
|
|
8
|
+
-0.20000E+02 0.88000E+01 0.34000E+00 0.87900E+00 0.10000E+01
|
|
9
|
+
0.10000E+02 0.50000E+00 0.44000E+00 0.64000E+02 0.00000E+00
|
|
10
|
+
0.10000E+00 0.00000E+00 0.10000E+01 0.18600E+03 0.10000E-01
|
|
11
|
+
0.00000E+00 0.00000E+00 0.10000E+00 0.00000E+00 0.00000E+00
|
|
12
|
+
0.00000E+00 0.10000E+01 0.00000E+00 0.00000E+00 0.10000E+01
|
|
13
|
+
0.25000E+00 0.28868E+00 0.30000E-01 0.19630E+00 0.14000E+00
|
|
14
|
+
0.24249E+00 0.41000E+01 0.00000E+00 0.30000E+01 0.00000E+00
|
|
15
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
16
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
17
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
18
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
19
|
+
0.64000E+02 0.64000E+02 0.25600E+03 0.25600E+03 0.51200E+03
|
|
20
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
21
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
22
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
23
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
24
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
25
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
26
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
27
|
+
0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00
|
|
28
|
+
30 # Simulation flags
|
|
29
|
+
TFTTFFTFFFTTFFFFFFFFFFFFFFFFFF
|
|
30
|
+
8 # Text Variables
|
|
31
|
+
ge-legp
|
|
32
|
+
none
|
|
33
|
+
none
|
|
34
|
+
none
|
|
35
|
+
none
|
|
36
|
+
none
|
|
37
|
+
none
|
|
38
|
+
none
|
|
39
|
+
12 # Data files
|
|
40
|
+
h2o
|
|
41
|
+
h2o
|
|
42
|
+
al
|
|
43
|
+
nai
|
|
44
|
+
cyl_un1
|
|
45
|
+
vox_brn
|
|
46
|
+
pmt
|
|
47
|
+
none
|
|
48
|
+
none
|
|
49
|
+
none
|
|
50
|
+
none
|
|
51
|
+
none
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Connector/adaptor APIs."""
|
|
2
|
+
|
|
3
|
+
from .base import BaseConnector
|
|
4
|
+
from .python_connector import (
|
|
5
|
+
NumpyConnector,
|
|
6
|
+
ProjectionResult,
|
|
7
|
+
RuntimeOperator,
|
|
8
|
+
SimindPythonConnector,
|
|
9
|
+
)
|
|
10
|
+
from .pytomography_adaptor import PyTomographySimindAdaptor
|
|
11
|
+
from .sirf_adaptor import SirfSimindAdaptor
|
|
12
|
+
from .stir_adaptor import StirSimindAdaptor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"BaseConnector",
|
|
17
|
+
"NumpyConnector",
|
|
18
|
+
"PyTomographySimindAdaptor",
|
|
19
|
+
"ProjectionResult",
|
|
20
|
+
"RuntimeOperator",
|
|
21
|
+
"SirfSimindAdaptor",
|
|
22
|
+
"SimindPythonConnector",
|
|
23
|
+
"StirSimindAdaptor",
|
|
24
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Helpers for extracting voxel spacing from SIRF/STIR image objects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _call_or_value(value: Any) -> Any:
|
|
9
|
+
return value() if callable(value) else value
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _voxel_size_from_spacing(spacing: Any) -> float | None:
|
|
13
|
+
try:
|
|
14
|
+
values = tuple(float(v) for v in spacing)
|
|
15
|
+
except Exception:
|
|
16
|
+
values = ()
|
|
17
|
+
|
|
18
|
+
if values:
|
|
19
|
+
if len(values) >= 4:
|
|
20
|
+
return float(values[3])
|
|
21
|
+
if len(values) >= 3:
|
|
22
|
+
return float(values[2])
|
|
23
|
+
|
|
24
|
+
if hasattr(spacing, "z"):
|
|
25
|
+
try:
|
|
26
|
+
return float(_call_or_value(getattr(spacing, "z")))
|
|
27
|
+
except Exception:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
if hasattr(spacing, "at"):
|
|
31
|
+
for index in (3, 2):
|
|
32
|
+
try:
|
|
33
|
+
return float(spacing.at(index))
|
|
34
|
+
except Exception:
|
|
35
|
+
continue
|
|
36
|
+
|
|
37
|
+
for index in (3, 2):
|
|
38
|
+
try:
|
|
39
|
+
return float(spacing[index])
|
|
40
|
+
except Exception:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def extract_voxel_size_mm(image: Any, backend_name: str) -> float:
|
|
47
|
+
"""Extract z voxel spacing in mm from backend image metadata."""
|
|
48
|
+
if hasattr(image, "voxel_sizes"):
|
|
49
|
+
voxel_sizes = image.voxel_sizes()
|
|
50
|
+
try:
|
|
51
|
+
if len(voxel_sizes) >= 3:
|
|
52
|
+
return float(voxel_sizes[2])
|
|
53
|
+
except Exception:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
if hasattr(image, "get_grid_spacing"):
|
|
57
|
+
voxel_size_mm = _voxel_size_from_spacing(image.get_grid_spacing())
|
|
58
|
+
if voxel_size_mm is not None:
|
|
59
|
+
return voxel_size_mm
|
|
60
|
+
raise ValueError(
|
|
61
|
+
f"Unable to read voxel spacing from {backend_name} get_grid_spacing()."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
raise ValueError(
|
|
65
|
+
f"{backend_name} source object must expose voxel_sizes() or get_grid_spacing()."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = ["extract_voxel_size_mm"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Abstract connector contract shared by all connector/adaptor implementations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import Any, Dict, Mapping
|
|
7
|
+
|
|
8
|
+
from simind_python_connector.core.config import SimulationConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseConnector(ABC):
|
|
12
|
+
"""Minimal interface for all SIMIND connector styles."""
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def add_config_value(self, index: int, value: Any) -> None:
|
|
16
|
+
"""Set a SIMIND config value by index."""
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def add_runtime_switch(self, switch: str, value: Any) -> None:
|
|
20
|
+
"""Set one runtime switch."""
|
|
21
|
+
|
|
22
|
+
def set_runtime_switches(self, switches: Mapping[str, Any]) -> None:
|
|
23
|
+
"""Set multiple runtime switches."""
|
|
24
|
+
for switch, value in switches.items():
|
|
25
|
+
self.add_runtime_switch(switch, value)
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def run(self, *args: Any, **kwargs: Any) -> Any:
|
|
29
|
+
"""Execute simulation and return connector-native outputs."""
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def get_outputs(self) -> Dict[str, Any]:
|
|
33
|
+
"""Return outputs from the latest successful run."""
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def get_config(self) -> SimulationConfig:
|
|
37
|
+
"""Return active simulation configuration."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = ["BaseConnector"]
|