ler 0.4.1__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 +1076 -818
  4. ler/gw_source_population/cbc_source_redshift_distribution.py +619 -295
  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 +44 -13
  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 +817 -885
  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 +129 -75
  22. ler/rates/ler.py +257 -116
  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 +553 -125
  29. {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/METADATA +22 -9
  30. ler-0.4.3.dist-info/RECORD +34 -0
  31. {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/WHEEL +1 -1
  32. ler/rates/ler copy.py +0 -2097
  33. ler-0.4.1.dist-info/RECORD +0 -25
  34. {ler-0.4.1.dist-info → ler-0.4.3.dist-info/licenses}/LICENSE +0 -0
  35. {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
3
  This module contains the LensGalaxyPopulation class, which is used to sample lens galaxy parameters, source parameters conditioned on the source being strongly lensed, image properties, and lensed SNRs. \n
4
- The class inherits from the CompactBinaryPopulation class, which is used to sample source parameters. \n
4
+ The class inherits from the CBCSourceParameterDistribution class, which is used to sample source parameters. \n
5
5
  """
6
6
 
7
7
  import warnings
@@ -120,8 +120,7 @@ class ImageProperties():
120
120
  z_max=10,
121
121
  n_min_images=2,
122
122
  n_max_images=4,
123
- geocent_time_min=1126259462.4,
124
- geocent_time_max=1126259462.4+365*24*3600*20,
123
+ time_window=365*24*3600*20,
125
124
  lens_model_list=['EPL_NUMBA', 'SHEAR'],
126
125
  cosmology=None,
127
126
  spin_zero=True,
@@ -136,8 +135,9 @@ class ImageProperties():
136
135
  self.lens_model_list = lens_model_list # list of lens models
137
136
  self.spin_zero = spin_zero
138
137
  self.spin_precession = spin_precession
139
- self.geocent_time_min = geocent_time_min
140
- self.geocent_time_max = geocent_time_max
138
+ self.time_window = time_window
139
+ # self.geocent_time_min = geocent_time_min
140
+ # self.geocent_time_max = geocent_time_max
141
141
  self.cosmo = cosmology if cosmology else cosmo
142
142
 
143
143
  # initialize the interpolator's parameters
@@ -341,6 +341,8 @@ class ImageProperties():
341
341
  ####################################
342
342
  lens_parameters.update(image_parameters)
343
343
  lens_parameters["n_images"] = n_images
344
+ lens_parameters["x_source"] = x_source
345
+ lens_parameters["y_source"] = y_source
344
346
 
345
347
  return lens_parameters
346
348
 
@@ -366,15 +368,20 @@ class ImageProperties():
366
368
  -------
367
369
  snrs : `dict`
368
370
  signal to noise ratio for each image in each event.
369
- (dictionary containing 'H1', 'L1', ..., and 'optimal_snr_net', which is the network snr, for each image as an array with dimensions (number_of_lensed_events,n_max_images) )
371
+ (dictionary containing 'H1', 'L1', ..., and 'snr_net', which is the network snr, for each image as an array with dimensions (number_of_lensed_events,n_max_images) )
370
372
 
371
373
  """
372
374
  # needed to calculate effective luminosity distance and effective time delay
373
375
  n_max_images = self.n_max_images
374
376
  magnifications = lensed_param["magnifications"]
375
377
  time_delays = lensed_param["time_delays"]
378
+ imgage_type = lensed_param["image_type"]
376
379
  size = len(magnifications)
377
380
 
381
+ # image type to morse phase
382
+ imgage_type[imgage_type==1.] = 0.
383
+ imgage_type[imgage_type==2.] = np.pi/2
384
+
378
385
  # Get the binary parameters
379
386
  number_of_lensed_events = len(magnifications)
380
387
  mass_1, mass_2, theta_jn, psi, ra, dec, phase, a_1, a_2, tilt_1, tilt_2, phi_12, phi_jl = (
@@ -405,7 +412,7 @@ class ImageProperties():
405
412
  # setting up snr dictionary
406
413
  result_dict = dict()
407
414
  if snr_calculator:
408
- result_dict["optimal_snr_net"] = (
415
+ result_dict["snr_net"] = (
409
416
  np.ones((number_of_lensed_events, n_max_images)) * np.nan
410
417
  )
411
418
  # setting up pdet dictionary
@@ -443,9 +450,23 @@ class ImageProperties():
443
450
  time_eff_present = True
444
451
  else:
445
452
  raise ValueError("geocent_time or effective_geocent_time not given")
453
+
454
+ if "phase" in lensed_param:
455
+ phase = lensed_param["phase"]
456
+ lensed_param["effective_phase"] = np.ones((number_of_lensed_events, n_max_images)) * np.nan
457
+ phase_eff_present = False
458
+ elif "effective_phase" in lensed_param:
459
+ phase_eff = lensed_param["effective_phase"]
460
+ phase_eff_present = True
461
+ else:
462
+ raise ValueError("phase or effective_phase not given")
463
+
446
464
 
447
465
  # Get the optimal signal to noise ratios for each image
448
466
  # iterate over the image type (column)
467
+ geocent_time_min = np.min(geocent_time)
468
+ geocent_time_max = geocent_time_min + self.time_window
469
+
449
470
  for i in range(n_max_images):
450
471
 
451
472
  # get the effective time for each image type
@@ -453,8 +474,10 @@ class ImageProperties():
453
474
  effective_geocent_time = geocent_time + time_delays[:, i]
454
475
  else:
455
476
  effective_geocent_time = time_eff[:, i]
477
+
456
478
  # choose only the events that are within the time range and also not nan
457
- idx = (effective_geocent_time <= self.geocent_time_max) & (effective_geocent_time >= self.geocent_time_min)
479
+ idx = (effective_geocent_time <= geocent_time_max) & (effective_geocent_time >= geocent_time_min)
480
+
458
481
  # get the effective luminosity distance for each image type
459
482
  if not dl_eff_present:
460
483
  effective_luminosity_distance = luminosity_distance / np.sqrt(
@@ -462,12 +485,17 @@ class ImageProperties():
462
485
  )
463
486
  else:
464
487
  effective_luminosity_distance = dl_eff[:, i]
488
+ # get the effective phase for each image type
489
+ if not phase_eff_present:
490
+ effective_phase = phase - imgage_type[:, i] # morse phase correction
491
+ else:
492
+ effective_phase = phase_eff[:, i]
465
493
 
466
494
  # check for nan values
467
- idx = idx & ~np.isnan(effective_luminosity_distance) & ~np.isnan(effective_geocent_time)
495
+ idx = idx & ~np.isnan(effective_luminosity_distance) & ~np.isnan(effective_geocent_time) & ~np.isnan(effective_phase)
468
496
 
469
497
  # Each image has their own effective luminosity distance and effective geocent time
470
- if len(effective_luminosity_distance) != 0:
498
+ if sum(idx) != 0:
471
499
  # Returns a dictionary
472
500
  if snr_calculator:
473
501
  optimal_snr = snr_calculator(
@@ -477,7 +505,7 @@ class ImageProperties():
477
505
  luminosity_distance=effective_luminosity_distance[idx],
478
506
  theta_jn=theta_jn[idx],
479
507
  psi=psi[idx],
480
- phase=phase[idx],
508
+ phase= effective_phase[idx],
481
509
  geocent_time=effective_geocent_time[idx],
482
510
  ra=ra[idx],
483
511
  dec=dec[idx],
@@ -490,7 +518,7 @@ class ImageProperties():
490
518
  ),
491
519
  output_jsonfile=False,
492
520
  )
493
- result_dict["optimal_snr_net"][idx, i] = optimal_snr["optimal_snr_net"]
521
+ result_dict["snr_net"][idx, i] = optimal_snr["snr_net"]
494
522
 
495
523
  if list_of_detectors:
496
524
  for detector in list_of_detectors:
@@ -505,7 +533,7 @@ class ImageProperties():
505
533
  luminosity_distance=effective_luminosity_distance[idx],
506
534
  theta_jn=theta_jn[idx],
507
535
  psi=psi[idx],
508
- phase=phase[idx],
536
+ phase= effective_phase[idx],
509
537
  geocent_time=effective_geocent_time[idx],
510
538
  ra=ra[idx],
511
539
  dec=dec[idx],
@@ -527,10 +555,13 @@ class ImageProperties():
527
555
 
528
556
  lensed_param["effective_luminosity_distance"][:, i] = effective_luminosity_distance
529
557
  lensed_param["effective_geocent_time"][:, i] = effective_geocent_time
558
+ lensed_param["effective_phase"][:, i] = effective_phase
530
559
 
531
560
  if dl_eff_present:
532
561
  del lensed_param["effective_luminosity_distance"]
533
562
  if time_eff_present:
534
563
  del lensed_param["effective_geocent_time"]
564
+ if phase_eff_present:
565
+ del lensed_param["effective_phase"]
535
566
 
536
567
  return result_dict, lensed_param
@@ -7,8 +7,8 @@ import numpy as np
7
7
  from lenstronomy.LensModel.lens_model import LensModel
8
8
  from lenstronomy.LensModel.Solver.lens_equation_solver import LensEquationSolver
9
9
  from lenstronomy.LensModel.Solver.epl_shear_solver import caustics_epl_shear
10
- from lenstronomy.Util.param_util import phi_q2_ellipticity
11
- from ..lens_galaxy_population.jit_functions import axis_ratio_rayleigh
10
+ # from lenstronomy.Util.param_util import phi_q2_ellipticity
11
+ # from ..lens_galaxy_population.jit_functions import axis_ratio_rayleigh
12
12
 
13
13
  # For sampling from caustic
14
14
  from shapely.geometry import Polygon
@@ -38,7 +38,7 @@ def solve_lens_equation(lens_parameters):
38
38
  Returns
39
39
  -------
40
40
  x_source : `float`
41
- x position of the source in the source plane
41
+ x position of the source in the source plane, unit: arcsec
42
42
  y_source : `float`
43
43
  y position of the source in the source plane
44
44
  x0_image_position : `float`
@@ -121,7 +121,7 @@ def solve_lens_equation(lens_parameters):
121
121
  )
122
122
  caustic = np.logical_not(np.isnan(caustic_double_points).any())
123
123
 
124
- # If there is a nan, caustic=False, draw a new gamma
124
+ # If there is a nan, caustic=False, this batch will be ignored and resampled outside in lens_parameters sampling
125
125
  if caustic:
126
126
  break
127
127
  else:
@@ -139,6 +139,7 @@ def solve_lens_equation(lens_parameters):
139
139
  iteration,
140
140
  )
141
141
 
142
+ # define region in the source plane where 2 or more images are formed
142
143
  caustic_double = Polygon(caustic_double_points.T)
143
144
 
144
145
  # check for strong lensed condition
@@ -242,208 +243,3 @@ def solve_lens_equation(lens_parameters):
242
243
  )
243
244
 
244
245
 
245
- # def solve_lens_equation(lens_parameters):
246
- # """
247
- # Function to solve the lens equation (min_image = 2)
248
-
249
- # Parameters
250
- # ----------
251
- # lens_parameters : `list`
252
- # a list of parameters
253
- # lens_parameters[0] = min_images : minimum number of images
254
- # lens_parameters[1] = e1 : ellipticity
255
- # lens_parameters[2] = e2 : ellipticity
256
- # lens_parameters[3] = gamma : power-law index
257
- # lens_parameters[4] = gamma1 : shear
258
- # lens_parameters[5] = gamma2 : shear
259
- # lens_parameters[6] = zl : redshift of the lens
260
- # lens_parameters[7] = zs : redshift of the source
261
- # lens_parameters[8] = einstein_radius : Einstein radius
262
- # lens_parameters[9] = iteration : iteration number
263
- # lens_parameters[10:] = lens_model_list : numpy array of lens models
264
-
265
- # Returns
266
- # -------
267
- # x_source : `float`
268
- # x position of the source in the source plane
269
- # y_source : `float`
270
- # y position of the source in the source plane
271
- # x0_image_position : `float`
272
- # x position of the images in the source plane
273
- # x1_image_position : `float`
274
- # y position of the images in the source plane
275
- # magnifications : `float`
276
- # magnification of the images
277
- # time_delays : `float`
278
- # time-delay of the images
279
- # nImages : `int`
280
- # number of images
281
- # determinant : `float`
282
- # determinant of the hessian matrix
283
- # trace : `float`
284
- # trace of the hessian matrix
285
- # iteration : `int`
286
- # iteration number
287
-
288
- # Examples
289
- # --------
290
- # >>> from ler.multiprocessing_routine import solve_lens_equation1
291
- # >>> import numpy as np
292
- # >>> from multiprocessing import Pool
293
- # >>> # lens parameters input contains 12 parameters [e1, e2, gamma, gamma1, gamma2, zl, zs, einstein_radius, iteration, lens_model_list]
294
- # >>> lens_parameters1 = np.array([2, 0.024069457093642648, -0.016002190961948142, 1.8945414936459974, 0.10117465203892329, 0.09600089396968613, 0.2503743800068136, 0.9418211055453296, 2.5055790287104725e-06, 0, 'EPL_NUMBA', 'SHEAR'], dtype=object)
295
- # >>> lens_parameters2 = np.array([2, -0.04030088581646998, -0.01419438113690042, 2.0068239327017, 0.08482718989370612, -0.015393332086560785, 1.0952303138971118, 2.5534097159384417, 1.0125570159563301e-06, 1, 'EPL_NUMBA', 'SHEAR'], dtype=object)
296
- # >>> input_arguments = np.vstack((lens_parameters1, lens_parameters2))
297
- # >>> # solve the lens equation for each set of lens parameters
298
- # >>> with Pool(2) as p:
299
- # ... result = p.map(solve_lens_equation1, input_arguments)
300
- # >>> # result is a list of tuples
301
- # >>> # each tuple contains the output parameters of the function
302
- # >>> # each output parameter contains x_source, y_source, x0_image_position, x1_image_position, magnifications, time_delays, nImages, determinant, trace, iteration
303
- # >>> print(f"magnification of images with lens parameters 'lens_parameters1' is {result[0][6]}")
304
- # magnification of images with lens parameters 'lens_parameters1' is [ 2.18973765 -1.27542831]
305
-
306
- # """
307
- # n_min_images = int(lens_parameters[0])
308
- # zl = lens_parameters[6]
309
- # zs = lens_parameters[7]
310
- # einstein_radius = lens_parameters[8]
311
- # iteration = lens_parameters[9]
312
- # # lensModel parameters are the same for the three functions used for image param calculation
313
- # # 1. x-y position of images in the source plane, 2. magnifications, 3. time-delays (relative)
314
- # lensModel = LensModel(
315
- # lens_model_list=lens_parameters[10:].tolist(), z_lens=zl, z_source=zs
316
- # )
317
-
318
- # lens_eq_solver = LensEquationSolver(lensModel)
319
-
320
- # factor = 1.0
321
- # # ---------------------------------------------------#
322
- # # x-y position of images in the source plane
323
- # # ---------------------------------------------------#
324
- # # Get the caustic curve cut by the lens
325
- # # First check if there is any nan in the caustic points
326
- # def check_caustic():
327
- # """
328
- # Function to check if there is any nan in the caustic points
329
- # """
330
- # while True:
331
- # kwargs_lens = [
332
- # {
333
- # "theta_E": factor,
334
- # "e1": lens_parameters[1],
335
- # "e2": lens_parameters[2],
336
- # "gamma": lens_parameters[3],
337
- # "center_x": 0.0,
338
- # "center_y": 0.0,
339
- # },
340
- # {
341
- # "gamma1": lens_parameters[4],
342
- # "gamma2": lens_parameters[5],
343
- # "ra_0": 0,
344
- # "dec_0": 0,
345
- # },
346
- # ]
347
- # caustic_double_points = caustics_epl_shear(
348
- # kwargs_lens, return_which="double", maginf=-100
349
- # )
350
- # caustic = np.logical_not(np.isnan(caustic_double_points).any())
351
-
352
- # # If there is a nan, caustic=False, draw a new gamma
353
- # if caustic:
354
- # break
355
- # else:
356
- # #
357
- # q = axis_ratio_rayleigh(sigma=np.array([160.]))[0]
358
- # phi = np.random.uniform(0.0, 2*np.pi, size=1)[0]
359
- # lens_parameters[1], lens_parameters[2] = phi_q2_ellipticity(phi, q)
360
- # # resampling power-law index and shear
361
- # lens_parameters[3] = np.random.normal(loc=2.0, scale=0.2, size=1)[0]
362
- # gamma1, gamma2 = np.random.normal(loc=0, scale=0.05,size=(2,1))
363
- # lens_parameters[4], lens_parameters[5] = gamma1[0], gamma2[0]
364
-
365
- # caustic_double = Polygon(caustic_double_points.T)
366
- # return caustic_double, kwargs_lens
367
-
368
- # caustic_double, kwargs_lens = check_caustic()
369
-
370
- # # check for strong lensed condition
371
- # strongly_lensed = False
372
- # i = 0
373
- # while strongly_lensed == False:
374
- # # Draw random points within the caustic
375
- # # sometimes x_source, y_source positions are at same location and the solver fails
376
- # # so we use a try-except block to catch the error and draw a new point
377
- # # try:
378
- # x_source, y_source = pointpats.random.poisson(caustic_double, size=1)
379
- # # Solve the lens equation
380
- # (
381
- # x0_image_position,
382
- # x1_image_position,
383
- # ) = lens_eq_solver.image_position_from_source(
384
- # sourcePos_x=x_source,
385
- # sourcePos_y=y_source,
386
- # kwargs_lens=kwargs_lens,
387
- # solver="analytical",
388
- # magnification_limit=1.0 / 1000.0,
389
- # arrival_time_sort=True,
390
- # )
391
- # nImages = len(x0_image_position) # shows how many images
392
- # if nImages >= n_min_images:
393
- # strongly_lensed = True
394
- # # except:
395
- # # pass
396
- # ## test ##
397
- # if i > 10:
398
- # print("Could not find a valid source position. Run the sampling again by setting resume=True")
399
- # caustic_double, kwargs_lens = check_caustic()
400
- # i = 0
401
- # i += 1
402
- # ##########
403
-
404
- # # ---------------------------------------------------#
405
- # # magnification and time-delay
406
- # # ---------------------------------------------------#
407
- # # theta_E is in arcsec
408
- # theta_E_nImages = einstein_radius * np.ones(nImages)
409
- # radian_to_arcseconds = 180.0 / np.pi * 3600.0
410
- # days_to_seconds = 24.0 * 3600.0
411
- # # can have multiple magnification
412
- # magnifications = lensModel.magnification(
413
- # x0_image_position, x1_image_position, kwargs_lens
414
- # )
415
- # time_delays = (
416
- # lensModel.arrival_time(x0_image_position, x1_image_position, kwargs_lens)
417
- # * (theta_E_nImages * radian_to_arcseconds) ** 2
418
- # * days_to_seconds
419
- # )
420
-
421
- # # ---------------------------------------------------#
422
- # # Params needed for image-type classification
423
- # # ---------------------------------------------------#
424
- # # it is faster to use numpy array operation to do image classification
425
- # # return: f_xx, f_xy, f_yx, f_yy components
426
- # hessian = lensModel.hessian(x0_image_position, x1_image_position, kwargs_lens)
427
- # determinant = np.array(
428
- # (1 - hessian[0]) * (1 - hessian[3]) - hessian[1] * hessian[2]
429
- # )
430
- # trace = np.array(2 - hessian[0] - hessian[3])
431
-
432
- # # return also gamma1, gamma2
433
- # return (
434
- # x_source,
435
- # y_source,
436
- # x0_image_position,
437
- # x1_image_position,
438
- # magnifications,
439
- # time_delays,
440
- # nImages,
441
- # determinant,
442
- # trace,
443
- # lens_parameters[1],
444
- # lens_parameters[2],
445
- # lens_parameters[3],
446
- # lens_parameters[4],
447
- # lens_parameters[5],
448
- # iteration,
449
- # )
@@ -2,3 +2,5 @@ from .lens_galaxy_parameter_distribution import *
2
2
  from .optical_depth import *
3
3
  from .mp import *
4
4
  from .jit_functions import *
5
+
6
+ from .import lens_param_data
File without changes
@@ -68,9 +68,10 @@ def pdf_phi_z_div_0(s, z):
68
68
  return phi_sim_z / phi_sim_0
69
69
 
70
70
  @njit
71
- def phi(s,z, cosmology_h=0.7):
71
+ def phi(s, z, alpha=0.94, beta=1.85, phistar=2.099e-2, sigmastar=113.78):
72
72
  """
73
73
  Function to calculate the lens galaxy velocity dispersion function at redshift z.
74
+ For Oguri et al. (2018b) model: alpha=0.94, beta=1.85, phistar=2.099e-2*(self.cosmo.h/0.7)**3, sigmastar=113.78
74
75
 
75
76
  Parameters
76
77
  ----------
@@ -85,15 +86,17 @@ def phi(s,z, cosmology_h=0.7):
85
86
  -------
86
87
  result : `float: array`
87
88
  """
88
-
89
- result = s**4*pdf_phi_z_div_0(s,z)*phi_loc_bernardi(sigma=s, cosmology_h=cosmology_h)
90
- # result[result < 0.] = 0.
89
+
90
+ result = pdf_phi_z_div_0(s,z) * phi_loc_bernardi(sigma=s, alpha=alpha, beta=beta, phistar=phistar, sigmastar=sigmastar)
91
+ result[result < 0.] = 0.
91
92
  return result
92
93
 
93
94
  @njit
94
- def phi_loc_bernardi(sigma, alpha=0.94, beta=1.85, phistar=2.099e-2, sigmastar=113.78, cosmology_h=0.7):
95
+ def phi_loc_bernardi(sigma, alpha, beta, phistar, sigmastar):
95
96
  """
96
97
  Function to calculate the local universe velocity dispersion function. Bernardi et al. (2010).
98
+ For Oguri et al. (2018b) model: alpha=0.94, beta=1.85, phistar=2.099e-2*(self.cosmo.h/0.7)**3, sigmastar=113.78
99
+ For Choi et al. (2008) model: alpha = 2.32 / 2.67, beta = 2.67, phistar = 8.0e-3*self.cosmo.h**3, sigmastar = 161.0
97
100
 
98
101
  Parameters
99
102
  ----------
@@ -109,7 +112,7 @@ def phi_loc_bernardi(sigma, alpha=0.94, beta=1.85, phistar=2.099e-2, sigmastar=1
109
112
  philoc_ : `float: array`
110
113
  """
111
114
 
112
- phistar = phistar * (cosmology_h / 0.7) ** 3 # Mpc**-3
115
+ # phistar = phistar * (cosmology_h / 0.7) ** 3 # Mpc**-3
113
116
  philoc_ = phistar*(sigma/sigmastar)**alpha * np.exp(-(sigma/sigmastar)**beta) * beta/gamma_(alpha/beta)/sigma
114
117
  return philoc_
115
118
 
@@ -143,7 +146,7 @@ def phi_cut_SIE(q):
143
146
  return result/np.pi
144
147
 
145
148
  @njit
146
- def axis_ratio_rayleigh(sigma, q_min=0.2, q_max=1.0):
149
+ def axis_ratio_rayleigh_rvs(sigma, q_min=0.2, q_max=1.0):
147
150
  """
148
151
  Function to sample axis ratio from rayleigh distribution with given velocity dispersion.
149
152
 
@@ -184,6 +187,16 @@ def axis_ratio_rayleigh(sigma, q_min=0.2, q_max=1.0):
184
187
 
185
188
  return q
186
189
 
190
+ @njit
191
+ def axis_ratio_rayleigh_pdf(q, sigma, q_min=0.2, q_max=1.0):
192
+
193
+ s = 0.38 - 5.7e-4 * sigma
194
+ idx = (q >= q_min) & (q <= q_max)
195
+ q_pdf = np.zeros_like(q)
196
+ q_pdf[idx] = (1-q[idx])/s[idx]**2 * np.exp(-0.5*(1-q[idx])**2/s[idx]**2)
197
+ return q_pdf
198
+
199
+
187
200
  @njit
188
201
  def velocity_dispersion_z_dependent(size, zl, zl_list, vd_inv_cdf):
189
202
  """
@@ -215,9 +228,9 @@ def velocity_dispersion_z_dependent(size, zl, zl_list, vd_inv_cdf):
215
228
  return samples
216
229
 
217
230
  @njit
218
- def lens_redshift_SDSS_catalogue(zs, splineDc, splineDcInv, u, cdf):
231
+ def lens_redshift_SDSS_catalogue_sis(zs, splineDc, splineDcInv, u, cdf):
219
232
  """
220
- Function to sample lens redshift from the SDSS catalogue.
233
+ Function to sample lens redshift from the SDSS catalogue. Haris et al. (2018) cdf = (10 * u**3 - 15 * u**4 + 6 * u**5)
221
234
 
222
235
  Parameters
223
236
  ----------
@@ -275,4 +288,83 @@ def bounded_normal_sample(size, mean, std, low, high):
275
288
  samples[i] = sample
276
289
  return samples
277
290
 
291
+
292
+ @njit
293
+ def phi_q2_ellipticity_hemanta(phi, q):
294
+ """Function to convert phi and q to ellipticity e1 and e2.
295
+
296
+ Parameters
297
+ ----------
298
+ phi : `float: array`
299
+ angle of the major axis in radians
300
+ q : `float: array`
301
+ axis ratio
302
+
303
+ Returns
304
+ -------
305
+ e1 : `float: array`
306
+ ellipticity component 1
307
+ e2 : `float: array`
308
+ """
309
+
310
+ e_1 = (1.0 - q) / (1.0 + q) * np.cos(2 * phi)
311
+ e_2 = (1.0 - q) / (1.0 + q) * np.sin(2 * phi)
312
+ return e_1, e_2
313
+
314
+ # @njit
315
+ # def sample_sigma_zl(pdf, sigma_min, sigma_max, zl_min, zl_max, zs, chunk_size=10000):
316
+ # x_sample = []
317
+ # y_sample = []
278
318
 
319
+ # for z in zs:
320
+ # xmin, xmax = sigma_min, sigma_max
321
+ # ymin, ymax = zl_min, z
322
+
323
+ # # Keep sampling until a valid (sigma, zl) pair is found for this z
324
+ # while True:
325
+ # x_try = np.random.uniform(xmin, xmax, chunk_size)
326
+ # y_try = np.random.uniform(ymin, ymax, chunk_size)
327
+ # pdf_xy_try = pdf(x_try, y_try)
328
+ # zmax = np.max(pdf_xy_try) # Maximum of the PDF for the current batch
329
+
330
+ # # Generate acceptance thresholds
331
+ # z_try = np.random.uniform(0, zmax, chunk_size)
332
+
333
+ # # Check which samples are accepted
334
+ # accepted_indices = z_try < pdf_xy_try
335
+ # if np.any(accepted_indices):
336
+ # # Accept the first valid sample
337
+ # x_sample.append(x_try[accepted_indices][0])
338
+ # y_sample.append(y_try[accepted_indices][0])
339
+ # break # Exit the loop once the first valid sample is collected
340
+
341
+ # return np.array(x_sample), np.array(y_sample)
342
+
343
+ @njit
344
+ def sample_sigma_zl(pdf, sigma_min, sigma_max, zl_min, zl_max, zs, chunk_size=10000):
345
+ x_sample = []
346
+ y_sample = []
347
+
348
+ for z in zs:
349
+ xmin, xmax = sigma_min, sigma_max
350
+ ymin, ymax = zl_min, zl_max # Use full range and then filter
351
+
352
+ valid_sample_found = False
353
+ while not valid_sample_found:
354
+ x_try = np.random.uniform(xmin, xmax, chunk_size)
355
+ y_try = np.random.uniform(ymin, ymax, chunk_size)
356
+ pdf_xy_try = pdf(x_try, y_try)
357
+ zmax = np.max(pdf_xy_try) # Find maximum PDF value for current batch
358
+
359
+ # Generate acceptance thresholds
360
+ z_try = np.random.uniform(0, zmax, chunk_size)
361
+
362
+ # Check and accept samples
363
+ accepted = (z_try < pdf_xy_try) & (y_try < z) # Ensure zl < zs condition
364
+ if np.any(accepted):
365
+ idx = np.argmax(accepted) # First valid index
366
+ x_sample.append(x_try[idx])
367
+ y_sample.append(y_try[idx])
368
+ valid_sample_found = True
369
+
370
+ return np.array(x_sample), np.array(y_sample)