diff --git a/simpa/utils/libraries/tissue_library.py b/simpa/utils/libraries/tissue_library.py index e6d6dab5..cd1d897e 100644 --- a/simpa/utils/libraries/tissue_library.py +++ b/simpa/utils/libraries/tissue_library.py @@ -1,10 +1,13 @@ # SPDX-FileCopyrightText: 2021 Division of Intelligent Medical Systems, DKFZ # SPDX-FileCopyrightText: 2021 Janek Groehl # SPDX-License-Identifier: MIT +import typing from simpa.utils import OpticalTissueProperties, SegmentationClasses, StandardProperties, MolecularCompositionGenerator from simpa.utils import Molecule from simpa.utils import MOLECULE_LIBRARY +from simpa.utils import Spectrum +from simpa.utils.libraries.molecule_library import MolecularComposition from simpa.utils.libraries.spectrum_library import AnisotropySpectrumLibrary, ScatteringSpectrumLibrary from simpa.utils.calculate import randomize_uniform from simpa.utils.libraries.spectrum_library import AbsorptionSpectrumLibrary @@ -21,17 +24,46 @@ def get_blood_volume_fractions(self, total_blood_volume_fraction=1e-10, oxygenat """ return [total_blood_volume_fraction*oxygenation, total_blood_volume_fraction*(1-oxygenation)] - def constant(self, mua=1e-10, mus=1e-10, g=1e-10): + def constant(self, mua: float = 1e-10, mus: float = 1e-10, g: float = 1e-10) -> MolecularComposition: """ - TODO + Returns a generic issue defined by the provided constant optical parameters. + + :param mua: The absorption coefficient in cm^{-1}. + :param mus: The scattering coefficient in cm^{-1}. + :param g: The anisotropy. + + :returns: The molecular composition of the tissue. + """ + mua_as_spectrum = AbsorptionSpectrumLibrary().CONSTANT_ABSORBER_ARBITRARY(mua) + mus_as_spectrum = ScatteringSpectrumLibrary.CONSTANT_SCATTERING_ARBITRARY(mus) + g_as_spectrum = AnisotropySpectrumLibrary.CONSTANT_ANISOTROPY_ARBITRARY(g) + return self.generic_tissue(mua_as_spectrum, mus_as_spectrum, g_as_spectrum, "constant_mua_mus_g") + + def generic_tissue(self, + mua: Spectrum = AbsorptionSpectrumLibrary().CONSTANT_ABSORBER_ARBITRARY(1e-10), + mus: Spectrum = AbsorptionSpectrumLibrary().CONSTANT_ABSORBER_ARBITRARY(1e-10), + g: Spectrum = AbsorptionSpectrumLibrary().CONSTANT_ABSORBER_ARBITRARY(1e-10), + molecule_name: typing.Optional[str] = "generic_tissue") -> MolecularComposition: """ - return (MolecularCompositionGenerator().append(Molecule(name="constant_mua_mus_g", - absorption_spectrum=AbsorptionSpectrumLibrary().CONSTANT_ABSORBER_ARBITRARY(mua), + Returns a generic issue defined by the provided optical parameters. + + :param mua: The absorption coefficient spectrum in cm^{-1}. + :param mus: The scattering coefficient spectrum in cm^{-1}. + :param g: The anisotropy spectrum. + :param molecule_name: The molecule name. + + :returns: The molecular composition of the tissue. + """ + assert isinstance(mua, Spectrum), type(mua) + assert isinstance(mus, Spectrum), type(mus) + assert isinstance(g, Spectrum), type(g) + assert isinstance(molecule_name, str) or molecule_name is None, type(molecule_name) + + return (MolecularCompositionGenerator().append(Molecule(name=molecule_name, + absorption_spectrum=mua, volume_fraction=1.0, - scattering_spectrum=ScatteringSpectrumLibrary. - CONSTANT_SCATTERING_ARBITRARY(mus), - anisotropy_spectrum=AnisotropySpectrumLibrary. - CONSTANT_ANISOTROPY_ARBITRARY(g))) + scattering_spectrum=mus, + anisotropy_spectrum=g)) .get_molecular_composition(SegmentationClasses.GENERIC)) def muscle(self, background_oxy=None, blood_volume_fraction=None): diff --git a/simpa_tests/automatic_tests/tissue_library/test_tissue_library.py b/simpa_tests/automatic_tests/tissue_library/test_tissue_library.py new file mode 100644 index 00000000..b36a734b --- /dev/null +++ b/simpa_tests/automatic_tests/tissue_library/test_tissue_library.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2021 Division of Intelligent Medical Systems, DKFZ +# SPDX-FileCopyrightText: 2021 Janek Groehl +# SPDX-License-Identifier: MIT + +import numpy as np +import pytest + +from simpa import Spectrum, SegmentationClasses, TISSUE_LIBRARY, Molecule + + +def test_if_optical_parameter_spectra_are_provided_correct_tissue_definition_is_returned_from_generic_tissue(): + wavelengths_sample = np.arange(400, 800, 25) + mua_sample = np.linspace(1e-6, 1e-5, wavelengths_sample.shape[0]) + mus_sample = np.linspace(1e-5, 5e-6, wavelengths_sample.shape[0]) + g_sample = np.linspace(0.8, 0.9, wavelengths_sample.shape[0]) + + mua_spectrum = Spectrum("Mua", wavelengths_sample, mua_sample) + mus_spectrum = Spectrum("Mus", wavelengths_sample, mus_sample) + g_spectrum = Spectrum("g", wavelengths_sample, g_sample) + + actual_tissue = TISSUE_LIBRARY.generic_tissue(mua_spectrum, mus_spectrum, g_spectrum) + assert actual_tissue.segmentation_type == SegmentationClasses.GENERIC + + assert len(actual_tissue) == 1 + molecule: Molecule = actual_tissue[0] + assert molecule.volume_fraction == 1.0 + assert molecule.spectrum == mua_spectrum + assert molecule.scattering_spectrum == mus_spectrum + assert molecule.anisotropy_spectrum == g_spectrum + + +def test_if_generic_tissue_is_called_with_invalid_arguments_error_is_raised(): + wavelengths_sample = np.arange(400, 800, 25) + mua_sample = np.linspace(1e-6, 1e-5, wavelengths_sample.shape[0]) + mus_sample = np.linspace(1e-5, 5e-6, wavelengths_sample.shape[0]) + g_sample = np.linspace(0.8, 0.9, wavelengths_sample.shape[0]) + + mua_spectrum = Spectrum("Mua", wavelengths_sample, mua_sample) + mus_spectrum = Spectrum("Mus", wavelengths_sample, mus_sample) + g_spectrum = Spectrum("g", wavelengths_sample, g_sample) + + with pytest.raises(AssertionError): + TISSUE_LIBRARY.generic_tissue(None, mus_spectrum, g_spectrum) + + with pytest.raises(AssertionError): + TISSUE_LIBRARY.generic_tissue(mua_spectrum, None, g_spectrum) + + with pytest.raises(AssertionError): + TISSUE_LIBRARY.generic_tissue(mua_spectrum, mus_spectrum, None) + + +def test_if_optical_parameter_spectra_are_provided_correct_tissue_definition_is_returned_from_constant(): + mua_sample = 1e-5 + mus_sample = 3e-6 + g_sample = 0.85 + + actual_tissue = TISSUE_LIBRARY.constant(mua_sample, mus_sample, g_sample) + assert actual_tissue.segmentation_type == SegmentationClasses.GENERIC + + assert len(actual_tissue) == 1 + molecule: Molecule = actual_tissue[0] + assert molecule.volume_fraction == 1.0 + assert (molecule.spectrum.values == mua_sample).all() + assert (molecule.scattering_spectrum.values == mus_sample).all() + assert (molecule.anisotropy_spectrum.values == g_sample).all() + + +def test_if_constant_is_called_with_invalid_arguments_error_is_raised(): + mua_sample = 1e-5 + mus_sample = 3e-6 + g_sample = 0.85 + + with pytest.raises(TypeError): + TISSUE_LIBRARY.constant(None, mus_sample, g_sample) + + with pytest.raises(TypeError): + TISSUE_LIBRARY.constant(mua_sample, None, g_sample) + + with pytest.raises(TypeError): + TISSUE_LIBRARY.constant(mua_sample, mus_sample, None)