From b4d4c1599b548c0b0f4c0ea07094fe7ca1b7d94f Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Mon, 28 Oct 2024 12:39:25 +0530 Subject: [PATCH 1/9] add option to get params from json file --- gw_eccentricity/load_data.py | 107 +++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 7109412..0280faf 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -7,6 +7,7 @@ import lal import lalsimulation as lalsim import warnings +import json from copy import deepcopy from .utils import peak_time_via_quadratic_fit from .utils import amplitude_using_all_modes @@ -89,7 +90,8 @@ def get_load_waveform_defaults(origin="LAL"): "zero_ecc_approximant", "num_orbits_to_remove_as_junk", "mode_array", - "extrap_order"] + "extrap_order", + "remove_memory"] return make_a_sub_dict(get_defaults_for_nr(), kwargs_list) # for waveforms in LVCNR format file using recommended function in LALSuite elif origin == "LVCNR": @@ -526,6 +528,13 @@ def get_defaults_for_nr(): extrap_order: int Extrapolation order to use for loading the waveform data. NOTE: This is used only for sxs catalog formatted waveforms. + + remove_memory: bool + If True, remove memory contribution from the waveform modes. + This will require metadata file to find t_relax which is used + to start the integration for computing memory contribution. + NOTE: This is currently implemented ony for sxs catalog formatted + waveforms. """ return {"filepath": None, "data_dir": None, @@ -537,7 +546,8 @@ def get_defaults_for_nr(): "metadata_path": None, "num_orbits_to_remove_as_junk": 2, "mode_array": [(2, 2)], - "extrap_order": 2} + "extrap_order": 2, + "remove_memory": False} def load_lvcnr_waveform(**kwargs): @@ -824,6 +834,11 @@ def load_sxs_catalogformat(**kwargs): to locate the strain file. This function will seek a file named `Strain_N{extrap_order}.h5` in the `data_dir`. + remove_memory: bool + If True, remove memory contribution from the waveform modes. + This will require metadata file to find t_relax which is used + to start the integration for computing memory contribution. + Returns ------- Returns a dictionary with the following quantities: @@ -989,9 +1004,9 @@ def check_sxs_data_dir(origin, **kwargs): "If you are using the new format, You should provide the h5 and json " f"file named `Strain_N{kwargs['extrap_order']}` since `extrap_order` " f"is {kwargs['extrap_order']}."} - # metadata.txt is required if include_zero_ecc or include_params_dict is - # True - if kwargs["include_zero_ecc"] or kwargs["include_params_dict"]: + # metadata.txt/metadata.json is required if include_zero_ecc or include_params_dict + # or remove_memory is True + if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], kwargs["remove_memory"]]): for k in required_files_dict: required_files_dict.update( {k: np.append(required_files_dict[k], ["metadata.txt"])}) @@ -1000,11 +1015,16 @@ def check_sxs_data_dir(origin, **kwargs): if not os.path.exists( os.path.join(kwargs["data_dir"], filename)): if filename == "metadata.txt": - message = ( - " `metadata.txt` file is required when " - "`include_zero_ecc` or `include_params_dict` " - "is set to True to get the binary parameters of " - "the NR simulation.") + # check if metadata.json exists + if os.path.exists( + os.path.join(kwargs["data_dir"], 'metadata.json')): + continue + else: + message = ( + " `metadata.txt` or `metadata.json` file is required when " + "`include_zero_ecc` or `include_params_dict` or `remove_memory` " + "is set to True to get the binary parameters of " + "the NR simulation.") else: message = message_dict[origin] raise FileNotFoundError( @@ -1053,9 +1073,13 @@ def make_return_dict_for_sxs_catalog_format(t, modes_dict, horizon_file_exits, # shift time axis by tpeak such that peak occurs at t = 0 dataDict = {"t": t - tpeak, "hlm": modes_dict} - if kwargs["include_zero_ecc"] or kwargs["include_params_dict"]: - params_dict = get_params_dict_from_sxs_metadata( - os.path.join(kwargs["data_dir"], "metadata.txt")) + if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], kwargs["remove_memory"]]): + if os.path.exists(os.path.join(kwargs["data_dir"], "metadata.txt")): + params_dict = get_params_dict_from_sxs_metadata( + os.path.join(kwargs["data_dir"], "metadata.txt")) + else: + params_dict = get_params_dict_from_sxs_metadata( + os.path.join(kwargs["data_dir"], "metadata.json")) # if include_zero_ecc is True, load zeroecc dataDict if kwargs["include_zero_ecc"]: params_dict_zero_ecc = params_dict.copy() @@ -1093,9 +1117,9 @@ def get_modes_dict_from_sxs_catalog_old_format(**kwargs): time = mode_data[:, 0] t = np.arange(time[0], time[-1], kwargs["deltaTOverM"]) hlm = mode_data[:, 1] + 1j * mode_data[:, 2] - amp_interp = interpolate(t, time, np.abs(hlm)) - phase_interp = interpolate(t, time, -np.unwrap(np.angle(hlm))) - hlm_interp = amp_interp * np.exp(-1j * phase_interp) + real_interp = interpolate(t, time, np.real(hlm)) + imag_interp = interpolate(t, time, np.imag(hlm)) + hlm_interp = real_interp + 1j * imag_interp modes_dict.update({(ell, m): hlm_interp}) return t, modes_dict @@ -1118,9 +1142,9 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): for mode in kwargs["mode_array"]: ell, m = mode hlm = waveform[:, waveform.index(ell, m)].data - amp_interp = interpolate(t, time, np.abs(hlm)) - phase_interp = interpolate(t, time, -np.unwrap(np.angle(hlm))) - hlm_interp = amp_interp * np.exp(-1j * phase_interp) + real_interp = interpolate(t, time, np.real(hlm)) + imag_interp = interpolate(t, time, np.imag(hlm)) + hlm_interp = real_interp + 1j * imag_interp modes_dict.update({(ell, m): hlm_interp}) return t, modes_dict @@ -1128,22 +1152,34 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): def get_params_dict_from_sxs_metadata(metadata_path): """Get binary parameters from sxs metadata file. - This file is usually located in the same directory as the waveform - file and has the name `metadata.txt`. It contains metadata related - to the NR simulation performed to obtain the waveform modes. + This file is usually located in the same directory as the waveform file and + has the name `metadata.txt` or `metadata.json`. It contains metadata + related to the NR simulation performed to obtain the waveform modes. """ - fl = open(metadata_path, "r") - lines = fl.readlines() - fl.close() - for line in lines: - if "reference-dimensionless-spin1" in line: - chi1 = [float(x.strip()) for x in line.split("=")[-1].split(",")] - if "reference-dimensionless-spin2" in line: - chi2 = [float(x.strip()) for x in line.split("=")[-1].split(",")] - if "reference-mass1" in line: - m1 = float(line.split("=")[-1].strip()) - if "reference-mass2" in line: - m2 = float(line.split("=")[-1].strip()) + if "metadata.txt" in metadata_path: + fl = open(metadata_path, "r") + lines = fl.readlines() + fl.close() + for line in lines: + if "reference-dimensionless-spin1" in line: + chi1 = [float(x.strip()) for x in line.split("=")[-1].split(",")] + if "reference-dimensionless-spin2" in line: + chi2 = [float(x.strip()) for x in line.split("=")[-1].split(",")] + if "reference-mass1" in line: + m1 = float(line.split("=")[-1].strip()) + if "reference-mass2" in line: + m2 = float(line.split("=")[-1].strip()) + if "relaxation-time" in line: + t_relax = float(line.split("=")[-1].strip()) + if "metadata.json" in metadata_path: + fl = open(metadata_path, "r") + data = json.load(fl) + fl.close() + chi1 = data["reference_dimensionless_spin1"] + chi2 = data["reference_dimensionless_spin2"] + m1 = data["reference_mass1"] + m2 = data["reference_mass2"] + t_relax = data["relaxation_time"] # numerical noise can make m1 slightly lesser than m2. Catch this whenver # it happens. Typically dq = (1 - q) is very small (dq <~ 1e-7) but for few # cases it can be dq ~ 1e-4. Therefore, if dq < 5e-4, we treat it as 1, @@ -1163,7 +1199,8 @@ def get_params_dict_from_sxs_metadata(metadata_path): f"1 - (m1/m2) = {dq} > {dq_tol}.") params_dict = {"q": q, "chi1": chi1, - "chi2": chi2} + "chi2": chi2, + "t_relax": t_relax} return params_dict From 49d2020155e4c99bb3b1a4d14b97ccfb5624c976 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Tue, 29 Oct 2024 11:09:26 +0530 Subject: [PATCH 2/9] add documentation on metadata file --- gw_eccentricity/load_data.py | 50 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 0280faf..4d01fe5 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -506,14 +506,13 @@ def get_defaults_for_nr(): metadata_path: str NOTE: Only for SXS catalog format waveform. - Path to the sxs metadata file. This file generally can be - found in the same directory as the waveform file and has the - name `metadata.txt`. It contains the metadata including binary - parameters along with other information related to the NR - simulation performed to obtain the waveform modes. - Required when `include_zero_ecc` is True. - If provided, a dictionary containing binary mass ratio and - spins is returned. + Path to the sxs metadata file. This file generally can be found in the + same directory as the waveform file and has the name `metadata.txt` or + `metadata.json`. It contains the metadata including binary parameters + along with other information related to the NR simulation performed to + obtain the waveform modes. Required when `include_zero_ecc` is True. + If provided, a dictionary containing binary mass ratio and spins is + returned. Default is None. num_orbits_to_remove_as_junk: float @@ -762,8 +761,8 @@ def load_sxs_catalogformat(**kwargs): 1. The strain file `Strain_N{extrap_order}.h5` (required) 2. The corresponding json file `Strain_N{extrap_order}.json` (required) - 3. The metadata file `metadata.txt` (required when `include_zero_ecc` - or `include_params_dict` is True) + 3. The metadata file `metadata.txt` or `metadata.json` (required when + `include_zero_ecc` or `include_params_dict` or `remove_memory` is True) 4. The horizon file `Horizons.h5` (optional) `Strain_N{extrap_order}.h5` contains the waveform extrapolated to @@ -771,9 +770,10 @@ def load_sxs_catalogformat(**kwargs): drift. This and `Strain_N{extrap_order}.json` must be provided to load waveform modes. - When `include_zero_ecc` or `include_params_dict` is True, - `metadata.txt` is required to obtain the parameters used in the NR - simulation. See more under `get_params_dict_from_sxs_metadata`. + When `include_zero_ecc` or `include_params_dict` or `remove_memory` is + True, `metadata.txt` or `metadata.json` is required to obtain the + parameters used in the NR simulation. See more under + `get_params_dict_from_sxs_metadata`. If `Horizons.h5` is provided, it is used to get a better estimate of the duration of an orbit from phase data to use it for removing junk @@ -789,10 +789,11 @@ def load_sxs_catalogformat(**kwargs): for the same set of parameters except with eccentricity set to zero. - When set to True, the function will search for the `metadata.txt` file - in the `data_dir` directory. Typically, the `metadata.txt` file is - located in the same directory as the waveform file within the sxs - catalog. The `metadata.txt` file is essential for extracting binary + When set to True, the function will search for the `metadata.txt` or + `metadata.json` file in the `data_dir` directory. Typically, the + `metadata.txt` or `metadata.json` file is located in the same directory + as the waveform file within the sxs catalog. The + `metadata.txt`/`metadata.json` file is essential for extracting binary parameters and related metadata, as it typically contains crucial information about the binary parameters and the NR simulation used to generate the waveform modes. @@ -916,9 +917,9 @@ def load_sxs_catalogformat_old(**kwargs): following files are looked for in the `data_dir` directory: 1. `rhOverM_Asymptotic_GeometricUnits_CoM.h5` (mandatory). - 2. `metadata.txt` (required when `include_zero_ecc` - or `include_params_dict` is True). For more details, see `data_dir` - under `load_sxs_catalogformat`. + 2. `metadata.txt` or `metadata.json` (required when `include_zero_ecc` or + `include_params_dict` or `remove_memory` is True). For more details, + see `data_dir` under `load_sxs_catalogformat`. 3. `Horizons.h5` (optional). For more details, see `data_dir` under `load_sxs_catalogformat`. """ @@ -960,9 +961,9 @@ def check_sxs_data_dir(origin, **kwargs): - `rhOverM_Asymptotic_GeometricUnits_CoM.h5`. These files are required to extract the waveform modes successfully. - - `metadata.txt` file to get the parameters of the NR Simulation. - This file is required when `include_zero_ecc` or `include_params_dict` - is True. + - `metadata.txt` or `metadata.json` file to get the parameters of the NR + Simulation. This file is required when `include_zero_ecc` or + `include_params_dict` or `remove_memory` is True. - `Horizons.h5` file to estimate the duration of an orbit using the orbital phase data. This file is optional. If it is not found, we use the phase of the (2, 2) mode to get the duration of an orbit assuming a phase @@ -1015,7 +1016,8 @@ def check_sxs_data_dir(origin, **kwargs): if not os.path.exists( os.path.join(kwargs["data_dir"], filename)): if filename == "metadata.txt": - # check if metadata.json exists + # In newer versions of sxs catalog, metadata.txt is replace by metadata.json. + # If metadata.txt is not found, we check if metadata.json exists if os.path.exists( os.path.join(kwargs["data_dir"], 'metadata.json')): continue From 674e8716f0ca7b86687fbc1d5079b9134e0dc072 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Tue, 29 Oct 2024 11:50:54 +0530 Subject: [PATCH 3/9] add function to remove memory --- gw_eccentricity/load_data.py | 55 ++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 4d01fe5..dc5e4ec 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -8,6 +8,7 @@ import lalsimulation as lalsim import warnings import json +import spherical_functions as sf from copy import deepcopy from .utils import peak_time_via_quadratic_fit from .utils import amplitude_using_all_modes @@ -90,8 +91,9 @@ def get_load_waveform_defaults(origin="LAL"): "zero_ecc_approximant", "num_orbits_to_remove_as_junk", "mode_array", - "extrap_order", - "remove_memory"] + "extrap_order"] + if origin == "SXSCatalog": + kwargs_list.append("remove_memory") return make_a_sub_dict(get_defaults_for_nr(), kwargs_list) # for waveforms in LVCNR format file using recommended function in LALSuite elif origin == "LVCNR": @@ -532,8 +534,7 @@ def get_defaults_for_nr(): If True, remove memory contribution from the waveform modes. This will require metadata file to find t_relax which is used to start the integration for computing memory contribution. - NOTE: This is currently implemented ony for sxs catalog formatted - waveforms. + NOTE: This is used only in the newer sxs catalog formatted waveforms """ return {"filepath": None, "data_dir": None, @@ -1099,6 +1100,41 @@ def make_return_dict_for_sxs_catalog_format(t, modes_dict, horizon_file_exits, return dataDict +def get_memory_contribution_from_sxs_catalog_format(sxs_waveform_object, t_relax): + """Get memory contribution in sxs waveform. + + The current sxs catalog format waveforms comes with memory correction. + This function estimates the memory contribution to the waveforms. It can be + used to get waveforms without the memory contribution. + + Parameters + ---------- + sxs_waveform_object: + Instance of `sxs.rpdmb.load`. + t_relax: + Relaxation time from the `metadata.json` file. This is used as the + starting time for the integration to get memory contribution from the + sxs waveforms. + + Returns + ------- + Memory contribution. + """ + # Get the memory contribution + h_sxs_mem_only = sxs.waveforms.memory.J_E( + sxs_waveform_object, + integration_start_time=t_relax) + + # NOTE: This is currently required becase the ell=0,1 modes + # get included by silly sxs when removing memory. + # So, we drop all modes before the first nonzero mode (2,-2). + # This should eventually not be required if fixed in sxs, but + # that should not break this code anyway. + h_sxs_mem_only_data = h_sxs_mem_only.data[ + :, sf.LM_index(2,-2, h_sxs_mem_only.ell_min):] + return h_sxs_mem_only_data + + def get_modes_dict_from_sxs_catalog_old_format(**kwargs): """Get modes from sxs catalog old format files. @@ -1135,6 +1171,15 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): # get the waveform object waveform = sxs.rpdmb.load( os.path.join(kwargs["data_dir"], f"Strain_N{kwargs['extrap_order']}")) + # remove memory if required + if kwargs["remove_memory"]: + params_dict = get_params_dict_from_sxs_metadata( + os.path.join(kwargs["data_dir"], "metadata.json")) + waveform_modes = ( + waveform.data + - get_memory_contribution_from_sxs_catalog_format(waveform, params_dict["t_relax"])) + else: + waveform_modes = waveform.data # get the time time = waveform.t # Create a time array with step = dt, to interpolate the waveform @@ -1143,7 +1188,7 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): modes_dict = {} for mode in kwargs["mode_array"]: ell, m = mode - hlm = waveform[:, waveform.index(ell, m)].data + hlm = waveform_modes[:, waveform.index(ell, m)] real_interp = interpolate(t, time, np.real(hlm)) imag_interp = interpolate(t, time, np.imag(hlm)) hlm_interp = real_interp + 1j * imag_interp From 561ef5d0cb8c43d48aa6f33e6993d632f93c63b9 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Tue, 29 Oct 2024 19:13:04 +0530 Subject: [PATCH 4/9] move memory removal inside mode function --- gw_eccentricity/load_data.py | 55 ++++++++++-------------------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index dc5e4ec..1fbcbdf 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -1017,8 +1017,9 @@ def check_sxs_data_dir(origin, **kwargs): if not os.path.exists( os.path.join(kwargs["data_dir"], filename)): if filename == "metadata.txt": - # In newer versions of sxs catalog, metadata.txt is replace by metadata.json. - # If metadata.txt is not found, we check if metadata.json exists + # In newer versions of sxs catalog, metadata.txt is replaced by + # metadata.json. If metadata.txt is not found, we check if + # metadata.json exists if os.path.exists( os.path.join(kwargs["data_dir"], 'metadata.json')): continue @@ -1100,41 +1101,6 @@ def make_return_dict_for_sxs_catalog_format(t, modes_dict, horizon_file_exits, return dataDict -def get_memory_contribution_from_sxs_catalog_format(sxs_waveform_object, t_relax): - """Get memory contribution in sxs waveform. - - The current sxs catalog format waveforms comes with memory correction. - This function estimates the memory contribution to the waveforms. It can be - used to get waveforms without the memory contribution. - - Parameters - ---------- - sxs_waveform_object: - Instance of `sxs.rpdmb.load`. - t_relax: - Relaxation time from the `metadata.json` file. This is used as the - starting time for the integration to get memory contribution from the - sxs waveforms. - - Returns - ------- - Memory contribution. - """ - # Get the memory contribution - h_sxs_mem_only = sxs.waveforms.memory.J_E( - sxs_waveform_object, - integration_start_time=t_relax) - - # NOTE: This is currently required becase the ell=0,1 modes - # get included by silly sxs when removing memory. - # So, we drop all modes before the first nonzero mode (2,-2). - # This should eventually not be required if fixed in sxs, but - # that should not break this code anyway. - h_sxs_mem_only_data = h_sxs_mem_only.data[ - :, sf.LM_index(2,-2, h_sxs_mem_only.ell_min):] - return h_sxs_mem_only_data - - def get_modes_dict_from_sxs_catalog_old_format(**kwargs): """Get modes from sxs catalog old format files. @@ -1175,9 +1141,18 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): if kwargs["remove_memory"]: params_dict = get_params_dict_from_sxs_metadata( os.path.join(kwargs["data_dir"], "metadata.json")) - waveform_modes = ( - waveform.data - - get_memory_contribution_from_sxs_catalog_format(waveform, params_dict["t_relax"])) + + # Get the memory contribution + waveform_mem_only = sxs.waveforms.memory.J_E( + waveform, integration_start_time=params_dict["t_relax"]) + + # NOTE: This is currently required because the ell = 0, 1 modes get + # included by silly sxs when removing memory. So, we drop all modes + # before the first nonzero mode (2, -2). This should eventually not be + # required if fixed in sxs, but that should not break this code anyway. + waveform_mem_only_data = waveform_mem_only.data[ + :, sf.LM_index(2, -2, waveform_mem_only.ell_min):] + waveform_modes = waveform.data - waveform_mem_only_data else: waveform_modes = waveform.data # get the time From 1176e8b490d9429a046337333e11af13ce47a926 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Tue, 29 Oct 2024 20:21:03 +0530 Subject: [PATCH 5/9] update doc on metadata.json --- gw_eccentricity/load_data.py | 71 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 1fbcbdf..cd04635 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -509,11 +509,13 @@ def get_defaults_for_nr(): metadata_path: str NOTE: Only for SXS catalog format waveform. Path to the sxs metadata file. This file generally can be found in the - same directory as the waveform file and has the name `metadata.txt` or - `metadata.json`. It contains the metadata including binary parameters - along with other information related to the NR simulation performed to - obtain the waveform modes. Required when `include_zero_ecc` is True. - If provided, a dictionary containing binary mass ratio and spins is + same directory as the waveform file and has the name `metadata.txt` + (for SXSCatalog_old) or `metadata.json` (for SXSCatalog). It contains + the metadata including binary parameters along with other information + related to the NR simulation performed to obtain the waveform modes. + Required when `include_zero_ecc` or `include_params_dict` or + `remove_memory` (available only for `SXSCatalog`) is True. If + provided, a dictionary containing binary mass ratio and spins is returned. Default is None. @@ -762,8 +764,8 @@ def load_sxs_catalogformat(**kwargs): 1. The strain file `Strain_N{extrap_order}.h5` (required) 2. The corresponding json file `Strain_N{extrap_order}.json` (required) - 3. The metadata file `metadata.txt` or `metadata.json` (required when - `include_zero_ecc` or `include_params_dict` or `remove_memory` is True) + 3. The metadata file `metadata.json` (required when `include_zero_ecc` + or `include_params_dict` or `remove_memory` is True) 4. The horizon file `Horizons.h5` (optional) `Strain_N{extrap_order}.h5` contains the waveform extrapolated to @@ -772,9 +774,8 @@ def load_sxs_catalogformat(**kwargs): waveform modes. When `include_zero_ecc` or `include_params_dict` or `remove_memory` is - True, `metadata.txt` or `metadata.json` is required to obtain the - parameters used in the NR simulation. See more under - `get_params_dict_from_sxs_metadata`. + True, `metadata.json` is required to obtain the parameters used in the + NR simulation. See more under `get_params_dict_from_sxs_metadata`. If `Horizons.h5` is provided, it is used to get a better estimate of the duration of an orbit from phase data to use it for removing junk @@ -790,11 +791,10 @@ def load_sxs_catalogformat(**kwargs): for the same set of parameters except with eccentricity set to zero. - When set to True, the function will search for the `metadata.txt` or - `metadata.json` file in the `data_dir` directory. Typically, the - `metadata.txt` or `metadata.json` file is located in the same directory - as the waveform file within the sxs catalog. The - `metadata.txt`/`metadata.json` file is essential for extracting binary + When set to True, the function will search for the `metadata.json` file + in the `data_dir` directory. Typically, the `metadata.json` file is + located in the same directory as the waveform file within the sxs + catalog. The `metadata.json` file is essential for extracting binary parameters and related metadata, as it typically contains crucial information about the binary parameters and the NR simulation used to generate the waveform modes. @@ -918,9 +918,11 @@ def load_sxs_catalogformat_old(**kwargs): following files are looked for in the `data_dir` directory: 1. `rhOverM_Asymptotic_GeometricUnits_CoM.h5` (mandatory). - 2. `metadata.txt` or `metadata.json` (required when `include_zero_ecc` or - `include_params_dict` or `remove_memory` is True). For more details, - see `data_dir` under `load_sxs_catalogformat`. + 2. `metadata.txt` (required when `include_zero_ecc` or + `include_params_dict` is True). For more details, see `data_dir` under + `load_sxs_catalogformat`. `metadata.txt` is required for sxs old + catalog format. In newer version it is replaced by `metadata.json` + file. 3. `Horizons.h5` (optional). For more details, see `data_dir` under `load_sxs_catalogformat`. """ @@ -963,8 +965,11 @@ def check_sxs_data_dir(origin, **kwargs): These files are required to extract the waveform modes successfully. - `metadata.txt` or `metadata.json` file to get the parameters of the NR - Simulation. This file is required when `include_zero_ecc` or - `include_params_dict` or `remove_memory` is True. + Simulation. `metadata.txt` is required for `SXSCatalog_old`. In + `SXSCatalog`, the newer format of sxs catalog, it is replaced by + `metadata.json`. This file is required when `include_zero_ecc` or + `include_params_dict` or `remove_memory` (available only for + `SXSCatalog`) is True. - `Horizons.h5` file to estimate the duration of an orbit using the orbital phase data. This file is optional. If it is not found, we use the phase of the (2, 2) mode to get the duration of an orbit assuming a phase @@ -1006,29 +1011,23 @@ def check_sxs_data_dir(origin, **kwargs): "If you are using the new format, You should provide the h5 and json " f"file named `Strain_N{kwargs['extrap_order']}` since `extrap_order` " f"is {kwargs['extrap_order']}."} - # metadata.txt/metadata.json is required if include_zero_ecc or include_params_dict - # or remove_memory is True if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], kwargs["remove_memory"]]): + # In newer versions of sxscatalog format, metadata.txt files are + # replaced by metadata.json file. + required_metadata_file = "metadata.json" if origin == "SXSCatalog" else "metadata.txt" for k in required_files_dict: required_files_dict.update( - {k: np.append(required_files_dict[k], ["metadata.txt"])}) + {k: np.append(required_files_dict[k], [required_metadata_file])}) # Check if all the required files exist for filename in required_files_dict[origin]: if not os.path.exists( os.path.join(kwargs["data_dir"], filename)): - if filename == "metadata.txt": - # In newer versions of sxs catalog, metadata.txt is replaced by - # metadata.json. If metadata.txt is not found, we check if - # metadata.json exists - if os.path.exists( - os.path.join(kwargs["data_dir"], 'metadata.json')): - continue - else: - message = ( - " `metadata.txt` or `metadata.json` file is required when " - "`include_zero_ecc` or `include_params_dict` or `remove_memory` " - "is set to True to get the binary parameters of " - "the NR simulation.") + if "metadata" in filename: + message = ( + f" {required_metadata_file} file is required when " + "`include_zero_ecc` or `include_params_dict` or `remove_memory` " + "is set to True to get the binary parameters of " + "the NR simulation.") else: message = message_dict[origin] raise FileNotFoundError( From c64d825df85d7df74725dc1383ca3c9ccd648864 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Wed, 30 Oct 2024 11:37:49 +0530 Subject: [PATCH 6/9] polishing --- gw_eccentricity/load_data.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index cd04635..62233a1 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -93,6 +93,9 @@ def get_load_waveform_defaults(origin="LAL"): "mode_array", "extrap_order"] if origin == "SXSCatalog": + # SXS waveforms in the new catalog format comes with memory + # correction. We can use the following kwarg to remove memory if + # needed kwargs_list.append("remove_memory") return make_a_sub_dict(get_defaults_for_nr(), kwargs_list) # for waveforms in LVCNR format file using recommended function in LALSuite @@ -515,8 +518,8 @@ def get_defaults_for_nr(): related to the NR simulation performed to obtain the waveform modes. Required when `include_zero_ecc` or `include_params_dict` or `remove_memory` (available only for `SXSCatalog`) is True. If - provided, a dictionary containing binary mass ratio and spins is - returned. + provided, a dictionary containing binary mass ratio, spins and the + relaxation time is returned. Default is None. num_orbits_to_remove_as_junk: float @@ -533,10 +536,12 @@ def get_defaults_for_nr(): NOTE: This is used only for sxs catalog formatted waveforms. remove_memory: bool - If True, remove memory contribution from the waveform modes. - This will require metadata file to find t_relax which is used - to start the integration for computing memory contribution. - NOTE: This is used only in the newer sxs catalog formatted waveforms + If True, remove memory contribution from the waveform modes. This will + require metadata file to find t_relax which is used to start the + integration for computing memory contribution. NOTE: This can be used + only in the newer sxs catalog formatted waveforms with + origin=`SXSCatalog` + Default is False. """ return {"filepath": None, "data_dir": None, @@ -921,8 +926,8 @@ def load_sxs_catalogformat_old(**kwargs): 2. `metadata.txt` (required when `include_zero_ecc` or `include_params_dict` is True). For more details, see `data_dir` under `load_sxs_catalogformat`. `metadata.txt` is required for sxs old - catalog format. In newer version it is replaced by `metadata.json` - file. + catalog format. This file contains the same information as found in + `metadata.json` in the newer sxs catalog format (origin=`SXSCatalog`). 3. `Horizons.h5` (optional). For more details, see `data_dir` under `load_sxs_catalogformat`. """ @@ -1138,6 +1143,9 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): os.path.join(kwargs["data_dir"], f"Strain_N{kwargs['extrap_order']}")) # remove memory if required if kwargs["remove_memory"]: + # Get parameters from the metadata file. We need the relaxation time + # `t_relax` to use as the starting time for the integration to compute + # the memory contribution params_dict = get_params_dict_from_sxs_metadata( os.path.join(kwargs["data_dir"], "metadata.json")) @@ -1151,6 +1159,7 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): # required if fixed in sxs, but that should not break this code anyway. waveform_mem_only_data = waveform_mem_only.data[ :, sf.LM_index(2, -2, waveform_mem_only.ell_min):] + # Get waveform modes without the memory waveform_modes = waveform.data - waveform_mem_only_data else: waveform_modes = waveform.data From 65a2204e6673465c6d185c0d0b7e981b78c6f1d7 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Wed, 30 Oct 2024 21:14:57 +0530 Subject: [PATCH 7/9] remove t_relax from zeroecc_params dict --- gw_eccentricity/load_data.py | 2 ++ gw_eccentricity/plot_settings.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 62233a1..148a233 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -1091,6 +1091,8 @@ def make_return_dict_for_sxs_catalog_format(t, modes_dict, horizon_file_exits, # if include_zero_ecc is True, load zeroecc dataDict if kwargs["include_zero_ecc"]: params_dict_zero_ecc = params_dict.copy() + # remove t_relax from the params dict + params_dict_zero_ecc.pop("t_relax", None) # provide the approximant to be used for zero eccentricity waveform params_dict_zero_ecc.update( {"approximant": kwargs["zero_ecc_approximant"], diff --git a/gw_eccentricity/plot_settings.py b/gw_eccentricity/plot_settings.py index dbc9ab3..4447a3c 100644 --- a/gw_eccentricity/plot_settings.py +++ b/gw_eccentricity/plot_settings.py @@ -205,5 +205,7 @@ def use_fancy_plotsettings(usetex=True, style="Notebook"): "res_omega_gw_dimless": r"$\Delta\omega_{\mathrm{gw}}$ [rad/$M$]", "res_amp_gw": r"$\Delta A_{\mathrm{gw}}$", "omega22_copr_symm": r"$\omega_{22}^{\mathrm{copr, sym}}$", - "amp22_copr_symm": r"$A_{22}^{\mathrm{copr, sym}}$" + "amp22_copr_symm": r"$A_{22}^{\mathrm{copr, sym}}$", + "res_omega22_copr_symm": r"$\Delta \omega_{22}^{\mathrm{copr, sym}}$", + "res_amp22_copr_symm": r"$\Delta A_{22}^{\mathrm{copr, sym}}$" } From 38b52a1aa42c0540d64fbb4e6bb0d70e14709de0 Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Sat, 2 Nov 2024 11:12:44 +0530 Subject: [PATCH 8/9] remove_memory -> keep memory #224 --- gw_eccentricity/load_data.py | 55 ++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index 148a233..ee38b31 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -94,9 +94,10 @@ def get_load_waveform_defaults(origin="LAL"): "extrap_order"] if origin == "SXSCatalog": # SXS waveforms in the new catalog format comes with memory - # correction. We can use the following kwarg to remove memory if - # needed - kwargs_list.append("remove_memory") + # correction. By default we remove this memory correction from the + # waveform modes for measuring eccentricity. One can opt to keep + # memory using the following kwarg. + kwargs_list.append("keep_memory") return make_a_sub_dict(get_defaults_for_nr(), kwargs_list) # for waveforms in LVCNR format file using recommended function in LALSuite elif origin == "LVCNR": @@ -517,7 +518,7 @@ def get_defaults_for_nr(): the metadata including binary parameters along with other information related to the NR simulation performed to obtain the waveform modes. Required when `include_zero_ecc` or `include_params_dict` or - `remove_memory` (available only for `SXSCatalog`) is True. If + `keep_memory` (available only for `SXSCatalog`) is False. If provided, a dictionary containing binary mass ratio, spins and the relaxation time is returned. Default is None. @@ -535,8 +536,8 @@ def get_defaults_for_nr(): Extrapolation order to use for loading the waveform data. NOTE: This is used only for sxs catalog formatted waveforms. - remove_memory: bool - If True, remove memory contribution from the waveform modes. This will + keep_memory: bool + If False, remove memory contribution from the waveform modes. This will require metadata file to find t_relax which is used to start the integration for computing memory contribution. NOTE: This can be used only in the newer sxs catalog formatted waveforms with @@ -554,7 +555,7 @@ def get_defaults_for_nr(): "num_orbits_to_remove_as_junk": 2, "mode_array": [(2, 2)], "extrap_order": 2, - "remove_memory": False} + "keep_memory": False} def load_lvcnr_waveform(**kwargs): @@ -770,7 +771,7 @@ def load_sxs_catalogformat(**kwargs): 1. The strain file `Strain_N{extrap_order}.h5` (required) 2. The corresponding json file `Strain_N{extrap_order}.json` (required) 3. The metadata file `metadata.json` (required when `include_zero_ecc` - or `include_params_dict` or `remove_memory` is True) + or `include_params_dict` is True or `keep_memory` is False) 4. The horizon file `Horizons.h5` (optional) `Strain_N{extrap_order}.h5` contains the waveform extrapolated to @@ -778,9 +779,10 @@ def load_sxs_catalogformat(**kwargs): drift. This and `Strain_N{extrap_order}.json` must be provided to load waveform modes. - When `include_zero_ecc` or `include_params_dict` or `remove_memory` is - True, `metadata.json` is required to obtain the parameters used in the - NR simulation. See more under `get_params_dict_from_sxs_metadata`. + When `include_zero_ecc` or `include_params_dict` is True or + `keep_memory` is False, `metadata.json` is required to obtain the + parameters used in the NR simulation. See more under + `get_params_dict_from_sxs_metadata`. If `Horizons.h5` is provided, it is used to get a better estimate of the duration of an orbit from phase data to use it for removing junk @@ -841,8 +843,8 @@ def load_sxs_catalogformat(**kwargs): to locate the strain file. This function will seek a file named `Strain_N{extrap_order}.h5` in the `data_dir`. - remove_memory: bool - If True, remove memory contribution from the waveform modes. + keep_memory: bool + If False, remove memory contribution from the waveform modes. This will require metadata file to find t_relax which is used to start the integration for computing memory contribution. @@ -973,8 +975,8 @@ def check_sxs_data_dir(origin, **kwargs): Simulation. `metadata.txt` is required for `SXSCatalog_old`. In `SXSCatalog`, the newer format of sxs catalog, it is replaced by `metadata.json`. This file is required when `include_zero_ecc` or - `include_params_dict` or `remove_memory` (available only for - `SXSCatalog`) is True. + `include_params_dict` is True or `keep_memory` (available only + for `SXSCatalog`) is False. - `Horizons.h5` file to estimate the duration of an orbit using the orbital phase data. This file is optional. If it is not found, we use the phase of the (2, 2) mode to get the duration of an orbit assuming a phase @@ -1016,7 +1018,8 @@ def check_sxs_data_dir(origin, **kwargs): "If you are using the new format, You should provide the h5 and json " f"file named `Strain_N{kwargs['extrap_order']}` since `extrap_order` " f"is {kwargs['extrap_order']}."} - if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], kwargs["remove_memory"]]): + if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], + not kwargs["keep_memory"]]): # In newer versions of sxscatalog format, metadata.txt files are # replaced by metadata.json file. required_metadata_file = "metadata.json" if origin == "SXSCatalog" else "metadata.txt" @@ -1030,9 +1033,9 @@ def check_sxs_data_dir(origin, **kwargs): if "metadata" in filename: message = ( f" {required_metadata_file} file is required when " - "`include_zero_ecc` or `include_params_dict` or `remove_memory` " - "is set to True to get the binary parameters of " - "the NR simulation.") + "`include_zero_ecc` or `include_params_dict` is True or " + "`keep_memory` is set to False to get the binary " + "parameters of the NR simulation.") else: message = message_dict[origin] raise FileNotFoundError( @@ -1081,7 +1084,8 @@ def make_return_dict_for_sxs_catalog_format(t, modes_dict, horizon_file_exits, # shift time axis by tpeak such that peak occurs at t = 0 dataDict = {"t": t - tpeak, "hlm": modes_dict} - if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], kwargs["remove_memory"]]): + if any([kwargs["include_zero_ecc"], kwargs["include_params_dict"], + not kwargs["keep_memory"]]): if os.path.exists(os.path.join(kwargs["data_dir"], "metadata.txt")): params_dict = get_params_dict_from_sxs_metadata( os.path.join(kwargs["data_dir"], "metadata.txt")) @@ -1141,10 +1145,13 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): default values. """ # get the waveform object - waveform = sxs.rpdmb.load( + waveform = sxs.load( os.path.join(kwargs["data_dir"], f"Strain_N{kwargs['extrap_order']}")) - # remove memory if required - if kwargs["remove_memory"]: + + if kwargs["keep_memory"]: + waveform_modes = waveform.data + else: + # remove memory contribution. # Get parameters from the metadata file. We need the relaxation time # `t_relax` to use as the starting time for the integration to compute # the memory contribution @@ -1163,8 +1170,6 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): :, sf.LM_index(2, -2, waveform_mem_only.ell_min):] # Get waveform modes without the memory waveform_modes = waveform.data - waveform_mem_only_data - else: - waveform_modes = waveform.data # get the time time = waveform.t # Create a time array with step = dt, to interpolate the waveform From 5b8405b0aac7f7010adf4ee275d0fc33271e03ea Mon Sep 17 00:00:00 2001 From: md-arif-shaikh Date: Sun, 3 Nov 2024 12:59:00 +0530 Subject: [PATCH 9/9] add comments on interpolating re and im --- gw_eccentricity/load_data.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gw_eccentricity/load_data.py b/gw_eccentricity/load_data.py index ee38b31..804874c 100644 --- a/gw_eccentricity/load_data.py +++ b/gw_eccentricity/load_data.py @@ -1131,6 +1131,9 @@ def get_modes_dict_from_sxs_catalog_old_format(**kwargs): time = mode_data[:, 0] t = np.arange(time[0], time[-1], kwargs["deltaTOverM"]) hlm = mode_data[:, 1] + 1j * mode_data[:, 2] + # See comments under `get_modes_dict_from_sxs_catalog_format` on why we + # interpolate real and imaginary parts instead of the amplitude and + # phase. real_interp = interpolate(t, time, np.real(hlm)) imag_interp = interpolate(t, time, np.imag(hlm)) hlm_interp = real_interp + 1j * imag_interp @@ -1179,6 +1182,14 @@ def get_modes_dict_from_sxs_catalog_format(**kwargs): for mode in kwargs["mode_array"]: ell, m = mode hlm = waveform_modes[:, waveform.index(ell, m)] + # NOTE: We interpolate the real and imaginary parts of the modes, + # instead of interpolating the amplitude and phase. We noticed that for + # systems with high eccentricity and extreme precession, interpolating + # amplitude and phase over smaller deltaTOverM values introduces + # artificial spikes in the frequency that are absent in the original + # data. These spikes become more pronounced as the spline order + # increases. In contrast, interpolating the real and imaginary parts + # avoids these issues. real_interp = interpolate(t, time, np.real(hlm)) imag_interp = interpolate(t, time, np.imag(hlm)) hlm_interp = real_interp + 1j * imag_interp