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.
- ler/__init__.py +26 -26
- ler/gw_source_population/__init__.py +1 -0
- ler/gw_source_population/cbc_source_parameter_distribution.py +1076 -818
- ler/gw_source_population/cbc_source_redshift_distribution.py +619 -295
- ler/gw_source_population/jit_functions.py +484 -9
- ler/gw_source_population/sfr_with_time_delay.py +107 -0
- ler/image_properties/image_properties.py +44 -13
- ler/image_properties/multiprocessing_routine.py +5 -209
- ler/lens_galaxy_population/__init__.py +2 -0
- ler/lens_galaxy_population/epl_shear_cross_section.py +0 -0
- ler/lens_galaxy_population/jit_functions.py +101 -9
- ler/lens_galaxy_population/lens_galaxy_parameter_distribution.py +817 -885
- ler/lens_galaxy_population/lens_param_data/density_profile_slope_sl.txt +5000 -0
- ler/lens_galaxy_population/lens_param_data/external_shear_sl.txt +2 -0
- ler/lens_galaxy_population/lens_param_data/number_density_zl_zs.txt +48 -0
- ler/lens_galaxy_population/lens_param_data/optical_depth_epl_shear_vd_ewoud.txt +48 -0
- ler/lens_galaxy_population/mp copy.py +554 -0
- ler/lens_galaxy_population/mp.py +736 -138
- ler/lens_galaxy_population/optical_depth.py +2248 -616
- ler/rates/__init__.py +1 -2
- ler/rates/gwrates.py +129 -75
- ler/rates/ler.py +257 -116
- ler/utils/__init__.py +2 -0
- ler/utils/function_interpolation.py +322 -0
- ler/utils/gwsnr_training_data_generator.py +233 -0
- ler/utils/plots.py +1 -1
- ler/utils/test.py +1078 -0
- ler/utils/utils.py +553 -125
- {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/METADATA +22 -9
- ler-0.4.3.dist-info/RECORD +34 -0
- {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/WHEEL +1 -1
- ler/rates/ler copy.py +0 -2097
- ler-0.4.1.dist-info/RECORD +0 -25
- {ler-0.4.1.dist-info → ler-0.4.3.dist-info/licenses}/LICENSE +0 -0
- {ler-0.4.1.dist-info → ler-0.4.3.dist-info}/top_level.txt +0 -0
ler/rates/ler.py
CHANGED
|
@@ -4,6 +4,7 @@ This module contains the main class for calculating the rates of detectable grav
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
+
# os.environ['OMP_NESTED'] = 'FALSE'
|
|
7
8
|
import warnings
|
|
8
9
|
warnings.filterwarnings("ignore")
|
|
9
10
|
import logging
|
|
@@ -16,12 +17,6 @@ from ..lens_galaxy_population import LensGalaxyParameterDistribution
|
|
|
16
17
|
from ..utils import load_json, append_json, get_param_from_json, batch_handler
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
# # multiprocessing guard code
|
|
20
|
-
# def main():
|
|
21
|
-
# obj = LeR()
|
|
22
|
-
|
|
23
|
-
# if __name__ == '__main__':
|
|
24
|
-
|
|
25
20
|
class LeR(LensGalaxyParameterDistribution):
|
|
26
21
|
"""Class to sample of lensed and unlensed events and calculate it's rates. Please note that parameters of the simulated events are stored in json file but not as an attribute of the class. This saves RAM memory.
|
|
27
22
|
|
|
@@ -59,7 +54,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
59
54
|
def snr_finder(gw_param_dict):
|
|
60
55
|
...
|
|
61
56
|
return optimal_snr_dict
|
|
62
|
-
where optimal_snr_dict.keys = ['
|
|
57
|
+
where optimal_snr_dict.keys = ['snr_net']. Refer to `gwsnr` package's GWSNR.snr attribute for more details.
|
|
63
58
|
pdet_finder : `function`
|
|
64
59
|
default pdet_finder = None.
|
|
65
60
|
The rate calculation uses either the pdet_finder or the snr_finder to calculate the detectable events. The custom pdet finder function should follow the following signature:
|
|
@@ -76,6 +71,23 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
76
71
|
interpolator_directory : `str`
|
|
77
72
|
directory to store the interpolators.
|
|
78
73
|
default interpolator_directory = './interpolator_pickle'. This is used for storing the various interpolators related to `ler` and `gwsnr` package.
|
|
74
|
+
create_new_interpolator : `bool` or `dict`
|
|
75
|
+
default create_new_interpolator = False.
|
|
76
|
+
if True, the all interpolators (including `gwsnr`'s)will be created again.
|
|
77
|
+
if False, the interpolators will be loaded from the interpolator_directory if they exist.
|
|
78
|
+
if dict, you can specify which interpolators to create new. Complete example (change any of them to True), create_new_interpolator = create_new_interpolator = dict(
|
|
79
|
+
redshift_distribution=dict(create_new=False, resolution=1000),
|
|
80
|
+
z_to_luminosity_distance=dict(create_new=False, resolution=1000),
|
|
81
|
+
velocity_dispersion=dict(create_new=False, resolution=1000),
|
|
82
|
+
axis_ratio=dict(create_new=False, resolution=1000),
|
|
83
|
+
optical_depth=dict(create_new=False, resolution=200),
|
|
84
|
+
z_to_Dc=dict(create_new=False, resolution=1000),
|
|
85
|
+
Dc_to_z=dict(create_new=False, resolution=1000),
|
|
86
|
+
angular_diameter_distance=dict(create_new=False, resolution=1000),
|
|
87
|
+
differential_comoving_volume=dict(create_new=False, resolution=1000),
|
|
88
|
+
Dl_to_z=dict(create_new=False, resolution=1000),
|
|
89
|
+
gwsnr=False,
|
|
90
|
+
)
|
|
79
91
|
ler_directory : `str`
|
|
80
92
|
directory to store the parameters.
|
|
81
93
|
default ler_directory = './ler_data'. This is used for storing the parameters of the simulated events.
|
|
@@ -98,7 +110,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
98
110
|
|
|
99
111
|
Instance Attributes
|
|
100
112
|
----------
|
|
101
|
-
LeR class has the following attributes
|
|
113
|
+
LeR class has the following attributes: \n
|
|
102
114
|
+-------------------------------------+----------------------------------+
|
|
103
115
|
| Atrributes | Type |
|
|
104
116
|
+=====================================+==================================+
|
|
@@ -141,14 +153,14 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
141
153
|
|
|
142
154
|
Instance Methods
|
|
143
155
|
----------
|
|
144
|
-
LeR class has the following methods
|
|
156
|
+
LeR class has the following methods:\n
|
|
145
157
|
+-------------------------------------+----------------------------------+
|
|
146
158
|
| Methods | Description |
|
|
147
159
|
+=====================================+==================================+
|
|
148
160
|
|:meth:`~class_initialization` | Function to initialize the |
|
|
149
161
|
| | parent classes |
|
|
150
162
|
+-------------------------------------+----------------------------------+
|
|
151
|
-
|:meth:`~
|
|
163
|
+
|:meth:`~gwsnr_initialization` | Function to initialize the |
|
|
152
164
|
| | gwsnr class |
|
|
153
165
|
+-------------------------------------+----------------------------------+
|
|
154
166
|
|:meth:`~snr` | Function to get the snr with the |
|
|
@@ -194,7 +206,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
194
206
|
| | ratio between lensed and |
|
|
195
207
|
| | unlensed events. |
|
|
196
208
|
+-------------------------------------+----------------------------------+
|
|
197
|
-
|:meth:`~
|
|
209
|
+
|:meth:`~rate_comparison_with_rate_calculation` |
|
|
198
210
|
+-------------------------------------+----------------------------------+
|
|
199
211
|
| | Function to calculate rates for |
|
|
200
212
|
| | unleesed and lensed events and |
|
|
@@ -437,11 +449,13 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
437
449
|
list_of_detectors=None,
|
|
438
450
|
json_file_names=None,
|
|
439
451
|
interpolator_directory="./interpolator_pickle",
|
|
452
|
+
create_new_interpolator=False,
|
|
440
453
|
ler_directory="./ler_data",
|
|
441
454
|
verbose=True,
|
|
442
455
|
**kwargs,
|
|
443
456
|
):
|
|
444
457
|
|
|
458
|
+
print("\nInitializing LeR class...\n")
|
|
445
459
|
self.npool = npool
|
|
446
460
|
self.z_min = z_min
|
|
447
461
|
self.z_max = z_max
|
|
@@ -453,6 +467,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
453
467
|
if json_file_names:
|
|
454
468
|
self.json_file_names.update(json_file_names)
|
|
455
469
|
self.interpolator_directory = interpolator_directory
|
|
470
|
+
kwargs["create_new_interpolator"] = create_new_interpolator
|
|
456
471
|
self.ler_directory = ler_directory
|
|
457
472
|
# create directory if not exists
|
|
458
473
|
if not os.path.exists(ler_directory):
|
|
@@ -463,7 +478,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
463
478
|
self.class_initialization(params=kwargs)
|
|
464
479
|
# initialization self.snr and self.pdet from GWSNR class
|
|
465
480
|
if not snr_finder and not pdet_finder:
|
|
466
|
-
self.
|
|
481
|
+
self.gwsnr_initialization(params=kwargs)
|
|
467
482
|
self.gwsnr = True
|
|
468
483
|
self.pdet = pdet_finder
|
|
469
484
|
else:
|
|
@@ -475,15 +490,15 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
475
490
|
# store all the ler input parameters
|
|
476
491
|
self.store_ler_params(output_jsonfile=self.json_file_names["ler_params"])
|
|
477
492
|
|
|
478
|
-
# if verbose, prevent anything from printing
|
|
493
|
+
# if not verbose, prevent anything from printing
|
|
479
494
|
if verbose:
|
|
480
495
|
initialization()
|
|
481
|
-
self.
|
|
496
|
+
self.print_all_params_ler()
|
|
482
497
|
else:
|
|
483
498
|
with contextlib.redirect_stdout(None):
|
|
484
499
|
initialization()
|
|
485
500
|
|
|
486
|
-
def
|
|
501
|
+
def print_all_params_ler(self):
|
|
487
502
|
"""
|
|
488
503
|
Function to print all the parameters.
|
|
489
504
|
"""
|
|
@@ -514,14 +529,15 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
514
529
|
print("\n # LeR also takes LensGalaxyParameterDistribution class params as kwargs, as follows:")
|
|
515
530
|
print(f"lens_type = '{self.gw_param_sampler_dict['lens_type']}',")
|
|
516
531
|
print(f"lens_functions = {self.gw_param_sampler_dict['lens_functions']},")
|
|
517
|
-
print(f"
|
|
518
|
-
print(f"
|
|
532
|
+
print(f"lens_param_samplers = {self.gw_param_sampler_dict['lens_param_samplers']},")
|
|
533
|
+
print(f"lens_param_samplers_params = {self.gw_param_sampler_dict['lens_param_samplers_params']},")
|
|
519
534
|
|
|
520
535
|
print("\n # LeR also takes ImageProperties class params as kwargs, as follows:")
|
|
521
536
|
print(f"n_min_images = {self.n_min_images},")
|
|
522
537
|
print(f"n_max_images = {self.n_max_images},")
|
|
523
|
-
print(f"
|
|
524
|
-
print(f"
|
|
538
|
+
print(f"time_window = {self.time_window},")
|
|
539
|
+
# print(f"geocent_time_min = {self.geocent_time_min},")
|
|
540
|
+
# print(f"geocent_time_max = {self.geocent_time_max},")
|
|
525
541
|
print(f"lens_model_list = {self.lens_model_list},")
|
|
526
542
|
|
|
527
543
|
if self.gwsnr:
|
|
@@ -585,14 +601,16 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
585
601
|
print("axis_ratio_params = ", self.lens_param_samplers_params["axis_ratio"])
|
|
586
602
|
print(f"axis_rotation_angle = '{self.lens_param_samplers['axis_rotation_angle']}'")
|
|
587
603
|
print("axis_rotation_angle_params = ", self.lens_param_samplers_params["axis_rotation_angle"])
|
|
588
|
-
print(f"shear = '{self.lens_param_samplers['
|
|
589
|
-
print("shear_params = ", self.lens_param_samplers_params[
|
|
590
|
-
print(f"
|
|
591
|
-
print("
|
|
604
|
+
print(f"shear = '{self.lens_param_samplers['external_shear']}'")
|
|
605
|
+
print("shear_params = ", self.lens_param_samplers_params['external_shear'])
|
|
606
|
+
print(f"density_profile_slope = '{self.lens_param_samplers['density_profile_slope']}'")
|
|
607
|
+
print("density_profile_slope_params = ", self.lens_param_samplers_params["density_profile_slope"])
|
|
592
608
|
# lens functions
|
|
593
609
|
print("Lens functions:")
|
|
594
610
|
print(f"strong_lensing_condition = '{self.lens_functions['strong_lensing_condition']}'")
|
|
595
611
|
print(f"optical_depth = '{self.lens_functions['optical_depth']}'")
|
|
612
|
+
print(f"optical_depth_params = '{self.lens_functions_params['optical_depth']}'")
|
|
613
|
+
print(f"param_sampler_type = '{self.lens_functions['param_sampler_type']}'")
|
|
596
614
|
|
|
597
615
|
@property
|
|
598
616
|
def snr(self):
|
|
@@ -724,15 +742,18 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
724
742
|
z_max=self.z_max,
|
|
725
743
|
cosmology=self.cosmo,
|
|
726
744
|
event_type=self.event_type,
|
|
727
|
-
lens_type="
|
|
745
|
+
lens_type="epl_shear_galaxy",
|
|
728
746
|
lens_functions= None,
|
|
729
|
-
|
|
730
|
-
|
|
747
|
+
lens_functions_params=None,
|
|
748
|
+
lens_param_samplers=None,
|
|
749
|
+
lens_param_samplers_params=None,
|
|
750
|
+
buffer_size=1000,
|
|
731
751
|
# ImageProperties class params
|
|
732
752
|
n_min_images=2,
|
|
733
753
|
n_max_images=4,
|
|
734
|
-
|
|
735
|
-
|
|
754
|
+
time_window=365*24*3600*20,
|
|
755
|
+
# geocent_time_min=1126259462.4,
|
|
756
|
+
# geocent_time_max=1126259462.4+365*24*3600*20,
|
|
736
757
|
lens_model_list=['EPL_NUMBA', 'SHEAR'],
|
|
737
758
|
# CBCSourceParameterDistribution class params
|
|
738
759
|
source_priors=None,
|
|
@@ -756,13 +777,16 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
756
777
|
event_type=input_params["event_type"],
|
|
757
778
|
lens_type=input_params["lens_type"],
|
|
758
779
|
lens_functions=input_params["lens_functions"],
|
|
759
|
-
|
|
760
|
-
|
|
780
|
+
lens_functions_params=input_params["lens_functions_params"],
|
|
781
|
+
lens_param_samplers=input_params["lens_param_samplers"],
|
|
782
|
+
lens_param_samplers_params=input_params["lens_param_samplers_params"],
|
|
761
783
|
n_min_images=input_params["n_min_images"],
|
|
762
784
|
n_max_images=input_params["n_max_images"],
|
|
763
|
-
|
|
764
|
-
|
|
785
|
+
time_window=input_params["time_window"],
|
|
786
|
+
# geocent_time_min=input_params["geocent_time_min"],
|
|
787
|
+
# geocent_time_max=input_params["geocent_time_max"],
|
|
765
788
|
lens_model_list=input_params["lens_model_list"],
|
|
789
|
+
buffer_size=input_params["buffer_size"],
|
|
766
790
|
source_priors=input_params["source_priors"],
|
|
767
791
|
source_priors_params=input_params["source_priors_params"],
|
|
768
792
|
spin_zero=input_params["spin_zero"],
|
|
@@ -773,11 +797,12 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
773
797
|
|
|
774
798
|
self.gw_param_sampler_dict["source_priors"]=self.gw_param_samplers.copy()
|
|
775
799
|
self.gw_param_sampler_dict["source_priors_params"]=self.gw_param_samplers_params.copy()
|
|
776
|
-
self.gw_param_sampler_dict["
|
|
777
|
-
self.gw_param_sampler_dict["
|
|
800
|
+
self.gw_param_sampler_dict["lens_param_samplers"]=self.lens_param_samplers.copy()
|
|
801
|
+
self.gw_param_sampler_dict["lens_param_samplers_params"]=self.lens_param_samplers_params.copy()
|
|
778
802
|
self.gw_param_sampler_dict["lens_functions"]=self.lens_functions.copy()
|
|
803
|
+
self.gw_param_sampler_dict["lens_functions_params"]=self.lens_functions_params.copy()
|
|
779
804
|
|
|
780
|
-
def
|
|
805
|
+
def gwsnr_initialization(self, params=None):
|
|
781
806
|
"""
|
|
782
807
|
Function to initialize the GWSNR class from the `gwsnr` package.
|
|
783
808
|
|
|
@@ -789,29 +814,55 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
789
814
|
from gwsnr import GWSNR
|
|
790
815
|
|
|
791
816
|
# initialization of GWSNR class
|
|
817
|
+
if 'mminbh' in self.gw_param_samplers_params['source_frame_masses']:
|
|
818
|
+
min_bh_mass = self.gw_param_samplers_params['source_frame_masses']['mminbh']
|
|
819
|
+
else:
|
|
820
|
+
min_bh_mass = 2.0
|
|
821
|
+
|
|
822
|
+
if 'mmaxbh' in self.gw_param_samplers_params['source_frame_masses']:
|
|
823
|
+
max_bh_mass = self.gw_param_samplers_params['source_frame_masses']['mmaxbh']
|
|
824
|
+
else:
|
|
825
|
+
max_bh_mass = 200.0
|
|
792
826
|
input_params = dict(
|
|
827
|
+
# General settings
|
|
793
828
|
npool=self.npool,
|
|
794
|
-
|
|
795
|
-
|
|
829
|
+
snr_method="interpolation_aligned_spins",
|
|
830
|
+
snr_type="optimal_snr",
|
|
831
|
+
gwsnr_verbose=True,
|
|
832
|
+
multiprocessing_verbose=True,
|
|
833
|
+
pdet_kwargs=None,
|
|
834
|
+
# Settings for interpolation grid
|
|
835
|
+
mtot_min=min_bh_mass*2,
|
|
836
|
+
mtot_max=max_bh_mass*2*(1+self.z_max) if max_bh_mass*2*(1+self.z_max)<500.0 else 500.0,
|
|
796
837
|
ratio_min=0.1,
|
|
797
838
|
ratio_max=1.0,
|
|
798
|
-
|
|
799
|
-
|
|
839
|
+
spin_max=0.99,
|
|
840
|
+
mtot_resolution=200,
|
|
841
|
+
ratio_resolution=20,
|
|
842
|
+
spin_resolution=10,
|
|
843
|
+
batch_size_interpolation=1000000,
|
|
844
|
+
interpolator_dir="./interpolator_pickle",
|
|
845
|
+
create_new_interpolator=False,
|
|
846
|
+
# GW signal settings
|
|
800
847
|
sampling_frequency=2048.0,
|
|
801
848
|
waveform_approximant="IMRPhenomD",
|
|
849
|
+
frequency_domain_source_model='lal_binary_black_hole',
|
|
802
850
|
minimum_frequency=20.0,
|
|
803
|
-
|
|
851
|
+
reference_frequency=None,
|
|
852
|
+
duration_max=None,
|
|
853
|
+
duration_min=None,
|
|
854
|
+
fixed_duration=None,
|
|
855
|
+
mtot_cut=False,
|
|
856
|
+
# Detector settings
|
|
804
857
|
psds=None,
|
|
805
858
|
ifos=None,
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
gwsnr_verbose=False,
|
|
809
|
-
multiprocessing_verbose=True,
|
|
810
|
-
mtot_cut=True,
|
|
811
|
-
pdet=False,
|
|
812
|
-
snr_th=8.0,
|
|
813
|
-
snr_th_net=8.0,
|
|
859
|
+
noise_realization=None, # not implemented yet
|
|
860
|
+
# ANN settings
|
|
814
861
|
ann_path_dict=None,
|
|
862
|
+
# Hybrid SNR recalculation settings
|
|
863
|
+
snr_recalculation=False,
|
|
864
|
+
snr_recalculation_range=[6,14],
|
|
865
|
+
snr_recalculation_waveform_approximant="IMRPhenomXPHM",
|
|
815
866
|
)
|
|
816
867
|
# if self.event_type == "BNS":
|
|
817
868
|
# input_params["mtot_max"]= 18.
|
|
@@ -820,37 +871,63 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
820
871
|
if key in input_params:
|
|
821
872
|
input_params[key] = value
|
|
822
873
|
self.snr_calculator_dict = input_params
|
|
874
|
+
|
|
875
|
+
# dealing with create_new_interpolator param
|
|
876
|
+
if isinstance(input_params["create_new_interpolator"], bool):
|
|
877
|
+
pass
|
|
878
|
+
elif isinstance(input_params["create_new_interpolator"], dict):
|
|
879
|
+
# check input_params["gwsnr"] exists
|
|
880
|
+
if "gwsnr" in input_params["create_new_interpolator"]:
|
|
881
|
+
if isinstance(input_params["create_new_interpolator"]["gwsnr"], bool):
|
|
882
|
+
input_params["create_new_interpolator"] = input_params["create_new_interpolator"]["gwsnr"]
|
|
883
|
+
else:
|
|
884
|
+
raise ValueError("create_new_interpolator['gwsnr'] should be a boolean.")
|
|
885
|
+
else:
|
|
886
|
+
input_params["create_new_interpolator"] = False
|
|
887
|
+
|
|
888
|
+
# initialization of GWSNR class
|
|
823
889
|
gwsnr = GWSNR(
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
890
|
+
npool=input_params["npool"],
|
|
891
|
+
snr_method=input_params["snr_method"],
|
|
892
|
+
snr_type=input_params["snr_type"],
|
|
893
|
+
gwsnr_verbose=input_params["gwsnr_verbose"],
|
|
894
|
+
multiprocessing_verbose=input_params["multiprocessing_verbose"],
|
|
895
|
+
pdet_kwargs=input_params["pdet_kwargs"],
|
|
896
|
+
mtot_min=input_params["mtot_min"],
|
|
897
|
+
mtot_max=input_params["mtot_max"],
|
|
898
|
+
ratio_min=input_params["ratio_min"],
|
|
899
|
+
ratio_max=input_params["ratio_max"],
|
|
900
|
+
spin_max=input_params["spin_max"],
|
|
901
|
+
mtot_resolution=input_params["mtot_resolution"],
|
|
902
|
+
ratio_resolution=input_params["ratio_resolution"],
|
|
903
|
+
spin_resolution=input_params["spin_resolution"],
|
|
904
|
+
batch_size_interpolation=input_params["batch_size_interpolation"],
|
|
905
|
+
interpolator_dir=input_params["interpolator_dir"],
|
|
906
|
+
create_new_interpolator=input_params["create_new_interpolator"],
|
|
907
|
+
sampling_frequency=input_params["sampling_frequency"],
|
|
908
|
+
waveform_approximant=input_params["waveform_approximant"],
|
|
909
|
+
frequency_domain_source_model=input_params["frequency_domain_source_model"],
|
|
910
|
+
minimum_frequency=input_params["minimum_frequency"],
|
|
911
|
+
reference_frequency=input_params["reference_frequency"],
|
|
912
|
+
duration_max=input_params["duration_max"],
|
|
913
|
+
duration_min=input_params["duration_min"],
|
|
914
|
+
fixed_duration=input_params["fixed_duration"],
|
|
915
|
+
mtot_cut=input_params["mtot_cut"],
|
|
916
|
+
psds=input_params["psds"],
|
|
917
|
+
ifos=input_params["ifos"],
|
|
918
|
+
noise_realization=input_params["noise_realization"],
|
|
919
|
+
ann_path_dict=input_params["ann_path_dict"],
|
|
920
|
+
snr_recalculation=input_params["snr_recalculation"],
|
|
921
|
+
snr_recalculation_range=input_params["snr_recalculation_range"],
|
|
922
|
+
snr_recalculation_waveform_approximant=input_params["snr_recalculation_waveform_approximant"],
|
|
923
|
+
)
|
|
847
924
|
|
|
848
|
-
self.snr = gwsnr.
|
|
925
|
+
self.snr = gwsnr.optimal_snr
|
|
849
926
|
self.list_of_detectors = gwsnr.detector_list
|
|
850
|
-
self.snr_bilby = gwsnr.
|
|
927
|
+
self.snr_bilby = gwsnr.optimal_snr_with_inner_product
|
|
851
928
|
self.snr_calculator_dict["mtot_max"] = gwsnr.mtot_max
|
|
852
929
|
self.snr_calculator_dict["psds"] = gwsnr.psds_list
|
|
853
|
-
|
|
930
|
+
self.pdet = gwsnr.pdet
|
|
854
931
|
|
|
855
932
|
def store_ler_params(self, output_jsonfile="ler_params.json"):
|
|
856
933
|
"""
|
|
@@ -888,12 +965,12 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
888
965
|
for key, value in snr_calculator_dict.items():
|
|
889
966
|
snr_calculator_dict[key] = str(value)
|
|
890
967
|
parameters_dict.update({"snr_calculator_dict": snr_calculator_dict})
|
|
891
|
-
|
|
892
|
-
file_name = output_jsonfile
|
|
893
|
-
append_json(self.ler_directory+"/"+file_name, parameters_dict, replace=True)
|
|
894
968
|
except:
|
|
895
969
|
# if snr_calculator is custom function
|
|
896
970
|
pass
|
|
971
|
+
|
|
972
|
+
file_name = output_jsonfile
|
|
973
|
+
append_json(self.ler_directory+"/"+file_name, parameters_dict, replace=True)
|
|
897
974
|
|
|
898
975
|
def unlensed_cbc_statistics(
|
|
899
976
|
self, size=None, resume=False, save_batch=False, output_jsonfile=None,
|
|
@@ -910,7 +987,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
910
987
|
resume = False (default) or True.
|
|
911
988
|
if True, the function will resume from the last batch.
|
|
912
989
|
save_batch : `bool`
|
|
913
|
-
if True, the function will save the parameters in batches. if False, the function will save all the parameters at the end of sampling. save_batch=False is faster.
|
|
990
|
+
if True, the function will save the parameters in batches. if False (default), the function will save all the parameters at the end of sampling. save_batch=False is faster.
|
|
914
991
|
output_jsonfile : `str`
|
|
915
992
|
json file name for storing the parameters.
|
|
916
993
|
default output_jsonfile = 'unlensed_params.json'. Note that this file will be stored in the self.ler_directory.
|
|
@@ -931,7 +1008,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
931
1008
|
output_jsonfile = output_jsonfile or self.json_file_names["unlensed_param"]
|
|
932
1009
|
self.json_file_names["unlensed_param"] = output_jsonfile
|
|
933
1010
|
output_path = os.path.join(self.ler_directory, output_jsonfile)
|
|
934
|
-
print(f"unlensed params will be
|
|
1011
|
+
print(f"unlensed params will be stored in {output_path}")
|
|
935
1012
|
|
|
936
1013
|
unlensed_param = batch_handler(
|
|
937
1014
|
size=size,
|
|
@@ -972,10 +1049,11 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
972
1049
|
# get gw params
|
|
973
1050
|
print("sampling gw source params...")
|
|
974
1051
|
unlensed_param = self.sample_gw_parameters(size=size)
|
|
1052
|
+
|
|
975
1053
|
# Get all of the signal to noise ratios
|
|
976
1054
|
if self.snr:
|
|
977
1055
|
print("calculating snrs...")
|
|
978
|
-
snrs = self.snr(gw_param_dict=unlensed_param)
|
|
1056
|
+
snrs = self.snr(gw_param_dict=unlensed_param.copy())
|
|
979
1057
|
unlensed_param.update(snrs)
|
|
980
1058
|
elif self.pdet:
|
|
981
1059
|
print("calculating pdet...")
|
|
@@ -1112,7 +1190,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1112
1190
|
dictionary of unlensed GW source parameters.
|
|
1113
1191
|
"""
|
|
1114
1192
|
|
|
1115
|
-
snr_param = unlensed_param["
|
|
1193
|
+
snr_param = unlensed_param["snr_net"]
|
|
1116
1194
|
idx_detectable = (snr_param > snr_threshold_recalculation[0]) & (snr_param < snr_threshold_recalculation[1])
|
|
1117
1195
|
# reduce the size of the dict
|
|
1118
1196
|
for key, value in unlensed_param.items():
|
|
@@ -1146,20 +1224,20 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1146
1224
|
"""
|
|
1147
1225
|
|
|
1148
1226
|
if self.snr:
|
|
1149
|
-
if "
|
|
1150
|
-
raise ValueError("'
|
|
1227
|
+
if "snr_net" not in unlensed_param:
|
|
1228
|
+
raise ValueError("'snr_net' not in unlensed param dict provided")
|
|
1151
1229
|
if detectability_condition == "step_function":
|
|
1152
|
-
print("given detectability_condition == 'step_function'")
|
|
1153
|
-
param = unlensed_param["
|
|
1230
|
+
#print("given detectability_condition == 'step_function'")
|
|
1231
|
+
param = unlensed_param["snr_net"]
|
|
1154
1232
|
threshold = snr_threshold
|
|
1155
1233
|
elif detectability_condition == "pdet":
|
|
1156
|
-
print("given detectability_condition == 'pdet'")
|
|
1157
|
-
param = 1 - norm.cdf(snr_threshold - unlensed_param["
|
|
1234
|
+
#print("given detectability_condition == 'pdet'")
|
|
1235
|
+
param = 1 - norm.cdf(snr_threshold - unlensed_param["snr_net"])
|
|
1158
1236
|
unlensed_param["pdet_net"] = param
|
|
1159
1237
|
threshold = pdet_threshold
|
|
1160
1238
|
elif self.pdet:
|
|
1161
1239
|
if "pdet_net" in unlensed_param:
|
|
1162
|
-
print("given detectability_condition == 'pdet'")
|
|
1240
|
+
#print("given detectability_condition == 'pdet'")
|
|
1163
1241
|
param = unlensed_param["pdet_net"]
|
|
1164
1242
|
threshold = pdet_threshold
|
|
1165
1243
|
else:
|
|
@@ -1375,11 +1453,12 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1375
1453
|
# check for invalid samples
|
|
1376
1454
|
idx = lensed_param["n_images"] < 2
|
|
1377
1455
|
|
|
1378
|
-
if np.sum(idx) == 0:
|
|
1379
|
-
|
|
1380
|
-
else:
|
|
1381
|
-
|
|
1382
|
-
|
|
1456
|
+
# if np.sum(idx) == 0:
|
|
1457
|
+
# break
|
|
1458
|
+
# else:
|
|
1459
|
+
# print(f"Invalid sample found. Resampling {np.sum(idx)} lensed events...")
|
|
1460
|
+
# size = np.sum(idx)
|
|
1461
|
+
break
|
|
1383
1462
|
|
|
1384
1463
|
# Get all of the signal to noise ratios
|
|
1385
1464
|
if self.snr:
|
|
@@ -1488,6 +1567,8 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1488
1567
|
# find index of detectable events
|
|
1489
1568
|
snr_hit = self._find_detectable_index_lensed(lensed_param, snr_threshold, pdet_threshold, num_img, detectability_condition, combine_image_snr=combine_image_snr, snr_cut_for_combine_image_snr=snr_cut_for_combine_image_snr)
|
|
1490
1569
|
|
|
1570
|
+
# select according to time delay
|
|
1571
|
+
|
|
1491
1572
|
# montecarlo integration
|
|
1492
1573
|
total_rate = self.rate_function(np.sum(snr_hit), total_events, param_type="lensed")
|
|
1493
1574
|
|
|
@@ -1556,10 +1637,10 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1556
1637
|
snr_threshold_recalculation_max, _ = self._check_snr_threshold_lensed(snr_threshold_recalculation[1], num_img)
|
|
1557
1638
|
|
|
1558
1639
|
# check optimal_snr_net is provided in dict
|
|
1559
|
-
if "
|
|
1640
|
+
if "snr_net" not in lensed_param:
|
|
1560
1641
|
raise ValueError("optimal_snr_net not provided in lensed_param dict. Exiting...")
|
|
1561
1642
|
|
|
1562
|
-
snr_param = lensed_param["
|
|
1643
|
+
snr_param = lensed_param["snr_net"]
|
|
1563
1644
|
snr_param = -np.sort(-snr_param, axis=1) # sort snr in descending order
|
|
1564
1645
|
|
|
1565
1646
|
# for each row: choose a threshold and check if the number of images above threshold. Sum over the images. If sum is greater than num_img, then snr_hit = True
|
|
@@ -1614,11 +1695,11 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1614
1695
|
boolean array to store the result of the threshold condition.
|
|
1615
1696
|
"""
|
|
1616
1697
|
|
|
1617
|
-
print(f"given detectability_condition == {detectability_condition}")
|
|
1698
|
+
#print(f"given detectability_condition == {detectability_condition}")
|
|
1618
1699
|
if detectability_condition == "step_function":
|
|
1619
|
-
if "
|
|
1620
|
-
raise ValueError("'
|
|
1621
|
-
snr_param = lensed_param["
|
|
1700
|
+
if "snr_net" not in lensed_param:
|
|
1701
|
+
raise ValueError("'snr_net' not in lensed parm dict provided")
|
|
1702
|
+
snr_param = lensed_param["snr_net"]
|
|
1622
1703
|
snr_param = -np.sort(-snr_param, axis=1) # sort snr in descending order
|
|
1623
1704
|
snr_hit = np.full(len(snr_param), True) # boolean array to store the result of the threshold condition
|
|
1624
1705
|
|
|
@@ -1634,6 +1715,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1634
1715
|
for i, snr_th in enumerate(snr_threshold):
|
|
1635
1716
|
idx_max = idx_max + num_img[i]
|
|
1636
1717
|
snr_hit = snr_hit & (np.sum((snr_param[:,j:idx_max] > snr_th), axis=1) >= num_img[i])
|
|
1718
|
+
# select according to time delays
|
|
1637
1719
|
j = idx_max
|
|
1638
1720
|
else:
|
|
1639
1721
|
# sqrt of the the sum of the squares of the snr of the images
|
|
@@ -1643,12 +1725,12 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1643
1725
|
|
|
1644
1726
|
elif detectability_condition == "pdet":
|
|
1645
1727
|
if "pdet_net" not in lensed_param:
|
|
1646
|
-
if "
|
|
1647
|
-
raise ValueError("'
|
|
1728
|
+
if "snr_net" not in lensed_param:
|
|
1729
|
+
raise ValueError("'snr_net' or 'pdet_net' not in lensed parm dict provided")
|
|
1648
1730
|
else:
|
|
1649
|
-
print("calculating pdet using '
|
|
1731
|
+
print("calculating pdet using 'snr_net'...")
|
|
1650
1732
|
# pdet dimension is (size, n_max_images)
|
|
1651
|
-
snr_param = lensed_param["
|
|
1733
|
+
snr_param = lensed_param["snr_net"]
|
|
1652
1734
|
snr_param = -np.sort(-snr_param, axis=1) # sort snr in descending order
|
|
1653
1735
|
|
|
1654
1736
|
# column index beyong np.sum(num_img)-1 are not considered
|
|
@@ -1670,7 +1752,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1670
1752
|
|
|
1671
1753
|
return snr_hit
|
|
1672
1754
|
|
|
1673
|
-
def
|
|
1755
|
+
def rate_comparison_with_rate_calculation(
|
|
1674
1756
|
self,
|
|
1675
1757
|
unlensed_param=None,
|
|
1676
1758
|
snr_threshold_unlensed=8.0,
|
|
@@ -1733,7 +1815,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1733
1815
|
>>> ler = LeR()
|
|
1734
1816
|
>>> ler.unlensed_cbc_statistics();
|
|
1735
1817
|
>>> ler.lensed_cbc_statistics();
|
|
1736
|
-
>>> rate_ratio, unlensed_param, lensed_param = ler.
|
|
1818
|
+
>>> rate_ratio, unlensed_param, lensed_param = ler.rate_comparison_with_rate_calculation()
|
|
1737
1819
|
"""
|
|
1738
1820
|
|
|
1739
1821
|
# call json_file_ler_param and add the results
|
|
@@ -1807,13 +1889,17 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1807
1889
|
self,
|
|
1808
1890
|
size=100,
|
|
1809
1891
|
batch_size=None,
|
|
1892
|
+
stopping_criteria=dict(
|
|
1893
|
+
relative_diff_percentage=0.5,
|
|
1894
|
+
number_of_last_batches_to_check=4,
|
|
1895
|
+
),
|
|
1810
1896
|
snr_threshold=8.0,
|
|
1811
1897
|
pdet_threshold=0.5,
|
|
1812
1898
|
resume=False,
|
|
1813
1899
|
output_jsonfile="n_unlensed_param_detectable.json",
|
|
1814
1900
|
meta_data_file="meta_unlensed.json",
|
|
1815
1901
|
detectability_condition="step_function",
|
|
1816
|
-
trim_to_size=
|
|
1902
|
+
trim_to_size=False,
|
|
1817
1903
|
snr_recalculation=False,
|
|
1818
1904
|
snr_threshold_recalculation=[4, 12],
|
|
1819
1905
|
):
|
|
@@ -1873,7 +1959,8 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1873
1959
|
n, events_total, output_path, meta_data_path, buffer_file, batch_size = self._initial_setup_for_n_event_selection(meta_data_file, output_jsonfile, resume, batch_size)
|
|
1874
1960
|
|
|
1875
1961
|
# loop until n samples are collected
|
|
1876
|
-
|
|
1962
|
+
continue_condition = True
|
|
1963
|
+
while continue_condition:
|
|
1877
1964
|
# disable print statements
|
|
1878
1965
|
with contextlib.redirect_stdout(None):
|
|
1879
1966
|
self.dict_buffer = None # this is used to store the sampled unlensed_param in batches when running the sampling_routine
|
|
@@ -1898,7 +1985,31 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1898
1985
|
total_rate = self.rate_function(n, events_total, param_type="unlensed", verbose=False)
|
|
1899
1986
|
|
|
1900
1987
|
# bookmark
|
|
1901
|
-
self._append_meta_data(meta_data_path, n, events_total, total_rate)
|
|
1988
|
+
buffer_dict = self._append_meta_data(meta_data_path, n, events_total, total_rate)
|
|
1989
|
+
|
|
1990
|
+
if isinstance(stopping_criteria, dict):
|
|
1991
|
+
total_rates = np.array(buffer_dict['total_rate'])
|
|
1992
|
+
limit = stopping_criteria['relative_diff_percentage']
|
|
1993
|
+
num_a = stopping_criteria['number_of_last_batches_to_check']
|
|
1994
|
+
if len(total_rates)>num_a:
|
|
1995
|
+
num_a = int(-1*(num_a))
|
|
1996
|
+
# num_b = int(num_a)
|
|
1997
|
+
percentage_diff = np.abs((total_rates[num_a:]-total_rates[-1])/total_rates[-1])*100
|
|
1998
|
+
print(f"percentage difference for the last {abs(num_a)} batches = {percentage_diff}")
|
|
1999
|
+
if np.any(percentage_diff>limit):
|
|
2000
|
+
continue_condition &= True
|
|
2001
|
+
else:
|
|
2002
|
+
print(rf"stopping criteria of rate relative difference of {limit}% reached. If you want to collect more events, reduce stopping_criteria['relative_diff_percentage'] or put stopping_criteria=None.")
|
|
2003
|
+
continue_condition &= False
|
|
2004
|
+
|
|
2005
|
+
if isinstance(size, int):
|
|
2006
|
+
if n<size:
|
|
2007
|
+
continue_condition |= True
|
|
2008
|
+
else:
|
|
2009
|
+
print(rf"Given size={size} reached")
|
|
2010
|
+
continue_condition |= False
|
|
2011
|
+
if stopping_criteria is None:
|
|
2012
|
+
continue_condition &= False
|
|
1902
2013
|
|
|
1903
2014
|
print(f"stored detectable unlensed params in {output_path}")
|
|
1904
2015
|
print(f"stored meta data in {meta_data_path}")
|
|
@@ -1926,6 +2037,10 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1926
2037
|
def selecting_n_lensed_detectable_events(
|
|
1927
2038
|
self,
|
|
1928
2039
|
size=100,
|
|
2040
|
+
stopping_criteria=dict(
|
|
2041
|
+
relative_diff_percentage=0.5,
|
|
2042
|
+
number_of_last_batches_to_check=4,
|
|
2043
|
+
),
|
|
1929
2044
|
batch_size=None,
|
|
1930
2045
|
snr_threshold=[8.0,8.0],
|
|
1931
2046
|
pdet_threshold=0.5,
|
|
@@ -1936,7 +2051,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
1936
2051
|
detectability_condition="step_function",
|
|
1937
2052
|
output_jsonfile="n_lensed_params_detectable.json",
|
|
1938
2053
|
meta_data_file="meta_lensed.json",
|
|
1939
|
-
trim_to_size=
|
|
2054
|
+
trim_to_size=False,
|
|
1940
2055
|
nan_to_num=False,
|
|
1941
2056
|
snr_recalculation=False,
|
|
1942
2057
|
snr_threshold_recalculation=[[4,4],[12,12]],
|
|
@@ -2005,7 +2120,8 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
2005
2120
|
# re-analyse the provided snr_threshold and num_img
|
|
2006
2121
|
snr_threshold, num_img = self._check_snr_threshold_lensed(snr_threshold, num_img)
|
|
2007
2122
|
|
|
2008
|
-
|
|
2123
|
+
continue_condition = True
|
|
2124
|
+
while continue_condition:
|
|
2009
2125
|
# disable print statements
|
|
2010
2126
|
with contextlib.redirect_stdout(None):
|
|
2011
2127
|
self.dict_buffer = None # this is used to store the sampled lensed_param in batches when running the sampling_routine
|
|
@@ -2030,7 +2146,30 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
2030
2146
|
total_rate = self.rate_function(n, events_total, param_type="lensed", verbose=False)
|
|
2031
2147
|
|
|
2032
2148
|
# save meta data
|
|
2033
|
-
self._append_meta_data(meta_data_path, n, events_total, total_rate)
|
|
2149
|
+
buffer_dict = self._append_meta_data(meta_data_path, n, events_total, total_rate)
|
|
2150
|
+
|
|
2151
|
+
if isinstance(stopping_criteria, dict):
|
|
2152
|
+
total_rates = np.array(buffer_dict['total_rate'])
|
|
2153
|
+
limit = stopping_criteria['relative_diff_percentage']
|
|
2154
|
+
num_a = stopping_criteria['number_of_last_batches_to_check']
|
|
2155
|
+
|
|
2156
|
+
if len(total_rates)>num_a:
|
|
2157
|
+
num_a = int(-1*(num_a))
|
|
2158
|
+
# num_b = int(num_a)
|
|
2159
|
+
percentage_diff = np.abs((total_rates[num_a:]-total_rates[-1])/total_rates[-1])*100
|
|
2160
|
+
print(f"percentage difference for the last {abs(num_a)} batches = {percentage_diff}")
|
|
2161
|
+
if np.any(percentage_diff>limit):
|
|
2162
|
+
continue_condition &= True
|
|
2163
|
+
else:
|
|
2164
|
+
print(rf"stopping criteria of rate relative difference of {limit}% reached. If you want to collect more events, reduce stopping_criteria['relative_diff_percentage']")
|
|
2165
|
+
continue_condition &= False
|
|
2166
|
+
|
|
2167
|
+
if isinstance(size, int):
|
|
2168
|
+
if n<size:
|
|
2169
|
+
continue_condition |= True
|
|
2170
|
+
else:
|
|
2171
|
+
print(rf"Given size={size} reached")
|
|
2172
|
+
continue_condition |= False
|
|
2034
2173
|
|
|
2035
2174
|
print(f"storing detectable lensed params in {output_path}")
|
|
2036
2175
|
print(f"storing meta data in {meta_data_path}")
|
|
@@ -2050,7 +2189,7 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
2050
2189
|
meta = get_param_from_json(meta_data_path)
|
|
2051
2190
|
data["detectable_lensed_rate_per_year"] = meta["total_rate"][-1]
|
|
2052
2191
|
data["detectability_condition_lensed"] = detectability_condition
|
|
2053
|
-
append_json(self.ler_directory+"/"+self.json_file_names["ler_params"], data, replace=True)
|
|
2192
|
+
buffer_dict = append_json(self.ler_directory+"/"+self.json_file_names["ler_params"], data, replace=True)
|
|
2054
2193
|
|
|
2055
2194
|
return param_final
|
|
2056
2195
|
|
|
@@ -2198,12 +2337,14 @@ class LeR(LensGalaxyParameterDistribution):
|
|
|
2198
2337
|
|
|
2199
2338
|
if os.path.exists(meta_data_path):
|
|
2200
2339
|
try:
|
|
2201
|
-
append_json(meta_data_path, meta_data, replace=False)
|
|
2340
|
+
dict_ = append_json(meta_data_path, meta_data, replace=False)
|
|
2202
2341
|
except:
|
|
2203
|
-
append_json(meta_data_path, meta_data, replace=True)
|
|
2342
|
+
dict_ = append_json(meta_data_path, meta_data, replace=True)
|
|
2204
2343
|
else:
|
|
2205
|
-
append_json(meta_data_path, meta_data, replace=True)
|
|
2344
|
+
dict_ = append_json(meta_data_path, meta_data, replace=True)
|
|
2206
2345
|
|
|
2207
2346
|
print("collected number of detectable events = ", n)
|
|
2208
2347
|
print("total number of events = ", events_total)
|
|
2209
|
-
print(f"total rate (yr^-1): {total_rate}")
|
|
2348
|
+
print(f"total rate (yr^-1): {total_rate}")
|
|
2349
|
+
|
|
2350
|
+
return dict_
|