Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update volume settings for segmentation and MSOT Acuity Echo #349

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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:
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