Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9d21a70
Segmentation fully works with the MSOT device and updates the setting…
frisograce Jul 12, 2024
fcf4849
Lots of extra type hints :)
frisograce Jul 12, 2024
34fdf5f
Lots of extra type hints :)
frisograce Jul 12, 2024
c3564f0
Updateremove accidental update to tags
frisograce Jul 12, 2024
72fada5
oops shouldnt have removed the tags...
frisograce Jul 12, 2024
271d029
Extra logging fo the new feature
frisograce Jul 15, 2024
766e369
Pep8 updates
frisograce Jul 16, 2024
94b40df
allow all properties to be variable, and thus make them all update fo…
frisograce Jul 23, 2024
83cd643
Merge branch 'refs/heads/develop' into T348_update_msot_for_segmentat…
frisograce Jul 30, 2024
d6316c9
fix device position
frisograce Aug 8, 2024
1e23196
Merge branch 'develop' into T348_update_msot_for_segmentations
frisograce Aug 9, 2024
769dab2
Merge branch 'refs/heads/develop' into T348_update_msot_for_segmentat…
frisograce Aug 15, 2024
5bf740a
Merge branch 'refs/heads/develop' into T348_update_msot_for_segmentat…
frisograce Aug 15, 2024
4dfd698
Merge branch 'develop' into T348_update_msot_for_segmentations
frisograce Aug 15, 2024
1f71625
Merge branch 'develop' into T348_update_msot_for_segmentations
frisograce Aug 15, 2024
bf8f785
Merge branch 'develop' into T348_update_msot_for_segmentations
frisograce Oct 4, 2024
bd497d7
Merge branch 'develop' into T348_update_msot_for_segmentations
jgroehl Nov 18, 2025
5f00050
Update simpa/utils/tags.py
jgroehl Nov 20, 2025
e74e632
Initial plan
Copilot Nov 20, 2025
4c7e3fb
Update simpa/core/device_digital_twins/pa_devices/ithera_msot_acuity.py
jgroehl Nov 20, 2025
f7a1418
Fix TISSUE_LIBRARY to TissueLibrary in ithera_msot_acuity.py
Copilot Nov 20, 2025
09e265d
Merge pull request #434 from IMSY-DKFZ/copilot/sub-pr-349
jgroehl Nov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# SPDX-FileCopyrightText: 2021 Janek Groehl
# SPDX-License-Identifier: MIT
import numpy as np
from typing import Union

from simpa.core.device_digital_twins import DetectionGeometryBase
from simpa.utils import Tags
from simpa import Settings, Tags


class CurvedArrayDetectionGeometry(DetectionGeometryBase):
Expand All @@ -13,17 +14,17 @@ class CurvedArrayDetectionGeometry(DetectionGeometryBase):
with a curved detection geometry. The origin for this device is the center (focus) of the curved array.
"""

def __init__(self, pitch_mm=0.5,
radius_mm=40,
number_detector_elements=256,
def __init__(self, pitch_mm: Union[float, int] = 0.5,
radius_mm: Union[float, int] = 40,
number_detector_elements: int = 256,
detector_element_width_mm=0.24,
detector_element_length_mm=13,
center_frequency_hz=3.96e6,
bandwidth_percent=55,
sampling_frequency_mhz=40,
angular_origin_offset=np.pi,
device_position_mm=None,
field_of_view_extent_mm=None):
angular_origin_offset: Union[float, int] = np.pi,
device_position_mm: np.ndarray = None,
field_of_view_extent_mm: np.ndarray = None):
"""

:param pitch_mm: In-plane distance between the beginning of one detector element to the next detector element.
Expand Down Expand Up @@ -85,6 +86,9 @@ def check_settings_prerequisites(self, global_settings) -> bool:
def update_settings_for_use_of_model_based_volume_creator(self, global_settings):
pass

def update_settings_for_use_of_segmentation_based_volume_creator(self, global_settings: Settings):
pass

def get_detector_element_positions_base_mm(self) -> np.ndarray:

pitch_angle = self.pitch_mm / self.radius_mm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@
from abc import abstractmethod
from simpa.core.device_digital_twins import DigitalDeviceTwinBase
import numpy as np
from typing import Union


class DetectionGeometryBase(DigitalDeviceTwinBase):
"""
This class is the base class for representing all detector geometries.
"""

def __init__(self, number_detector_elements, detector_element_width_mm,
detector_element_length_mm, center_frequency_hz, bandwidth_percent,
sampling_frequency_mhz, device_position_mm: np.ndarray = None,
field_of_view_extent_mm: np.ndarray = None):
def __init__(self, number_detector_elements: int, detector_element_width_mm: Union[float, int],
detector_element_length_mm: Union[float, int], center_frequency_hz: Union[float, int],
bandwidth_percent: Union[float, int], sampling_frequency_mhz: Union[float, int],
device_position_mm: np.ndarray = None, field_of_view_extent_mm: np.ndarray = None):
"""

:param number_detector_elements: Total number of detector elements.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: 2021 Janek Groehl
# SPDX-License-Identifier: MIT
import numpy as np
from typing import Union

from simpa.core.device_digital_twins import DetectionGeometryBase
from simpa.utils import Settings, Tags
Expand All @@ -15,7 +16,7 @@ class LinearArrayDetectionGeometry(DetectionGeometryBase):

"""

def __init__(self, pitch_mm=0.5,
def __init__(self, pitch_mm: Union[float, int] = 0.5,
number_detector_elements=100,
detector_element_width_mm=0.24,
detector_element_length_mm=0.5,
Expand Down Expand Up @@ -51,7 +52,7 @@ def __init__(self, pitch_mm=0.5,
self.pitch_mm = pitch_mm
self.probe_width_mm = (number_detector_elements - 1) * self.pitch_mm

def check_settings_prerequisites(self, global_settings: Settings) -> bool:
def check_settings_prerequisites(self, global_settings) -> bool:
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent type hint: the global_settings parameter has its type hint Settings removed here, but it's added to the same method in other geometry classes (e.g., planar_array.py line 85, curved_array.py line 89). For consistency, either add the type hint here or remove it from the other implementations.

Suggested change
def check_settings_prerequisites(self, global_settings) -> bool:
def check_settings_prerequisites(self, global_settings: Settings) -> bool:

Copilot uses AI. Check for mistakes.
if global_settings[Tags.DIM_VOLUME_X_MM] < self.probe_width_mm + global_settings[Tags.SPACING_MM]:
self.logger.error("Volume x dimension is too small to encompass MSOT device in simulation!"
"Must be at least {} mm but was {} mm"
Expand All @@ -63,6 +64,9 @@ def check_settings_prerequisites(self, global_settings: Settings) -> bool:
def update_settings_for_use_of_model_based_volume_creator(self, global_settings):
pass

def update_settings_for_use_of_segmentation_based_volume_creator(self, global_settings: Settings):
pass

def get_detector_element_positions_base_mm(self) -> np.ndarray:

detector_positions = np.zeros((self.number_detector_elements, 3))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from simpa.core.device_digital_twins import DetectionGeometryBase
from simpa.utils import Settings, Tags
from typing import Union


class PlanarArrayDetectionGeometry(DetectionGeometryBase):
Expand All @@ -14,7 +15,7 @@ class PlanarArrayDetectionGeometry(DetectionGeometryBase):

"""

def __init__(self, pitch_mm=0.5,
def __init__(self, pitch_mm: Union[float, int] = 0.5,
number_detector_elements_x=100,
number_detector_elements_y=100,
detector_element_width_mm=0.24,
Expand Down Expand Up @@ -81,6 +82,9 @@ def check_settings_prerequisites(self, global_settings: Settings) -> bool:
def update_settings_for_use_of_model_based_volume_creator(self, global_settings):
pass

def update_settings_for_use_of_segmentation_based_volume_creator(self, global_settings: Settings):
pass

def get_detector_element_positions_base_mm(self) -> np.ndarray:
detector_element_positions_mm = np.zeros((self.number_detector_elements, 3))
for x in range(self.number_detector_elements_x):
Expand Down
17 changes: 14 additions & 3 deletions simpa/core/device_digital_twins/digital_device_twin_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import uuid
from simpa.utils.serializer import SerializableSIMPAClass
from simpa.utils.calculate import are_equal
from simpa.utils import Settings


class DigitalDeviceTwinBase(SerializableSIMPAClass):
Expand All @@ -17,7 +18,7 @@ class DigitalDeviceTwinBase(SerializableSIMPAClass):
which has representations of both.
"""

def __init__(self, device_position_mm=None, field_of_view_extent_mm=None):
def __init__(self, device_position_mm: np.ndarray = None, field_of_view_extent_mm: np.ndarray = None):
"""
:param device_position_mm: Each device has an internal position which serves as origin for internal \
representations of e.g. detector element positions or illuminator positions.
Expand Down Expand Up @@ -54,7 +55,7 @@ def __eq__(self, other):
return False

@abstractmethod
def check_settings_prerequisites(self, global_settings) -> bool:
def check_settings_prerequisites(self, global_settings: Settings) -> bool:
"""
It might be that certain device geometries need a certain dimensionality of the simulated PAI volume, or that
it requires the existence of certain Tags in the global global_settings.
Expand All @@ -72,7 +73,7 @@ def check_settings_prerequisites(self, global_settings) -> bool:
pass

@abstractmethod
def update_settings_for_use_of_model_based_volume_creator(self, global_settings):
def update_settings_for_use_of_model_based_volume_creator(self, global_settings: Settings):
"""
This method can be overwritten by a PA device if the device poses special constraints to the
volume that should be considered by the model-based volume creator.
Expand All @@ -82,6 +83,16 @@ def update_settings_for_use_of_model_based_volume_creator(self, global_settings)
"""
pass

@abstractmethod
def update_settings_for_use_of_segmentation_based_volume_creator(self, global_settings: Settings):
"""
This method can be overwritten by a PA device if the device poses special constraints to the
volume that should be considered by the segmentation-based volume creator.
:param global_settings: Settings for the entire simulation pipeline.
:type global_settings: Settings
"""
pass

def get_field_of_view_mm(self) -> np.ndarray:
"""
Returns the absolute field of view in mm where the probe position is already
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from simpa.core.device_digital_twins import IlluminationGeometryBase
from simpa.utils import Tags
from typing import Union


class DiskIlluminationGeometry(IlluminationGeometryBase):
Expand All @@ -12,7 +13,7 @@ class DiskIlluminationGeometry(IlluminationGeometryBase):
The device position is defined as the middle of the disk.
"""

def __init__(self, beam_radius_mm=None, device_position_mm=None, field_of_view_extent_mm=None):
def __init__(self, beam_radius_mm: Union[int, float] = None, device_position_mm=None, field_of_view_extent_mm=None):
"""
:param beam_radius_mm: Radius of the disk in mm.
:type beam_radius_mm: int, float
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from collections.abc import Sized
from simpa.core.device_digital_twins import IlluminationGeometryBase
from simpa.utils import Tags
from typing import Union


class GaussianBeamIlluminationGeometry(IlluminationGeometryBase):
Expand All @@ -14,8 +15,8 @@ class GaussianBeamIlluminationGeometry(IlluminationGeometryBase):
The position is defined as the middle of the beam.
"""

def __init__(self, beam_radius_mm=None, focal_length_mm=None, device_position_mm=None,
field_of_view_extent_mm=None):
def __init__(self, beam_radius_mm: Union[int, float] = None, focal_length_mm: Union[int, float] = None,
device_position_mm=None, field_of_view_extent_mm=None):
"""
:param beam_radius_mm: Initial radius of the gaussian beam at half maximum (full width at half maximum (FWHM))
in mm.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class IlluminationGeometryBase(DigitalDeviceTwinBase):
This class is the base class for representing all illumination geometries.
"""

def __init__(self, device_position_mm=None, source_direction_vector=None, field_of_view_extent_mm=None):
def __init__(self, device_position_mm=None, source_direction_vector: np.ndarray = None,
field_of_view_extent_mm=None):
"""
:param device_position_mm: Each device has an internal position which serves as origin for internal \
representations of illuminator positions.
Expand All @@ -38,7 +39,7 @@ def __init__(self, device_position_mm=None, source_direction_vector=None, field_
self.source_direction_vector)

@abstractmethod
def get_mcx_illuminator_definition(self, global_settings) -> dict:
def get_mcx_illuminator_definition(self, global_settings: Settings) -> dict:
"""
IMPORTANT: This method creates a dictionary that contains tags as they are expected for the
mcx simulation tool to represent the illumination geometry of this device.
Expand All @@ -57,6 +58,9 @@ def check_settings_prerequisites(self, global_settings) -> bool:
def update_settings_for_use_of_model_based_volume_creator(self, global_settings) -> Settings:
return global_settings

def update_settings_for_use_of_segmentation_based_volume_creator(self, global_settings: Settings):
pass

def serialize(self) -> dict:
serialized_device = self.__dict__
device_dict = {"IlluminationGeometryBase": serialized_device}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@ class MSOTInVisionIlluminationGeometry(IlluminationGeometryBase):
This class represents the illumination geometry of the MSOT InVision photoacoustic device.
"""

def __init__(self, invision_position=None):
def __init__(self, invision_position: list = [0, 0, 0]):
super().__init__()

if invision_position is None:
self.invision_position = [0, 0, 0]
else:
self.invision_position = invision_position
self.invision_position = invision_position

det_sep_half = 24.74 / 2
detector_iso_distance = 74.05 / 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class PencilArrayIlluminationGeometry(IlluminationGeometryBase):
The device position is defined as the middle of the array.
"""

def __init__(self, pitch_mm=0.5, number_illuminators_x=100, number_illuminators_y=100, device_position_mm=None,
field_of_view_extent_mm=None):
def __init__(self, pitch_mm: float = 0.5, number_illuminators_x: int = 100, number_illuminators_y: int = 100,
device_position_mm=None, field_of_view_extent_mm=None):
"""
:param pitch_mm: Defines the x and y distance between the illumination positions
:type pitch_mm: float
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SlitIlluminationGeometry(IlluminationGeometryBase):
The device position is defined as the middle of the slit.
"""

def __init__(self, slit_vector_mm=None, direction_vector_mm=None, device_position_mm=None,
def __init__(self, slit_vector_mm: list = None, direction_vector_mm: list = None, device_position_mm=None,
field_of_view_extent_mm=None):
"""
:param slit_vector_mm: Defines the slit in vector form. For example a slit along the x-axis with length 5mm
Expand Down
Loading
Loading