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
@@ -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
@@ -368,15 +368,20 @@ class ImageProperties():
368
368
  -------
369
369
  snrs : `dict`
370
370
  signal to noise ratio for each image in each event.
371
- (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) )
372
372
 
373
373
  """
374
374
  # needed to calculate effective luminosity distance and effective time delay
375
375
  n_max_images = self.n_max_images
376
376
  magnifications = lensed_param["magnifications"]
377
377
  time_delays = lensed_param["time_delays"]
378
+ imgage_type = lensed_param["image_type"]
378
379
  size = len(magnifications)
379
380
 
381
+ # image type to morse phase
382
+ imgage_type[imgage_type==1.] = 0.
383
+ imgage_type[imgage_type==2.] = np.pi/2
384
+
380
385
  # Get the binary parameters
381
386
  number_of_lensed_events = len(magnifications)
382
387
  mass_1, mass_2, theta_jn, psi, ra, dec, phase, a_1, a_2, tilt_1, tilt_2, phi_12, phi_jl = (
@@ -407,7 +412,7 @@ class ImageProperties():
407
412
  # setting up snr dictionary
408
413
  result_dict = dict()
409
414
  if snr_calculator:
410
- result_dict["optimal_snr_net"] = (
415
+ result_dict["snr_net"] = (
411
416
  np.ones((number_of_lensed_events, n_max_images)) * np.nan
412
417
  )
413
418
  # setting up pdet dictionary
@@ -445,9 +450,23 @@ class ImageProperties():
445
450
  time_eff_present = True
446
451
  else:
447
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
+
448
464
 
449
465
  # Get the optimal signal to noise ratios for each image
450
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
+
451
470
  for i in range(n_max_images):
452
471
 
453
472
  # get the effective time for each image type
@@ -455,8 +474,10 @@ class ImageProperties():
455
474
  effective_geocent_time = geocent_time + time_delays[:, i]
456
475
  else:
457
476
  effective_geocent_time = time_eff[:, i]
477
+
458
478
  # choose only the events that are within the time range and also not nan
459
- 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
+
460
481
  # get the effective luminosity distance for each image type
461
482
  if not dl_eff_present:
462
483
  effective_luminosity_distance = luminosity_distance / np.sqrt(
@@ -464,12 +485,17 @@ class ImageProperties():
464
485
  )
465
486
  else:
466
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]
467
493
 
468
494
  # check for nan values
469
- 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)
470
496
 
471
497
  # Each image has their own effective luminosity distance and effective geocent time
472
- if len(effective_luminosity_distance) != 0:
498
+ if sum(idx) != 0:
473
499
  # Returns a dictionary
474
500
  if snr_calculator:
475
501
  optimal_snr = snr_calculator(
@@ -479,7 +505,7 @@ class ImageProperties():
479
505
  luminosity_distance=effective_luminosity_distance[idx],
480
506
  theta_jn=theta_jn[idx],
481
507
  psi=psi[idx],
482
- phase=phase[idx],
508
+ phase= effective_phase[idx],
483
509
  geocent_time=effective_geocent_time[idx],
484
510
  ra=ra[idx],
485
511
  dec=dec[idx],
@@ -492,7 +518,7 @@ class ImageProperties():
492
518
  ),
493
519
  output_jsonfile=False,
494
520
  )
495
- result_dict["optimal_snr_net"][idx, i] = optimal_snr["optimal_snr_net"]
521
+ result_dict["snr_net"][idx, i] = optimal_snr["snr_net"]
496
522
 
497
523
  if list_of_detectors:
498
524
  for detector in list_of_detectors:
@@ -507,7 +533,7 @@ class ImageProperties():
507
533
  luminosity_distance=effective_luminosity_distance[idx],
508
534
  theta_jn=theta_jn[idx],
509
535
  psi=psi[idx],
510
- phase=phase[idx],
536
+ phase= effective_phase[idx],
511
537
  geocent_time=effective_geocent_time[idx],
512
538
  ra=ra[idx],
513
539
  dec=dec[idx],
@@ -529,10 +555,13 @@ class ImageProperties():
529
555
 
530
556
  lensed_param["effective_luminosity_distance"][:, i] = effective_luminosity_distance
531
557
  lensed_param["effective_geocent_time"][:, i] = effective_geocent_time
558
+ lensed_param["effective_phase"][:, i] = effective_phase
532
559
 
533
560
  if dl_eff_present:
534
561
  del lensed_param["effective_luminosity_distance"]
535
562
  if time_eff_present:
536
563
  del lensed_param["effective_geocent_time"]
564
+ if phase_eff_present:
565
+ del lensed_param["effective_phase"]
537
566
 
538
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)