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.
- ler/__init__.py +26 -26
- ler/gw_source_population/__init__.py +1 -0
- ler/gw_source_population/cbc_source_parameter_distribution.py +1073 -815
- ler/gw_source_population/cbc_source_redshift_distribution.py +618 -294
- 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 +41 -12
- 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 +813 -881
- 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 +126 -72
- ler/rates/ler.py +218 -111
- 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 +492 -125
- {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/METADATA +30 -17
- ler-0.4.3.dist-info/RECORD +34 -0
- {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/WHEEL +1 -1
- ler/rates/ler copy.py +0 -2097
- ler-0.4.2.dist-info/RECORD +0 -25
- {ler-0.4.2.dist-info → ler-0.4.3.dist-info/licenses}/LICENSE +0 -0
- {ler-0.4.2.dist-info → ler-0.4.3.dist-info}/top_level.txt +0 -0
ler/utils/utils.py
CHANGED
|
@@ -10,8 +10,9 @@ import numpy as np
|
|
|
10
10
|
import json
|
|
11
11
|
from scipy.interpolate import interp1d
|
|
12
12
|
from scipy.interpolate import CubicSpline
|
|
13
|
-
from scipy.integrate import quad
|
|
13
|
+
from scipy.integrate import quad
|
|
14
14
|
from numba import njit
|
|
15
|
+
from importlib import resources
|
|
15
16
|
# import datetime
|
|
16
17
|
|
|
17
18
|
|
|
@@ -139,9 +140,20 @@ def save_json(file_name, param):
|
|
|
139
140
|
json file name for storing the parameters.
|
|
140
141
|
param : `dict`
|
|
141
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")
|
|
142
150
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
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)
|
|
145
157
|
|
|
146
158
|
def append_json(file_name, new_dictionary, old_dictionary=None, replace=False):
|
|
147
159
|
"""
|
|
@@ -246,6 +258,28 @@ def get_param_from_json(json_file):
|
|
|
246
258
|
param[key] = np.array(value)
|
|
247
259
|
return param
|
|
248
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
|
+
|
|
249
283
|
def rejection_sample(pdf, xmin, xmax, size=100, chunk_size=10000):
|
|
250
284
|
"""
|
|
251
285
|
Helper function for rejection sampling from a pdf with maximum and minimum arguments.
|
|
@@ -487,7 +521,7 @@ def create_func_pdf_invcdf(x, y, category="function"):
|
|
|
487
521
|
pdf = interp1d(x, y, kind="cubic", fill_value="extrapolate")
|
|
488
522
|
return pdf
|
|
489
523
|
# cdf
|
|
490
|
-
cdf_values =
|
|
524
|
+
cdf_values = cumulative_trapezoid(y, x, initial=0)
|
|
491
525
|
idx = np.argwhere(cdf_values > 0)[0][0]
|
|
492
526
|
cdf_values = cdf_values[idx:]
|
|
493
527
|
x = x[idx:]
|
|
@@ -613,7 +647,7 @@ def create_inv_cdf_array(x, y):
|
|
|
613
647
|
idx = np.argwhere(np.isnan(y))
|
|
614
648
|
x = np.delete(x, idx)
|
|
615
649
|
y = np.delete(y, idx)
|
|
616
|
-
cdf_values =
|
|
650
|
+
cdf_values = cumulative_trapezoid(y, x, initial=0)
|
|
617
651
|
cdf_values = cdf_values / cdf_values[-1]
|
|
618
652
|
# to remove duplicate values on x-axis before interpolation
|
|
619
653
|
# idx = np.argwhere(cdf_values > 0)[0][0]
|
|
@@ -668,8 +702,9 @@ def create_conditioned_inv_cdf_array(x, conditioned_y, pdf_func):
|
|
|
668
702
|
"""
|
|
669
703
|
|
|
670
704
|
list_ = []
|
|
705
|
+
size = len(x)
|
|
671
706
|
for y in conditioned_y:
|
|
672
|
-
phi = pdf_func(x,y)
|
|
707
|
+
phi = pdf_func(x,y*np.ones(size))
|
|
673
708
|
list_.append(create_inv_cdf_array(x, phi))
|
|
674
709
|
|
|
675
710
|
return np.array(list_)
|
|
@@ -796,11 +831,10 @@ def interpolator_pickle_path(
|
|
|
796
831
|
path1 = full_dir + "/init_dict.pickle"
|
|
797
832
|
if not os.path.exists(path1):
|
|
798
833
|
dict_list = []
|
|
799
|
-
|
|
800
|
-
pickle.dump(dict_list, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
|
834
|
+
save_pickle(path1, dict_list)
|
|
801
835
|
|
|
802
836
|
# check if the input dict is the same as one of the dict inside the pickle file
|
|
803
|
-
param_dict_stored =
|
|
837
|
+
param_dict_stored = load_pickle(path1)
|
|
804
838
|
|
|
805
839
|
path2 = full_dir
|
|
806
840
|
len_ = len(param_dict_stored)
|
|
@@ -817,122 +851,34 @@ def interpolator_pickle_path(
|
|
|
817
851
|
it_exist = False
|
|
818
852
|
path_inv_cdf = path2 + "/" + interpolator_name + "_" + str(len_) + ".pickle"
|
|
819
853
|
param_dict_stored.append(param_dict_given)
|
|
820
|
-
|
|
821
|
-
pickle.dump(param_dict_stored, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
|
854
|
+
save_pickle(path1, param_dict_stored)
|
|
822
855
|
|
|
823
856
|
return path_inv_cdf, it_exist
|
|
824
857
|
|
|
825
|
-
def interpolator_pdf_conditioned(x, conditioned_y, y_array, interpolator_list):
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
Parameters
|
|
830
|
-
----------
|
|
831
|
-
x : `numpy.ndarray`
|
|
832
|
-
x values.
|
|
833
|
-
conditioned_y : `float`
|
|
834
|
-
conditioned y value.
|
|
835
|
-
y_array : `numpy.ndarray`
|
|
836
|
-
y values.
|
|
837
|
-
interpolator_list : `list`
|
|
838
|
-
list of interpolators.
|
|
839
|
-
|
|
840
|
-
Returns
|
|
841
|
-
----------
|
|
842
|
-
interpolator_list[idx](x) : `numpy.ndarray`
|
|
843
|
-
samples from the interpolator.
|
|
844
|
-
"""
|
|
845
|
-
# find the index of z in zlist
|
|
846
|
-
idx = np.searchsorted(y_array, conditioned_y)
|
|
847
|
-
|
|
848
|
-
return interpolator_list[idx](x)
|
|
849
|
-
|
|
850
|
-
def interpolator_sampler_conditioned(conditioned_y, y_array, interpolator_list, size=1000):
|
|
851
|
-
"""
|
|
852
|
-
Function to find sampler interpolator coefficients from the conditioned y.
|
|
853
|
-
|
|
854
|
-
Parameters
|
|
855
|
-
----------
|
|
856
|
-
conditioned_y : `float`
|
|
857
|
-
conditioned y value.
|
|
858
|
-
y_array : `numpy.ndarray`
|
|
859
|
-
y values.
|
|
860
|
-
interpolator_list : `list`
|
|
861
|
-
list of interpolators.
|
|
862
|
-
size : `int`
|
|
863
|
-
number of samples.
|
|
864
|
-
|
|
865
|
-
Returns
|
|
866
|
-
----------
|
|
867
|
-
"""
|
|
868
|
-
|
|
869
|
-
# find the index of z in zlist
|
|
870
|
-
idx = np.searchsorted(y_array, conditioned_y)
|
|
871
|
-
u = np.random.uniform(0, 1, size=size)
|
|
872
|
-
return interpolator_list[idx](u)
|
|
873
|
-
|
|
874
|
-
@njit
|
|
875
|
-
def cubic_spline_interpolator(xnew, coefficients, x):
|
|
876
|
-
"""
|
|
877
|
-
Function to interpolate using cubic spline.
|
|
878
|
-
|
|
879
|
-
Parameters
|
|
880
|
-
----------
|
|
881
|
-
xnew : `numpy.ndarray`
|
|
882
|
-
new x values.
|
|
883
|
-
coefficients : `numpy.ndarray`
|
|
884
|
-
coefficients of the cubic spline.
|
|
885
|
-
x : `numpy.ndarray`
|
|
886
|
-
x values.
|
|
887
|
-
|
|
888
|
-
Returns
|
|
889
|
-
----------
|
|
890
|
-
result : `numpy.ndarray`
|
|
891
|
-
interpolated values.
|
|
892
|
-
"""
|
|
893
|
-
|
|
894
|
-
# Handling extrapolation
|
|
895
|
-
i = np.searchsorted(x, xnew) - 1
|
|
896
|
-
idx1 = xnew <= x[0]
|
|
897
|
-
idx2 = xnew > x[-1]
|
|
898
|
-
i[idx1] = 0
|
|
899
|
-
i[idx2] = len(x) - 2
|
|
900
|
-
|
|
901
|
-
# Calculate the relative position within the interval
|
|
902
|
-
dx = xnew - x[i]
|
|
903
|
-
|
|
904
|
-
# Calculate the interpolated value
|
|
905
|
-
# Cubic polynomial: a + b*dx + c*dx^2 + d*dx^3
|
|
906
|
-
a, b, c, d = coefficients[:, i]
|
|
907
|
-
#result = a + b*dx + c*dx**2 + d*dx**3
|
|
908
|
-
result = d + c*dx + b*dx**2 + a*dx**3
|
|
909
|
-
return result
|
|
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.
|
|
910
861
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
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.
|
|
915
872
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
x values.
|
|
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)
|
|
924
880
|
|
|
925
|
-
|
|
926
|
-
----------
|
|
927
|
-
samples : `numpy.ndarray`
|
|
928
|
-
samples from the cdf.
|
|
929
|
-
"""
|
|
930
|
-
|
|
931
|
-
u = np.random.uniform(0, 1, size)
|
|
932
|
-
idx = np.searchsorted(cdf, u)
|
|
933
|
-
x1, x0, y1, y0 = cdf[idx], cdf[idx-1], x[idx], x[idx-1]
|
|
934
|
-
samples = y0 + (y1 - y0) * (u - x0) / (x1 - x0)
|
|
935
|
-
return samples
|
|
881
|
+
# return interpolator_list[idx](x)
|
|
936
882
|
|
|
937
883
|
def batch_handler(size, batch_size, sampling_routine, output_jsonfile, save_batch=True, resume=False, param_name='parameters'):
|
|
938
884
|
"""
|
|
@@ -975,11 +921,6 @@ def batch_handler(size, batch_size, sampling_routine, output_jsonfile, save_batc
|
|
|
975
921
|
else:
|
|
976
922
|
num_batches = size // batch_size + 1
|
|
977
923
|
|
|
978
|
-
print(
|
|
979
|
-
f"chosen batch size = {batch_size} with total size = {size}"
|
|
980
|
-
)
|
|
981
|
-
print(f"There will be {num_batches} batche(s)")
|
|
982
|
-
|
|
983
924
|
# note frac_batches+(num_batches-1)*batch_size = size
|
|
984
925
|
if size > batch_size:
|
|
985
926
|
frac_batches = size - (num_batches - 1) * batch_size
|
|
@@ -1075,4 +1016,430 @@ def create_batch_params(sampling_routine, frac_batches, dict_buffer, save_batch,
|
|
|
1075
1016
|
# store all params in json file
|
|
1076
1017
|
dict_buffer = append_json(file_name=output_jsonfile, new_dictionary=param, old_dictionary=dict_buffer, replace=not (resume))
|
|
1077
1018
|
|
|
1078
|
-
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
|
+
|