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

1# Copyright (C) 2025 LMU Munich 

2# Author: Luca Tortorelli 

3# created: Apr 2025 

4 

5import numpy as np 

6 

7from galsbi.ucat.galaxy_population_models.galaxy_size import r50_phys_to_ang 

8 

9 

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. 

15 

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) 

32 

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) 

36 

37 return r50_ang_pix, r50_ang_arcsec, r50_phys 

38 

39 

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. 

51 

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) 

64 

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 

71 

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 

84 

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}") 

95 

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 

100 

101 return r50_phys