Coverage for src / galsbi / ucat_sps / galaxy_population_models / galaxy_size.py: 100%
40 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-17 09:47 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-17 09:47 +0000
1# Copyright (C) 2025 LMU Munich
2# Author: Luca Tortorelli
3# created: Apr 2025
5import numpy as np
7from galsbi.ucat.galaxy_population_models.galaxy_size import r50_phys_to_ang
10def sample_r50_from_stellar_mass(
11 redshifts, log10_stellar_mass, cosmology, par, galaxy_type="blue", seed=None
12):
13 """
14 This function samples galaxy sizes conditioned on their stellar masses and types.
16 :param redshifts: (array_like[n_gal,]) redshifts drawn from the stellar mass
17 function.
18 :param log10_stellar_mass: (array_like[n_gal,]) log10 of the stellar masses drawn
19 from the stellar mass function.
20 :param cosmology: (obj) PyCosmo class object.
21 :param par: (obj) par objects containing the Ucat parameters.
22 :param galaxy_type: (str) "blue" or "red" galaxy population.
23 :param seed: (int) random seed.
24 :return r50_ang: (array_like[n_gal,]) angular sizes in pixel.
25 :return r50_phys: (array_like[n_gal,]) physical sizes of galaxies in kpc.
26 """
27 r50_phys = sample_r50_phys_from_stellar_mass(
28 redshifts, log10_stellar_mass, par, galaxy_type, seed=seed
29 )
30 # convert physical size to observerd angular size
31 r50_ang = r50_phys_to_ang(r50_phys, cosmology, redshifts)
33 r50_ang_pix = r50_ang.astype(par.catalog_precision) / par.pixscale
34 r50_ang_arcsec = r50_ang.astype(par.catalog_precision)
35 r50_phys = r50_phys.astype(par.catalog_precision)
37 return r50_ang_pix, r50_ang_arcsec, r50_phys
40def sample_r50_phys_from_stellar_mass(
41 redshifts, log10_stellar_mass, par, galaxy_type, seed=None
42):
43 """
44 This function samples the physical galaxy sizes conditioned on the stellar mass.
45 The mean size has a power-law dependence from stellar mass. A single power-law
46 correctly represents blue galaxy sizes, while a flattend power-law at low sizes is
47 required for red galaxies. The parameters of the power-laws evolve linearly with
48 redshift. The actual galaxy sizes are drawn from a log-normal distribution centred
49 on the mean size from the power-law and with scatter value taken from Shen+2003. The
50 functional forms are from Nedkova+2021.
52 :param redshifts: (array_like[n_gal,]) redshifts drawn from the stellar mass
53 function.
54 :param log10_stellar_mass: (array_like[n_gal,]) log10 of the stellar masses drawn
55 from the stellar mass function.
56 :param par: (obj) par objects containing the Ucat parameters.
57 :param galaxy_type: (str) "blue" or "red" galaxy population.
58 :param seed: (int) random seed.
59 :return r50_phys: (array_like[n_gal,]) physical sizes of galaxies in kpc.
60 """
61 if seed is None:
62 seed = 42
63 rng = np.random.default_rng(seed)
65 log10A_slope = par.r50_stellar_mass_logA_blue_slope
66 log10A_intcpt = par.r50_stellar_mass_logA_blue_intcpt
67 log10A = log10A_intcpt + log10A_slope * redshifts
68 B_slope = par.r50_stellar_mass_B_blue_slope
69 B_intcpt = par.r50_stellar_mass_B_blue_intcpt
70 B = B_intcpt + B_slope * redshifts
72 eta_slope = par.r50_stellar_mass_eta_red_slope
73 eta_intcpt = par.r50_stellar_mass_eta_red_intcpt
74 eta = eta_intcpt + eta_slope * redshifts
75 theta_slope = par.r50_stellar_mass_theta_red_slope
76 theta_intcpt = par.r50_stellar_mass_theta_red_intcpt
77 theta = theta_intcpt + theta_slope * redshifts
78 log10zeta_slope = par.r50_stellar_mass_logzeta_red_slope
79 log10zeta_intcpt = par.r50_stellar_mass_logzeta_red_intcpt
80 log10zeta = log10zeta_intcpt + log10zeta_slope * redshifts
81 delta_slope = par.r50_stellar_mass_delta_red_slope
82 delta_intcpt = par.r50_stellar_mass_delta_red_intcpt
83 delta = delta_intcpt + delta_slope * redshifts
85 if galaxy_type == "blue":
86 r50_phys_mean = (
87 10**log10A * ((10**log10_stellar_mass) / (5 * 10**10)) ** B
88 ) # unit: kpc
89 elif galaxy_type == "red":
90 r50_phys_mean = ((10**log10zeta) * (10**log10_stellar_mass) ** eta) * (
91 1 + ((10**log10_stellar_mass) / (10**delta))
92 ) ** (theta - eta)
93 else:
94 raise ValueError(f"Unknown galaxy type: {galaxy_type}")
96 # sample from log-normal distribution
97 r50_phys_std = getattr(par, f"logr50_stellar_mass_std_{galaxy_type}")
98 r50_phys = rng.normal(loc=np.log(r50_phys_mean), scale=r50_phys_std)
99 r50_phys = np.exp(r50_phys) # unit: kpc
101 return r50_phys