From 54c2457d2f1fae099d2d872586357b726a460f31 Mon Sep 17 00:00:00 2001 From: Simon Birrer Date: Fri, 15 Nov 2024 10:12:47 -0500 Subject: [PATCH] refactoring LOS classes and split into individual LOS and population of LOS --- slsim/FalsePositives/false_positive.py | 28 ++++---- slsim/FalsePositives/false_positive_pop.py | 16 ++--- slsim/LOS/__init__.py | 0 slsim/LOS/los_individual.py | 38 +++++++++++ .../los_config.py => LOS/los_pop.py} | 45 +++++-------- slsim/lens.py | 60 +++++++---------- slsim/lens_pop.py | 42 +++++++----- slsim/lensed_system_base.py | 6 +- .../test_false_positive.py | 9 ++- tests/test_lens.py | 43 ++++++------ tests/test_los_config.py | 66 ++++++++----------- tests/test_roman_image_simulation.py | 3 +- 12 files changed, 183 insertions(+), 173 deletions(-) create mode 100644 slsim/LOS/__init__.py create mode 100644 slsim/LOS/los_individual.py rename slsim/{ParamDistributions/los_config.py => LOS/los_pop.py} (79%) diff --git a/slsim/FalsePositives/false_positive.py b/slsim/FalsePositives/false_positive.py index 1f01b2f4c..2d9493d11 100644 --- a/slsim/FalsePositives/false_positive.py +++ b/slsim/FalsePositives/false_positive.py @@ -1,6 +1,7 @@ import numpy as np from slsim.lens import Lens + class FalsePositive(Lens): """Class to manage individual false positive. Here, false positives refer to a configuration that includes an elliptical galaxy at the center with blue galaxies @@ -12,8 +13,7 @@ def __init__( deflector_class, cosmo, test_area=4 * np.pi, - los_config=None, - los_dict=None, + los_class=None, ): """ :param source_class: A Source class instance or list of Source class instance @@ -23,21 +23,16 @@ def __init__( :param cosmo: astropy.cosmology instance :param test_area: area of disk around one lensing galaxies to be investigated on (in arc-seconds^2). - :param los_config: LOSConfig instance which manages line-of-sight (LOS) effects - and Gaussian mixture models in a simulation or analysis context. - :param los_dict: line of sight dictionary (optional, takes these values instead - of drawing from distribution) Takes "gamma" = [gamma1, gamma2] and - "kappa" = kappa as entries - :type los_dict: dict + :param los_class: line of sight dictionary (optional, takes these values instead of drawing from distribution) + :type los_class: ~LOSIndividual() class object """ Lens.__init__(self, - source_class=source_class, - deflector_class=deflector_class, - cosmo=cosmo, - test_area=test_area, - los_config=los_config, - los_dict=los_dict, - ) + source_class=source_class, + deflector_class=deflector_class, + cosmo=cosmo, + test_area=test_area, + los_class=los_class, + ) def lenstronomy_kwargs(self, band=None): """Generates lenstronomy dictionary conventions for the class object. @@ -72,5 +67,4 @@ def lenstronomy_kwargs(self, band=None): "kwargs_lens_light": combined_kwargs_lens_light, "kwargs_ps": kwargs_ps, } - - return kwargs_model, kwargs_params \ No newline at end of file + return kwargs_model, kwargs_params diff --git a/slsim/FalsePositives/false_positive_pop.py b/slsim/FalsePositives/false_positive_pop.py index 390f362ed..f651c19f1 100644 --- a/slsim/FalsePositives/false_positive_pop.py +++ b/slsim/FalsePositives/false_positive_pop.py @@ -1,6 +1,6 @@ from slsim.FalsePositives.false_positive import FalsePositive -from slsim.ParamDistributions.los_config import LOSConfig from slsim.lens_pop import draw_test_area +from slsim.LOS.los_pop import LOSPop import random @@ -15,22 +15,22 @@ def __init__( elliptical_galaxy_population, blue_galaxy_population, cosmo=None, - los_config=None, + los_pop=None, source_number_choice=[1, 2, 3], weights_for_source_number=None, test_area_factor=1 ): """ Args: - :param elliptical_galaxy_population: Deflector population as an deflectors class + :param elliptical_galaxy_population: Deflector population as a deflectors class instance. - :param blue_galaxy_population: Source population as an sources class inatnce. + :param blue_galaxy_population: Source population as a sources class inatnce. :param cosmo: astropy.cosmology instance - :param los_config: LOSConfig instance which manages line-of-sight (LOS) effects + :param los_pop: LOSPop instance which manages line-of-sight (LOS) effects and Gaussian mixture models in a simulation or analysis context. :param source_number_choice: A list of integers to choose source number from. If None, defaults to [1, 2, 3]. - :param weights: A list of weights corresponding to the probabilities of + :param weights_for_source_number: A list of weights corresponding to the probabilities of selecting each value in source_number_choice. If None, all choices are equally likely. Defaults to None. :param test_area_factor: A multiplicative factor of a test_area. A test area is @@ -44,9 +44,9 @@ def __init__( self._choice = source_number_choice self._weights = weights_for_source_number self._test_area_factor = test_area_factor - self.los_config = los_config + self.los_config = los_pop if self.los_config is None: - self.los_config = LOSConfig() + self.los_config = LOSPop() def draw_deflector(self): """Draw and prepare a deflector (lens) with tolerance-based z_max. diff --git a/slsim/LOS/__init__.py b/slsim/LOS/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/slsim/LOS/los_individual.py b/slsim/LOS/los_individual.py new file mode 100644 index 000000000..c5905db2e --- /dev/null +++ b/slsim/LOS/los_individual.py @@ -0,0 +1,38 @@ + + +class LOSIndividual(object): + """ + class to store the quantities of an individual line of sight + """ + def __init__(self, kappa=None, gamma=None): + """ + + :param gamma: [gamma1, gamma2] (takes these values if present) + :type gamma: list of floats + :param kappa: convergence (takes this values if present) + :type kappa: float + """ + if kappa is None: + kappa = 0 + if gamma is None: + gamma = [0, 0] + self._kappa = kappa + self._gamma = gamma + + @property + def convergence(self): + """ + line of sight convergence + + :return: kappa + """ + return self._kappa + + @property + def shear(self): + """ + line of sight shear + + :return: gamma1, gamma2 + """ + return self._gamma[0], self._gamma[1] diff --git a/slsim/ParamDistributions/los_config.py b/slsim/LOS/los_pop.py similarity index 79% rename from slsim/ParamDistributions/los_config.py rename to slsim/LOS/los_pop.py index b4b065a56..ba34ab467 100644 --- a/slsim/ParamDistributions/los_config.py +++ b/slsim/LOS/los_pop.py @@ -1,9 +1,10 @@ from slsim.ParamDistributions.gaussian_mixture_model import GaussianMixtureModel from slsim.ParamDistributions.kext_gext_distributions import LineOfSightDistribution +from slsim.LOS.los_individual import LOSIndividual import numpy as np -class LOSConfig(object): +class LOSPop(object): """Configuration class for setting parameters related to line-of-sight (LOS) effects and Gaussian mixture models in a simulation or analysis context. @@ -41,8 +42,6 @@ def __init__( nonlinear_los_bool=False, nonlinear_correction_path=None, no_correction_path=None, - gamma=None, - kappa=None, ): """ :param los_bool: Boolean to include line-of-sight distortions, default is True. @@ -61,10 +60,6 @@ def __init__( :type nonlinear_correction_path: str or None :param no_correction_path: Path to the no non-linear correction distributions stored in an H5 file, default is None. :type no_correction_path: str or None - :param gamma: [gamma1, gamma2] (takes these values if present) - :type gamma: list of floats - :param kappa: convergence (takes this values if present) - :type kappa: float """ self.mixgauss_gamma = mixgauss_gamma @@ -75,39 +70,31 @@ def __init__( self.nonlinear_los_bool = nonlinear_los_bool self.nonlinear_correction_path = nonlinear_correction_path self.no_correction_path = no_correction_path - if gamma is not None: - self._gamma = gamma - if kappa is not None: - self._kappa = kappa - def calculate_los_linear_distortions(self, source_redshift, deflector_redshift): - """Calculate line-of-sight distortions in shear and convergence. + def draw_los(self, source_redshift, deflector_redshift): + """Calculate line-of-sight distortions in shear and convergence for an individual realisation. :param source_redshift: redshift of the source galaxy object. :type source_redshift: float :param deflector_redshift: redshift of the deflector galaxy object. :type deflector_redshift: float - :return: kappa, gamma1, gamma2 + :return: LOSIndividual class instance """ if not self.los_bool: - return 0, 0, 0 - if hasattr(self, "_gamma") and hasattr(self, "_kappa"): - return self._gamma[0], self._gamma[1], self._kappa + return LOSIndividual(kappa=0, gamma=[0, 0]) if self.mixgauss_gamma and not self.nonlinear_los_bool: - if not hasattr(self, "_gamma"): mixture = GaussianMixtureModel( means=self.mixgauss_means, stds=self.mixgauss_stds, weights=self.mixgauss_weights, ) - gamma = np.abs(mixture.rvs(size=1))[0] + gamma_abs = np.abs(mixture.rvs(size=1))[0] phi = 2 * np.pi * np.random.random() - gamma1 = gamma * np.cos(2 * phi) - gamma2 = gamma * np.sin(2 * phi) - self._gamma = [gamma1, gamma2] - if not hasattr(self, "_kappa"): - self._kappa = np.random.normal(loc=0, scale=0.05) + gamma1 = gamma_abs * np.cos(2 * phi) + gamma2 = gamma_abs * np.sin(2 * phi) + gamma = [gamma1, gamma2] + kappa = np.random.normal(loc=0, scale=0.05) elif self.mixgauss_gamma and self.nonlinear_los_bool: raise ValueError( "Can only choose one method for external shear and convergence" @@ -119,12 +106,12 @@ def calculate_los_linear_distortions(self, source_redshift, deflector_redshift): nonlinear_correction_path=self.nonlinear_correction_path, no_correction_path=self.no_correction_path, ) - gamma, self._kappa = LOS.get_kappa_gamma( + gamma_abs, kappa = LOS.get_kappa_gamma( z_source, z_lens, self.nonlinear_los_bool ) phi = 2 * np.pi * np.random.random() - gamma1 = gamma * np.cos(2 * phi) - gamma2 = gamma * np.sin(2 * phi) - self._gamma = [gamma1, gamma2] + gamma1 = gamma_abs * np.cos(2 * phi) + gamma2 = gamma_abs * np.sin(2 * phi) + gamma = [gamma1, gamma2] - return self._gamma[0], self._gamma[1], self._kappa + return LOSIndividual(kappa=kappa, gamma=gamma) diff --git a/slsim/lens.py b/slsim/lens.py index 56723e7c5..7151939d1 100644 --- a/slsim/lens.py +++ b/slsim/lens.py @@ -6,8 +6,8 @@ from lenstronomy.LensModel.Solver.lens_equation_solver import ( analytical_lens_model_support, ) -from slsim.ParamDistributions.los_config import LOSConfig from slsim.Util.param_util import ellipticity_slsim_to_lenstronomy +from slsim.LOS.los_individual import LOSIndividual from lenstronomy.LightModel.light_model import LightModel from lenstronomy.Util import constants from lenstronomy.Util import data_util @@ -15,6 +15,7 @@ from slsim.lensed_system_base import LensedSystemBase + class Lens(LensedSystemBase): """Class to manage individual lenses.""" @@ -26,8 +27,7 @@ def __init__( lens_equation_solver="lenstronomy_analytical", test_area=4 * np.pi, magnification_limit=0.01, - los_config=None, - los_dict=None, + los_class=None, ): """ @@ -63,11 +63,8 @@ def __init__( :param magnification_limit: absolute lensing magnification lower limit to register a point source (ignore highly de-magnified images) :type magnification_limit: float >= 0 - :param los_config: LOSConfig instance which manages line-of-sight (LOS) effects - and Gaussian mixture models in a simulation or analysis context. - :param los_dict: line of sight dictionary (optional, takes these values instead of drawing from distribution) - Takes "gamma" = [gamma1, gamma2] and "kappa" = kappa as entries - :type los_dict: dict + :param los_class: line of sight dictionary (optional, takes these values instead of drawing from distribution) + :type los_class: ~LOSIndividual() class object """ self.deflector = deflector_class self.cosmo = cosmo @@ -77,7 +74,7 @@ def __init__( if isinstance(source_class, list): self.source = source_class - # choose a highest resdshift source to use conventionally use in lens + # chose a highest resdshift source to use conventionally use in lens # mass model. self.max_redshift_source_class = max( self.source, key=lambda obj: obj.redshift) @@ -101,13 +98,9 @@ def __init__( z_source=float(self.max_redshift_source_class.redshift), cosmo=self.cosmo, ) - - self._los_linear_distortions_cache = None - self.los_config = los_config - if self.los_config is None: - if los_dict is None: - los_dict = {} - self.los_config = LOSConfig(**los_dict) + if los_class is None: + los_class = LOSIndividual() + self.los_class = los_class @property def image_number(self): @@ -361,14 +354,23 @@ def source_redshift_list(self): source_redshifts.append(source.redshift) return source_redshifts + @property + def los_linear_distortions(self): + """Line-of-sight distortions in shear and convergence. + + :return: kappa, gamma1, gamma2 + """ + kappa = self.los_class.convergence + gamma1, gamma2 = self.los_class.shear + return kappa, gamma1, gamma2 + @property def external_convergence(self): """ :return: external convergence """ - _, _, kappa_ext = self.los_linear_distortions - return kappa_ext + return self.los_class.convergence @property def external_shear(self): @@ -376,7 +378,7 @@ def external_shear(self): :return: the absolute external shear """ - gamma1, gamma2, _ = self.los_linear_distortions + gamma1, gamma2 = self.los_class.shear return (gamma1**2 + gamma2**2) ** 0.5 @property @@ -407,7 +409,7 @@ def _einstein_radius(self, source): z_source=float(source.redshift), cosmo=self.cosmo, ) - _, _, kappa_ext = self.los_linear_distortions + kappa_ext = self.los_class.convergence gamma_pl = self.deflector.halo_properties theta_E = _lens_cosmo.sis_sigma_v2theta_E( float(self.deflector.velocity_dispersion(cosmo=self.cosmo)) @@ -449,24 +451,6 @@ def deflector_velocity_dispersion(self): """ return self.deflector.velocity_dispersion(cosmo=self.cosmo) - @property - def los_linear_distortions(self): - if self._los_linear_distortions_cache is None: - self._los_linear_distortions_cache = ( - self._calculate_los_linear_distortions() - ) - return self._los_linear_distortions_cache - - def _calculate_los_linear_distortions(self): - """Line-of-sight distortions in shear and convergence. - - :return: kappa, gamma1, gamma2 - """ - return self.los_config.calculate_los_linear_distortions( - source_redshift=self.max_redshift_source_class.redshift, - deflector_redshift=self.deflector_redshift, - ) - def deflector_magnitude(self, band): """Apparent magnitude of the deflector for a given band. diff --git a/slsim/lens_pop.py b/slsim/lens_pop.py index cf022ed5a..846379039 100644 --- a/slsim/lens_pop.py +++ b/slsim/lens_pop.py @@ -5,7 +5,7 @@ from astropy.cosmology import Cosmology from slsim.lens import theta_e_when_source_infinity from slsim.Sources.source_pop_base import SourcePopBase -from slsim.ParamDistributions.los_config import LOSConfig +from slsim.LOS.los_pop import LOSPop from slsim.Deflectors.deflectors_base import DeflectorsBase from slsim.lensed_population_base import LensedPopulationBase @@ -19,16 +19,17 @@ def __init__( source_population: SourcePopBase, cosmo: Optional[Cosmology] = None, sky_area: Optional[float] = None, - los_config: Optional[LOSConfig] = None, + los_pop: Optional[LOSPop] = None, ): """ - :param deflector_population: Deflector population as an deflectors class + :param deflector_population: Deflector population as an deflectors class instance. :param source_population: Source population as an sources class inatnce. :param cosmo: astropy.cosmology instance :param sky_area: Sky area (solid angle) over which Lens population is sampled. :type sky_area: `~astropy.units.Quantity` - :param los_config: Configuration for line of sight distribution. Defaults to None. + :param los_pop: Configuration for line of sight distribution. Defaults to None. + :type los_pop: `~LOSPop` or None """ # TODO: ADD EXCEPTION FOR DEFLECTOR AND SOURCE POP FILTER MISMATCH @@ -46,9 +47,9 @@ def __init__( self._factor_deflector = self.sky_area.to_value( "deg2" ) / self._lens_galaxies.sky_area.to_value("deg2") - self.los_config = los_config - if self.los_config is None: - self.los_config = LOSConfig() + self.los_pop = los_pop + if self.los_pop is None: + self.los_pop = LOSPop() def select_lens_at_random(self, test_area=None, **kwargs_lens_cut): """Draw a random lens within the cuts of the lens and source, with possible @@ -63,18 +64,19 @@ def select_lens_at_random(self, test_area=None, **kwargs_lens_cut): while True: #This creates a single deflector - single_source lens. _source = self._sources.draw_source() - _lens = self._lens_galaxies.draw_deflector() + _deflector = self._lens_galaxies.draw_deflector() + _los = self.los_pop.draw_los(source_redshift=_source.redshift, deflector_redshift=_deflector.redshift) if test_area is None: - vel_disp=_lens.velocity_dispersion(cosmo=self.cosmo) + vel_disp=_deflector.velocity_dispersion(cosmo=self.cosmo) test_area = draw_test_area(v_sigma=vel_disp) else: test_area = test_area gg_lens = Lens( - deflector_class=_lens, + deflector_class=_deflector, source_class=_source, cosmo=self.cosmo, test_area=test_area, - los_config=self.los_config, + los_class=_los, ) if gg_lens.validity_test(**kwargs_lens_cut): return gg_lens @@ -142,24 +144,28 @@ def draw_population(self, kwargs_lens_cuts, speed_factor=1): # Draw a population of galaxy-galaxy lenses within the area. for _ in range(int(num_lenses / speed_factor)): - _lens = self._lens_galaxies.draw_deflector() - vel_disp=_lens.velocity_dispersion(cosmo=self.cosmo) + _deflector = self._lens_galaxies.draw_deflector() + vel_disp=_deflector.velocity_dispersion(cosmo=self.cosmo) test_area = draw_test_area(v_sigma=vel_disp) num_sources_tested = self.get_num_sources_tested( testarea=test_area * speed_factor ) - + if num_sources_tested > 0: valid_sources = [] n = 0 while n < num_sources_tested: _source = self._sources.draw_source() + if n == 0: + # TODO: this is only consistent for a single source. If there are multiple sources at different redshift, this is not fully acurate + los_class = self.los_pop.draw_los(source_redshift=_source.redshift, + deflector_redshift=_deflector.redshift) lens_class = Lens( - deflector_class=_lens, + deflector_class=_deflector, source_class=_source, cosmo=self.cosmo, test_area=test_area, - los_config=self.los_config, + los_class=los_class, ) # Check the validity of the lens system if lens_class.validity_test(**kwargs_lens_cuts): @@ -173,11 +179,11 @@ def draw_population(self, kwargs_lens_cuts, speed_factor=1): else: final_sources = valid_sources lens_final = Lens( - deflector_class=_lens, + deflector_class=_deflector, source_class=final_sources, cosmo=self.cosmo, test_area=test_area, - los_config=self.los_config, + los_class=los_class, ) lens_population.append(lens_final) return lens_population diff --git a/slsim/lensed_system_base.py b/slsim/lensed_system_base.py index 970303623..985239a75 100644 --- a/slsim/lensed_system_base.py +++ b/slsim/lensed_system_base.py @@ -1,22 +1,26 @@ from abc import ABC, abstractmethod + class LensedSystemBase(ABC): """Abstract Base class to create a lens system with all lensing properties required to render populations.""" - def __init__(self, source_class, deflector_class): + def __init__(self, source_class, deflector_class, los_class): """ :param source_class: :param source_class: A Source class instance or list of Source class instance :type source_class: Source class instance from slsim.Sources.source. :param deflector_class: deflector instance :type deflector_class: Deflector class instance from slsim.Deflectors.deflector + :param los_class: Line of sight distortion class + :type los_class: ~LOSIndividual instance """ self.deflector = deflector_class if isinstance(source_class, list): self.source = source_class else: self.source = [source_class] + @abstractmethod def deflector_position(self): """Center of the deflector position. diff --git a/tests/test_FalsePositives/test_false_positive.py b/tests/test_FalsePositives/test_false_positive.py index 8faf7072a..f03d86d00 100644 --- a/tests/test_FalsePositives/test_false_positive.py +++ b/tests/test_FalsePositives/test_false_positive.py @@ -1,9 +1,8 @@ import pytest import numpy as np from astropy.cosmology import FlatLambdaCDM -from slsim.ParamDistributions.los_config import LOSConfig +from slsim.LOS.los_individual import LOSIndividual from slsim.Sources.source import Source -from slsim.Deflectors.deflector import Deflector import slsim.Sources as sources import slsim.Deflectors as deflectors import slsim.Pipelines as pipelines @@ -70,7 +69,7 @@ def test_false_positive(): ), ] # LOS configuration - los_config = LOSConfig() + los_class = LOSIndividual() # Create an instance of FalsePositive false_positive_instance_1 = FalsePositive( @@ -84,14 +83,14 @@ def test_false_positive(): deflector_class=lens, cosmo=cosmo, test_area=4 * np.pi, - los_config=los_config, + los_class=los_class, ) false_positive_instance_3 = FalsePositive( source_class=source2, deflector_class=lens, cosmo=cosmo, test_area=4 * np.pi, - los_config=los_config, + los_class=los_class, ) required_keys = { "magnitude", diff --git a/tests/test_lens.py b/tests/test_lens.py index d5c39bd57..c704c1929 100644 --- a/tests/test_lens.py +++ b/tests/test_lens.py @@ -8,7 +8,8 @@ image_separation_from_positions, theta_e_when_source_infinity, ) -from slsim.ParamDistributions.los_config import LOSConfig +from slsim.LOS.los_individual import LOSIndividual +from slsim.LOS.los_pop import LOSPop from slsim.Sources.source import Source from slsim.Deflectors.deflector import Deflector import os @@ -367,8 +368,9 @@ def setup_method(self): deflector_type="EPL", deflector_dict=self.deflector_dict, ) + def test_different_setting(self): - los1 = LOSConfig( + los1 = LOSPop( los_bool=True, mixgauss_gamma=True, nonlinear_los_bool=False, @@ -377,13 +379,14 @@ def test_different_setting(self): source_class=self.source6, deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los1, + los_class=los1.draw_los(source_redshift=self.source6.redshift, + deflector_redshift=self.deflector6.redshift), ) assert gg_lens.external_shear >= 0 assert isinstance(gg_lens.external_convergence, float) assert isinstance(gg_lens.external_shear, float) - los2 = LOSConfig( + los2 = LOSPop( los_bool=True, mixgauss_gamma=False, nonlinear_los_bool=True, @@ -393,23 +396,25 @@ def test_different_setting(self): source_class=self.source6, deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los2, + los_class=los2.draw_los(source_redshift=self.source6.redshift, + deflector_redshift=self.deflector6.redshift), ) assert gg_lens_2.external_shear >= 0 assert isinstance(gg_lens_2.external_convergence, float) assert isinstance(gg_lens_2.external_shear, float) - los3 = LOSConfig(los_bool=False) + los3 = LOSPop(los_bool=False) gg_lens_3 = Lens( source_class=self.source6, deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los3, + los_class=los3.draw_los(source_redshift=self.source6.redshift, + deflector_redshift=self.deflector6.redshift), ) assert gg_lens_3.external_convergence == 0 assert gg_lens_3.external_shear == 0 - los4 = LOSConfig( + los4 = LOSPop( los_bool=True, mixgauss_gamma=True, nonlinear_los_bool=True, @@ -419,21 +424,18 @@ def test_different_setting(self): source_class=self.source6, deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los4, + los_class=los4.draw_los(deflector_redshift=self.deflector6.redshift, + source_redshift=self.source6.redshift), ) gg_lens_4.external_convergence() def test_image_number(self): - los = LOSConfig( - los_bool=True, - mixgauss_gamma=True, - nonlinear_los_bool=False, - ) + los = LOSIndividual(kappa=0, gamma=[0, 0]) gg_lens_number = Lens( source_class=self.source6, deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los, + los_class=los, ) image_number = gg_lens_number.image_number assert (image_number[0] == 4) or (image_number[0] == 2) or (image_number[0] == 1) @@ -442,7 +444,7 @@ def test_image_number(self): source_class=[self.source6, self.source6], deflector_class=self.deflector6, cosmo=self.cosmo, - los_config=los, + los_class=los, ) kwargs_model = gg_lens_multisource.lenstronomy_kwargs()[0] kwargs_model_keys = kwargs_model.keys() @@ -462,6 +464,7 @@ def test_image_number(self): assert expected_kwargs_model[5] in kwargs_model_keys assert expected_kwargs_model[6] in kwargs_model_keys + @pytest.fixture def supernovae_lens_instance_double_sersic_multisource(): path = os.path.dirname(__file__) @@ -501,6 +504,7 @@ def supernovae_lens_instance_double_sersic_multisource(): break return supernovae_lens + def test_double_sersic_multisource(supernovae_lens_instance_double_sersic_multisource): lens_class = supernovae_lens_instance_double_sersic_multisource results = lens_class.source_light_model_lenstronomy(band="i") @@ -508,6 +512,7 @@ def test_double_sersic_multisource(supernovae_lens_instance_double_sersic_multis assert len(results[1]["kwargs_source"]) == 2 assert len(results[1]["kwargs_ps"]) == 2 + class TestMultiSource(object): def setup_method(self): self.cosmo = FlatLambdaCDM(H0=70, Om0=0.3) @@ -578,17 +583,17 @@ def setup_method(self): deflector_type="EPL", deflector_dict=deflector_dict, ) - lens_class1 = Lens( + lens_class1 = Lens( deflector_class=self.deflector, source_class=self.source1, cosmo=self.cosmo, ) - lens_class2 = Lens( + lens_class2 = Lens( deflector_class=self.deflector, source_class=self.source2, cosmo=self.cosmo, ) - lens_class3 = Lens( + lens_class3 = Lens( deflector_class=self.deflector, source_class=[self.source1, self.source2], cosmo=self.cosmo, diff --git a/tests/test_los_config.py b/tests/test_los_config.py index 4ae8e4c30..4f1cbf418 100644 --- a/tests/test_los_config.py +++ b/tests/test_los_config.py @@ -1,4 +1,4 @@ -from slsim.ParamDistributions.los_config import LOSConfig +from slsim.LOS.los_pop import LOSPop import os from astropy.cosmology import FlatLambdaCDM import pytest @@ -14,7 +14,7 @@ def test_default_settings(): - config = LOSConfig() + config = LOSPop() assert config.mixgauss_gamma is False assert config.mixgauss_means is None assert config.mixgauss_stds is None @@ -25,23 +25,10 @@ def test_default_settings(): assert config.no_correction_path is None -def test_known_input(): - kappa = 0.1 - gamma1, gamma2 = -0.05, 0.05 - los_dict = {"gamma": [gamma1, gamma2], "kappa": kappa} - config = LOSConfig(**los_dict) - gamma1_, gamma2_, kappa_ = config.calculate_los_linear_distortions( - source_redshift=0, deflector_redshift=0 - ) - assert gamma1_ == gamma1 - assert gamma2_ == gamma2 - assert kappa_ == kappa - - @pytest.fixture -def los_config(): +def los_pop(): # Create an instance of LOSConfig with some default settings - config = LOSConfig( + los_pop = LOSPop( los_bool=True, mixgauss_gamma=False, mixgauss_means=[0.1], @@ -51,44 +38,49 @@ def los_config(): nonlinear_correction_path=None, no_correction_path=None, ) - return config + return los_pop -def test_no_los_effects(los_config): - los_config.los_bool = False - los_config.nonlinear_los_bool = False +def test_no_los_effects(los_pop): + los_pop.los_bool = False + los_pop.nonlinear_los_bool = False source = 0.5 deflector = 0.2 - assert los_config.calculate_los_linear_distortions(source, deflector) == (0, 0, 0) + los_class = los_pop.draw_los(source, deflector) + kappa = los_class.convergence + gamma1, gamma2 = los_class.shear + assert (kappa, gamma1, gamma2) == (0, 0, 0) -def test_gaussian_mixture_model_gamma(los_config): - los_config.mixgauss_gamma = True +def test_gaussian_mixture_model_gamma(los_pop): + los_pop.mixgauss_gamma = True source = 0.4 deflector = 0.2 - gamma1, gamma2, kappa = los_config.calculate_los_linear_distortions( - source, deflector - ) + los_class = los_pop.draw_los(source, deflector) + kappa = los_class.convergence + gamma1, gamma2 = los_class.shear assert isinstance(gamma1, float) assert isinstance(gamma2, float) assert isinstance(kappa, float) -def test_conflicting_settings_error(los_config): - los_config.mixgauss_gamma = True - los_config.nonlinear_los_bool = True +def test_conflicting_settings_error(los_pop): + los_pop.mixgauss_gamma = True + los_pop.nonlinear_los_bool = True source = 0.3 deflector = 0.1 with pytest.raises(ValueError): - los_config.calculate_los_linear_distortions(source, deflector) + los_pop.draw_los(source, deflector) -def test_nonlinear_los_corrections(los_config): - los_config.nonlinear_los_bool = False - los_config.no_correction_path = path_to_h5 +def test_nonlinear_los_corrections(los_pop): + los_pop.nonlinear_los_bool = False + los_pop.no_correction_path = path_to_h5 source = 0.2 deflector = 0.1 - g1, g2, kappa = los_config.calculate_los_linear_distortions(source, deflector) - assert isinstance(g1, float) - assert isinstance(g2, float) + los_class = los_pop.draw_los(source, deflector) + kappa = los_class.convergence + gamma1, gamma2 = los_class.shear + assert isinstance(gamma1, float) + assert isinstance(gamma2, float) assert isinstance(kappa, float) diff --git a/tests/test_roman_image_simulation.py b/tests/test_roman_image_simulation.py index 0ffb85b91..3b363e899 100644 --- a/tests/test_roman_image_simulation.py +++ b/tests/test_roman_image_simulation.py @@ -5,6 +5,7 @@ from slsim.image_simulation import simulate_image from slsim.Sources.source import Source from slsim.Deflectors.deflector import Deflector +from slsim.LOS.los_individual import LOSIndividual import os import pickle import pytest @@ -60,7 +61,7 @@ LENS = Lens( source_class=source, deflector_class=deflector, - los_dict=LOS_DICT, + los_class=LOSIndividual(**LOS_DICT), cosmo=COSMO, )