ler 0.4.2__py3-none-any.whl → 0.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ler might be problematic. Click here for more details.

Files changed (35) hide show
  1. ler/__init__.py +26 -26
  2. ler/gw_source_population/__init__.py +1 -0
  3. ler/gw_source_population/cbc_source_parameter_distribution.py +1073 -815
  4. ler/gw_source_population/cbc_source_redshift_distribution.py +618 -294
  5. ler/gw_source_population/jit_functions.py +484 -9
  6. ler/gw_source_population/sfr_with_time_delay.py +107 -0
  7. ler/image_properties/image_properties.py +41 -12
  8. ler/image_properties/multiprocessing_routine.py +5 -209
  9. ler/lens_galaxy_population/__init__.py +2 -0
  10. ler/lens_galaxy_population/epl_shear_cross_section.py +0 -0
  11. ler/lens_galaxy_population/jit_functions.py +101 -9
  12. ler/lens_galaxy_population/lens_galaxy_parameter_distribution.py +813 -881
  13. ler/lens_galaxy_population/lens_param_data/density_profile_slope_sl.txt +5000 -0
  14. ler/lens_galaxy_population/lens_param_data/external_shear_sl.txt +2 -0
  15. ler/lens_galaxy_population/lens_param_data/number_density_zl_zs.txt +48 -0
  16. ler/lens_galaxy_population/lens_param_data/optical_depth_epl_shear_vd_ewoud.txt +48 -0
  17. ler/lens_galaxy_population/mp copy.py +554 -0
  18. ler/lens_galaxy_population/mp.py +736 -138
  19. ler/lens_galaxy_population/optical_depth.py +2248 -616
  20. ler/rates/__init__.py +1 -2
  21. ler/rates/gwrates.py +126 -72
  22. ler/rates/ler.py +218 -111
  23. ler/utils/__init__.py +2 -0
  24. ler/utils/function_interpolation.py +322 -0
  25. ler/utils/gwsnr_training_data_generator.py +233 -0
  26. ler/utils/plots.py +1 -1
  27. ler/utils/test.py +1078 -0
  28. ler/utils/utils.py +492 -125
  29. {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/METADATA +30 -17
  30. ler-0.4.3.dist-info/RECORD +34 -0
  31. {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/WHEEL +1 -1
  32. ler/rates/ler copy.py +0 -2097
  33. ler-0.4.2.dist-info/RECORD +0 -25
  34. {ler-0.4.2.dist-info → ler-0.4.3.dist-info/licenses}/LICENSE +0 -0
  35. {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/top_level.txt +0 -0
@@ -15,17 +15,16 @@ from astropy.cosmology import LambdaCDM
15
15
  # from gwcosmo import priors as p
16
16
  from scipy.integrate import quad
17
17
 
18
- # for generating mass distribution
19
- from gwcosmo import priors as p
20
-
21
18
  # for multiprocessing
22
19
  # Import helper routines
23
- from ..utils import interpolator_from_pickle, cubic_spline_interpolator
20
+ from ..utils import FunctionConditioning
24
21
 
25
22
  # import redshift distribution sampler
26
23
  from .cbc_source_redshift_distribution import CBCSourceRedshiftDistribution
27
24
 
28
- from .jit_functions import lognormal_distribution_2D, inverse_transform_sampler_m1m2
25
+ from .jit_functions import lognormal_distribution_2D, bns_bimodal_pdf, inverse_transform_sampler_m1m2, sample_powerlaw_gaussian_source_bbh_masses, sample_broken_powerlaw_nsbh_masses
26
+
27
+ chunk_size = 10000
29
28
 
30
29
 
31
30
  class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
@@ -72,7 +71,7 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
72
71
  ----------
73
72
  >>> from ler.gw_source_population import CBCSourceParameterDistribution
74
73
  >>> cbc = CBCSourceParameterDistribution()
75
- >>> params = cbc.sample_gw_parameters(size=1000)
74
+ >>> params = cbc.gw_parameters(size=1000)
76
75
  >>> print("sampled parameters=",list(params.keys()))
77
76
 
78
77
  Instance Attributes
@@ -128,46 +127,46 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
128
127
  | | table for converting redshift |
129
128
  | | to luminosity distance |
130
129
  +-------------------------------------+----------------------------------+
131
- |:meth:`~sample_gw_parameters` | Function to sample all the |
130
+ |:meth:`~gw_parameters` | Function to sample all the |
132
131
  | | intrinsic and extrinsic |
133
132
  | | parameters of compact binaries |
134
133
  +-------------------------------------+----------------------------------+
135
- |:meth:`~sample_source_frame_masses` | Function to sample source mass1 |
134
+ |:meth:`~source_frame_masses` | Function to sample source mass1 |
136
135
  | | and mass2 |
137
136
  +-------------------------------------+----------------------------------+
138
- |:meth:`~sample_geocent_time` | Function to sample geocent time |
137
+ |:meth:`~geocent_time` | Function to sample geocent time |
139
138
  +-------------------------------------+----------------------------------+
140
- |:meth:`~sample_zs` | Function to sample source |
139
+ |:meth:`~zs` | Function to sample source |
141
140
  | | redshift |
142
141
  +-------------------------------------+----------------------------------+
143
- |:meth:`~sample_ra` | Function to sample right |
142
+ |:meth:`~ra` | Function to sample right |
144
143
  | | ascension (sky position) |
145
144
  +-------------------------------------+----------------------------------+
146
- |:meth:`~sample_dec` | Function to sample declination |
145
+ |:meth:`~dec` | Function to sample declination |
147
146
  | | (sky position) |
148
147
  +-------------------------------------+----------------------------------+
149
- |:meth:`~sample_phase` | Function to sample coalescence |
148
+ |:meth:`~phase` | Function to sample coalescence |
150
149
  | | phase |
151
150
  +-------------------------------------+----------------------------------+
152
- |:meth:`~sample_psi` | Function to sample polarization |
151
+ |:meth:`~psi` | Function to sample polarization |
153
152
  | | angle |
154
153
  +-------------------------------------+----------------------------------+
155
- |:meth:`~sample_theta_jn` | Function to sample inclination |
154
+ |:meth:`~theta_jn` | Function to sample inclination |
156
155
  | | angle |
157
156
  +-------------------------------------+----------------------------------+
158
- |:meth:`~sample_a1` | Function to sample spin1 |
157
+ |:meth:`~a_1` | Function to sample spin1 |
159
158
  | | magnitude |
160
159
  +-------------------------------------+----------------------------------+
161
- |:meth:`~sample_a2` | Function to sample spin2 |
160
+ |:meth:`~a_2` | Function to sample spin2 |
162
161
  | | magnitude |
163
162
  +-------------------------------------+----------------------------------+
164
- |:meth:`~sample_tilt_1` | Function to sample tilt1 angle |
163
+ |:meth:`~tilt_1` | Function to sample tilt1 angle |
165
164
  +-------------------------------------+----------------------------------+
166
- |:meth:`~sample_tilt_2` | Function to sample tilt2 angle |
165
+ |:meth:`~tilt_2` | Function to sample tilt2 angle |
167
166
  +-------------------------------------+----------------------------------+
168
- |:meth:`~sample_phi_12` | Function to sample phi12 angle |
167
+ |:meth:`~phi_12` | Function to sample phi12 angle |
169
168
  +-------------------------------------+----------------------------------+
170
- |:meth:`~sample_phi_jl` | Function to sample phi_jl angle |
169
+ |:meth:`~phi_jl` | Function to sample phi_jl angle |
171
170
  +-------------------------------------+----------------------------------+
172
171
  |:meth:`~binary_masses_BBH_popI_II_powerlaw_gaussian` |
173
172
  +-------------------------------------+----------------------------------+
@@ -190,12 +189,6 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
190
189
  | | Refer to Ng et al. 2022. Eqn. 1 |
191
190
  | | and 4 |
192
191
  +-------------------------------------+----------------------------------+
193
- |:meth:`~binary_masses_BNS_gwcosmo` |
194
- +-------------------------------------+----------------------------------+
195
- | | Function to sample source mass1 |
196
- | | and mass2 from powerlaw |
197
- | | distribution. |
198
- +-------------------------------------+----------------------------------+
199
192
  |:meth:`~binary_masses_BNS_bimodal` | Function to sample source mass1 |
200
193
  | | and mass2 from bimodal |
201
194
  | | distribution. Refer to |
@@ -267,33 +260,21 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
267
260
  self.spin_zero = spin_zero
268
261
  self.spin_precession = spin_precession
269
262
  self.directory = directory
270
- # initialize the interpolator's parameters
271
- self.create_new_interpolator = dict(
272
- redshift_distribution=dict(create_new=False, resolution=1000),
273
- z_to_luminosity_distance=dict(create_new=False, resolution=1000),
274
- differential_comoving_volume=dict(create_new=False, resolution=1000),
275
- )
276
- if isinstance(create_new_interpolator, dict):
277
- self.create_new_interpolator.update(create_new_interpolator)
278
- elif create_new_interpolator is True:
279
- self.create_new_interpolator = dict(
280
- redshift_distribution=dict(create_new=True, resolution=500),
281
- z_to_luminosity_distance=dict(create_new=True, resolution=500),
282
- differential_comoving_volume=dict(create_new=True, resolution=500),
283
- )
263
+
264
+ # setting up the interpolator creation parameters
265
+ create_new_interpolator = self.setup_decision_dictionary_gw_params(create_new_interpolator)
284
266
 
285
267
  # dealing with prior functions and categorization
286
268
  (
287
269
  self.gw_param_samplers,
288
270
  self.gw_param_samplers_params,
289
- self.sampler_names,
290
271
  ) = self.source_priors_categorization(
291
272
  event_type, source_priors, source_priors_params
292
273
  )
293
274
 
294
275
  # initialize the SourceGalaxyPopulationModel mother class
295
276
  # for redshift distribution
296
- # instance attribute sample_source_redshift is initialized here
277
+ # instance attribute source_redshift is initialized here
297
278
  super().__init__(
298
279
  z_min=z_min,
299
280
  z_max=z_max,
@@ -304,86 +285,266 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
304
285
  ],
305
286
  cosmology=cosmology,
306
287
  directory=directory,
307
- create_new_interpolator=self.create_new_interpolator,
288
+ create_new_interpolator=create_new_interpolator,
308
289
  )
309
290
 
291
+ print("\nInitializing CBCSourceParameterDistribution...\n")
310
292
  # initializing samplers
311
293
  # it goes through the setter functions and assign the sampler functions
312
- self.sample_source_frame_masses = self.gw_param_samplers["source_frame_masses"]
313
- self.sample_geocent_time = self.gw_param_samplers["geocent_time"]
314
- self.sample_zs = self.gw_param_samplers["zs"]
315
- self.sample_ra = self.gw_param_samplers["ra"]
316
- self.sample_dec = self.gw_param_samplers["dec"]
317
- self.sample_phase = self.gw_param_samplers["phase"]
318
- self.sample_psi = self.gw_param_samplers["psi"]
319
- self.sample_theta_jn = self.gw_param_samplers["theta_jn"]
294
+ # self.source_redshift is already initialized in the super class
295
+ self.zs = self.gw_param_samplers["zs"]
296
+ self.source_frame_masses = self.gw_param_samplers["source_frame_masses"]
297
+ self.geocent_time = self.gw_param_samplers["geocent_time"]
298
+ self.ra = self.gw_param_samplers["ra"]
299
+ self.dec = self.gw_param_samplers["dec"]
300
+ self.phase = self.gw_param_samplers["phase"]
301
+ self.psi = self.gw_param_samplers["psi"]
302
+ self.theta_jn = self.gw_param_samplers["theta_jn"]
320
303
  # initialize the spin prior attribute
321
304
  # remove spin prior if spin_zero is True
322
305
  if not spin_zero:
323
- self.sample_a_1 = self.gw_param_samplers["a_1"]
324
- self.sample_a_2 = self.gw_param_samplers["a_2"]
306
+ self.a_1 = self.gw_param_samplers["a_1"]
307
+ self.a_2 = self.gw_param_samplers["a_2"]
325
308
  if spin_precession:
326
- self.sample_tilt_1 = self.gw_param_samplers["tilt_1"]
327
- self.sample_tilt_2 = self.gw_param_samplers["tilt_2"]
328
- self.sample_phi_12 = self.gw_param_samplers["phi_12"]
329
- self.sample_phi_jl = self.gw_param_samplers["phi_jl"]
309
+ self.tilt_1 = self.gw_param_samplers["tilt_1"]
310
+ self.tilt_2 = self.gw_param_samplers["tilt_2"]
311
+ self.phi_12 = self.gw_param_samplers["phi_12"]
312
+ self.phi_jl = self.gw_param_samplers["phi_jl"]
330
313
 
331
- def lookup_table_luminosity_distance(self, z_min, z_max, directory):
314
+
315
+ def setup_decision_dictionary_gw_params(self, create_new_interpolator):
332
316
  """
333
- Function to create a lookup table for the differential comoving volume
334
- and luminosity distance wrt redshift.
317
+ Method to set up a decision dictionary for interpolator creation.
335
318
 
336
319
  Parameters
337
320
  ----------
338
- z_min : `float`
339
- Minimum redshift of the source population
340
- z_max : `float`
341
- Maximum redshift of the source population
321
+ create_new_interpolator : `dict`, `bool`
322
+ If `dict`, dictionary of boolean values and resolution to create new interpolator.
323
+ If `bool`, boolean value to create new interpolator for all quantities.
342
324
 
343
- Attributes
344
- ----------
345
- z_to_luminosity_distance : `scipy.interpolate.interpolate`
346
- Function to convert redshift to luminosity distance
347
- differential_comoving_volume : `scipy.interpolate.interpolate`
348
- Function to calculate the differential comoving volume
325
+ Returns
326
+ -------
327
+ create_new_interpolator_ : `dict`
328
+ Dictionary of boolean values and resolution to create new interpolator.
329
+ e.g. dict(redshift_distribution=dict(create_new=False, resolution=1000), luminosity_distance=dict(create_new=False, resolution=1000), differential_comoving_volume=dict(create_new=False, resolution=1000))
349
330
  """
350
-
351
- # initialing cosmological functions for fast calculation through interpolation
352
- resolution = self.c_n_i["z_to_luminosity_distance"]["resolution"]
353
- create_new = self.c_n_i["z_to_luminosity_distance"]["create_new"]
354
- spline1 = interpolator_from_pickle(
355
- param_dict_given=dict(
356
- z_min=z_min, z_max=z_max, cosmology=self.cosmo, resolution=resolution
357
- ),
358
- directory=directory,
359
- sub_directory="z_to_luminosity_distance",
360
- name="z_to_luminosity_distance",
361
- x=np.linspace(z_min, z_max, resolution),
362
- pdf_func=lambda z_: self.cosmo.luminosity_distance(z_).value,
363
- conditioned_y=None,
364
- dimension=1,
365
- category="function",
366
- create_new=create_new,
331
+ create_new_interpolator_ = dict(
332
+ source_frame_masses=dict(create_new=False, resolution=500),
333
+ geocent_time=dict(create_new=False, resolution=500),
334
+ ra=dict(create_new=False, resolution=500),
335
+ dec=dict(create_new=False, resolution=500),
336
+ phase=dict(create_new=False, resolution=500),
337
+ psi=dict(create_new=False, resolution=500),
338
+ theta_jn=dict(create_new=False, resolution=500),
339
+ a_1=dict(create_new=False, resolution=500),
340
+ a_2=dict(create_new=False, resolution=500),
341
+ tilt_1=dict(create_new=False, resolution=500),
342
+ tilt_2=dict(create_new=False, resolution=500),
343
+ phi_12=dict(create_new=False, resolution=500),
344
+ phi_jl=dict(create_new=False, resolution=500),
345
+ merger_rate_density=dict(create_new=False, resolution=500),
346
+ redshift_distribution=dict(create_new=False, resolution=500),
347
+ luminosity_distance=dict(create_new=False, resolution=500),
348
+ differential_comoving_volume=dict(create_new=False, resolution=500),
367
349
  )
368
- self.z_to_luminosity_distance = njit(
369
- lambda z_: cubic_spline_interpolator(z_, spline1[0], spline1[1])
370
- )
371
- self.z_to_luminosity_distance.__doc__ = """
372
- Function to convert redshift to luminosity distance.
373
-
350
+ if isinstance(create_new_interpolator, dict):
351
+ create_new_interpolator_.update(create_new_interpolator)
352
+ elif create_new_interpolator is True:
353
+ for key in create_new_interpolator_:
354
+ create_new_interpolator_[key]["create_new"] = True
355
+
356
+ return create_new_interpolator_
357
+
358
+ def source_priors_categorization(
359
+ self, event_type, source_priors, source_prior_params
360
+ ):
361
+ """
362
+ Function to categorize the event priors and its parameters.
363
+
374
364
  Parameters
375
365
  ----------
376
- zs : `numpy.ndarray`
377
- 1D array of floats
378
- Source redshifts
366
+ event_type : `str`
367
+ Type of event to generate.
368
+ e.g. 'BBH', 'BNS', 'BBH_popIII', 'BBH_primordial', 'NSBH'
369
+ source_priors : `dict`
370
+ Dictionary of prior sampler functions for each parameter
371
+ source_prior_params : `dict`
372
+ Dictionary of sampler parameters for each GW parameter
379
373
 
380
374
  Returns
381
375
  ----------
382
- luminosity_distance : `numpy.ndarray`
383
- 1D array of floats
384
- luminosity distance
376
+ source_priors_ : `dict`
377
+ Dictionary of prior sampler functions for each parameter
378
+ source_prior_params_ : `dict`
379
+ Dictionary of sampler parameters for each parameter
380
+ sampler_names_ : `dict`
381
+ Dictionary of sampler names with description
382
+
383
+ Examples
384
+ ----------
385
+ >>> from ler.gw_source_population import CBCSourceParameterDistribution
386
+ >>> cbc = CBCSourceParameterDistribution()
387
+ >>> source_priors, source_prior_params, sampler_names = cbc.source_priors_categorization(event_type='BBH', source_priors=None, source_prior_params=None)
388
+ >>> print(source_priors.keys())
389
+ >>> print(source_prior_params.keys())
390
+ >>> print(sampler_names.keys())
385
391
  """
386
392
 
393
+ # for BBH
394
+ if event_type == "BBH":
395
+ merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
396
+ merger_rate_density_prior_params = dict(
397
+ R0=23.9 * 1e-9, b2=1.6, b3=2.1, b4=30 #
398
+ )
399
+ source_frame_masses_prior = "binary_masses_BBH_popI_II_powerlaw_gaussian"
400
+ source_frame_masses_prior_params = dict(
401
+ mminbh=4.98,
402
+ mmaxbh=112.5,
403
+ alpha=3.78,
404
+ mu_g=32.27,
405
+ sigma_g=3.88,
406
+ lambda_peak=0.03,
407
+ delta_m=4.8,
408
+ beta=0.81,
409
+ )
410
+ a_max = 0.8
411
+
412
+ elif event_type == "BNS":
413
+ merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
414
+ merger_rate_density_prior_params = dict(
415
+ R0=105.5 * 1e-9, b2=1.6, b3=2.1, b4=30
416
+ )
417
+ source_frame_masses_prior = "binary_masses_BNS_bimodal"
418
+ source_frame_masses_prior_params = dict(
419
+ w=0.643,
420
+ muL=1.352,
421
+ sigmaL=0.08,
422
+ muR=1.88,
423
+ sigmaR=0.3,
424
+ mmin=1.0,
425
+ mmax=2.3,
426
+ )
427
+ a_max = 0.05
428
+
429
+ elif event_type == "NSBH":
430
+ merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
431
+ merger_rate_density_prior_params = dict(
432
+ R0=27.0 * 1e-9, b2=1.6, b3=2.1, b4=30
433
+ )
434
+ source_frame_masses_prior = "binary_masses_NSBH_broken_powerlaw"
435
+ source_frame_masses_prior_params = dict(
436
+ mminbh=26,
437
+ mmaxbh=125,
438
+ alpha_1=6.75,
439
+ alpha_2=6.75,
440
+ b=0.5,
441
+ delta_m=5,
442
+ mminns=1.0,
443
+ mmaxns=3.0,
444
+ alphans=0.0,
445
+ )
446
+ a_max = 0.8
447
+
448
+ elif event_type == "BBH_popIII":
449
+ merger_rate_density_prior = "merger_rate_density_bbh_popIII_ken2022"
450
+ merger_rate_density_prior_params = dict(
451
+ n0=19.2 * 1e-9, aIII=0.66, bIII=0.3, zIII=11.6
452
+ )
453
+ source_frame_masses_prior = "binary_masses_BBH_popIII_lognormal"
454
+ source_frame_masses_prior_params = dict(
455
+ m_min=5.0, m_max=150.0, Mc=30.0, sigma=0.3, chunk_size=chunk_size
456
+ )
457
+ a_max = 0.8
458
+
459
+ elif event_type == "BBH_primordial":
460
+ merger_rate_density_prior = "merger_rate_density_bbh_primordial_ken2022"
461
+ merger_rate_density_prior_params = dict(
462
+ n0=0.044 * 1e-9, t0=13.786885302009708
463
+ )
464
+ source_frame_masses_prior = "binary_masses_BBH_primordial_lognormal"
465
+ source_frame_masses_prior_params = dict(
466
+ m_min=1.0, m_max=100.0, Mc=20.0, sigma=0.3, chunk_size=chunk_size
467
+ )
468
+ a_max = 0.8
469
+
470
+ else:
471
+ raise ValueError("event_type is not recognized")
472
+
473
+ # setting the priors and its parameters
474
+ source_priors_ = dict(
475
+ merger_rate_density=merger_rate_density_prior,
476
+ zs='source_redshift',
477
+ source_frame_masses=source_frame_masses_prior,
478
+ geocent_time="sampler_uniform",
479
+ ra="sampler_uniform",
480
+ dec="sampler_cosine",
481
+ phase="sampler_uniform",
482
+ psi="sampler_uniform",
483
+ theta_jn="sampler_sine",
484
+ )
485
+ source_prior_params_ = dict(
486
+ merger_rate_density=merger_rate_density_prior_params,
487
+ zs=None,
488
+ source_frame_masses=source_frame_masses_prior_params,
489
+ geocent_time=dict(xmin=1238166018, xmax=1269702018),
490
+ ra=dict(xmin=0., xmax=2.*np.pi),
491
+ dec=None, # dict(xmin=-np.pi/2, xmax=np.pi/2),
492
+ phase=dict(xmin=0., xmax=2.*np.pi),
493
+ psi=dict(xmin=0., xmax=np.pi),
494
+ theta_jn=None, # dict(xmin=0., xmax=np.pi),
495
+ )
496
+
497
+ # spin
498
+ if not self.spin_zero:
499
+ source_priors_["a_1"] = "sampler_uniform"
500
+ source_prior_params_["a_1"] = dict(xmin=-a_max, xmax=a_max)
501
+ source_priors_["a_2"] = "sampler_uniform"
502
+ source_prior_params_["a_2"] = dict(xmin=-a_max, xmax=a_max)
503
+
504
+ if self.spin_precession:
505
+ source_priors_["a_1"] = "sampler_uniform"
506
+ source_prior_params_["a_1"] = dict(xmin=0.0, xmax=a_max)
507
+ source_priors_["a_2"] = "sampler_uniform"
508
+ source_prior_params_["a_2"] = dict(xmin=0.0, xmax=a_max)
509
+ source_priors_["tilt_1"] = "sampler_sine"
510
+ source_prior_params_["tilt_1"] = None
511
+
512
+ source_priors_["tilt_2"] = "sampler_sine"
513
+ source_prior_params_["tilt_2"] = None
514
+
515
+ source_priors_["phi_12"] = "sampler_uniform"
516
+ source_prior_params_["phi_12"] = dict(xmin=0, xmax=2 * np.pi)
517
+ source_priors_["phi_jl"] = "sampler_uniform"
518
+ source_prior_params_["phi_jl"] = dict(xmin=0, xmax=2 * np.pi)
519
+
520
+ # update the priors if input is given
521
+ if source_priors:
522
+ source_priors_.update(source_priors)
523
+ if source_prior_params:
524
+ source_prior_params_.update(source_prior_params)
525
+
526
+ # taking care of source_prior_params from the available_gw_prior_list_and_its_params
527
+ for key, value in source_priors_.items():
528
+ if isinstance(value, str):
529
+ dict_ = self.available_gw_prior_list_and_its_params[key] # e.g. all source_frame_masses_prior function names and its parameters
530
+ if value in dict_:
531
+ param_dict = dict_[value]
532
+ if source_prior_params_[key] is None:
533
+ source_prior_params_[key] = param_dict
534
+ else:
535
+ param_dict.update(source_prior_params_[key])
536
+ source_prior_params_[key] = param_dict
537
+ else:
538
+ raise ValueError(
539
+ f"source_prior_params_['{key}'] is not in available_gw_prior_list_and_its_params"
540
+ )
541
+ elif not callable(value):
542
+ raise ValueError(
543
+ f"source_prior_params_['{key}'] should be either a string name of available sampler or a function"
544
+ )
545
+
546
+ return (source_priors_, source_prior_params_)
547
+
387
548
  def sample_gw_parameters(self, size=1000, param=None):
388
549
  """
389
550
  Function to sample BBH/BNS/NSBH intrinsic and extrinsics parameters.
@@ -403,36 +564,38 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
403
564
  ----------
404
565
  >>> from ler.gw_source_population import CBCSourceParameterDistribution
405
566
  >>> cbc = CBCSourceParameterDistribution()
406
- >>> params = cbc.sample_gw_parameters(size=1000)
567
+ >>> params = cbc.gw_parameters(size=1000)
407
568
  >>> print("sampled parameters=",list(params.keys()))
408
569
  """
409
570
 
410
571
  # check for input parameters
572
+ # allow some of the parameters to be fixed
411
573
  if param is None:
412
- param = {}
413
- param_keys = param.keys()
574
+ param = {} # empty
575
+ param_keys = param.keys() # empty
414
576
  else:
415
577
  param_keys = param.keys()
416
578
 
417
579
  # sample parameters
418
580
  param_names = list(self.gw_param_samplers.keys())
419
581
  del param_names[0] # remove merger_rate_density
420
- # make sure the order is correct
421
- sampler_names = list(self.sampler_names.keys())
422
582
 
423
583
  gw_parameters = {} # initialize dictionary to store parameters
424
- for name, sampler in zip(param_names, sampler_names):
584
+ for sampler_name in param_names:
425
585
  # print(name)
426
- if name not in param_keys:
586
+ if sampler_name not in param_keys:
427
587
  # Sample the parameter using the specified sampler function
428
- gw_parameters[name] = getattr(self, sampler)(size)
588
+ # try:
589
+ gw_parameters[sampler_name] = getattr(self, str(sampler_name))(size)
590
+ # except:
591
+ # raise Exception(f"Sampler {sampler_name} is not defined.")
429
592
  else:
430
593
  # Use the provided value from kwargs
431
- gw_parameters[name] = param[name]
594
+ gw_parameters[sampler_name] = param[sampler_name]
432
595
 
433
596
  # calculate luminosity distance
434
597
  zs = gw_parameters["zs"]
435
- gw_parameters["luminosity_distance"] = self.z_to_luminosity_distance(zs) # Mpc
598
+ gw_parameters["luminosity_distance"] = self.luminosity_distance(zs) # Mpc
436
599
 
437
600
  # mass1 and mass2
438
601
  m1, m2 = gw_parameters["source_frame_masses"] # Msun
@@ -450,16 +613,8 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
450
613
  def binary_masses_BBH_popI_II_powerlaw_gaussian(
451
614
  self,
452
615
  size,
453
- mminbh=4.98,
454
- mmaxbh=112.5,
455
- alpha=3.78,
456
- mu_g=32.27,
457
- sigma_g=3.88,
458
- lambda_peak=0.03,
459
- delta_m=4.8,
460
- beta=0.81,
461
616
  get_attribute=False,
462
- param=None,
617
+ **kwargs,
463
618
  ):
464
619
  """
465
620
  Function to sample source mass1 and mass2 with PowerLaw+PEAK model
@@ -509,48 +664,55 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
509
664
  >>> m1_src, m2_src = cbc.binary_masses_BBH_popI_II_powerlaw_gaussian(size=1000)
510
665
  """
511
666
 
512
- if param:
513
- mminbh = param["mminbh"]
514
- mmaxbh = param["mmaxbh"]
515
- alpha = param["alpha"]
516
- mu_g = param["mu_g"]
517
- sigma_g = param["sigma_g"]
518
- lambda_peak = param["lambda_peak"]
519
- delta_m = param["delta_m"]
520
- beta = param["beta"]
667
+ identifier_dict = {'name': "binary_masses_BBH_popI_II_powerlaw_gaussian"}
668
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_BBH_popI_II_powerlaw_gaussian"].copy()
669
+ if param_dict:
670
+ param_dict.update(kwargs)
671
+ else:
672
+ param_dict = kwargs
673
+ identifier_dict.update(param_dict)
521
674
 
522
- # check if the cdf exist
523
675
 
524
676
  # mass function
525
- model = p.BBH_powerlaw_gaussian(
526
- mminbh=mminbh,
527
- mmaxbh=mmaxbh,
528
- alpha=alpha,
529
- mu_g=mu_g,
530
- sigma_g=sigma_g,
531
- lambda_peak=lambda_peak,
532
- delta_m=delta_m,
533
- beta=beta,
677
+ rvs_ = lambda size: sample_powerlaw_gaussian_source_bbh_masses(
678
+ size=size,
679
+ mminbh=identifier_dict["mminbh"],
680
+ mmaxbh=identifier_dict["mmaxbh"],
681
+ alpha=identifier_dict["alpha"],
682
+ mu_g=identifier_dict["mu_g"],
683
+ sigma_g=identifier_dict['sigma_g'],
684
+ lambda_peak=identifier_dict['lambda_peak'],
685
+ delta_m=identifier_dict['delta_m'],
686
+ beta=identifier_dict['beta'],
687
+ )
688
+
689
+ mass_object = FunctionConditioning(
690
+ function=None,
691
+ x_array=None,
692
+ param_dict_given=identifier_dict,
693
+ directory=self.directory,
694
+ sub_directory="source_frame_masses",
695
+ name=identifier_dict['name'],
696
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
697
+ create_function_inverse=False,
698
+ create_function=False,
699
+ create_pdf=False,
700
+ create_rvs=rvs_,
701
+ callback='rvs',
534
702
  )
535
- if get_attribute:
536
- sampler_function = lambda size: model.sample(Nsample=size)
537
- return sampler_function
538
- else:
539
- # sample mass1 and mass2
540
- mass_1_source, mass_2_source = model.sample(Nsample=size)
541
703
 
542
- return (mass_1_source, mass_2_source)
704
+ return mass_object if get_attribute else mass_object.rvs(size)
543
705
 
544
706
  def binary_masses_BBH_popIII_lognormal(
545
707
  self,
546
708
  size,
547
- m_min=5.0,
548
- m_max=150.0,
549
- Mc=30.0,
550
- sigma=0.3,
551
- chunk_size=10000,
709
+ # m_min=5.0,
710
+ # m_max=150.0,
711
+ # Mc=30.0,
712
+ # sigma=0.3,
713
+ # chunk_size=10000,
552
714
  get_attribute=False,
553
- param=None,
715
+ **kwargs,
554
716
  ):
555
717
  """
556
718
  Function to sample source mass1 and mass2 with pop III origin. Refer to Eqn. 1 and 4 of Ng et al. 2022
@@ -589,43 +751,50 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
589
751
  >>> m1_src, m2_src = cbc.binary_masses_BBH_popIII_lognormal(size=1000)
590
752
  """
591
753
 
592
- if param:
593
- m_min = param["m_min"]
594
- m_max = param["m_max"]
595
- Mc = param["Mc"]
596
- sigma = param["sigma"]
597
-
598
- if get_attribute:
599
- return njit(
600
- lambda size: lognormal_distribution_2D(
601
- size,
602
- m_min=m_min,
603
- m_max=m_max,
604
- Mc=Mc,
605
- sigma=sigma,
606
- chunk_size=chunk_size,
607
- )
608
- )
754
+ identifier_dict = {'name': "binary_masses_BBH_popIII_lognormal"}
755
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_BBH_popIII_lognormal"].copy()
756
+ if param_dict:
757
+ param_dict.update(kwargs)
609
758
  else:
610
- return lognormal_distribution_2D(
611
- size,
612
- m_min=m_min,
613
- m_max=m_max,
614
- Mc=Mc,
615
- sigma=sigma,
616
- chunk_size=chunk_size,
617
- )
759
+ param_dict = kwargs
760
+ identifier_dict.update(param_dict)
761
+
762
+ rvs_ = lambda size: lognormal_distribution_2D(
763
+ size,
764
+ m_min=identifier_dict["m_min"],
765
+ m_max=identifier_dict["m_max"],
766
+ Mc=identifier_dict["Mc"],
767
+ sigma=identifier_dict["sigma"],
768
+ chunk_size=chunk_size,
769
+ )
770
+
771
+ mass_object = FunctionConditioning(
772
+ function=None,
773
+ x_array=None,
774
+ param_dict_given=identifier_dict,
775
+ directory=self.directory,
776
+ sub_directory="source_frame_masses",
777
+ name=identifier_dict['name'],
778
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
779
+ create_function_inverse=False,
780
+ create_function=False,
781
+ create_pdf=False,
782
+ create_rvs=rvs_,
783
+ callback='rvs',
784
+ )
785
+
786
+ return mass_object if get_attribute else mass_object.rvs(size)
618
787
 
619
788
  def binary_masses_BBH_primordial_lognormal(
620
789
  self,
621
790
  size,
622
- m_min=1.0,
623
- m_max=100.0,
624
- Mc=20.0,
625
- sigma=0.3,
626
- chunk_size=10000,
791
+ # m_min=1.0,
792
+ # m_max=100.0,
793
+ # Mc=20.0,
794
+ # sigma=0.3,
795
+ # chunk_size=10000,
627
796
  get_attribute=False,
628
- param=None,
797
+ **kwargs,
629
798
  ):
630
799
  """
631
800
  Function to sample source mass1 and mass2 with primordial origin. Refer to Eqn. 1 and 4 of Ng et al. 2022
@@ -655,87 +824,113 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
655
824
  Array of mass2 in source frame (Msun)
656
825
  """
657
826
 
658
- if param:
659
- m_min = param["m_min"]
660
- m_max = param["m_max"]
661
- Mc = param["Mc"]
662
- sigma = param["sigma"]
663
-
664
- if get_attribute:
665
- return njit(
666
- lambda size: lognormal_distribution_2D(
667
- size,
668
- m_min=m_min,
669
- m_max=m_max,
670
- Mc=Mc,
671
- sigma=sigma,
672
- chunk_size=chunk_size,
673
- )
674
- )
827
+ identifier_dict = {'name': "binary_masses_BBH_primordial_lognormal"}
828
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_BBH_primordial_lognormal"].copy()
829
+ if param_dict:
830
+ param_dict.update(kwargs)
675
831
  else:
676
- return lognormal_distribution_2D(
677
- size,
678
- m_min=m_min,
679
- m_max=m_max,
680
- Mc=Mc,
681
- sigma=sigma,
682
- chunk_size=chunk_size,
683
- )
684
-
685
- def binary_masses_BNS_gwcosmo(
686
- self, size, mminns=1.0, mmaxns=3.0, alphans=0.0, get_attribute=False, param=None
687
- ):
688
- """
689
- Function to calculate source mass1 and mass2 of BNS from powerlaw distribution (gwcosmo)
690
-
691
- Parameters
692
- ----------
693
- size : `int`
694
- Number of samples to draw
695
- mminns : `float`
696
- Minimum mass of the BNS (Msun)
697
- default: 1.0
698
- mmaxns : `float`
699
- Maximum mass of the BNS (Msun)
700
- default: 3.0
701
- alphans : `float`
702
- Power law index
703
- default: 0.0
704
-
705
- Returns
706
- ----------
707
- mass_1_source : `numpy.ndarray` (1D array of floats)
708
- Array of mass1 in source frame (Msun)
709
- mass_2_source : `numpy.ndarray` (1D array of floats)
710
- Array of mass2 in source frame (Msun)
711
-
712
- Examples
713
- ----------
714
- >>> from ler.gw_source_population import CBCSourceParameterDistribution
715
- >>> cbc = CBCSourceParameterDistribution()
716
- >>> m1_src, m2_src = cbc.binary_masses_BNS_gwcosmo(size=1000)
717
- """
718
-
719
- if param:
720
- mminns = param["mminns"]
721
- mmaxns = param["mmaxns"]
722
- alphans = param["alphans"]
723
-
724
- # mass function for BNS
725
- model = p.BNS(mminns=mminns, mmaxns=mmaxns, alphans=alphans)
832
+ param_dict = kwargs
833
+ identifier_dict.update(param_dict)
834
+
835
+ rvs_ = lambda size: lognormal_distribution_2D(
836
+ size,
837
+ m_min=identifier_dict["m_min"],
838
+ m_max=identifier_dict["m_max"],
839
+ Mc=identifier_dict["Mc"],
840
+ sigma=identifier_dict["sigma"],
841
+ chunk_size=chunk_size,
842
+ )
726
843
 
727
- if get_attribute:
728
- sampler_function = lambda size: model.sample(Nsample=size)
729
- return sampler_function
730
- else:
731
- # sampling
732
- mass_1_source, mass_2_source = model.sample(Nsample=size)
844
+ mass_object = FunctionConditioning(
845
+ function=None,
846
+ x_array=None,
847
+ param_dict_given=identifier_dict,
848
+ directory=self.directory,
849
+ sub_directory="source_frame_masses",
850
+ name=identifier_dict['name'],
851
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
852
+ create_function_inverse=False,
853
+ create_function=False,
854
+ create_pdf=False,
855
+ create_rvs=rvs_,
856
+ callback='rvs',
857
+ )
733
858
 
734
- return (mass_1_source, mass_2_source)
859
+ return mass_object if get_attribute else mass_object.rvs(size)
860
+
861
+ # def binary_masses_BNS_gwcosmo(
862
+ # self, size, get_attribute=False, **kwargs
863
+ # ):
864
+ # """
865
+ # Function to calculate source mass1 and mass2 of BNS from powerlaw distribution (gwcosmo)
866
+
867
+ # Parameters
868
+ # ----------
869
+ # size : `int`
870
+ # Number of samples to draw
871
+ # mminns : `float`
872
+ # Minimum mass of the BNS (Msun)
873
+ # default: 1.0
874
+ # mmaxns : `float`
875
+ # Maximum mass of the BNS (Msun)
876
+ # default: 3.0
877
+ # alphans : `float`
878
+ # Power law index
879
+ # default: 0.0
880
+
881
+ # Returns
882
+ # ----------
883
+ # mass_1_source : `numpy.ndarray` (1D array of floats)
884
+ # Array of mass1 in source frame (Msun)
885
+ # mass_2_source : `numpy.ndarray` (1D array of floats)
886
+ # Array of mass2 in source frame (Msun)
887
+
888
+ # Examples
889
+ # ----------
890
+ # >>> from ler.gw_source_population import CBCSourceParameterDistribution
891
+ # >>> cbc = CBCSourceParameterDistribution()
892
+ # >>> m1_src, m2_src = cbc.binary_masses_BNS_gwcosmo(size=1000)
893
+ # """
894
+
895
+ # # if param:
896
+ # # mminns = param["mminns"]
897
+ # # mmaxns = param["mmaxns"]
898
+ # # alphans = param["alphans"]
899
+
900
+ # identifier_dict = {'name': "binary_masses_BNS_gwcosmo"}
901
+ # param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_BNS_gwcosmo"].copy()
902
+ # if param_dict is not None:
903
+ # param_dict.update(kwargs)
904
+ # else:
905
+ # param_dict = kwargs
906
+ # identifier_dict.update(param_dict)
907
+
908
+ # # mass function for BNS
909
+ # model = p.BNS(
910
+ # mminns=identifier_dict["mminns"],
911
+ # mmaxns=identifier_dict["mmaxns"],
912
+ # alphans=identifier_dict["alphans"],
913
+ # )
914
+ # rvs_ = lambda size: model.sample(Nsample=size)
915
+
916
+ # mass_object = FunctionConditioning(
917
+ # function=None,
918
+ # x_array=None,
919
+ # param_dict_given=identifier_dict,
920
+ # directory=self.directory,
921
+ # sub_directory="source_frame_masses",
922
+ # name=identifier_dict['name'],
923
+ # create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
924
+ # create_function_inverse=False,
925
+ # create_function=False,
926
+ # create_pdf=False,
927
+ # create_rvs=rvs_,
928
+ # callback='rvs',
929
+ # )
930
+
931
+ # return mass_object if get_attribute else mass_object(size)
735
932
 
736
- def binary_masses_NSBH_broken_powerlaw(
737
- self, size, mminbh=26, mmaxbh=125, alpha_1=6.75, alpha_2=6.75, b=0.5, delta_m=5, mminns=1.0, mmaxns=3.0, alphans=0.0, get_attribute=False, param=None
738
- ):
933
+ def binary_masses_NSBH_broken_powerlaw(self, size, get_attribute=False, **kwargs):
739
934
  """
740
935
  Function to calculate source mass1 and mass2 of NSBH from powerlaw distribution (gwcosmo). Parameters are mminbh=26,mmaxbh=125,alpha_1=6.75,alpha_2=6.75,b=0.5,delta_m=5,mminns=1.0,mmaxns=3.0,alphans=0.0.
741
936
 
@@ -789,46 +984,50 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
789
984
  >>> m1_src, m2_src = cbc.binary_masses_NSBH_broken_powerlaw(size=1000)
790
985
  """
791
986
 
792
- if param:
793
- mminbh = param["mminbh"]
794
- mmaxbh = param["mmaxbh"]
795
- alpha_1 = param["alpha_1"]
796
- alpha_2 = param["alpha_2"]
797
- b = param["b"]
798
- delta_m = param["delta_m"]
799
- mminns = param["mminns"]
800
- mmaxns = param["mmaxns"]
801
- alphans = param["alphans"]
987
+ identifier_dict = {'name': "binary_masses_NSBH_broken_powerlaw"}
988
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_NSBH_broken_powerlaw"].copy()
989
+ if param_dict:
990
+ param_dict.update(kwargs)
991
+ else:
992
+ param_dict = kwargs
993
+ identifier_dict.update(param_dict)
802
994
 
803
995
  # mass function for NSBH
804
- model = p.NSBH_broken_powerlaw(
805
- mminbh=mminbh,
806
- mmaxbh=mmaxbh,
807
- alpha_1=alpha_1,
808
- alpha_2=alpha_2,
809
- b=b,
810
- delta_m=delta_m,
811
- mminns=mminns,
812
- mmaxns=mmaxns,
813
- alphans=alphans,
996
+ rvs_ = lambda size: sample_broken_powerlaw_nsbh_masses(
997
+ Nsample=size,
998
+ mminbh=identifier_dict["mminbh"],
999
+ mmaxbh=identifier_dict["mmaxbh"],
1000
+ alpha_1=identifier_dict["alpha_1"],
1001
+ alpha_2=identifier_dict["alpha_2"],
1002
+ b=identifier_dict["b"],
1003
+ delta_m=identifier_dict["delta_m"],
1004
+ mminns=identifier_dict["mminns"],
1005
+ mmaxns=identifier_dict["mmaxns"],
1006
+ alphans=identifier_dict["alphans"],
814
1007
  )
815
1008
 
816
- if get_attribute:
817
- sampler_function = lambda size: model.sample(Nsample=size)
818
- return sampler_function
819
- else:
820
- # sampling
821
- mass_1_source, mass_2_source = model.sample(Nsample=size)
1009
+ mass_object = FunctionConditioning(
1010
+ function=None,
1011
+ x_array=None,
1012
+ param_dict_given=identifier_dict,
1013
+ directory=self.directory,
1014
+ sub_directory="source_frame_masses",
1015
+ name=identifier_dict['name'],
1016
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
1017
+ create_function_inverse=False,
1018
+ create_function=False,
1019
+ create_pdf=False,
1020
+ create_rvs=rvs_,
1021
+ callback='rvs',
1022
+ )
1023
+
1024
+ return mass_object if get_attribute else mass_object.rvs(size)
822
1025
 
823
- return (mass_1_source, mass_2_source)
824
-
825
1026
  def binary_masses_uniform(
826
1027
  self,
827
1028
  size,
828
- m_min=1.0,
829
- m_max=3.0,
830
1029
  get_attribute=False,
831
- param=None,
1030
+ **kwargs,
832
1031
  ):
833
1032
  """
834
1033
  Function to sample source mass1 and mass2 from uniform distribution.
@@ -863,28 +1062,48 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
863
1062
  >>> m1_src, m2_src = cbc.binary_masses_uniform(size=1000)
864
1063
  """
865
1064
 
866
- if param:
867
- m_min = param["m_min"]
868
- m_max = param["m_max"]
1065
+ identifier_dict = {'name': "binary_masses_uniform"}
1066
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_uniform"].copy()
1067
+ if param_dict:
1068
+ param_dict.update(kwargs)
1069
+ else:
1070
+ param_dict = kwargs
1071
+ identifier_dict.update(param_dict)
869
1072
 
870
- if get_attribute:
871
- return njit(lambda size: (np.random.uniform(m_min, m_max, size), np.random.uniform(m_min, m_max, size)))
872
- return np.random.uniform(m_min, m_max, size), np.random.uniform(m_min, m_max, size)
1073
+ m_min = identifier_dict["m_min"]
1074
+ m_max = identifier_dict["m_max"]
1075
+ rvs_ = njit(lambda size: (np.random.uniform(m_min, m_max, size), np.random.uniform(m_min, m_max, size)))
1076
+
1077
+ mass_object = FunctionConditioning(
1078
+ function=None,
1079
+ x_array=None,
1080
+ param_dict_given=identifier_dict,
1081
+ directory=self.directory,
1082
+ sub_directory="source_frame_masses",
1083
+ name=identifier_dict['name'],
1084
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
1085
+ create_function_inverse=False,
1086
+ create_function=False,
1087
+ create_pdf=False,
1088
+ create_rvs=rvs_,
1089
+ callback='rvs',
1090
+ )
1091
+
1092
+ return mass_object if get_attribute else mass_object.rvs(size)
873
1093
 
874
1094
  def binary_masses_BNS_bimodal(
875
1095
  self,
876
1096
  size,
877
- w=0.643,
878
- muL=1.352,
879
- sigmaL=0.08,
880
- muR=1.88,
881
- sigmaR=0.3,
882
- mmin=1.0,
883
- mmax=2.3,
884
- resolution=500,
885
- create_new=False,
1097
+ # w=0.643,
1098
+ # muL=1.352,
1099
+ # sigmaL=0.08,
1100
+ # muR=1.88,
1101
+ # sigmaR=0.3,
1102
+ # mmin=1.0,
1103
+ # mmax=2.3,
1104
+ # resolution=500,
886
1105
  get_attribute=False,
887
- param=None,
1106
+ **kwargs,
888
1107
  ):
889
1108
  """
890
1109
  Function to sample source mass1 and mass2 from bimodal distribution. Refer to Will M. Farr et al. 2020 Eqn. 6, https://arxiv.org/pdf/2005.00032.pdf .
@@ -940,59 +1159,59 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
940
1159
  >>> m1_src, m2_src = cbc.binary_masses_BNS_bimodal(size=1000)
941
1160
  """
942
1161
 
943
- if param:
944
- w, muL, sigmaL, muR, sigmaR, mmin, mmax = (
945
- param["w"],
946
- param["muL"],
947
- param["sigmaL"],
948
- param["muR"],
949
- param["sigmaR"],
950
- param["mmin"],
951
- param["mmax"],
952
- )
953
- # left and right peak
954
- pdf_unnormL = lambda m: np.exp(-((m - muL) ** 2) / (2 * sigmaL**2))
955
- normL = quad(pdf_unnormL, mmin, mmax)[0] # normalization constant
956
- pdf_unnormR = lambda m: np.exp(-((m - muR) ** 2) / (2 * sigmaR**2))
957
- normR = quad(pdf_unnormR, mmin, mmax)[0] # normalization constant
958
- # total pdf
959
- pdf = lambda m: w * pdf_unnormL(m) / normL + (1 - w) * pdf_unnormR(m) / normR
960
-
961
- # find inverse cdf
962
- inv_cdf = interpolator_from_pickle(
963
- param_dict_given=dict(
964
- w=w,
965
- muL=muL,
966
- sigmaL=sigmaL,
967
- muR=muR,
968
- sigmaR=sigmaR,
969
- mmin=mmin,
970
- mmax=mmax,
971
- resolution=500,
972
- ),
1162
+ identifier_dict = {'name': "binary_masses_BNS_bimodal"}
1163
+ identifier_dict['resolution'] = self.create_new_interpolator["source_frame_masses"]["resolution"]
1164
+ param_dict = self.available_gw_prior_list_and_its_params["source_frame_masses"]["binary_masses_BNS_bimodal"].copy()
1165
+ if param_dict:
1166
+ param_dict.update(kwargs)
1167
+ else:
1168
+ param_dict = kwargs
1169
+ identifier_dict.update(param_dict)
1170
+
1171
+ # mass function for BNS
1172
+ mass = np.linspace(identifier_dict["mmin"], identifier_dict["mmax"], identifier_dict["resolution"])
1173
+ model = lambda mass: bns_bimodal_pdf(
1174
+ mass,
1175
+ w=identifier_dict["w"],
1176
+ muL=identifier_dict["muL"],
1177
+ sigmaL=identifier_dict["sigmaL"],
1178
+ muR=identifier_dict["muR"],
1179
+ sigmaR=identifier_dict["sigmaR"],
1180
+ mmin=identifier_dict["mmin"],
1181
+ mmax=identifier_dict["mmax"],
1182
+ )
1183
+
1184
+ mass_object = FunctionConditioning(
1185
+ function=model,
1186
+ x_array=mass,
1187
+ param_dict_given=identifier_dict,
973
1188
  directory=self.directory,
974
- sub_directory="binary_masses_BNS_bimodal",
975
- name="binary_masses_BNS_bimodal",
976
- x=np.linspace(mmin, mmax, resolution),
977
- pdf_func=pdf,
978
- conditioned_y=None,
979
- dimension=1,
980
- category="inv_cdf",
981
- create_new=create_new,
1189
+ sub_directory="source_frame_masses",
1190
+ name=identifier_dict['name'],
1191
+ create_new=self.create_new_interpolator["source_frame_masses"]["create_new"],
1192
+ create_function_inverse=False,
1193
+ create_function=True,
1194
+ create_pdf=True,
1195
+ create_rvs=True,
1196
+ callback='rvs',
1197
+ )
1198
+
1199
+ cdf_values = mass_object.cdf_values
1200
+ x_array = mass_object.x_array
1201
+
1202
+ mass_object.rvs = njit(lambda size: inverse_transform_sampler_m1m2(
1203
+ size,
1204
+ cdf_values,
1205
+ x_array,)
982
1206
  )
983
1207
 
984
- # sample from inverse cdf
985
1208
  if get_attribute:
986
- return njit(
987
- lambda size: inverse_transform_sampler_m1m2(
988
- size, inv_cdf[0], inv_cdf[1]
989
- )
990
- )
1209
+ return mass_object
991
1210
  else:
992
- return inverse_transform_sampler_m1m2(size, inv_cdf[0], inv_cdf[1])
1211
+ return mass_object(size)
993
1212
 
994
1213
  def constant_values_n_size(
995
- self, size=100, value=0.0, get_attribute=False, param=None
1214
+ self, size=100, get_attribute=False, **kwargs
996
1215
  ):
997
1216
  """
998
1217
  Function to sample constant values of size n.
@@ -1001,14 +1220,11 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1001
1220
  ----------
1002
1221
  size : `int`
1003
1222
  Number of samples to draw
1004
- value : `float`
1005
- Constant value
1006
- default: 0.0
1007
1223
  get_attribute : `bool`
1008
1224
  If True, return the njitted sampler function with size as the only input where parameters are fixed to the given values.
1009
- param : `dict`
1010
- Allows to pass in above parameters as dict.
1011
- e.g. param = dict(value=0.0)
1225
+ kwargs : `keyword arguments`
1226
+ Additional parameters to pass to the function
1227
+
1012
1228
 
1013
1229
  Returns
1014
1230
  ----------
@@ -1022,16 +1238,32 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1022
1238
  >>> value = cbc.constant_values_n_size(size=1000)
1023
1239
  """
1024
1240
 
1025
- if param:
1026
- value = param["value"]
1241
+ # if param:
1242
+ # value = param["value"]
1243
+ identifier_dict = {'name': "constant_values_n_size"}
1244
+ param_dict = dict(value=0.0)
1245
+ param_dict.update(kwargs)
1246
+ identifier_dict.update(param_dict)
1247
+
1248
+ value = identifier_dict["value"]
1249
+ # pdf_, zero everywhere except at value
1250
+ pdf_ = njit(lambda x: np.where(x == value, 1.0, 0.0))
1251
+ # rvs_, return value
1252
+ rvs_ = njit(lambda size: np.ones(size) * value)
1253
+
1254
+ object_ = FunctionConditioning(
1255
+ create_pdf=pdf_,
1256
+ create_rvs=rvs_,
1257
+ callback='rvs',
1258
+ )
1027
1259
 
1028
1260
  if get_attribute:
1029
- return njit(lambda size: np.ones(size) * value)
1261
+ return object_
1030
1262
  else:
1031
- return np.ones(size) * value
1263
+ return object_(size)
1032
1264
 
1033
1265
  def sampler_uniform(
1034
- self, size, min_=0, max_=np.pi, get_attribute=False, param=None
1266
+ self, size, get_attribute=False, **kwargs
1035
1267
  ):
1036
1268
  """
1037
1269
  Function to sample values from uniform distribution.
@@ -1040,12 +1272,6 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1040
1272
  ----------
1041
1273
  size : `int`
1042
1274
  Number of samples to draw
1043
- start_time : `float`
1044
- Start time of the uniform distribution
1045
- default: 1238166018
1046
- end_time : `float`
1047
- End time of the uniform distribution
1048
- default: 1238166018 + 31536000
1049
1275
  get_attribute : `bool`
1050
1276
  If True, return the njitted sampler function with size as the only input where parameters are fixed to the given values.
1051
1277
  param : `dict`
@@ -1062,18 +1288,32 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1062
1288
  >>> cbc = CBCSourceParameterDistribution()
1063
1289
  >>> value = cbc.sampler_uniform(size=1000)
1064
1290
  """
1065
-
1066
- if param:
1067
- min_ = param["min_"]
1068
- max_ = param["max_"]
1291
+
1292
+ identifier_dict = {'name': "sampler_uniform"}
1293
+ param_dict = dict(xmin=0.0, xmax=1.0)
1294
+ param_dict.update(kwargs)
1295
+ identifier_dict.update(param_dict)
1296
+
1297
+ xmin = identifier_dict['xmin']
1298
+ xmax = identifier_dict['xmax']
1299
+
1300
+ pdf_ = njit(lambda x: 1.0 / (xmax - xmin) * np.ones(len(x)))
1301
+ rvs_ = njit(lambda size: np.random.uniform(xmin, xmax, size=size))
1302
+
1303
+ object_ = FunctionConditioning(
1304
+ param_dict_given=identifier_dict,
1305
+ create_pdf=pdf_,
1306
+ create_rvs=rvs_,
1307
+ callback='rvs',
1308
+ )
1069
1309
 
1070
1310
  if get_attribute:
1071
- return njit(lambda size: np.random.uniform(min_, max_, size=size))
1311
+ return object_
1072
1312
  else:
1073
- return np.random.uniform(min_, max_, size=size)
1313
+ return object_(size)
1074
1314
 
1075
1315
  def sampler_cosine(
1076
- self, size, get_attribute=False, param=None
1316
+ self, size, get_attribute=False, **kwargs
1077
1317
  ):
1078
1318
  """
1079
1319
  Function to sample from sine distribution at the limit of [-np.pi/2, np.pi/2]
@@ -1093,15 +1333,26 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1093
1333
  Array of values in the range of [-np.pi/2, np.pi/2]
1094
1334
  """
1095
1335
 
1336
+ identifier_dict = {}
1337
+ identifier_dict['name'] = "sampler_cosine"
1338
+ identifier_dict.update(kwargs)
1339
+
1340
+ pdf_ = njit(lambda x: 0.5 * np.cos(x))
1341
+ rvs_ = njit(lambda size: np.arcsin((np.random.uniform(0, 1, size=size) * 2 - 1)))
1342
+
1343
+ object_ = FunctionConditioning(
1344
+ create_pdf=pdf_,
1345
+ create_rvs=rvs_,
1346
+ callback='rvs',
1347
+ )
1348
+
1096
1349
  if get_attribute:
1097
- return njit(
1098
- lambda size: np.arcsin((np.random.uniform(0, 1, size=size) * 2 - 1))
1099
- )
1350
+ return object_
1100
1351
  else:
1101
- return np.arcsin((np.random.uniform(0, 1, size=size) * 2 - 1))
1352
+ return object_(size)
1102
1353
 
1103
1354
  def sampler_sine(
1104
- self, size, get_attribute=False, param=None
1355
+ self, size, get_attribute=False, **kwargs
1105
1356
  ):
1106
1357
  """
1107
1358
  Function to sample from sine distribution at the limit of [0, np.pi]
@@ -1121,284 +1372,28 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1121
1372
  Array of values in the range of [0, np.pi]
1122
1373
  """
1123
1374
 
1124
- if get_attribute:
1125
- return njit(
1126
- lambda size: np.arccos((np.random.uniform(0, 1, size=size) - 0.5) * 2)
1127
- )
1128
- else:
1129
- return np.arccos((np.random.uniform(0, 1, size=size) - 0.5) * 2)
1375
+ identifier_dict = {}
1376
+ identifier_dict['name'] = "sampler_sine"
1377
+ identifier_dict.update(kwargs)
1130
1378
 
1131
- @property
1132
- def available_gw_prior_list_and_its_params(self):
1133
- """
1134
- Dictionary with list all the available priors and it's corresponding parameters. This is an immutable instance attribute.
1135
-
1136
- Examples
1137
- ----------
1138
- >>> from ler.gw_source_population import CBCSourceParameterDistribution
1139
- >>> cbc = CBCSourceParameterDistribution()
1140
- >>> priors = cbc.available_gw_prior_list_and_its_params
1141
- >>> priors.keys() # type of priors
1142
- dict_keys(['merger_rate_density', 'source_frame_masses', 'spin', 'geocent_time', 'ra', 'phase', 'psi', 'theta_jn'])
1143
- >>> priors['source_frame_masses'].keys() # type of source_frame_masses priors
1144
- dict_keys(['binary_masses_BBH_popI_II_powerlaw_gaussian', 'binary_masses_BBH_popIII_lognormal', 'binary_masses_BBH_primordial_lognormal', 'binary_masses_BNS_gwcosmo', 'binary_masses_BNS_bimodal'])
1145
- >>> priors['source_frame_masses']['binary_masses_BBH_popI_II_powerlaw_gaussian'].keys() # parameters of binary_masses_BBH_popI_II_powerlaw_gaussian
1146
- dict_keys(['mminbh', 'mmaxbh', 'alpha', 'mu_g', 'sigma_g', 'lambda_peak', 'delta_m', 'beta'])
1147
- """
1148
-
1149
- self._available_gw_prior_list_and_its_params = dict(
1150
- merger_rate_density=self.merger_rate_density_model_list,
1151
- source_frame_masses=dict(
1152
- binary_masses_BBH_popI_II_powerlaw_gaussian=dict(
1153
- mminbh=4.98,
1154
- mmaxbh=112.5,
1155
- alpha=3.78,
1156
- mu_g=32.27,
1157
- sigma_g=3.88,
1158
- lambda_peak=0.03,
1159
- delta_m=4.8,
1160
- beta=0.81,
1161
- ),
1162
- binary_masses_BBH_popIII_lognormal=dict(Mc=30.0, sigma=0.3, beta=1.1),
1163
- binary_masses_BBH_primordial_lognormal=dict(
1164
- Mc=30.0, sigma=0.3, beta=1.1
1165
- ),
1166
- binary_masses_BNS_gwcosmo=dict(mminns=1.0, mmaxns=3.0, alphans=0.0),
1167
- binary_masses_BNS_bimodal=dict(
1168
- w=0.643,
1169
- muL=1.352,
1170
- sigmaL=0.08,
1171
- muR=1.88,
1172
- sigmaR=0.3,
1173
- mmin=1.0,
1174
- mmax=2.3,
1175
- ),
1176
- ),
1177
- zs=dict(
1178
- sample_source_redshift=dict(zs=None),
1179
- ),
1180
- spin=dict(
1181
- constant_values_n_size=dict(value=0.0),
1182
- binary_spin_BBH_bilby=None,
1183
- binary_spin_BNS_bilby=None,
1184
- ),
1185
- geocent_time=dict(
1186
- geocent_time_uniform=dict(
1187
- start_time=1238166018, end_time=1238166018 + 31536000
1188
- )
1189
- ),
1190
- ra=dict(ra_uniform_bilby=None),
1191
- phase=dict(phase_uniform_bilby=None),
1192
- psi=dict(psi_uniform_bilby=None),
1193
- theta_jn=dict(theta_jn_uniform_bilby=None),
1194
- )
1195
-
1196
- return self._available_gw_prior_list_and_its_params
1197
-
1198
- def source_priors_categorization(
1199
- self, event_type, source_priors, event_prior_params
1200
- ):
1201
- """
1202
- Function to categorize the event priors and its parameters.
1203
-
1204
- Parameters
1205
- ----------
1206
- event_type : `str`
1207
- Type of event to generate.
1208
- e.g. 'BBH', 'BNS', 'BBH_popIII', 'BBH_primordial', 'NSBH'
1209
- source_priors : `dict`
1210
- Dictionary of prior sampler functions for each parameter
1211
- event_prior_params : `dict`
1212
- Dictionary of sampler parameters for each GW parameter
1213
-
1214
- Returns
1215
- ----------
1216
- source_priors_ : `dict`
1217
- Dictionary of prior sampler functions for each parameter
1218
- event_prior_params_ : `dict`
1219
- Dictionary of sampler parameters for each parameter
1220
- sampler_names_ : `dict`
1221
- Dictionary of sampler names with description
1222
-
1223
- Examples
1224
- ----------
1225
- >>> from ler.gw_source_population import CBCSourceParameterDistribution
1226
- >>> cbc = CBCSourceParameterDistribution()
1227
- >>> source_priors, event_prior_params, sampler_names = cbc.source_priors_categorization(event_type='BBH', source_priors=None, event_prior_params=None)
1228
- >>> print(source_priors.keys())
1229
- >>> print(event_prior_params.keys())
1230
- >>> print(sampler_names.keys())
1231
- """
1232
-
1233
- # for BBH
1234
- if event_type == "BBH":
1235
- merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
1236
- merger_rate_density_prior_params = dict(
1237
- R0=23.9 * 1e-9, b2=1.6, b3=2.0, b4=30 #
1238
- )
1239
- source_frame_masses_prior = "binary_masses_BBH_popI_II_powerlaw_gaussian"
1240
- source_frame_masses_prior_params = dict(
1241
- mminbh=4.98,
1242
- mmaxbh=112.5,
1243
- alpha=3.78,
1244
- mu_g=32.27,
1245
- sigma_g=3.88,
1246
- lambda_peak=0.03,
1247
- delta_m=4.8,
1248
- beta=0.81,
1249
- )
1250
- a_max = 0.8
1379
+ pdf_ = njit(lambda x: 0.5 * np.sin(x))
1380
+ rvs_ = njit(lambda size: np.arccos((np.random.uniform(0, 1, size=size) - 0.5) * 2))
1251
1381
 
1252
- elif event_type == "BNS":
1253
- merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
1254
- merger_rate_density_prior_params = dict(
1255
- R0=105.5 * 1e-9, b2=1.6, b3=2.0, b4=30
1256
- )
1257
- source_frame_masses_prior = "binary_masses_BNS_bimodal"
1258
- source_frame_masses_prior_params = dict(
1259
- w=0.643,
1260
- muL=1.352,
1261
- sigmaL=0.08,
1262
- muR=1.88,
1263
- sigmaR=0.3,
1264
- mmin=1.0,
1265
- mmax=2.3,
1266
- )
1267
- a_max = 0.05
1268
-
1269
- elif event_type == "NSBH":
1270
- merger_rate_density_prior = "merger_rate_density_bbh_popI_II_oguri2018"
1271
- merger_rate_density_prior_params = dict(
1272
- R0=27.0 * 1e-9, b2=1.6, b3=2.0, b4=30
1273
- )
1274
- source_frame_masses_prior = "binary_masses_NSBH_broken_powerlaw"
1275
- source_frame_masses_prior_params = dict(
1276
- mminbh=26,
1277
- mmaxbh=125,
1278
- alpha_1=6.75,
1279
- alpha_2=6.75,
1280
- b=0.5,
1281
- delta_m=5,
1282
- mminns=1.0,
1283
- mmaxns=3.0,
1284
- alphans=0.0,
1285
- )
1286
- a_max = 0.8
1287
-
1288
- elif event_type == "BBH_popIII":
1289
- merger_rate_density_prior = "merger_rate_density_bbh_popIII_ken2022"
1290
- merger_rate_density_prior_params = dict(
1291
- n0=19.2 * 1e-9, aIII=0.66, bIII=0.3, zIII=11.6
1292
- )
1293
- source_frame_masses_prior = "binary_masses_BBH_popIII_lognormal"
1294
- source_frame_masses_prior_params = dict(
1295
- m_min=5.0, m_max=150.0, Mc=30.0, sigma=0.3, chunk_size=10000
1296
- )
1297
- a_max = 0.8
1298
-
1299
- elif event_type == "BBH_primordial":
1300
- merger_rate_density_prior = "merger_rate_density_bbh_primordial_ken2022"
1301
- merger_rate_density_prior_params = dict(
1302
- n0=0.044 * 1e-9, t0=13.786885302009708
1303
- )
1304
- source_frame_masses_prior = "binary_masses_BBH_primordial_lognormal"
1305
- source_frame_masses_prior_params = dict(
1306
- m_min=1.0, m_max=100.0, Mc=20.0, sigma=0.3, chunk_size=10000
1307
- )
1308
- a_max = 0.8
1382
+ object_ = FunctionConditioning(
1383
+ create_pdf=pdf_,
1384
+ create_rvs=rvs_,
1385
+ callback='rvs',
1386
+ )
1309
1387
 
1388
+ if get_attribute:
1389
+ return object_
1310
1390
  else:
1311
- raise ValueError("event_type is not recognized")
1312
-
1313
- # setting the priors and its parameters
1314
- source_priors_ = dict(
1315
- merger_rate_density=merger_rate_density_prior,
1316
- source_frame_masses=source_frame_masses_prior,
1317
- zs="sample_source_redshift",
1318
- geocent_time="sampler_uniform",
1319
- ra="sampler_uniform",
1320
- dec="sampler_cosine",
1321
- phase="sampler_uniform",
1322
- psi="sampler_uniform",
1323
- theta_jn="sampler_sine",
1324
- )
1325
- event_prior_params_ = dict(
1326
- merger_rate_density=merger_rate_density_prior_params,
1327
- source_frame_masses=source_frame_masses_prior_params,
1328
- zs=None,
1329
- geocent_time=dict(min_=1238166018, max_=1269702018),
1330
- ra=dict(min_=0., max_=2.*np.pi),
1331
- dec=None,
1332
- phase=dict(min_=0., max_=2.*np.pi),
1333
- psi=dict(min_=0., max_=np.pi),
1334
- theta_jn=None,
1335
- )
1336
-
1337
- # dict of sampler names with description
1338
- sampler_names_ = dict(
1339
- sample_source_frame_masses="samples mass1 and mass2 of the compact binaries",
1340
- sample_zs="samples source redshifts",
1341
- sample_geocent_time="samples geocent_time",
1342
- sample_ra="samples right ascension of sky position",
1343
- sample_dec="samples declination of sky position",
1344
- sample_phase="samples coalescence phase",
1345
- sample_psi="samples polarization angle",
1346
- sample_theta_jn="samples inclination angle",
1347
- )
1348
-
1349
- # spin
1350
- if not self.spin_zero:
1351
- source_priors_["a_1"] = "sampler_uniform"
1352
- event_prior_params_["a_1"] = dict(min_=-a_max, max_=a_max)
1353
- sampler_names_[
1354
- "sample_a_1"
1355
- ] = "samples spin magnitude of the compact binaries (body1)"
1356
- source_priors_["a_2"] = "sampler_uniform"
1357
- event_prior_params_["a_2"] = dict(min_=-a_max, max_=a_max)
1358
- sampler_names_[
1359
- "sample_a_2"
1360
- ] = "samples spin magnitude of the compact binaries (body2)"
1361
-
1362
- if self.spin_precession:
1363
- source_priors_["a_1"] = "sampler_uniform"
1364
- event_prior_params_["a_1"] = dict(min_=0.0, max_=a_max)
1365
- source_priors_["a_2"] = "sampler_uniform"
1366
- event_prior_params_["a_2"] = dict(min_=0.0, max_=a_max)
1367
- source_priors_["tilt_1"] = "sampler_sine"
1368
- event_prior_params_["tilt_1"] = None
1369
- sampler_names_[
1370
- "sample_tilt_1"
1371
- ] = "samples tilt angle of the compact binaries (body1)"
1372
-
1373
- source_priors_["tilt_2"] = "sampler_sine"
1374
- event_prior_params_["tilt_2"] = None
1375
- sampler_names_[
1376
- "sample_tilt_2"
1377
- ] = "samples tilt angle of the compact binaries (body2)"
1378
-
1379
- source_priors_["phi_12"] = "sampler_uniform"
1380
- event_prior_params_["phi_12"] = dict(min_=0, max_=2 * np.pi)
1381
- sampler_names_[
1382
- "sample_phi_12"
1383
- ] = "samples azimuthal angle between the two spins"
1384
- source_priors_["phi_jl"] = "sampler_uniform"
1385
- event_prior_params_["phi_jl"] = dict(min_=0, max_=2 * np.pi)
1386
- sampler_names_[
1387
- "sample_phi_jl"
1388
- ] = "samples azimuthal angle between the total angular momentum and the orbital angular momentum"
1389
-
1390
- # update the priors if input is given
1391
- if source_priors:
1392
- source_priors_.update(source_priors)
1393
- if event_prior_params:
1394
- event_prior_params_.update(event_prior_params)
1395
-
1396
- return (source_priors_, event_prior_params_, sampler_names_)
1391
+ return object_(size)
1397
1392
 
1398
1393
  @property
1399
- def sample_zs(self):
1394
+ def source_frame_masses(self):
1400
1395
  """
1401
- Function to sample redshifts with the initialized prior.
1396
+ Function to sample source frame masses (mass1_source, mass2_source) with the initialized prior.
1402
1397
 
1403
1398
  Parameters
1404
1399
  ----------
@@ -1407,77 +1402,74 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1407
1402
 
1408
1403
  Returns
1409
1404
  ----------
1410
- zs : `numpy.ndarray` (1D array of floats)
1411
- Array of redshifts
1405
+ mass_1_source : `numpy.ndarray` (1D array of floats)
1406
+ Array of mass1 in source frame
1407
+ mass_2_source : `numpy.ndarray` (1D array of floats)
1408
+ Array of mass2 in source frame
1412
1409
  """
1413
1410
 
1414
- return self._sample_zs
1415
-
1416
- @sample_zs.setter
1417
- def sample_zs(self, prior):
1418
- try:
1419
- try:
1420
- self._sample_zs = getattr(self, prior)
1421
- except:
1422
- args = self.gw_param_samplers_params["zs"]
1423
- self._sample_zs = getattr(self, prior)(
1424
- size=None, get_attribute=True, param=args
1425
- )
1426
- except:
1427
- self._sample_zs = prior
1411
+ return self._source_frame_masses
1428
1412
 
1413
+ @source_frame_masses.setter
1414
+ def source_frame_masses(self, prior):
1415
+ if prior in self.available_gw_prior_list_and_its_params["source_frame_masses"]:
1416
+ print(f"using ler available source_frame_masses function : {prior}")
1417
+ args = self.gw_param_samplers_params["source_frame_masses"]
1418
+ if args is None:
1419
+ self._source_frame_masses = getattr(self, prior)(
1420
+ size=None, get_attribute=True
1421
+ )
1422
+ else:
1423
+ # follwing should return a sampler function with only one argument (size)
1424
+ self._source_frame_masses = getattr(self, prior)(
1425
+ size=None, get_attribute=True, **args
1426
+ )
1427
+ elif callable(prior):
1428
+ print("using user defined custom source_frame_masses function")
1429
+ self._source_frame_masses = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1430
+ elif isinstance(prior, object):
1431
+ print("using user defined custom source_frame_masses class/object")
1432
+ self._source_frame_masses = prior
1433
+ else:
1434
+ raise ValueError(
1435
+ "source_frame_masses prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1436
+ )
1437
+
1429
1438
  @property
1430
- def sample_source_frame_masses(self):
1439
+ def zs(self):
1431
1440
  """
1432
- Function to sample source frame masses (mass1_source, mass2_source) with the initialized prior.
1441
+ Function to sample source redshift with the initialized prior.
1433
1442
 
1434
1443
  Parameters
1435
1444
  ----------
1436
1445
  size : `int`
1437
1446
  Number of samples to draw
1438
-
1447
+
1439
1448
  Returns
1440
1449
  ----------
1441
- mass_1_source : `numpy.ndarray` (1D array of floats)
1442
- Array of mass1 in source frame
1443
- mass_2_source : `numpy.ndarray` (1D array of floats)
1444
- Array of mass2 in source frame
1450
+ zs : `numpy.ndarray` (1D array of floats)
1451
+ Array of source redshift
1445
1452
  """
1446
1453
 
1447
- return self._sample_source_frame_masses
1448
-
1449
- # following setter is an example if the user wants to use a custom prior with custom input
1450
- # @sample_source_frame_masses.setter
1451
- # def sample_source_frame_masses(self, prior):
1452
- # args = self.gw_param_samplers_params["source_frame_masses"]
1454
+ return self._zs
1453
1455
 
1454
- # # Check if 'prior' is a callable attribute of self
1455
- # args = self.gw_param_samplers_params["source_frame_masses"]
1456
- # try:
1457
- # # If prior is a method of the class
1458
- # self._sample_source_frame_masses = getattr(self, prior)(
1459
- # size=None, get_attribute=True, param=args,
1460
- # )
1461
- # except:
1462
- # # If prior is a standalone function
1463
- # try:
1464
- # self._sample_source_frame_masses = lambda size: prior(size, param=args)
1465
- # except:
1466
- # raise ValueError("given source_frame_masses function should follow the signature of the default ones")
1467
-
1468
- @sample_source_frame_masses.setter
1469
- def sample_source_frame_masses(self, prior):
1470
- try:
1471
- args = self.gw_param_samplers_params["source_frame_masses"]
1472
- # follwing should return a sampler function with only one argument (size)
1473
- self._sample_source_frame_masses = getattr(self, prior)(
1474
- size=None, get_attribute=True, param=args,
1456
+ @zs.setter
1457
+ def zs(self, prior):
1458
+ if prior in self.available_gw_prior_list_and_its_params["zs"]:
1459
+ print(f"using ler available zs function : {prior}")
1460
+ self._zs = getattr(self, prior)
1461
+ elif callable(prior):
1462
+ print("using user defined custom zs function")
1463
+ self._zs = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1464
+ elif isinstance(prior, object):
1465
+ print("using user defined custom zs class/object")
1466
+ else:
1467
+ raise ValueError(
1468
+ "zs prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1475
1469
  )
1476
- except:
1477
- self._sample_source_frame_masses = prior
1478
1470
 
1479
1471
  @property
1480
- def sample_geocent_time(self):
1472
+ def geocent_time(self):
1481
1473
  """
1482
1474
  Function to sample geocent time with the initialized prior.
1483
1475
 
@@ -1492,21 +1484,35 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1492
1484
  Array of geocent_time or time of coalescence
1493
1485
  """
1494
1486
 
1495
- return self._sample_geocent_time
1487
+ return self._geocent_time
1496
1488
 
1497
- @sample_geocent_time.setter
1498
- def sample_geocent_time(self, prior):
1499
- try:
1489
+ @geocent_time.setter
1490
+ def geocent_time(self, prior):
1491
+ if prior in self.available_gw_prior_list_and_its_params["geocent_time"]:
1492
+ print(f"using ler available geocent_time function : {prior}")
1500
1493
  args = self.gw_param_samplers_params["geocent_time"]
1501
- # follwing should return a sampler function with only one argument (size)
1502
- self._sample_geocent_time = getattr(self, prior)(
1503
- size=None, get_attribute=True, param=args,
1494
+ if args is None:
1495
+ self._geocent_time = getattr(self, prior)(
1496
+ size=None, get_attribute=True
1497
+ )
1498
+ else:
1499
+ # follwing should return a sampler function with only one argument (size)
1500
+ self._geocent_time = getattr(self, prior)(
1501
+ size=None, get_attribute=True, **args
1502
+ )
1503
+ elif callable(prior):
1504
+ print("using user defined custom geocent_time function")
1505
+ self._geocent_time = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1506
+ elif isinstance(prior, object):
1507
+ print("using user defined custom geocent_time class/object")
1508
+ self._geocent_time = prior
1509
+ else:
1510
+ raise ValueError(
1511
+ "geocent_time prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1504
1512
  )
1505
- except:
1506
- self._sample_geocent_time = prior
1507
1513
 
1508
1514
  @property
1509
- def sample_ra(self):
1515
+ def ra(self):
1510
1516
  """
1511
1517
  Function to sample right ascension of sky position with the initialized prior.
1512
1518
 
@@ -1521,20 +1527,30 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1521
1527
  Array of right ascension of sky position
1522
1528
  """
1523
1529
 
1524
- return self._sample_ra
1530
+ return self._ra
1525
1531
 
1526
- @sample_ra.setter
1527
- def sample_ra(self, prior):
1528
- try:
1532
+ @ra.setter
1533
+ def ra(self, prior):
1534
+ if prior in self.available_gw_prior_list_and_its_params["ra"]:
1529
1535
  args = self.gw_param_samplers_params["ra"]
1530
- self._sample_ra = getattr(self, prior)(
1531
- size=None, get_attribute=True, param=args
1536
+ if args is None:
1537
+ self._ra = getattr(self, prior)(size=None, get_attribute=True)
1538
+ else:
1539
+ # follwing should return a sampler function with only one argument (size)
1540
+ self._ra = getattr(self, prior)(size=None, get_attribute=True, **args)
1541
+ elif callable(prior):
1542
+ print("using user defined custom ra function")
1543
+ self._ra = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1544
+ elif isinstance(prior, object):
1545
+ print("using user defined custom ra class/object")
1546
+ self._ra = prior
1547
+ else:
1548
+ raise ValueError(
1549
+ "ra prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1532
1550
  )
1533
- except:
1534
- self._sample_ra = prior
1535
1551
 
1536
1552
  @property
1537
- def sample_dec(self):
1553
+ def dec(self):
1538
1554
  """
1539
1555
  Function to sample declination of sky position with the initialized prior.
1540
1556
 
@@ -1549,20 +1565,31 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1549
1565
  Array of declination of sky position
1550
1566
  """
1551
1567
 
1552
- return self._sample_dec
1568
+ return self._dec
1553
1569
 
1554
- @sample_dec.setter
1555
- def sample_dec(self, prior):
1556
- try:
1570
+ @dec.setter
1571
+ def dec(self, prior):
1572
+ if prior in self.available_gw_prior_list_and_its_params["dec"]:
1573
+ print(f"using ler available dec function : {prior}")
1557
1574
  args = self.gw_param_samplers_params["dec"]
1558
- self._sample_dec = getattr(self, prior)(
1559
- size=None, get_attribute=True, param=args
1575
+ if args is None:
1576
+ self._dec = getattr(self, prior)(size=None, get_attribute=True)
1577
+ else:
1578
+ # follwing should return a sampler function with only one argument (size)
1579
+ self._dec = getattr(self, prior)(size=None, get_attribute=True, **args)
1580
+ elif callable(prior):
1581
+ print("using user provided custom dec function")
1582
+ self._dec = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1583
+ elif isinstance(prior, object):
1584
+ print("using user provided custom dec class/object")
1585
+ self._dec = prior
1586
+ else:
1587
+ raise ValueError(
1588
+ "dec prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1560
1589
  )
1561
- except:
1562
- self._sample_dec = prior
1563
1590
 
1564
1591
  @property
1565
- def sample_phase(self):
1592
+ def phase(self):
1566
1593
  """
1567
1594
  Function to sample coalescence phase with the initialized prior.
1568
1595
 
@@ -1577,20 +1604,31 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1577
1604
  Array of coalescence phase
1578
1605
  """
1579
1606
 
1580
- return self._sample_phase
1607
+ return self._phase
1581
1608
 
1582
- @sample_phase.setter
1583
- def sample_phase(self, prior):
1584
- try:
1609
+ @phase.setter
1610
+ def phase(self, prior):
1611
+ if prior in self.available_gw_prior_list_and_its_params["phase"]:
1612
+ print(f"using ler available phase function : {prior}")
1585
1613
  args = self.gw_param_samplers_params["phase"]
1586
- self._sample_phase = getattr(self, prior)(
1587
- size=None, get_attribute=True, param=args
1614
+ if args is None:
1615
+ self._phase = getattr(self, prior)(size=None, get_attribute=True)
1616
+ else:
1617
+ # follwing should return a sampler function with only one argument (size)
1618
+ self._phase = getattr(self, prior)(size=None, get_attribute=True, **args)
1619
+ elif callable(prior):
1620
+ print("using user provided custom phase function")
1621
+ self._phase = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1622
+ elif isinstance(prior, object):
1623
+ print("using user provided custom phase class/object")
1624
+ self._phase = prior
1625
+ else:
1626
+ raise ValueError(
1627
+ "phase prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1588
1628
  )
1589
- except:
1590
- self._sample_phase = prior
1591
1629
 
1592
1630
  @property
1593
- def sample_psi(self):
1631
+ def psi(self):
1594
1632
  """
1595
1633
  Function to sample polarization angle with the initialized prior.
1596
1634
 
@@ -1605,20 +1643,31 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1605
1643
  Array of polarization angle
1606
1644
  """
1607
1645
 
1608
- return self._sample_psi
1646
+ return self._psi
1609
1647
 
1610
- @sample_psi.setter
1611
- def sample_psi(self, prior):
1612
- try:
1648
+ @psi.setter
1649
+ def psi(self, prior):
1650
+ if prior in self.available_gw_prior_list_and_its_params["psi"]:
1651
+ print(f"using ler available psi function : {prior}")
1613
1652
  args = self.gw_param_samplers_params["psi"]
1614
- self._sample_psi = getattr(self, prior)(
1615
- size=None, get_attribute=True, param=args
1653
+ if args is None:
1654
+ self._psi = getattr(self, prior)(size=None, get_attribute=True)
1655
+ else:
1656
+ # follwing should return a sampler function with only one argument (size)
1657
+ self._psi = getattr(self, prior)(size=None, get_attribute=True, **args)
1658
+ elif callable(prior):
1659
+ print("using user provided custom psi function")
1660
+ self._psi = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1661
+ elif isinstance(prior, object):
1662
+ print("using user provided custom psi class/object")
1663
+ self._psi = prior
1664
+ else:
1665
+ raise ValueError(
1666
+ "psi prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function."
1616
1667
  )
1617
- except:
1618
- self._sample_psi = prior
1619
1668
 
1620
1669
  @property
1621
- def sample_theta_jn(self):
1670
+ def theta_jn(self):
1622
1671
  """
1623
1672
  Function to sample theta_jn with the initialized prior.
1624
1673
 
@@ -1632,20 +1681,33 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1632
1681
  theta_jn : `numpy.ndarray` (1D array of floats)
1633
1682
  Array of theta_jn
1634
1683
  """
1635
- return self._sample_theta_jn
1684
+ return self._theta_jn
1636
1685
 
1637
- @sample_theta_jn.setter
1638
- def sample_theta_jn(self, prior):
1639
- try:
1686
+ @theta_jn.setter
1687
+ def theta_jn(self, prior):
1688
+ if prior in self.available_gw_prior_list_and_its_params["theta_jn"]:
1689
+ print(f"using ler available theta_jn function : {prior}")
1640
1690
  args = self.gw_param_samplers_params["theta_jn"]
1641
- self._sample_theta_jn = getattr(self, prior)(
1642
- size=None, get_attribute=True, param=args
1691
+ if args is None:
1692
+ self._theta_jn = getattr(self, prior)(
1693
+ size=None, get_attribute=True
1643
1694
  )
1644
- except:
1645
- self._sample_theta_jn = prior
1695
+ else:
1696
+ # follwing should return a sampler function with only one argument (size)
1697
+ self._theta_jn = getattr(self, prior)(
1698
+ size=None, get_attribute=True, **args
1699
+ )
1700
+ elif callable(prior):
1701
+ print("using user provided custom theta_jn function")
1702
+ self._theta_jn = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1703
+ elif isinstance(prior, object):
1704
+ print("using user provided custom theta_jn class/object")
1705
+ self._theta_jn = prior
1706
+ else:
1707
+ raise ValueError("theta_jn prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1646
1708
 
1647
1709
  @property
1648
- def sample_a_1(self):
1710
+ def a_1(self):
1649
1711
  """
1650
1712
  Function to sample spin magnitude of the compact binaries (body1) with the initialized prior.
1651
1713
 
@@ -1659,20 +1721,33 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1659
1721
  a_1 : `numpy.ndarray` (1D array of floats)
1660
1722
  Array of spin magnitude of the compact binaries (body1)
1661
1723
  """
1662
- return self._sample_a_1
1724
+ return self._a_1
1663
1725
 
1664
- @sample_a_1.setter
1665
- def sample_a_1(self, prior):
1666
- try:
1726
+ @a_1.setter
1727
+ def a_1(self, prior):
1728
+ if prior in self.available_gw_prior_list_and_its_params["a_1"]:
1729
+ print(f"using ler available a_1 function : {prior}")
1667
1730
  args = self.gw_param_samplers_params["a_1"]
1668
- self._sample_a_1 = getattr(self, prior)(
1669
- size=None, get_attribute=True, param=args
1731
+ if args is None:
1732
+ self._a_1 = getattr(self, prior)(
1733
+ size=None, get_attribute=True
1670
1734
  )
1671
- except:
1672
- self._sample_a_1 = prior
1735
+ else:
1736
+ # follwing should return a sampler function with only one argument (size)
1737
+ self._a_1 = getattr(self, prior)(
1738
+ size=None, get_attribute=True, **args
1739
+ )
1740
+ elif callable(prior):
1741
+ print("using user provided custom a_1 function")
1742
+ self._a_1 = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1743
+ elif isinstance(prior, object):
1744
+ print("using user provided custom a_1 class/object")
1745
+ self._a_1 = prior
1746
+ else:
1747
+ raise ValueError("a_1 prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1673
1748
 
1674
1749
  @property
1675
- def sample_a_2(self):
1750
+ def a_2(self):
1676
1751
  """
1677
1752
  Function to sample spin magnitude of the compact binaries (body2) with the initialized prior.
1678
1753
 
@@ -1686,20 +1761,33 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1686
1761
  a_2 : `numpy.ndarray` (1D array of floats)
1687
1762
  Array of spin magnitude of the compact binaries (body2)
1688
1763
  """
1689
- return self._sample_a_2
1764
+ return self._a_2
1690
1765
 
1691
- @sample_a_2.setter
1692
- def sample_a_2(self, prior):
1693
- try:
1766
+ @a_2.setter
1767
+ def a_2(self, prior):
1768
+ if prior in self.available_gw_prior_list_and_its_params["a_2"]:
1769
+ print(f"using ler available a_2 function : {prior}")
1694
1770
  args = self.gw_param_samplers_params["a_2"]
1695
- self._sample_a_2 = getattr(self, prior)(
1696
- size=None, get_attribute=True, param=args
1771
+ if args is None:
1772
+ self._a_2 = getattr(self, prior)(
1773
+ size=None, get_attribute=True
1697
1774
  )
1698
- except:
1699
- self._sample_a_2 = prior
1775
+ else:
1776
+ # follwing should return a sampler function with only one argument (size)
1777
+ self._a_2 = getattr(self, prior)(
1778
+ size=None, get_attribute=True, **args
1779
+ )
1780
+ elif callable(prior):
1781
+ print("using user provided custom a_2 function")
1782
+ self._a_2 = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1783
+ elif isinstance(prior, object):
1784
+ print("using user provided custom a_2 class/object")
1785
+ self._a_2 = prior
1786
+ else:
1787
+ raise ValueError("a_2 prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1700
1788
 
1701
1789
  @property
1702
- def sample_tilt_1(self):
1790
+ def tilt_1(self):
1703
1791
  """
1704
1792
  Function to sample tilt angle of the compact binaries (body1) with the initialized prior.
1705
1793
 
@@ -1713,20 +1801,32 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1713
1801
  tilt_1 : `numpy.ndarray` (1D array of floats)
1714
1802
  Array of tilt angle of the compact binaries (body1)
1715
1803
  """
1716
- return self._sample_tilt_1
1804
+ return self._tilt_1
1717
1805
 
1718
- @sample_tilt_1.setter
1719
- def sample_tilt_1(self, prior):
1720
- try:
1806
+ @tilt_1.setter
1807
+ def tilt_1(self, prior):
1808
+ if prior in self.available_gw_prior_list_and_its_params["tilt_1"]:
1809
+ print(f"using ler available tilt_1 function : {prior}")
1721
1810
  args = self.gw_param_samplers_params["tilt_1"]
1722
- self._sample_tilt_1 = getattr(self, prior)(
1723
- size=None, get_attribute=True, param=args
1811
+ if args is None:
1812
+ self._tilt_1 = getattr(self, prior)(
1813
+ size=None, get_attribute=True
1724
1814
  )
1725
- except:
1726
- self._sample_tilt_1 = prior
1815
+ else:
1816
+ self._tilt_1 = getattr(self, prior)(
1817
+ size=None, get_attribute=True, **args
1818
+ )
1819
+ elif callable(prior):
1820
+ print("using user provided custom tilt_1 function")
1821
+ self._tilt_1 = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1822
+ elif isinstance(prior, object):
1823
+ print("using user provided custom tilt_1 class/object")
1824
+ self._tilt_1 = prior
1825
+ else:
1826
+ raise ValueError("tilt_1 prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1727
1827
 
1728
1828
  @property
1729
- def sample_tilt_2(self):
1829
+ def tilt_2(self):
1730
1830
  """
1731
1831
  Function to sample tilt angle of the compact binaries (body2) with the initialized prior.
1732
1832
 
@@ -1741,20 +1841,32 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1741
1841
  Array of tilt angle of the compact binaries (body2)
1742
1842
  """
1743
1843
 
1744
- return self._sample_tilt_2
1844
+ return self._tilt_2
1745
1845
 
1746
- @sample_tilt_2.setter
1747
- def sample_tilt_2(self, prior):
1748
- try:
1846
+ @tilt_2.setter
1847
+ def tilt_2(self, prior):
1848
+ if prior in self.available_gw_prior_list_and_its_params["tilt_2"]:
1849
+ print(f"using ler available tilt_2 function : {prior}")
1749
1850
  args = self.gw_param_samplers_params["tilt_2"]
1750
- self._sample_tilt_2 = getattr(self, prior)(
1751
- size=None, get_attribute=True, param=args
1851
+ if args is None:
1852
+ self._tilt_2 = getattr(self, prior)(
1853
+ size=None, get_attribute=True
1752
1854
  )
1753
- except:
1754
- self._sample_tilt_2 = prior
1755
-
1855
+ else:
1856
+ self._tilt_2 = getattr(self, prior)(
1857
+ size=None, get_attribute=True, **args
1858
+ )
1859
+ elif callable(prior):
1860
+ print("using user provided custom tilt_2 function")
1861
+ self._tilt_2 = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1862
+ elif isinstance(prior, object):
1863
+ print("using user provided custom tilt_2 class/object")
1864
+ self._tilt_2 = prior
1865
+ else:
1866
+ raise ValueError("tilt_2 prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1867
+
1756
1868
  @property
1757
- def sample_phi_12(self):
1869
+ def phi_12(self):
1758
1870
  """
1759
1871
  Function to sample azimuthal angle between the two spins with the initialized prior.
1760
1872
 
@@ -1769,20 +1881,32 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1769
1881
  Array of azimuthal angle between the two spins
1770
1882
  """
1771
1883
 
1772
- return self._sample_phi_12
1884
+ return self._phi_12
1773
1885
 
1774
- @sample_phi_12.setter
1775
- def sample_phi_12(self, prior):
1776
- try:
1886
+ @phi_12.setter
1887
+ def phi_12(self, prior):
1888
+ if prior in self.available_gw_prior_list_and_its_params["phi_12"]:
1889
+ print(f"using ler available phi_12 function : {prior}")
1777
1890
  args = self.gw_param_samplers_params["phi_12"]
1778
- self._sample_phi_12 = getattr(self, prior)(
1779
- size=None, get_attribute=True, param=args
1780
- )
1781
- except:
1782
- self._sample_phi_12 = prior
1891
+ if args is None:
1892
+ self._phi_12 = getattr(self, prior)(
1893
+ size=None, get_attribute=True
1894
+ )
1895
+ else:
1896
+ self._phi_12 = getattr(self, prior)(
1897
+ size=None, get_attribute=True, **args
1898
+ )
1899
+ elif callable(prior):
1900
+ print("using user provided custom phi_12 function")
1901
+ self._phi_12 = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1902
+ elif isinstance(prior, object):
1903
+ print("using user provided custom phi_12 class/object")
1904
+ self._phi_12 = prior
1905
+ else:
1906
+ raise ValueError("phi_12 prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1783
1907
 
1784
1908
  @property
1785
- def sample_phi_jl(self):
1909
+ def phi_jl(self):
1786
1910
  """
1787
1911
  Function to sample azimuthal angle between the total angular momentum and the orbital angular momentum with the initialized prior.
1788
1912
 
@@ -1796,14 +1920,148 @@ class CBCSourceParameterDistribution(CBCSourceRedshiftDistribution):
1796
1920
  phi_jl : `numpy.ndarray` (1D array of floats)
1797
1921
  Array of azimuthal angle between the total angular momentum and the orbital angular momentum
1798
1922
  """
1799
- return self._sample_phi_jl
1923
+ return self._phi_jl
1800
1924
 
1801
- @sample_phi_jl.setter
1802
- def sample_phi_jl(self, prior):
1803
- try:
1925
+ @phi_jl.setter
1926
+ def phi_jl(self, prior):
1927
+ if prior in self.available_gw_prior_list_and_its_params["phi_jl"]:
1928
+ print(f"using ler available phi_jl function : {prior}")
1804
1929
  args = self.gw_param_samplers_params["phi_jl"]
1805
- self._sample_phi_jl = getattr(self, prior)(
1806
- size=None, get_attribute=True, param=args
1930
+ if args is None:
1931
+ self._phi_jl = getattr(self, prior)(
1932
+ size=None, get_attribute=True
1807
1933
  )
1808
- except:
1809
- self._sample_phi_jl = prior
1934
+ else:
1935
+ self._phi_jl = getattr(self, prior)(
1936
+ size=None, get_attribute=True, **args
1937
+ )
1938
+ elif callable(prior):
1939
+ print("using user provided custom phi_jl function")
1940
+ self._phi_jl = FunctionConditioning(function=None, x_array=None, create_rvs=prior)
1941
+ elif isinstance(prior, object):
1942
+ print("using user provided custom phi_jl class/object")
1943
+ self._phi_jl = prior
1944
+ else:
1945
+ raise ValueError("phi_jl prior not available in available_gw_prior_list_and_its_params. Must be a string or a callable function.")
1946
+
1947
+ @property
1948
+ def available_gw_prior_list_and_its_params(self):
1949
+ """
1950
+ Dictionary with list all the available priors and it's corresponding parameters. This is an immutable instance attribute.
1951
+
1952
+ Examples
1953
+ ----------
1954
+ >>> from ler.gw_source_population import CBCSourceParameterDistribution
1955
+ >>> cbc = CBCSourceParameterDistribution()
1956
+ >>> priors = cbc.available_gw_prior_list_and_its_params
1957
+ >>> priors.keys() # type of priors
1958
+ dict_keys(['merger_rate_density', 'source_frame_masses', 'spin', 'geocent_time', 'ra', 'phase', 'psi', 'theta_jn'])
1959
+ >>> priors['source_frame_masses'].keys() # type of source_frame_masses priors
1960
+ dict_keys(['binary_masses_BBH_popI_II_powerlaw_gaussian', 'binary_masses_BBH_popIII_lognormal', 'binary_masses_BBH_primordial_lognormal', 'binary_masses_BNS_bimodal'])
1961
+ >>> priors['source_frame_masses']['binary_masses_BBH_popI_II_powerlaw_gaussian'].keys() # parameters of binary_masses_BBH_popI_II_powerlaw_gaussian
1962
+ dict_keys(['mminbh', 'mmaxbh', 'alpha', 'mu_g', 'sigma_g', 'lambda_peak', 'delta_m', 'beta'])
1963
+ """
1964
+
1965
+ self._available_gw_prior_list_and_its_params = dict(
1966
+ merger_rate_density=self.merger_rate_density_model_list,
1967
+ zs=dict(
1968
+ source_redshift=None,
1969
+ ),
1970
+ source_frame_masses=dict(
1971
+ binary_masses_BBH_popI_II_powerlaw_gaussian=dict(
1972
+ mminbh=4.98,
1973
+ mmaxbh=112.5,
1974
+ alpha=3.78,
1975
+ mu_g=32.27,
1976
+ sigma_g=3.88,
1977
+ lambda_peak=0.03,
1978
+ delta_m=4.8,
1979
+ beta=0.81,
1980
+ ),
1981
+ binary_masses_BBH_popIII_lognormal=dict(m_min=5.0, m_max=150.0, Mc=30.0, sigma=0.3),
1982
+ binary_masses_BBH_primordial_lognormal=dict(
1983
+ Mc=30.0, sigma=0.3, beta=1.1
1984
+ ),
1985
+ binary_masses_NSBH_broken_powerlaw=dict(
1986
+ mminbh=26,
1987
+ mmaxbh=125,
1988
+ alpha_1=6.75,
1989
+ alpha_2=0.0,
1990
+ b=0.5,
1991
+ delta_m=5,
1992
+ mminns=1.0,
1993
+ mmaxns=3.0,
1994
+ alphans=0.0,
1995
+ ),
1996
+ binary_masses_uniform=dict(m_min=1.0, m_max=3.0),
1997
+ binary_masses_BNS_bimodal=dict(
1998
+ w=0.643,
1999
+ muL=1.352,
2000
+ sigmaL=0.08,
2001
+ muR=1.88,
2002
+ sigmaR=0.3,
2003
+ mmin=1.0,
2004
+ mmax=2.3,
2005
+ ),
2006
+ ),
2007
+ a_1=dict(
2008
+ constant_values_n_size=dict(value=0.0),
2009
+ sampler_uniform=dict(xmin=-0.8, xmax=0.8),
2010
+ ) if self.spin_zero else dict(
2011
+ constant_values_n_size=dict(value=0.0),
2012
+ sampler_uniform=dict(xmin=0.0, xmax=0.8),
2013
+ ),
2014
+ a_2=dict(
2015
+ constant_values_n_size=dict(value=0.0),
2016
+ sampler_uniform=dict(xmin=-0.8, xmax=0.8),
2017
+ ) if self.spin_zero else dict(
2018
+ constant_values_n_size=dict(value=0.0),
2019
+ sampler_uniform=dict(xmin=0.0, xmax=0.8),
2020
+ ),
2021
+ tilt_1=dict(
2022
+ constant_values_n_size=dict(value=0.0),
2023
+ sampler_sine=None,
2024
+ ),
2025
+ tilt_2=dict(
2026
+ constant_values_n_size=dict(value=0.0),
2027
+ sampler_sine=None,
2028
+ ),
2029
+ phi_12=dict(
2030
+ constant_values_n_size=dict(value=0.0),
2031
+ sampler_uniform=dict(xmin=0.0, xmax=2 * np.pi),
2032
+ ),
2033
+ phi_jl=dict(
2034
+ constant_values_n_size=dict(value=0.0),
2035
+ sampler_uniform=dict(xmin=0.0, xmax=2 * np.pi),
2036
+ ),
2037
+ geocent_time=dict(
2038
+ sampler_uniform=dict(
2039
+ xmin=1238166018, xmax=1238166018 + 31557600.0
2040
+ ),
2041
+ constant_values_n_size=dict(value=1238166018),
2042
+ ),
2043
+ ra=dict(
2044
+ sampler_uniform=dict(xmin=0.0, xmax=2 * np.pi),
2045
+ constant_values_n_size=dict(value=0.0),
2046
+ ),
2047
+ dec=dict(
2048
+ sampler_cosine=None,
2049
+ constant_values_n_size=dict(value=0.0),
2050
+ sampler_uniform=dict(xmin=-np.pi / 2, xmax=np.pi / 2),
2051
+ ),
2052
+ phase=dict(
2053
+ sampler_uniform=dict(xmin=0.0, xmax=2 * np.pi),
2054
+ constant_values_n_size=dict(value=0.0),
2055
+ ),
2056
+ psi=dict(
2057
+ sampler_uniform=dict(xmin=0.0, xmax=np.pi),
2058
+ constant_values_n_size=dict(value=0.0),
2059
+ ),
2060
+ theta_jn=dict(
2061
+ sampler_sine=None,
2062
+ constant_values_n_size=dict(value=0.0),
2063
+ sampler_uniform=dict(xmin=0.0, xmax=np.pi),
2064
+ ),
2065
+ )
2066
+
2067
+ return self._available_gw_prior_list_and_its_params