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/utils/utils.py
CHANGED
|
@@ -5,12 +5,14 @@ This module contains helper routines for other modules in the ler package.
|
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
7
|
import pickle
|
|
8
|
+
import h5py
|
|
8
9
|
import numpy as np
|
|
9
10
|
import json
|
|
10
11
|
from scipy.interpolate import interp1d
|
|
11
12
|
from scipy.interpolate import CubicSpline
|
|
12
|
-
from scipy.integrate import quad
|
|
13
|
+
from scipy.integrate import quad
|
|
13
14
|
from numba import njit
|
|
15
|
+
from importlib import resources
|
|
14
16
|
# import datetime
|
|
15
17
|
|
|
16
18
|
|
|
@@ -52,6 +54,66 @@ class NumpyEncoder(json.JSONEncoder):
|
|
|
52
54
|
return obj.tolist()
|
|
53
55
|
return json.JSONEncoder.default(self, obj)
|
|
54
56
|
|
|
57
|
+
def load_pickle(file_name):
|
|
58
|
+
"""Load a pickle file.
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
file_name : `str`
|
|
63
|
+
pickle file name for storing the parameters.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
----------
|
|
67
|
+
param : `dict`
|
|
68
|
+
"""
|
|
69
|
+
with open(file_name, "rb") as handle:
|
|
70
|
+
param = pickle.load(handle)
|
|
71
|
+
|
|
72
|
+
return param
|
|
73
|
+
|
|
74
|
+
def save_pickle(file_name, param):
|
|
75
|
+
"""Save a dictionary as a pickle file.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
file_name : `str`
|
|
80
|
+
pickle file name for storing the parameters.
|
|
81
|
+
param : `dict`
|
|
82
|
+
dictionary to be saved as a pickle file.
|
|
83
|
+
"""
|
|
84
|
+
with open(file_name, "wb") as handle:
|
|
85
|
+
pickle.dump(param, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
|
86
|
+
|
|
87
|
+
# hdf5
|
|
88
|
+
def load_hdf5(file_name):
|
|
89
|
+
"""Load a hdf5 file.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
file_name : `str`
|
|
94
|
+
hdf5 file name for storing the parameters.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
----------
|
|
98
|
+
param : `dict`
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
return h5py.File(file_name, 'r')
|
|
102
|
+
|
|
103
|
+
def save_hdf5(file_name, param):
|
|
104
|
+
"""Save a dictionary as a hdf5 file.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
file_name : `str`
|
|
109
|
+
hdf5 file name for storing the parameters.
|
|
110
|
+
param : `dict`
|
|
111
|
+
dictionary to be saved as a hdf5 file.
|
|
112
|
+
"""
|
|
113
|
+
with h5py.File(file_name, 'w') as f:
|
|
114
|
+
for key, value in param.items():
|
|
115
|
+
f.create_dataset(key, data=value)
|
|
116
|
+
|
|
55
117
|
def load_json(file_name):
|
|
56
118
|
"""Load a json file.
|
|
57
119
|
|
|
@@ -78,9 +140,20 @@ def save_json(file_name, param):
|
|
|
78
140
|
json file name for storing the parameters.
|
|
79
141
|
param : `dict`
|
|
80
142
|
dictionary to be saved as a json file.
|
|
143
|
+
|
|
144
|
+
Example
|
|
145
|
+
----------
|
|
146
|
+
>>> from ler.utils import save_json, load_json
|
|
147
|
+
>>> param = dict_list = [{"name": "lens_mass", "type": "cubic_spline", "x": np.array([0, 1, 2, 3]), "y": [0, 1, 0, 1]},]
|
|
148
|
+
>>> save_json("param.json", param)
|
|
149
|
+
>>> param = load_json("param.json")
|
|
81
150
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
151
|
+
try:
|
|
152
|
+
with open(file_name, "w", encoding="utf-8") as write_file:
|
|
153
|
+
json.dump(param, write_file)
|
|
154
|
+
except:
|
|
155
|
+
with open(file_name, "w", encoding="utf-8") as write_file:
|
|
156
|
+
json.dump(param, write_file, indent=4, cls=NumpyEncoder)
|
|
84
157
|
|
|
85
158
|
def append_json(file_name, new_dictionary, old_dictionary=None, replace=False):
|
|
86
159
|
"""
|
|
@@ -185,6 +258,28 @@ def get_param_from_json(json_file):
|
|
|
185
258
|
param[key] = np.array(value)
|
|
186
259
|
return param
|
|
187
260
|
|
|
261
|
+
def load_txt_from_module(package, directory, filename):
|
|
262
|
+
"""
|
|
263
|
+
Function to load a specific dataset from a .txt file within the package
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
package : str
|
|
268
|
+
name of the package
|
|
269
|
+
directory : str
|
|
270
|
+
name of the directory within the package
|
|
271
|
+
filename : str
|
|
272
|
+
name of the .txt file
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
----------
|
|
276
|
+
data : `dict`
|
|
277
|
+
Dictionary loaded from the .txt file
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
with resources.path(package + '.' + directory, filename) as txt_path:
|
|
281
|
+
return np.loadtxt(txt_path)
|
|
282
|
+
|
|
188
283
|
def rejection_sample(pdf, xmin, xmax, size=100, chunk_size=10000):
|
|
189
284
|
"""
|
|
190
285
|
Helper function for rejection sampling from a pdf with maximum and minimum arguments.
|
|
@@ -426,7 +521,7 @@ def create_func_pdf_invcdf(x, y, category="function"):
|
|
|
426
521
|
pdf = interp1d(x, y, kind="cubic", fill_value="extrapolate")
|
|
427
522
|
return pdf
|
|
428
523
|
# cdf
|
|
429
|
-
cdf_values =
|
|
524
|
+
cdf_values = cumulative_trapezoid(y, x, initial=0)
|
|
430
525
|
idx = np.argwhere(cdf_values > 0)[0][0]
|
|
431
526
|
cdf_values = cdf_values[idx:]
|
|
432
527
|
x = x[idx:]
|
|
@@ -552,7 +647,7 @@ def create_inv_cdf_array(x, y):
|
|
|
552
647
|
idx = np.argwhere(np.isnan(y))
|
|
553
648
|
x = np.delete(x, idx)
|
|
554
649
|
y = np.delete(y, idx)
|
|
555
|
-
cdf_values =
|
|
650
|
+
cdf_values = cumulative_trapezoid(y, x, initial=0)
|
|
556
651
|
cdf_values = cdf_values / cdf_values[-1]
|
|
557
652
|
# to remove duplicate values on x-axis before interpolation
|
|
558
653
|
# idx = np.argwhere(cdf_values > 0)[0][0]
|
|
@@ -607,8 +702,9 @@ def create_conditioned_inv_cdf_array(x, conditioned_y, pdf_func):
|
|
|
607
702
|
"""
|
|
608
703
|
|
|
609
704
|
list_ = []
|
|
705
|
+
size = len(x)
|
|
610
706
|
for y in conditioned_y:
|
|
611
|
-
phi = pdf_func(x,y)
|
|
707
|
+
phi = pdf_func(x,y*np.ones(size))
|
|
612
708
|
list_.append(create_inv_cdf_array(x, phi))
|
|
613
709
|
|
|
614
710
|
return np.array(list_)
|
|
@@ -735,11 +831,10 @@ def interpolator_pickle_path(
|
|
|
735
831
|
path1 = full_dir + "/init_dict.pickle"
|
|
736
832
|
if not os.path.exists(path1):
|
|
737
833
|
dict_list = []
|
|
738
|
-
|
|
739
|
-
pickle.dump(dict_list, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
|
834
|
+
save_pickle(path1, dict_list)
|
|
740
835
|
|
|
741
836
|
# check if the input dict is the same as one of the dict inside the pickle file
|
|
742
|
-
param_dict_stored =
|
|
837
|
+
param_dict_stored = load_pickle(path1)
|
|
743
838
|
|
|
744
839
|
path2 = full_dir
|
|
745
840
|
len_ = len(param_dict_stored)
|
|
@@ -756,122 +851,34 @@ def interpolator_pickle_path(
|
|
|
756
851
|
it_exist = False
|
|
757
852
|
path_inv_cdf = path2 + "/" + interpolator_name + "_" + str(len_) + ".pickle"
|
|
758
853
|
param_dict_stored.append(param_dict_given)
|
|
759
|
-
|
|
760
|
-
pickle.dump(param_dict_stored, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
|
854
|
+
save_pickle(path1, param_dict_stored)
|
|
761
855
|
|
|
762
856
|
return path_inv_cdf, it_exist
|
|
763
857
|
|
|
764
|
-
def interpolator_pdf_conditioned(x, conditioned_y, y_array, interpolator_list):
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
Parameters
|
|
769
|
-
----------
|
|
770
|
-
x : `numpy.ndarray`
|
|
771
|
-
x values.
|
|
772
|
-
conditioned_y : `float`
|
|
773
|
-
conditioned y value.
|
|
774
|
-
y_array : `numpy.ndarray`
|
|
775
|
-
y values.
|
|
776
|
-
interpolator_list : `list`
|
|
777
|
-
list of interpolators.
|
|
778
|
-
|
|
779
|
-
Returns
|
|
780
|
-
----------
|
|
781
|
-
interpolator_list[idx](x) : `numpy.ndarray`
|
|
782
|
-
samples from the interpolator.
|
|
783
|
-
"""
|
|
784
|
-
# find the index of z in zlist
|
|
785
|
-
idx = np.searchsorted(y_array, conditioned_y)
|
|
786
|
-
|
|
787
|
-
return interpolator_list[idx](x)
|
|
788
|
-
|
|
789
|
-
def interpolator_sampler_conditioned(conditioned_y, y_array, interpolator_list, size=1000):
|
|
790
|
-
"""
|
|
791
|
-
Function to find sampler interpolator coefficients from the conditioned y.
|
|
792
|
-
|
|
793
|
-
Parameters
|
|
794
|
-
----------
|
|
795
|
-
conditioned_y : `float`
|
|
796
|
-
conditioned y value.
|
|
797
|
-
y_array : `numpy.ndarray`
|
|
798
|
-
y values.
|
|
799
|
-
interpolator_list : `list`
|
|
800
|
-
list of interpolators.
|
|
801
|
-
size : `int`
|
|
802
|
-
number of samples.
|
|
803
|
-
|
|
804
|
-
Returns
|
|
805
|
-
----------
|
|
806
|
-
"""
|
|
807
|
-
|
|
808
|
-
# find the index of z in zlist
|
|
809
|
-
idx = np.searchsorted(y_array, conditioned_y)
|
|
810
|
-
u = np.random.uniform(0, 1, size=size)
|
|
811
|
-
return interpolator_list[idx](u)
|
|
812
|
-
|
|
813
|
-
@njit
|
|
814
|
-
def cubic_spline_interpolator(xnew, coefficients, x):
|
|
815
|
-
"""
|
|
816
|
-
Function to interpolate using cubic spline.
|
|
817
|
-
|
|
818
|
-
Parameters
|
|
819
|
-
----------
|
|
820
|
-
xnew : `numpy.ndarray`
|
|
821
|
-
new x values.
|
|
822
|
-
coefficients : `numpy.ndarray`
|
|
823
|
-
coefficients of the cubic spline.
|
|
824
|
-
x : `numpy.ndarray`
|
|
825
|
-
x values.
|
|
826
|
-
|
|
827
|
-
Returns
|
|
828
|
-
----------
|
|
829
|
-
result : `numpy.ndarray`
|
|
830
|
-
interpolated values.
|
|
831
|
-
"""
|
|
832
|
-
|
|
833
|
-
# Handling extrapolation
|
|
834
|
-
i = np.searchsorted(x, xnew) - 1
|
|
835
|
-
idx1 = xnew <= x[0]
|
|
836
|
-
idx2 = xnew > x[-1]
|
|
837
|
-
i[idx1] = 0
|
|
838
|
-
i[idx2] = len(x) - 2
|
|
839
|
-
|
|
840
|
-
# Calculate the relative position within the interval
|
|
841
|
-
dx = xnew - x[i]
|
|
842
|
-
|
|
843
|
-
# Calculate the interpolated value
|
|
844
|
-
# Cubic polynomial: a + b*dx + c*dx^2 + d*dx^3
|
|
845
|
-
a, b, c, d = coefficients[:, i]
|
|
846
|
-
#result = a + b*dx + c*dx**2 + d*dx**3
|
|
847
|
-
result = d + c*dx + b*dx**2 + a*dx**3
|
|
848
|
-
return result
|
|
849
|
-
|
|
850
|
-
@njit
|
|
851
|
-
def inverse_transform_sampler(size, cdf, x):
|
|
852
|
-
"""
|
|
853
|
-
Function to sample from the inverse transform method.
|
|
858
|
+
# def interpolator_pdf_conditioned(x, conditioned_y, y_array, interpolator_list):
|
|
859
|
+
# """
|
|
860
|
+
# Function to find the pdf interpolator coefficients from the conditioned y.
|
|
854
861
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
862
|
+
# Parameters
|
|
863
|
+
# ----------
|
|
864
|
+
# x : `numpy.ndarray`
|
|
865
|
+
# x values.
|
|
866
|
+
# conditioned_y : `float`
|
|
867
|
+
# conditioned y value.
|
|
868
|
+
# y_array : `numpy.ndarray`
|
|
869
|
+
# y values.
|
|
870
|
+
# interpolator_list : `list`
|
|
871
|
+
# list of interpolators.
|
|
863
872
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
873
|
+
# Returns
|
|
874
|
+
# ----------
|
|
875
|
+
# interpolator_list[idx](x) : `numpy.ndarray`
|
|
876
|
+
# samples from the interpolator.
|
|
877
|
+
# """
|
|
878
|
+
# # find the index of z in zlist
|
|
879
|
+
# idx = np.searchsorted(y_array, conditioned_y)
|
|
869
880
|
|
|
870
|
-
|
|
871
|
-
idx = np.searchsorted(cdf, u)
|
|
872
|
-
x1, x0, y1, y0 = cdf[idx], cdf[idx-1], x[idx], x[idx-1]
|
|
873
|
-
samples = y0 + (y1 - y0) * (u - x0) / (x1 - x0)
|
|
874
|
-
return samples
|
|
881
|
+
# return interpolator_list[idx](x)
|
|
875
882
|
|
|
876
883
|
def batch_handler(size, batch_size, sampling_routine, output_jsonfile, save_batch=True, resume=False, param_name='parameters'):
|
|
877
884
|
"""
|
|
@@ -914,11 +921,6 @@ def batch_handler(size, batch_size, sampling_routine, output_jsonfile, save_batc
|
|
|
914
921
|
else:
|
|
915
922
|
num_batches = size // batch_size + 1
|
|
916
923
|
|
|
917
|
-
print(
|
|
918
|
-
f"chosen batch size = {batch_size} with total size = {size}"
|
|
919
|
-
)
|
|
920
|
-
print(f"There will be {num_batches} batche(s)")
|
|
921
|
-
|
|
922
924
|
# note frac_batches+(num_batches-1)*batch_size = size
|
|
923
925
|
if size > batch_size:
|
|
924
926
|
frac_batches = size - (num_batches - 1) * batch_size
|
|
@@ -1014,4 +1016,430 @@ def create_batch_params(sampling_routine, frac_batches, dict_buffer, save_batch,
|
|
|
1014
1016
|
# store all params in json file
|
|
1015
1017
|
dict_buffer = append_json(file_name=output_jsonfile, new_dictionary=param, old_dictionary=dict_buffer, replace=not (resume))
|
|
1016
1018
|
|
|
1017
|
-
return track_batches, dict_buffer
|
|
1019
|
+
return track_batches, dict_buffer
|
|
1020
|
+
|
|
1021
|
+
def monte_carlo_integration(function, uniform_prior, size=10000):
|
|
1022
|
+
"""
|
|
1023
|
+
Function to perform Monte Carlo integration.
|
|
1024
|
+
|
|
1025
|
+
Parameters
|
|
1026
|
+
----------
|
|
1027
|
+
function : `function`
|
|
1028
|
+
function to be integrated.
|
|
1029
|
+
prior : `function`
|
|
1030
|
+
prior function.
|
|
1031
|
+
|
|
1032
|
+
Returns
|
|
1033
|
+
----------
|
|
1034
|
+
integral : `float`
|
|
1035
|
+
integral value.
|
|
1036
|
+
"""
|
|
1037
|
+
|
|
1038
|
+
# sample from the prior
|
|
1039
|
+
x = uniform_prior(size=size)
|
|
1040
|
+
# calculate the function
|
|
1041
|
+
y = np.array([function(x[i]) for i in range(size)])
|
|
1042
|
+
# calculate the integral
|
|
1043
|
+
integral = np.mean(y)*(np.max(x)-np.min(x))
|
|
1044
|
+
return integral
|
|
1045
|
+
|
|
1046
|
+
@njit
|
|
1047
|
+
def cubic_spline_interpolator(xnew, coefficients, x):
|
|
1048
|
+
"""
|
|
1049
|
+
Function to interpolate using cubic spline.
|
|
1050
|
+
|
|
1051
|
+
Parameters
|
|
1052
|
+
----------
|
|
1053
|
+
xnew : `numpy.ndarray`
|
|
1054
|
+
new x values.
|
|
1055
|
+
coefficients : `numpy.ndarray`
|
|
1056
|
+
coefficients of the cubic spline.
|
|
1057
|
+
x : `numpy.ndarray`
|
|
1058
|
+
x values.
|
|
1059
|
+
|
|
1060
|
+
Returns
|
|
1061
|
+
----------
|
|
1062
|
+
result : `numpy.ndarray`
|
|
1063
|
+
interpolated values.
|
|
1064
|
+
"""
|
|
1065
|
+
|
|
1066
|
+
# Handling extrapolation
|
|
1067
|
+
i = np.searchsorted(x, xnew) - 1
|
|
1068
|
+
idx1 = xnew <= x[0]
|
|
1069
|
+
idx2 = xnew > x[-1]
|
|
1070
|
+
i[idx1] = 0
|
|
1071
|
+
i[idx2] = len(x) - 2
|
|
1072
|
+
#i = np.array(i, dtype=np.int32)
|
|
1073
|
+
# x = np.array(x, dtype=np.float64)
|
|
1074
|
+
|
|
1075
|
+
# Calculate the relative position within the interval
|
|
1076
|
+
#print(f"i = {i}\n xnew = {xnew}\n x = {x}")
|
|
1077
|
+
#print(x[i])
|
|
1078
|
+
dx = xnew - x[i]
|
|
1079
|
+
|
|
1080
|
+
# Calculate the interpolated value
|
|
1081
|
+
# Cubic polynomial: a + b*dx + c*dx^2 + d*dx^3
|
|
1082
|
+
# coefficients = np.array(coefficients, dtype=np.float64)
|
|
1083
|
+
#print(f"coefficients = {coefficients}")
|
|
1084
|
+
a, b, c, d = coefficients[:, i]
|
|
1085
|
+
#result = a + b*dx + c*dx**2 + d*dx**3
|
|
1086
|
+
result = d + c*dx + b*dx**2 + a*dx**3
|
|
1087
|
+
return result
|
|
1088
|
+
|
|
1089
|
+
@njit
|
|
1090
|
+
def pdf_cubic_spline_interpolator2d_array(xnew_array, ynew_array, norm_array, coefficients, x, y):
|
|
1091
|
+
"""
|
|
1092
|
+
Function to calculate the interpolated value of snr_partialscaled given the mass ratio (ynew) and total mass (xnew). This is based off 2D bicubic spline interpolation.
|
|
1093
|
+
|
|
1094
|
+
Parameters
|
|
1095
|
+
----------
|
|
1096
|
+
xnew_array : `numpy.ndarray`
|
|
1097
|
+
Total mass of the binary.
|
|
1098
|
+
ynew_array : `numpy.ndarray`
|
|
1099
|
+
Mass ratio of the binary.
|
|
1100
|
+
coefficients : `numpy.ndarray`
|
|
1101
|
+
Array of coefficients for the cubic spline interpolation.
|
|
1102
|
+
x : `numpy.ndarray`
|
|
1103
|
+
Array of total mass values for the coefficients.
|
|
1104
|
+
y : `numpy.ndarray`
|
|
1105
|
+
Array of mass ratio values for the coefficients.
|
|
1106
|
+
|
|
1107
|
+
Returns
|
|
1108
|
+
-------
|
|
1109
|
+
result : `float`
|
|
1110
|
+
Interpolated value of snr_partialscaled.
|
|
1111
|
+
"""
|
|
1112
|
+
result_array = []
|
|
1113
|
+
for i in range(len(xnew_array)):
|
|
1114
|
+
xnew = xnew_array[i]
|
|
1115
|
+
ynew = ynew_array[i]
|
|
1116
|
+
|
|
1117
|
+
len_y = len(y)
|
|
1118
|
+
# find the index nearest to the ynew in y
|
|
1119
|
+
y_idx = np.searchsorted(y, ynew) - 1 if ynew > y[0] else 0
|
|
1120
|
+
|
|
1121
|
+
if (ynew>y[0]) and (ynew<y[1]):
|
|
1122
|
+
if ynew > y[y_idx] + (y[y_idx+1] - y[y_idx]) / 2:
|
|
1123
|
+
y_idx = y_idx + 1
|
|
1124
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx], x[y_idx])[0]/norm_array[y_idx])
|
|
1125
|
+
elif y_idx == 0: # lower end point
|
|
1126
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[0], x[0])[0]/norm_array[0])
|
|
1127
|
+
# print("a")
|
|
1128
|
+
elif y_idx+1 == len_y: # upper end point
|
|
1129
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[-1], x[-1])[0]/norm_array[-1])
|
|
1130
|
+
# print("b")
|
|
1131
|
+
elif y_idx+2 == len_y: # upper end point
|
|
1132
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[-1], x[-1])[0]/norm_array[-1])
|
|
1133
|
+
# print("b")
|
|
1134
|
+
else:
|
|
1135
|
+
y_idx1 = y_idx - 1
|
|
1136
|
+
y_idx2 = y_idx
|
|
1137
|
+
y_idx3 = y_idx + 1
|
|
1138
|
+
y_idx4 = y_idx + 2
|
|
1139
|
+
coeff_low, coeff_high = 4, 8
|
|
1140
|
+
# print("c")
|
|
1141
|
+
y1, y2, y3, y4 = y[y_idx1], y[y_idx2], y[y_idx3], y[y_idx4]
|
|
1142
|
+
z1 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx1], x[y_idx1])[0]/norm_array[y_idx1]
|
|
1143
|
+
z2 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx2], x[y_idx2])[0]/norm_array[y_idx2]
|
|
1144
|
+
z3 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx3], x[y_idx3])[0]/norm_array[y_idx3]
|
|
1145
|
+
z4 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx4], x[y_idx4])[0]/norm_array[y_idx4]
|
|
1146
|
+
|
|
1147
|
+
coeff = coefficients_generator_ler(y1, y2, y3, y4, z1, z2, z3, z4)
|
|
1148
|
+
matrixD = coeff[coeff_low:coeff_high]
|
|
1149
|
+
matrixB = np.array([ynew**3, ynew**2, ynew, 1])
|
|
1150
|
+
result_array.append(np.dot(matrixB, matrixD))
|
|
1151
|
+
|
|
1152
|
+
return np.array(result_array)
|
|
1153
|
+
|
|
1154
|
+
@njit
|
|
1155
|
+
def cubic_spline_interpolator2d_array(xnew_array, ynew_array, coefficients, x, y):
|
|
1156
|
+
"""
|
|
1157
|
+
Function to calculate the interpolated value of snr_partialscaled given the mass ratio (ynew) and total mass (xnew). This is based off 2D bicubic spline interpolation.
|
|
1158
|
+
|
|
1159
|
+
Parameters
|
|
1160
|
+
----------
|
|
1161
|
+
xnew_array : `numpy.ndarray`
|
|
1162
|
+
Total mass of the binary.
|
|
1163
|
+
ynew_array : `numpy.ndarray`
|
|
1164
|
+
Mass ratio of the binary.
|
|
1165
|
+
coefficients : `numpy.ndarray`
|
|
1166
|
+
Array of coefficients for the cubic spline interpolation.
|
|
1167
|
+
x : `numpy.ndarray`
|
|
1168
|
+
Array of total mass values for the coefficients.
|
|
1169
|
+
y : `numpy.ndarray`
|
|
1170
|
+
Array of mass ratio values for the coefficients.
|
|
1171
|
+
|
|
1172
|
+
Returns
|
|
1173
|
+
-------
|
|
1174
|
+
result : `float`
|
|
1175
|
+
Interpolated value of snr_partialscaled.
|
|
1176
|
+
"""
|
|
1177
|
+
result_array = []
|
|
1178
|
+
for i in range(len(xnew_array)):
|
|
1179
|
+
xnew = xnew_array[i]
|
|
1180
|
+
ynew = ynew_array[i]
|
|
1181
|
+
|
|
1182
|
+
len_y = len(y)
|
|
1183
|
+
# find the index nearest to the ynew in y
|
|
1184
|
+
y_idx = np.searchsorted(y, ynew) - 1 if ynew > y[0] else 0
|
|
1185
|
+
|
|
1186
|
+
if (ynew>y[0]) and (ynew<y[1]):
|
|
1187
|
+
if ynew > y[y_idx] + (y[y_idx+1] - y[y_idx]) / 2:
|
|
1188
|
+
y_idx = y_idx + 1
|
|
1189
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx], x[y_idx])[0])
|
|
1190
|
+
# print(f"a) idx = {y_idx}")
|
|
1191
|
+
elif y_idx == 0: # lower end point
|
|
1192
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[0], x[0])[0])
|
|
1193
|
+
# print(f"a) idx = {y_idx}")
|
|
1194
|
+
elif y_idx+1 == len_y: # upper end point
|
|
1195
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[-1], x[-1])[0])
|
|
1196
|
+
# print(f"b) idx = {y_idx}")
|
|
1197
|
+
elif y_idx+2 == len_y: # upper end point
|
|
1198
|
+
result_array.append(cubic_spline_interpolator(np.array([xnew]), coefficients[-1], x[-1])[0])
|
|
1199
|
+
# print(f"c) idx = {y_idx}")
|
|
1200
|
+
else:
|
|
1201
|
+
y_idx1 = y_idx - 1
|
|
1202
|
+
y_idx2 = y_idx
|
|
1203
|
+
y_idx3 = y_idx + 1
|
|
1204
|
+
y_idx4 = y_idx + 2
|
|
1205
|
+
coeff_low, coeff_high = 4, 8
|
|
1206
|
+
# print(f"d) idx1, idx2, idx3, idx4 = {y_idx1}, {y_idx2}, {y_idx3}, {y_idx4}")
|
|
1207
|
+
y1, y2, y3, y4 = y[y_idx1], y[y_idx2], y[y_idx3], y[y_idx4]
|
|
1208
|
+
z1 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx1], x[y_idx1])[0]
|
|
1209
|
+
z2 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx2], x[y_idx2])[0]
|
|
1210
|
+
z3 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx3], x[y_idx3])[0]
|
|
1211
|
+
z4 = cubic_spline_interpolator(np.array([xnew]), coefficients[y_idx4], x[y_idx4])[0]
|
|
1212
|
+
|
|
1213
|
+
coeff = coefficients_generator_ler(y1, y2, y3, y4, z1, z2, z3, z4)
|
|
1214
|
+
matrixD = coeff[coeff_low:coeff_high]
|
|
1215
|
+
matrixB = np.array([ynew**3, ynew**2, ynew, 1])
|
|
1216
|
+
result_array.append(np.dot(matrixB, matrixD))
|
|
1217
|
+
|
|
1218
|
+
return result_array
|
|
1219
|
+
|
|
1220
|
+
@njit
|
|
1221
|
+
def coefficients_generator_ler(y1, y2, y3, y4, z1, z2, z3, z4):
|
|
1222
|
+
"""
|
|
1223
|
+
Function to generate the coefficients for the cubic spline interpolation of fn(y)=z.
|
|
1224
|
+
|
|
1225
|
+
Parameters
|
|
1226
|
+
----------
|
|
1227
|
+
y1, y2, y3, y4, z1, z2, z3, z4: `float`
|
|
1228
|
+
Values of y and z for the cubic spline interpolation.
|
|
1229
|
+
|
|
1230
|
+
Returns
|
|
1231
|
+
-------
|
|
1232
|
+
coefficients: `numpy.ndarray`
|
|
1233
|
+
Coefficients for the cubic spline interpolation.
|
|
1234
|
+
"""
|
|
1235
|
+
matrixA = np.array([
|
|
1236
|
+
[y1**3, y1**2, y1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
1237
|
+
[y2**3, y2**2, y2, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
1238
|
+
[0, 0, 0, 0, y2**3, y2**2, y2, 1, 0, 0, 0, 0],
|
|
1239
|
+
[0, 0, 0, 0, y3**3, y3**2, y3, 1, 0, 0, 0, 0],
|
|
1240
|
+
[0, 0, 0, 0, 0, 0, 0, 0, y3**3, y3**2, y3, 1],
|
|
1241
|
+
[0, 0, 0, 0, 0, 0, 0, 0, y4**3, y4**2, y4, 1],
|
|
1242
|
+
[3*y2**2, 2*y2, 1, 0, -3*y2**2, -2*y2, -1, 0, 0, 0, 0, 0],
|
|
1243
|
+
[0, 0, 0, 0, 3*y3**2, 2*y3, 1, 0, -3*y3**2, -2*y3, -1, 0],
|
|
1244
|
+
[6*y2, 2, 0, 0, -6*y2, -2, 0, 0, 0, 0, 0, 0],
|
|
1245
|
+
[0, 0, 0, 0, 6*y3, 2, 0, 0, -6*y3, -2, 0, 0],
|
|
1246
|
+
[6*y1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
1247
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 6*y4, 2, 0, 0],
|
|
1248
|
+
])
|
|
1249
|
+
matrixC = np.array([z1, z2, z2, z3, z3, z4, 0, 0, 0, 0, 0, 0])
|
|
1250
|
+
return np.dot(np.linalg.inv(matrixA), matrixC)
|
|
1251
|
+
|
|
1252
|
+
@njit
|
|
1253
|
+
def inverse_transform_sampler2d(size, conditioned_y, cdf2d, x2d, y1d):
|
|
1254
|
+
"""
|
|
1255
|
+
Function to find sampler interpolator coefficients from the conditioned y.
|
|
1256
|
+
|
|
1257
|
+
Parameters
|
|
1258
|
+
----------
|
|
1259
|
+
size: `int`
|
|
1260
|
+
Size of the sample.
|
|
1261
|
+
conditioned_y: `float`
|
|
1262
|
+
Conditioned y value.
|
|
1263
|
+
cdf2d: `numpy.ndarray`
|
|
1264
|
+
2D array of cdf values.
|
|
1265
|
+
x2d: `numpy.ndarray`
|
|
1266
|
+
2D array of x values.
|
|
1267
|
+
y1d: `numpy.ndarray`
|
|
1268
|
+
1D array of y values.
|
|
1269
|
+
|
|
1270
|
+
Returns
|
|
1271
|
+
-------
|
|
1272
|
+
samples: `numpy.ndarray`
|
|
1273
|
+
Samples of the conditioned y.
|
|
1274
|
+
"""
|
|
1275
|
+
|
|
1276
|
+
samples = np.zeros(size)
|
|
1277
|
+
for i, y in enumerate(conditioned_y):
|
|
1278
|
+
# find the index nearest to the conditioned_y in y1d
|
|
1279
|
+
y_idx = np.searchsorted(y1d, y) - 1 if y > y1d[0] else 0
|
|
1280
|
+
if y > y1d[y_idx] + (y1d[y_idx+1] - y1d[y_idx]) / 2:
|
|
1281
|
+
y_idx = y_idx + 1
|
|
1282
|
+
|
|
1283
|
+
# linear scaling
|
|
1284
|
+
# new cdf values
|
|
1285
|
+
x1, x0, y1, y0 = y1d[y_idx], y1d[y_idx-1], cdf2d[y_idx], cdf2d[y_idx-1]
|
|
1286
|
+
cdf = y0 + (y1 - y0) * (y - x0) / (x1 - x0)
|
|
1287
|
+
# new x values
|
|
1288
|
+
# x=x2d[0], if all rows are same
|
|
1289
|
+
x1, x0, y1, y0 = y1d[y_idx], y1d[y_idx-1], x2d[y_idx], x2d[y_idx-1]
|
|
1290
|
+
x = y0 + (y1 - y0) * (y - x0) / (x1 - x0)
|
|
1291
|
+
|
|
1292
|
+
while True:
|
|
1293
|
+
u = np.random.uniform(0, 1)
|
|
1294
|
+
idx = np.searchsorted(cdf, u)
|
|
1295
|
+
x1, x0, y1, y0 = cdf[idx], cdf[idx-1], x[idx], x[idx-1]
|
|
1296
|
+
samples[i] = y0 + (y1 - y0) * (u - x0) / (x1 - x0)
|
|
1297
|
+
if not np.isnan(samples[i]):
|
|
1298
|
+
break
|
|
1299
|
+
return samples
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
@njit
|
|
1303
|
+
def inverse_transform_sampler(size, cdf, x):
|
|
1304
|
+
"""
|
|
1305
|
+
Function to sample from the inverse transform method.
|
|
1306
|
+
|
|
1307
|
+
Parameters
|
|
1308
|
+
----------
|
|
1309
|
+
size : `int`
|
|
1310
|
+
number of samples.
|
|
1311
|
+
cdf : `numpy.ndarray`
|
|
1312
|
+
cdf values.
|
|
1313
|
+
x : `numpy.ndarray`
|
|
1314
|
+
x values.
|
|
1315
|
+
|
|
1316
|
+
Returns
|
|
1317
|
+
----------
|
|
1318
|
+
samples : `numpy.ndarray`
|
|
1319
|
+
samples from the cdf.
|
|
1320
|
+
"""
|
|
1321
|
+
|
|
1322
|
+
u = np.random.uniform(0, 1, size)
|
|
1323
|
+
idx = np.searchsorted(cdf, u)
|
|
1324
|
+
x1, x0, y1, y0 = cdf[idx], cdf[idx-1], x[idx], x[idx-1]
|
|
1325
|
+
samples = y0 + (y1 - y0) * (u - x0) / (x1 - x0)
|
|
1326
|
+
return samples
|
|
1327
|
+
|
|
1328
|
+
@njit
|
|
1329
|
+
def normal_pdf(x, mean=0., std=0.05):
|
|
1330
|
+
"""
|
|
1331
|
+
Calculate the value of a normal probability density function.
|
|
1332
|
+
|
|
1333
|
+
Parameters
|
|
1334
|
+
----------
|
|
1335
|
+
x : `float` or `numpy.ndarray`
|
|
1336
|
+
The value(s) at which to evaluate the PDF.
|
|
1337
|
+
mean : `float`, optional
|
|
1338
|
+
The mean of the normal distribution. Default is 0.
|
|
1339
|
+
std : `float`, optional
|
|
1340
|
+
The standard deviation of the normal distribution. Default is 0.05.
|
|
1341
|
+
|
|
1342
|
+
Returns
|
|
1343
|
+
-------
|
|
1344
|
+
pdf : `float` or `numpy.ndarray`
|
|
1345
|
+
The probability density function value(s) at x.
|
|
1346
|
+
"""
|
|
1347
|
+
|
|
1348
|
+
return (1 / (std * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x - mean) / std)**2)
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
@njit
|
|
1352
|
+
def normal_pdf_2d(x, y, mean_x=0., std_x=0.05, mean_y=0., std_y=0.05):
|
|
1353
|
+
"""
|
|
1354
|
+
Calculate the value of a 2D normal probability density function.
|
|
1355
|
+
|
|
1356
|
+
Parameters
|
|
1357
|
+
----------
|
|
1358
|
+
x : `float`
|
|
1359
|
+
The x-coordinate for which the PDF is evaluated.
|
|
1360
|
+
y : `float`
|
|
1361
|
+
The y-coordinate for which the PDF is evaluated.
|
|
1362
|
+
mean_x : `float`, optional
|
|
1363
|
+
The mean of the normal distribution along the x-axis. Default is 0.
|
|
1364
|
+
std_x : `float`, optional
|
|
1365
|
+
The standard deviation of the normal distribution along the x-axis. Default is 0.05.
|
|
1366
|
+
mean_y : `float`, optional
|
|
1367
|
+
The mean of the normal distribution along the y-axis. Default is 0.
|
|
1368
|
+
std_y : `float`, optional
|
|
1369
|
+
The standard deviation of the normal distribution along the y-axis. Default is 0.05.
|
|
1370
|
+
|
|
1371
|
+
Returns
|
|
1372
|
+
-------
|
|
1373
|
+
`float`
|
|
1374
|
+
The probability density function value at the given x and y coordinates.
|
|
1375
|
+
"""
|
|
1376
|
+
|
|
1377
|
+
factor_x = (1 / (std_x * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x - mean_x) / std_x)**2)
|
|
1378
|
+
factor_y = (1 / (std_y * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((y - mean_y) / std_y)**2)
|
|
1379
|
+
return factor_x * factor_y
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
def load_txt_from_module(package, directory, filename):
|
|
1383
|
+
"""
|
|
1384
|
+
"""
|
|
1385
|
+
|
|
1386
|
+
with resources.path(package + '.' + directory, filename) as txt_path:
|
|
1387
|
+
return np.loadtxt(txt_path)
|
|
1388
|
+
|
|
1389
|
+
@njit
|
|
1390
|
+
def cumulative_trapezoid(y, x=None, dx=1.0, initial=0.0):
|
|
1391
|
+
"""
|
|
1392
|
+
Compute the cumulative integral of a function using the trapezoidal rule.
|
|
1393
|
+
"""
|
|
1394
|
+
if x is None:
|
|
1395
|
+
x = np.arange(len(y)) * dx
|
|
1396
|
+
|
|
1397
|
+
# Calculate the cumulative integral using trapezoidal rule
|
|
1398
|
+
cumsum = np.zeros_like(y)
|
|
1399
|
+
cumsum[0] = initial
|
|
1400
|
+
for i in range(1, len(y)):
|
|
1401
|
+
cumsum[i] = cumsum[i - 1] + (y[i - 1] + y[i]) * (x[i] - x[i - 1]) / 2.0
|
|
1402
|
+
|
|
1403
|
+
return cumsum
|
|
1404
|
+
|
|
1405
|
+
@njit
|
|
1406
|
+
def sample_from_powerlaw_distribution(size, alphans, mminns, mmaxns):
|
|
1407
|
+
"""
|
|
1408
|
+
Inverse transform sampling for a power-law mass distribution:
|
|
1409
|
+
p(m) ∝ m^{-alphans}, m in [mminns, mmaxns]
|
|
1410
|
+
|
|
1411
|
+
Parameters
|
|
1412
|
+
----------
|
|
1413
|
+
size : int
|
|
1414
|
+
Number of samples to generate.
|
|
1415
|
+
alphans : float
|
|
1416
|
+
Power-law index (α).
|
|
1417
|
+
mminns : float
|
|
1418
|
+
Minimum neutron star mass (lower bound).
|
|
1419
|
+
mmaxns : float
|
|
1420
|
+
Maximum neutron star mass (upper bound).
|
|
1421
|
+
random_state : int, np.random.Generator, or None
|
|
1422
|
+
Seed or random generator for reproducibility.
|
|
1423
|
+
|
|
1424
|
+
Returns
|
|
1425
|
+
-------
|
|
1426
|
+
m : ndarray
|
|
1427
|
+
Array of sampled neutron star masses.
|
|
1428
|
+
"""
|
|
1429
|
+
|
|
1430
|
+
u = np.random.uniform(0, 1, size)
|
|
1431
|
+
|
|
1432
|
+
if alphans == 1.0:
|
|
1433
|
+
# Special case α=1
|
|
1434
|
+
m = mminns * (mmaxns / mminns) ** u
|
|
1435
|
+
elif alphans == 0.0:
|
|
1436
|
+
# Special case α=0 (uniform distribution)
|
|
1437
|
+
m = mminns + (mmaxns - mminns) * u
|
|
1438
|
+
else:
|
|
1439
|
+
pow1 = 1.0 - alphans
|
|
1440
|
+
mmin_pow = mminns ** pow1
|
|
1441
|
+
mmax_pow = mmaxns ** pow1
|
|
1442
|
+
m = (u * (mmax_pow - mmin_pow) + mmin_pow) ** (1.0 / pow1)
|
|
1443
|
+
|
|
1444
|
+
return m
|
|
1445
|
+
|