Skip to content

Commit

Permalink
Merge pull request #360 from IMSY-DKFZ/T359_BaseClasses
Browse files Browse the repository at this point in the history
Refactored (base) classes from init.py into separate files
  • Loading branch information
kdreher authored Aug 13, 2024
2 parents b1f0671 + 0c34e50 commit 1f5d66e
Show file tree
Hide file tree
Showing 78 changed files with 1,014 additions and 965 deletions.
33 changes: 17 additions & 16 deletions simpa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,38 @@
from .log import Logger
from importlib.metadata import version, PackageNotFoundError


try:
__version__ = version("simpa")
except PackageNotFoundError:
__version__ = "unknown version"

from .core.simulation_modules.volume_creation_module.volume_creation_module_model_based_adapter import \
ModelBasedVolumeCreationAdapter
from .core.simulation_modules.volume_creation_module.volume_creation_module_segmentation_based_adapter import \
SegmentationBasedVolumeCreationAdapter
from .core.simulation_modules.optical_simulation_module.optical_forward_model_mcx_adapter import \
from .core.simulation_modules.volume_creation_module.model_based_adapter import \
ModelBasedAdapter
from .core.simulation_modules.volume_creation_module.segmentation_based_adapter import \
SegmentationBasedAdapter
from .core.simulation_modules.optical_module.mcx_adapter import \
MCXAdapter
from .core.simulation_modules.optical_simulation_module.optical_forward_model_mcx_reflectance_adapter import \
MCXAdapterReflectance
from .core.simulation_modules.acoustic_forward_module.acoustic_forward_module_k_wave_adapter import \
from .core.simulation_modules.optical_module.mcx_reflectance_adapter import \
MCXReflectanceAdapter
from .core.simulation_modules.acoustic_module.k_wave_adapter import \
KWaveAdapter
from .core.simulation_modules.reconstruction_module.reconstruction_module_delay_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.delay_and_sum_adapter import \
DelayAndSumAdapter
from .core.simulation_modules.reconstruction_module.reconstruction_module_delay_multiply_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.delay_multiply_and_sum_adapter import \
DelayMultiplyAndSumAdapter
from .core.simulation_modules.reconstruction_module.reconstruction_module_signed_delay_multiply_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.signed_delay_multiply_and_sum_adapter import \
SignedDelayMultiplyAndSumAdapter
from .core.simulation_modules.reconstruction_module.reconstruction_module_time_reversal_adapter import \
from .core.simulation_modules.reconstruction_module.time_reversal_adapter import \
TimeReversalAdapter

from .core.simulation_modules.reconstruction_module.reconstruction_module_delay_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.delay_and_sum_adapter import \
reconstruct_delay_and_sum_pytorch
from .core.simulation_modules.reconstruction_module.reconstruction_module_delay_multiply_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.delay_multiply_and_sum_adapter import \
reconstruct_delay_multiply_and_sum_pytorch
from .core.simulation_modules.reconstruction_module.reconstruction_module_signed_delay_multiply_and_sum_adapter import \
from .core.simulation_modules.reconstruction_module.signed_delay_multiply_and_sum_adapter import \
reconstruct_signed_delay_multiply_and_sum_pytorch
from .core.simulation_modules.acoustic_forward_module.acoustic_forward_module_k_wave_adapter import \
from .core.simulation_modules.acoustic_module.k_wave_adapter import \
perform_k_wave_acoustic_forward_simulation

from simpa.core.processing_components.monospectral.noise import GaussianNoise
Expand Down
31 changes: 1 addition & 30 deletions simpa/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,4 @@
# SPDX-FileCopyrightText: 2021 Division of Intelligent Medical Systems, DKFZ
# SPDX-FileCopyrightText: 2021 Janek Groehl
# SPDX-License-Identifier: MIT
from abc import abstractmethod

from simpa.core.device_digital_twins import DigitalDeviceTwinBase
from simpa.log import Logger
from simpa.utils import Settings
from simpa.utils.processing_device import get_processing_device


class PipelineModule:
"""
Defines a pipeline module (either simulation or processing module) that implements a run method and can be called by running the pipeline's simulate method.
"""

def __init__(self, global_settings: Settings):
"""
:param global_settings: The SIMPA settings dictionary
:type global_settings: Settings
"""
self.logger = Logger()
self.global_settings = global_settings
self.torch_device = get_processing_device(self.global_settings)

@abstractmethod
def run(self, digital_device_twin: DigitalDeviceTwinBase):
"""
Executes the respective simulation module
:param digital_device_twin: The digital twin that can be used by the digital device_twin.
"""
pass
from .pipeline_element_base import PipelineElementBase
170 changes: 19 additions & 151 deletions simpa/core/device_digital_twins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,154 +2,22 @@
# SPDX-FileCopyrightText: 2021 Janek Groehl
# SPDX-License-Identifier: MIT

from abc import abstractmethod
from simpa.log import Logger
import numpy as np
import hashlib
import uuid
from simpa.utils.serializer import SerializableSIMPAClass
from simpa.utils.calculate import are_equal


class DigitalDeviceTwinBase(SerializableSIMPAClass):
"""
This class represents a device that can be used for illumination, detection or a combined photoacoustic device
which has representations of both.
"""

def __init__(self, device_position_mm=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 e.g. detector element positions or illuminator positions.
:type device_position_mm: ndarray
:param field_of_view_extent_mm: Field of view which is defined as a numpy array of the shape \
[xs, xe, ys, ye, zs, ze], where x, y, and z denote the coordinate axes and s and e denote the start and end \
positions.
:type field_of_view_extent_mm: ndarray
"""
if device_position_mm is None:
self.device_position_mm = np.array([0, 0, 0])
else:
self.device_position_mm = device_position_mm

if field_of_view_extent_mm is None:
self.field_of_view_extent_mm = np.asarray([-10, 10, -10, 10, -10, 10])
else:
self.field_of_view_extent_mm = field_of_view_extent_mm

self.logger = Logger()

def __eq__(self, other):
"""
Checks each key, value pair in the devices.
"""
if isinstance(other, DigitalDeviceTwinBase):
if self.__dict__.keys() != other.__dict__.keys():
return False
for self_key, self_value in self.__dict__.items():
other_value = other.__dict__[self_key]
if not are_equal(self_value, other_value):
return False
return True
return False

@abstractmethod
def check_settings_prerequisites(self, global_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.
To this end, a PAI device should use this method to inform the user about a mismatch of the desired device and
throw a ValueError if that is the case.
:param global_settings: Settings for the entire simulation pipeline.
:type global_settings: Settings
:raises ValueError: raises a value error if the prerequisites are not matched.
:returns: True if the prerequisites are met, False if they are not met, but no exception has been raised.
:rtype: bool
"""
pass

@abstractmethod
def update_settings_for_use_of_model_based_volume_creator(self, global_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.
: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
accounted for.
It is defined as a numpy array of the shape [xs, xe, ys, ye, zs, ze],
where x, y, and z denote the coordinate axes and s and e denote the start and end
positions.
:return: Absolute field of view in mm where the probe position is already accounted for.
:rtype: ndarray
"""
position = self.device_position_mm
field_of_view_extent = self.field_of_view_extent_mm

field_of_view = np.asarray([position[0] + field_of_view_extent[0],
position[0] + field_of_view_extent[1],
position[1] + field_of_view_extent[2],
position[1] + field_of_view_extent[3],
position[2] + field_of_view_extent[4],
position[2] + field_of_view_extent[5]
])
if min(field_of_view) < 0:
self.logger.warning(f"The field of view of the chosen device is not fully within the simulated volume, "
f"field of view is: {field_of_view}")
field_of_view[field_of_view < 0] = 0

return field_of_view

def generate_uuid(self):
"""
Generates a universally unique identifier (uuid) for each device.
:return:
"""
class_dict = self.__dict__
m = hashlib.md5()
m.update(str(class_dict).encode('utf-8'))
return str(uuid.UUID(m.hexdigest()))

def serialize(self) -> dict:
serialized_device = self.__dict__
return {"DigitalDeviceTwinBase": serialized_device}

@staticmethod
def deserialize(dictionary_to_deserialize):
deserialized_device = DigitalDeviceTwinBase(
device_position_mm=dictionary_to_deserialize["device_position_mm"],
field_of_view_extent_mm=dictionary_to_deserialize["field_of_view_extent_mm"])
return deserialized_device


"""
It is important to have these relative imports after the definition of the DigitalDeviceTwinBase class to avoid circular imports triggered by imported child classes
"""
from .pa_devices import PhotoacousticDevice # nopep8
from simpa.core.device_digital_twins.detection_geometries import DetectionGeometryBase # nopep8
from simpa.core.device_digital_twins.illumination_geometries import IlluminationGeometryBase # nopep8
from .detection_geometries.curved_array import CurvedArrayDetectionGeometry # nopep8
from .detection_geometries.linear_array import LinearArrayDetectionGeometry # nopep8
from .detection_geometries.planar_array import PlanarArrayDetectionGeometry # nopep8
from .illumination_geometries.slit_illumination import SlitIlluminationGeometry # nopep8
from .illumination_geometries.gaussian_beam_illumination import GaussianBeamIlluminationGeometry # nopep8
from .illumination_geometries.pencil_array_illumination import PencilArrayIlluminationGeometry # nopep8
from .illumination_geometries.pencil_beam_illumination import PencilBeamIlluminationGeometry # nopep8
from .illumination_geometries.disk_illumination import DiskIlluminationGeometry # nopep8
from .illumination_geometries.rectangle_illumination import RectangleIlluminationGeometry # nopep8
from .illumination_geometries.ring_illumination import RingIlluminationGeometry # nopep8
from .illumination_geometries.ithera_msot_acuity_illumination import MSOTAcuityIlluminationGeometry # nopep8
from .illumination_geometries.ithera_msot_invision_illumination import MSOTInVisionIlluminationGeometry # nopep8
from .pa_devices.ithera_msot_invision import InVision256TF # nopep8
from .pa_devices.ithera_msot_acuity import MSOTAcuityEcho # nopep8
from .pa_devices.ithera_rsom import RSOMExplorerP50 # nopep8
from .digital_device_twin_base import DigitalDeviceTwinBase
from .pa_devices import PhotoacousticDevice
from .detection_geometries import DetectionGeometryBase
from .detection_geometries.curved_array import CurvedArrayDetectionGeometry
from .detection_geometries.linear_array import LinearArrayDetectionGeometry
from .detection_geometries.planar_array import PlanarArrayDetectionGeometry
from .illumination_geometries import IlluminationGeometryBase
from .illumination_geometries.slit_illumination import SlitIlluminationGeometry
from .illumination_geometries.gaussian_beam_illumination import GaussianBeamIlluminationGeometry
from .illumination_geometries.pencil_array_illumination import PencilArrayIlluminationGeometry
from .illumination_geometries.pencil_beam_illumination import PencilBeamIlluminationGeometry
from .illumination_geometries.disk_illumination import DiskIlluminationGeometry
from .illumination_geometries.rectangle_illumination import RectangleIlluminationGeometry
from .illumination_geometries.ring_illumination import RingIlluminationGeometry
from .illumination_geometries.ithera_msot_acuity_illumination import MSOTAcuityIlluminationGeometry
from .illumination_geometries.ithera_msot_invision_illumination import MSOTInVisionIlluminationGeometry
from .pa_devices.ithera_msot_invision import InVision256TF
from .pa_devices.ithera_msot_acuity import MSOTAcuityEcho
from .pa_devices.ithera_rsom import RSOMExplorerP50
Loading

0 comments on commit 1f5d66e

Please sign in to comment.