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

Refactoring SLSim - Merging DeflectorBase and SourcePopBase into single Population class. #237

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
844c8e6
init commit
jacob-hjortlund Aug 15, 2024
ca24d92
Merge branch 'refactor/simplify_lenspop' into refactor/merge_deflecto…
jacob-hjortlund Aug 15, 2024
dce2c7a
added PopulationBase and GalaxyPopulation skeleton
jacob-hjortlund Aug 15, 2024
210c509
simplified preprocessing using for-loop, need to include deflector re…
jacob-hjortlund Aug 15, 2024
30f8200
Merge branch 'refactor/simplify_lenspop' into refactor/merge_deflecto…
jacob-hjortlund Aug 16, 2024
59bca8f
Merge branch 'refactor/simplify_lenspop' into refactor/merge_deflecto…
jacob-hjortlund Aug 19, 2024
5cd960e
added helper funcs from elliptical_lens_galaxies, expect to be moved …
jacob-hjortlund Aug 19, 2024
a58ff51
moved exceptions to init
jacob-hjortlund Aug 19, 2024
bfe9cfa
minor
jacob-hjortlund Aug 19, 2024
d6e24bf
vectorized epsilon2e
jacob-hjortlund Aug 19, 2024
6e8c084
vectorized elliptical_projected_eccentricity
jacob-hjortlund Aug 19, 2024
a4eb6c1
minor fix to validity check
jacob-hjortlund Aug 19, 2024
7dd3845
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 19, 2024
a84c00c
updated docstring and type hinting for vel_disp_from_m_star
jacob-hjortlund Aug 19, 2024
2b59275
Merge branch 'refactor/merge_deflector_and_source' of github.com:jaco…
jacob-hjortlund Aug 19, 2024
2ac5f3a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 19, 2024
69e0b63
updated preprocessing of galaxy tables, added todos
jacob-hjortlund Aug 19, 2024
33d55a7
Merge branch 'refactor/merge_deflector_and_source' of github.com:jaco…
jacob-hjortlund Aug 19, 2024
4187170
minor
jacob-hjortlund Aug 19, 2024
17f0f94
minor
jacob-hjortlund Aug 19, 2024
1078754
minor
jacob-hjortlund Aug 20, 2024
98e55cf
started velocity_dispersion.py
jacob-hjortlund Aug 20, 2024
a0a08b1
never leave stuff uncommited when leaving for the day...
jacob-hjortlund Aug 22, 2024
c42da9b
Merge remote-tracking branch 'slsim-project/main' into refactor/merge…
jacob-hjortlund Aug 22, 2024
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
Empty file added slsim/Populations/__init__.py
Empty file.
265 changes: 265 additions & 0 deletions slsim/Populations/populations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
import warnings

Check warning on line 1 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L1

Added line #L1 was not covered by tests

import numpy as np
import slsim.Populations.velocity_dispersion as vd

Check warning on line 4 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L3-L4

Added lines #L3 - L4 were not covered by tests

from typing import Union, Optional
from abc import ABC, abstractmethod
from astropy.units import Quantity
from astropy.table import Table, Column
from astropy.cosmology import Cosmology

Check warning on line 10 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L6-L10

Added lines #L6 - L10 were not covered by tests


class PopulationBase(ABC):

Check warning on line 13 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L13

Added line #L13 was not covered by tests

def __init__(self, cosmo: Cosmology, sky_area: Quantity):

Check warning on line 15 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L15

Added line #L15 was not covered by tests

self.cosmo = cosmo
self.sky_area = sky_area

Check warning on line 18 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L17-L18

Added lines #L17 - L18 were not covered by tests

@abstractmethod
def __len__(self) -> int:
pass

Check warning on line 22 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L20-L22

Added lines #L20 - L22 were not covered by tests

@abstractmethod
def sample(self, seed: Optional[int] = None, n: Optional[int] = 1):
pass

Check warning on line 26 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L24-L26

Added lines #L24 - L26 were not covered by tests


class GalaxyPopulation(PopulationBase):

Check warning on line 29 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L29

Added line #L29 was not covered by tests

def __init__(

Check warning on line 31 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L31

Added line #L31 was not covered by tests
self,
cosmo: Cosmology,
galaxy_table: Union[Table, list[Table]],
kwargs_cut: dict,
sky_area: Quantity,
light_profile: str = "single_sersic",
):

super().__init__(cosmo=cosmo, sky_area=sky_area)

Check warning on line 40 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L40

Added line #L40 was not covered by tests

self.galaxy_table = galaxy_table
self.kwargs_cut = kwargs_cut
self.light_profile = light_profile

Check warning on line 44 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L42-L44

Added lines #L42 - L44 were not covered by tests

if light_profile not in ["single_sersic", "double_sersic"]:
raise ValueError(

Check warning on line 47 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L46-L47

Added lines #L46 - L47 were not covered by tests
"light_profile %s not supported. Choose between single_sersic or double_sersic."
% light_profile
)

is_table = isinstance(galaxy_table, Table)
is_list = isinstance(galaxy_table, list)
if is_list:
containts_only_tables = all(

Check warning on line 55 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L52-L55

Added lines #L52 - L55 were not covered by tests
isinstance(table, Table) for table in galaxy_table
)
if not (is_table or is_list and containts_only_tables):
raise ValueError(

Check warning on line 59 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L58-L59

Added lines #L58 - L59 were not covered by tests
"galaxy_table must be an astropy table or a list of astropy tables."
)

def __len__(self) -> int:
return len(self.galaxy_table)

Check warning on line 64 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L63-L64

Added lines #L63 - L64 were not covered by tests

def _preprocess_galaxy_tables(

Check warning on line 66 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L66

Added line #L66 was not covered by tests
self, galaxy_tables: Union[Table, list[Table]]
) -> Union[Table, list[Table]]:

is_table = isinstance(galaxy_tables, Table)
if is_table:
galaxy_tables = [galaxy_tables]

Check warning on line 72 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L70-L72

Added lines #L70 - L72 were not covered by tests

# TODO: Rename E1, E2 and e1_light, e2_light to shared e1_0, e2_0,
# make addititional components responsibility of catalog objects.
expected_columns = [

Check warning on line 76 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L76

Added line #L76 was not covered by tests
"e1",
"e2",
"n_sersic",
"n_sersic_0",
"n_sersic_1",
"e0_1",
"e0_2",
"e1_1",
"e1_2",
"angular_size0",
"angular_size1",
"e1_light",
"e2_light",
"e1_mass",
"e2_mass",
"vel_disp",
]

# TODO START: MAKE THIS THE RESPONSIBILITY OF FUTURE CATALOG OBJECTS
for galaxy_table, i in enumerate(galaxy_tables):
galaxy_tables[i] = convert_to_slsim_convention(

Check warning on line 97 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L96-L97

Added lines #L96 - L97 were not covered by tests
galaxy_catalog=galaxy_table,
light_profile=self.light_profile,
input_catalog_type=catalog_type,
)

for expected_column in expected_columns:
for galaxy_table in galaxy_tables:
column_names = galaxy_table.columns
n_rows = len(galaxy_table)
if expected_column not in column_names:
column = Column([-1] * n_rows, name=expected_column)
galaxy_table.add_column(column)
if "ellipticity" not in column_names:
raise ValueError("ellipticity is missing in galaxy_table columns.")

Check warning on line 111 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L103-L111

Added lines #L103 - L111 were not covered by tests
# TODO END

# TODO: CONSIDER MAKING RESPONSIBILITY OF FUTURE CATALOG OBJECTS
for galaxy_table in galaxy_tables:

Check warning on line 115 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L115

Added line #L115 was not covered by tests

# TODO: SETUP VELOCITY_DISPERSION.PY THAT INCLUDES DEFAULTING TO STELLAR MASS
galaxy_table["vel_disp"] = np.where(

Check warning on line 118 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L118

Added line #L118 was not covered by tests
galaxy_table["vel_disp"] == -1,
vd.vel_disp_from_m_star(galaxy_table["stellar_mass"]),
galaxy_table["vel_disp"],
)

e1_light, e2_light, e1_mass, e2_mass = elliptical_projected_eccentricity(

Check warning on line 124 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L124

Added line #L124 was not covered by tests
ellipticity=galaxy_table["ellipticity"],
)
galaxy_table["e1_light"] = np.where(

Check warning on line 127 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L127

Added line #L127 was not covered by tests
galaxy_table["e1_light"] == -1, e1_light, galaxy_table["e1_light"]
)
galaxy_table["e2_light"] = np.where(

Check warning on line 130 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L130

Added line #L130 was not covered by tests
galaxy_table["e2_light"] == -1, e2_light, galaxy_table["e2_light"]
)
galaxy_table["e1_mass"] = np.where(

Check warning on line 133 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L133

Added line #L133 was not covered by tests
galaxy_table["e1_mass"] == -1, e1_mass, galaxy_table["e1_mass"]
)
galaxy_table["e2_mass"] = np.where(

Check warning on line 136 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L136

Added line #L136 was not covered by tests
galaxy_table["e2_mass"] == -1, e2_mass, galaxy_table["e2_mass"]
)

galaxy_table["n_sersic"] = np.where(

Check warning on line 140 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L140

Added line #L140 was not covered by tests
galaxy_table["n_sersic"] == -1, 4, galaxy_table["n_sersic"]
)

if is_table:
galaxy_tables = galaxy_tables[0]

Check warning on line 145 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L144-L145

Added lines #L144 - L145 were not covered by tests

return galaxy_tables

Check warning on line 147 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L147

Added line #L147 was not covered by tests

@abstractmethod
def sample(self, seed: Optional[int] = None, n: Optional[int] = 1):
pass

Check warning on line 151 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L149-L151

Added lines #L149 - L151 were not covered by tests


def epsilon2e(epsilon: Union[float, np.ndarray]) -> Union[float, np.ndarray]:

Check warning on line 154 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L154

Added line #L154 was not covered by tests
"""Translates ellipticity definitions from.

.. math::
\epsilon = \\equic \\frac{1 - q^2}{1 + q^2}

to

.. math::
e = \\equic \\frac{1-q}{1+q}

Args:
epsilon (Union[float, np.ndarray]): Ellipticity

Raises:
ValueError: If epsilon is not in the range [0, 1]

Returns:
Union[float, np.ndarray]: Eccentricity
"""

is_valid = np.all((epsilon >= 0) & (epsilon <= 1))
if not is_valid:
raise ValueError("epsilon must be in the range [0, 1].")

Check warning on line 177 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L175-L177

Added lines #L175 - L177 were not covered by tests

# Catch warnings from division by zero
# since epsilon = 0 is a valid input
with warnings.catch_warnings():
warnings.simplefilter("ignore")
e = (1 - np.sqrt(1 - epsilon**2)) / epsilon
e = np.where(np.isnan(e), 0, e)

Check warning on line 184 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L181-L184

Added lines #L181 - L184 were not covered by tests

return e

Check warning on line 186 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L186

Added line #L186 was not covered by tests


def elliptical_projected_eccentricity(

Check warning on line 189 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L189

Added line #L189 was not covered by tests
ellipticity: Union[float, np.ndarray],
light2mass_e_scaling: Union[float, np.ndarray] = 1.0,
light2mass_e_scatter: Union[float, np.ndarray] = 0.1,
light2mass_angle_scatter: Union[float, np.ndarray] = 0.1,
rng: Optional[np.random.Generator] = None,
**kwargs
) -> tuple[Union[float, np.ndarray]]:
"""Projected eccentricity of elliptical galaxies as a function of other deflector
parameters.

Args:
ellipticity (Union[float, np.ndarray]): Eccentricity amplitude (1-q^2)/(1+q^2).
light2mass_e_scaling (Union[float, np.ndarray], optional): Scaling factor of mass eccentricity / light eccentricity. Defaults to 1.0.
light2mass_e_scatter (Union[float, np.ndarray], optional): Scatter in light and mass eccentricities from the scaling relation. Defaults to 0.1.
light2mass_angle_scatter (Union[float, np.ndarray], optional): Scatter in orientation angle between light and mass eccentricities. Defaults to 0.1.
rng (Optional[np.random.Generator], optional): Numpy Random Generator instance. If None, use np.random. default_rng. Defaults to None.

Raises:
ValueError: If light2mass arguments do not have the same length as input ellipticity.

Returns:
tuple[Union[float, np.ndarray]]: e1_light, e2_light, e1_mass, e2_mass eccentricity components
"""

if rng is None:
rng = np.random.default_rng()

Check warning on line 215 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L214-L215

Added lines #L214 - L215 were not covered by tests

ellipticity_is_float = isinstance(ellipticity, float)
light2mass_are_float = (

Check warning on line 218 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L217-L218

Added lines #L217 - L218 were not covered by tests
isinstance(light2mass_e_scaling, float)
and isinstance(light2mass_e_scatter, float)
and isinstance(light2mass_angle_scatter, float)
)

ellipticity = np.atleast_1d(ellipticity)
light2mass_e_scaling = np.atleast_1d(light2mass_e_scaling)
light2mass_e_scatter = np.atleast_1d(light2mass_e_scatter)
light2mass_angle_scatter = np.atleast_1d(light2mass_angle_scatter)
n = len(ellipticity)

Check warning on line 228 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L224-L228

Added lines #L224 - L228 were not covered by tests

if light2mass_are_float:
light2mass_e_scaling = np.full(n, light2mass_e_scaling)
light2mass_e_scatter = np.full(n, light2mass_e_scatter)
light2mass_angle_scatter = np.full(n, light2mass_angle_scatter)

Check warning on line 233 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L230-L233

Added lines #L230 - L233 were not covered by tests

light2mass_args_valid = (

Check warning on line 235 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L235

Added line #L235 was not covered by tests
n == len(light2mass_e_scaling)
and n == len(light2mass_e_scatter)
and n == len(light2mass_angle_scatter)
)
if not light2mass_args_valid:
raise ValueError(

Check warning on line 241 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L240-L241

Added lines #L240 - L241 were not covered by tests
"light2mass arguments must have the same length as input ellipticity."
)

e_light = epsilon2e(ellipticity)
phi_light = rng.uniform(0, np.pi, size=n)
e1_light = e_light * np.cos(2 * phi_light)
e2_light = e_light * np.sin(2 * phi_light)

Check warning on line 248 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L245-L248

Added lines #L245 - L248 were not covered by tests

e_mass = light2mass_e_scaling * ellipticity + rng.normal(

Check warning on line 250 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L250

Added line #L250 was not covered by tests
loc=0, scale=light2mass_e_scatter, size=n
)
phi_mass = phi_light + rng.normal(loc=0, scale=light2mass_angle_scatter, size=n)
e1_mass = e_mass * np.cos(2 * phi_mass)
e2_mass = e_mass * np.sin(2 * phi_mass)

Check warning on line 255 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L253-L255

Added lines #L253 - L255 were not covered by tests

if ellipticity_is_float:
e1_light, e2_light, e1_mass, e2_mass = (

Check warning on line 258 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L257-L258

Added lines #L257 - L258 were not covered by tests
e1_light[0],
e2_light[0],
e1_mass[0],
e2_mass[0],
)

return e1_light, e2_light, e1_mass, e2_mass

Check warning on line 265 in slsim/Populations/populations.py

View check run for this annotation

Codecov / codecov/patch

slsim/Populations/populations.py#L265

Added line #L265 was not covered by tests
Loading
Loading