From 408072568aab2ebea18d2b19fbf79a8a29788a7c Mon Sep 17 00:00:00 2001 From: Alexander Carpenter Date: Thu, 16 Jan 2025 20:15:02 -0500 Subject: [PATCH] Clean up ringdown script --- src/Evolution/Ringdown/Python/Bindings.cpp | 2 +- src/Evolution/Ringdown/Python/CMakeLists.txt | 1 - ...ComputeAhCCoefsInRingdownDistortedFrame.py | 23 ++-- .../Python/FunctionsOfTimeFromVolume.py | 63 --------- ...ahlkorperCoefsInRingdownDistortedFrame.cpp | 47 +++++-- ...ahlkorperCoefsInRingdownDistortedFrame.hpp | 11 +- src/IO/H5/Python/CMakeLists.txt | 1 + src/IO/H5/Python/FunctionsOfTimeFromVolume.py | 64 ++++++++++ support/Pipelines/Bbh/Ringdown.py | 120 +++++++++--------- support/Pipelines/Bbh/Ringdown.yaml | 15 +-- ...ComputeAhCCoefsInRingdownDistortedFrame.py | 13 +- tests/Unit/IO/H5/Python/CMakeLists.txt | 6 + .../Python/Test_FunctionsOfTimeFromVolume.py | 119 +++++++++++++++++ 13 files changed, 314 insertions(+), 171 deletions(-) delete mode 100644 src/Evolution/Ringdown/Python/FunctionsOfTimeFromVolume.py create mode 100644 src/IO/H5/Python/FunctionsOfTimeFromVolume.py create mode 100644 tests/Unit/IO/H5/Python/Test_FunctionsOfTimeFromVolume.py diff --git a/src/Evolution/Ringdown/Python/Bindings.cpp b/src/Evolution/Ringdown/Python/Bindings.cpp index f79df52dc805..4861f536ada7 100644 --- a/src/Evolution/Ringdown/Python/Bindings.cpp +++ b/src/Evolution/Ringdown/Python/Bindings.cpp @@ -30,7 +30,7 @@ void bind_strahlkorper_coefs_in_ringdown_distorted_frame(py::module& m) { py::arg("requested_number_of_times_from_end"), py::arg("match_time"), py::arg("settling_timescale"), py::arg("exp_func_and_2_derivs"), py::arg("exp_outer_bdry_func_and_2_derivs"), - py::arg("rot_func_and_2_derivs")); + py::arg("rot_func_and_2_derivs"), py::arg("trans_func_and_2_derivs")); } } // namespace evolution::Ringdown::py_bindings diff --git a/src/Evolution/Ringdown/Python/CMakeLists.txt b/src/Evolution/Ringdown/Python/CMakeLists.txt index 556bbee0ab8b..1178a104c3bb 100644 --- a/src/Evolution/Ringdown/Python/CMakeLists.txt +++ b/src/Evolution/Ringdown/Python/CMakeLists.txt @@ -12,7 +12,6 @@ spectre_python_add_module( PYTHON_FILES __init__.py ComputeAhCCoefsInRingdownDistortedFrame.py - FunctionsOfTimeFromVolume.py ) spectre_python_headers( diff --git a/src/Evolution/Ringdown/Python/ComputeAhCCoefsInRingdownDistortedFrame.py b/src/Evolution/Ringdown/Python/ComputeAhCCoefsInRingdownDistortedFrame.py index e96d461e3976..2b3b72f07dc8 100644 --- a/src/Evolution/Ringdown/Python/ComputeAhCCoefsInRingdownDistortedFrame.py +++ b/src/Evolution/Ringdown/Python/ComputeAhCCoefsInRingdownDistortedFrame.py @@ -70,9 +70,7 @@ def fit_to_a_cubic(times, coefs, match_time, zero_coefs_eps): def compute_ahc_coefs_in_ringdown_distorted_frame( ahc_reductions_path, ahc_subfile, - exp_func_and_2_derivs, - exp_outer_bdry_func_and_2_derivs, - rot_func_and_2_derivs, + evaluated_fot_dict, number_of_ahc_finds_for_fit, match_time, settling_timescale, @@ -119,9 +117,10 @@ def compute_ahc_coefs_in_ringdown_distorted_frame( number_of_ahc_finds_for_fit, match_time, settling_timescale, - exp_func_and_2_derivs, - exp_outer_bdry_func_and_2_derivs, - rot_func_and_2_derivs, + evaluated_fot_dict["Expansion"], + evaluated_fot_dict["ExpansionOuterBoundary"], + evaluated_fot_dict["Rotation"], + None, ) ) @@ -151,24 +150,24 @@ def compute_ahc_coefs_in_ringdown_distorted_frame( -number_of_ahc_finds_for_fit: ] - logger.info("AhC times available: " + str(ahc_times.shape[0])) - logger.info( + logger.debug("AhC times available: " + str(ahc_times.shape[0])) + logger.debug( "AhC available time range: " + str(np.min(ahc_times)) + " - " + str(np.max(ahc_times)) ) - logger.info("AhC times used: " + str(ahc_times_for_fit.shape[0])) - logger.info( + logger.debug("AhC times used: " + str(ahc_times_for_fit.shape[0])) + logger.debug( "AhC used time range: " + str(np.min(ahc_times_for_fit)) + " - " + str(np.max(ahc_times_for_fit)) ) - logger.info( + logger.debug( "Coef times available: " + str(coefs_at_different_times.shape[0]) ) - logger.info( + logger.debug( "Coef times used: " + str(coefs_at_different_times_for_fit.shape[0]) ) diff --git a/src/Evolution/Ringdown/Python/FunctionsOfTimeFromVolume.py b/src/Evolution/Ringdown/Python/FunctionsOfTimeFromVolume.py deleted file mode 100644 index a64fc28d4869..000000000000 --- a/src/Evolution/Ringdown/Python/FunctionsOfTimeFromVolume.py +++ /dev/null @@ -1,63 +0,0 @@ -# Distributed under the MIT License. -# See LICENSE.txt for details. - -import logging -from pathlib import Path -from typing import Optional, Union - -import click -import numpy as np -import yaml -from rich.pretty import pretty_repr - -import spectre.IO.H5 as spectre_h5 -from spectre.Domain import deserialize_functions_of_time - -logger = logging.getLogger(__name__) - - -# Transform AhC coefs to ringdown distorted frame and get other data -# needed to start a ringdown, such as initial values for functions of time -def functions_of_time_from_volume( - fot_vol_h5_path, fot_vol_subfile, match_time, which_obs_id -): - exp_func_and_2_derivs = [] - exp_outer_bdry_func_and_2_derivs = [] - rot_func_and_2_derivs = [] - - with spectre_h5.H5File(fot_vol_h5_path, "r") as h5file: - if fot_vol_subfile.split(".")[-1] == "vol": - fot_vol_subfile = fot_vol_subfile.split(".")[0] - volfile = h5file.get_vol("/" + fot_vol_subfile) - obs_ids = volfile.list_observation_ids() - logger.info("About to deserialize functions of time") - fot_times = list(map(volfile.get_observation_value, obs_ids)) - serialized_fots = volfile.get_functions_of_time(obs_ids[which_obs_id]) - functions_of_time = deserialize_functions_of_time(serialized_fots) - logger.info("Deserialized functions of time") - - # The inspiral expansion map includes two functions of time: - # an expansion map allowing the black holes to move closer together in - # comoving coordinates, and an expansion map causing the outer boundary - # to move slightly inwards. The ringdown only requires the outer - # boundary expansion map, so set the other map to the identity. - exp_func_and_2_derivs = [1.0, 0.0, 0.0] - - exp_outer_bdry_func_and_2_derivs = [ - x[0] - for x in functions_of_time[ - "ExpansionOuterBoundary" - ].func_and_2_derivs(fot_times[which_obs_id]) - ] - rot_func_and_2_derivs_tuple = functions_of_time[ - "Rotation" - ].func_and_2_derivs(fot_times[which_obs_id]) - rot_func_and_2_derivs = [ - [coef for coef in x] for x in rot_func_and_2_derivs_tuple - ] - - return ( - exp_func_and_2_derivs, - exp_outer_bdry_func_and_2_derivs, - rot_func_and_2_derivs, - ) diff --git a/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.cpp b/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.cpp index bc25619cf100..f87535940c27 100644 --- a/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.cpp +++ b/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.cpp @@ -26,9 +26,13 @@ std::vector strahlkorper_coefs_in_ringdown_distorted_frame( const std::string& surface_subfile_name, const size_t requested_number_of_times_from_end, const double match_time, const double settling_timescale, - const std::array& exp_func_and_2_derivs, - const std::array& exp_outer_bdry_func_and_2_derivs, - const std::vector>& rot_func_and_2_derivs) { + const std::optional>& exp_func_and_2_derivs, + const std::optional>& + exp_outer_bdry_func_and_2_derivs, + const std::optional>>& + rot_func_and_2_derivs, + const std::optional, 3>>& + trans_func_and_2_derivs) { // Read the AhC coefficients from the H5 file const std::vector>& ahc_inertial_h5 = ylm::read_surface_ylm( @@ -49,16 +53,35 @@ std::vector strahlkorper_coefs_in_ringdown_distorted_frame( // Create a time-dependent domain; only the the time-dependent map options // matter; the domain is just a spherical shell with inner and outer // radii chosen so any conceivable common horizon will fit between them. - const domain::creators::time_dependent_options::ExpansionMapOptions - expansion_map_options{exp_func_and_2_derivs, settling_timescale, - exp_outer_bdry_func_and_2_derivs, - settling_timescale}; - const domain::creators::time_dependent_options::RotationMapOptions - rotation_map_options{rot_func_and_2_derivs, settling_timescale}; + const auto expansion_map_options = + exp_func_and_2_derivs.has_value() + ? domain::creators::time_dependent_options:: + ExpansionMapOptions{exp_func_and_2_derivs.value(), + settling_timescale, + exp_outer_bdry_func_and_2_derivs.value(), + settling_timescale} + : std::optional>{}; + const auto rotation_map_options = + rot_func_and_2_derivs.has_value() + ? domain::creators::time_dependent_options:: + RotationMapOptions{rot_func_and_2_derivs.value(), + settling_timescale} + : std::optional>{}; + const auto translation_map_options = + trans_func_and_2_derivs.has_value() + ? domain::creators::sphere::TimeDependentMapOptions:: + TranslationMapOptions{trans_func_and_2_derivs.value()} + : std::optional{}; const domain::creators::sphere::TimeDependentMapOptions - time_dependent_map_options{match_time, std::nullopt, - rotation_map_options, expansion_map_options, - std::nullopt, true}; + time_dependent_map_options{match_time, + std::nullopt, + rotation_map_options, + expansion_map_options, + translation_map_options, + true}; const domain::creators::Sphere domain_creator{ 0.01, 200.0, diff --git a/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.hpp b/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.hpp index ea6c83b7d109..04a63281ff4f 100644 --- a/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.hpp +++ b/src/Evolution/Ringdown/StrahlkorperCoefsInRingdownDistortedFrame.hpp @@ -37,7 +37,12 @@ std::vector strahlkorper_coefs_in_ringdown_distorted_frame( const std::string& surface_subfile_name, size_t requested_number_of_times_from_end, double match_time, double settling_timescale, - const std::array& exp_func_and_2_derivs, - const std::array& exp_outer_bdry_func_and_2_derivs, - const std::vector>& rot_func_and_2_derivs); + const std::optional>& exp_func_and_2_derivs = + std::nullopt, + const std::optional>& + exp_outer_bdry_func_and_2_derivs = std::nullopt, + const std::optional>>& + rot_func_and_2_derivs = std::nullopt, + const std::optional, 3>>& + trans_func_and_2_derivs = std::nullopt); } // namespace evolution::Ringdown diff --git a/src/IO/H5/Python/CMakeLists.txt b/src/IO/H5/Python/CMakeLists.txt index 63664919aa4c..553e7f2a9d86 100644 --- a/src/IO/H5/Python/CMakeLists.txt +++ b/src/IO/H5/Python/CMakeLists.txt @@ -22,6 +22,7 @@ spectre_python_add_module( ExtendConnectivityData.py ExtractDatFromH5.py ExtractInputSourceYamlFromH5.py + FunctionsOfTimeFromVolume.py IterElements.py MODULE_PATH "IO" ) diff --git a/src/IO/H5/Python/FunctionsOfTimeFromVolume.py b/src/IO/H5/Python/FunctionsOfTimeFromVolume.py new file mode 100644 index 000000000000..614792eedcfb --- /dev/null +++ b/src/IO/H5/Python/FunctionsOfTimeFromVolume.py @@ -0,0 +1,64 @@ +# Distributed under the MIT License. +# See LICENSE.txt for details. + +import logging +from pathlib import Path +from typing import Optional, Union + +import click +import numpy as np +import yaml +from rich.pretty import pretty_repr + +import spectre.IO.H5 as spectre_h5 +from spectre.Domain import deserialize_functions_of_time + +logger = logging.getLogger(__name__) + + +def functions_of_time_from_volume( + fot_vol_h5_path, fot_vol_subfile, match_time, fot_to_observe=None +): + """This function returns a dictionary of the FunctionsOfTime from a volume + h5 file evaluated at a desired time along with the time closest to the + match_time passed in. + + Arguments: + fot_vol_h5_path: The full path to volume data containing functions of time + that have been evaluated at the match time. + fot_vol_subfile: The subfile containing volume data with functions of time + evaulated at match time. + match_time: The desired time to retrieve the function of time values. + """ + + functions_of_time_at_match_time_dict = {} + + with spectre_h5.H5File(fot_vol_h5_path, "r") as h5file: + if fot_vol_subfile.split(".")[-1] == "vol": + fot_vol_subfile = fot_vol_subfile.split(".")[0] + volfile = h5file.get_vol("/" + fot_vol_subfile) + obs_ids = volfile.list_observation_ids() + fot_times = np.array(list(map(volfile.get_observation_value, obs_ids))) + which_obs_id = np.argmin(np.abs(fot_times - match_time)) + serialized_fots = volfile.get_functions_of_time(obs_ids[which_obs_id]) + functions_of_time = deserialize_functions_of_time(serialized_fots) + logger.debug("Desired match time: " + str(match_time)) + logger.debug("Selected ObservationID: " + str(which_obs_id)) + logger.debug("Selected match time: " + str(fot_times[which_obs_id])) + + functions_of_time_at_match_time_dict["MatchTime"] = fot_times[ + which_obs_id + ] + + for fot_name, fot in functions_of_time.items(): + fot_at_match_time = fot.func_and_2_derivs(fot_times[which_obs_id]) + if len(fot_at_match_time[0]) != 1: + functions_of_time_at_match_time_dict[fot_name] = [ + [coef for coef in x] for x in fot_at_match_time + ] + else: + functions_of_time_at_match_time_dict[fot_name] = [ + x[0] for x in fot_at_match_time + ] + + return functions_of_time_at_match_time_dict diff --git a/support/Pipelines/Bbh/Ringdown.py b/support/Pipelines/Bbh/Ringdown.py index 4d28a494d71d..42e70ee42c80 100644 --- a/support/Pipelines/Bbh/Ringdown.py +++ b/support/Pipelines/Bbh/Ringdown.py @@ -16,7 +16,7 @@ ) # next import out of order to avoid Unrecognized PUP::able::PUP_ID error -from spectre.Evolution.Ringdown.FunctionsOfTimeFromVolume import ( +from spectre.IO.H5.FunctionsOfTimeFromVolume import ( functions_of_time_from_volume, ) from spectre.support.Schedule import schedule, scheduler_options @@ -117,8 +117,8 @@ def start_ringdown( fot_vol_h5_path: The full path to any volume data containing the functions of time at the time of AhC finds, defaults to BbhVolume0.h5 in the inspiral_run_dir. - fot_vol_subfile: Subfile containing volume data where at times of AhC - finds, defaults to 'ForContinuation'. + fot_vol_subfile: Subfile containing volume data at times of AhC finds, + defaults to 'ForContinuation'. path_to_output_h5: H5 file to output horizon coefficients needed for Ringdown. output_subfile_prefix: Subfile prefix for output data, defaults to @@ -163,37 +163,41 @@ def start_ringdown( polynomial_order=polynomial_order, ) - # Compute ringdown shape coefficients and function of time info - # for ringdown - with spectre_h5.H5File(str(fot_vol_h5_path), "r") as h5file: - if fot_vol_subfile.split(".")[-1] == "vol": - fot_vol_subfile = fot_vol_subfile.split(".")[0] - volfile = h5file.get_vol("/" + fot_vol_subfile) - obs_ids = volfile.list_observation_ids() - fot_times = np.array(list(map(volfile.get_observation_value, obs_ids))) - which_obs_id = np.argmin(np.abs(fot_times - match_time)) - - logger.info("Desired match time: " + str(match_time)) - logger.info("Selected ObservationID: " + str(which_obs_id)) - logger.info("Selected match time: " + str(fot_times[which_obs_id])) - - match_time = fot_times[which_obs_id] - - ( - expansion_func_with_2_derivs, - expansion_func_outer_boundary_with_2_derivs, - rotation_func_with_2_derivs, - ) = functions_of_time_from_volume( - str(fot_vol_h5_path), fot_vol_subfile, match_time, which_obs_id + evaluated_fot_dict = functions_of_time_from_volume( + str(fot_vol_h5_path), fot_vol_subfile, match_time ) + match_time = evaluated_fot_dict["MatchTime"] + + # This section checks for functions of time in the dictionary. It also + # alters some values in the evaluated functions of time dictionary. The + # ringdown only requires the outer boundary expansion map so here we set the + # inner expansion map to the identity (this should be changed to a settle to + # const at a later time). We also set the translation map to 0 since + # translation is not supported in the transition to ringdown yet. + if "ExpansionOuterBoundary" not in evaluated_fot_dict: + raise ValueError( + f"The transition to ringdown script requires the " + f" ExpansionOuterBoundary functions of time to be valid at the" + f" match time. " + ) + if "Rotation" not in evaluated_fot_dict: + evaluated_fot_dict["Rotation"] = [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ] + evaluated_fot_dict["Expansion"] = [1.0, 0.0, 0.0] + evaluated_fot_dict["Translation"] = [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ] ringdown_ylm_coefs, ringdown_ylm_legend = ( compute_ahc_coefs_in_ringdown_distorted_frame( str(ahc_reductions_path), ahc_subfile, - expansion_func_with_2_derivs, - expansion_func_outer_boundary_with_2_derivs, - rotation_func_with_2_derivs, + evaluated_fot_dict, number_of_ahc_finds_for_fit, match_time, settling_timescale, @@ -227,42 +231,38 @@ def start_ringdown( version=0, ) ahc_dt2_datfile.append(ringdown_ylm_coefs[2]) - logger.info("Obtained ringdown coefs") + logger.debug("Obtained ringdown coefs") # Print out coefficients for insertion into BBH domain - logger.info("Expansion: " + str(expansion_func_with_2_derivs)) - logger.info( - "ExpansionOutrBdry: " + str(expansion_func_outer_boundary_with_2_derivs) + logger.debug("Expansion: " + str(evaluated_fot_dict["Expansion"])) + logger.debug( + "ExpansionOutrBdry: " + + str(evaluated_fot_dict["ExpansionOuterBoundary"]) ) - logger.info("Rotation: " + str(rotation_func_with_2_derivs)) - logger.info("Match time: " + str(match_time)) - logger.info("Settling timescale: " + str(settling_timescale)) - logger.info("Lmax: " + str(int(ringdown_ylm_coefs[0][4]))) + logger.debug("Rotation: " + str(evaluated_fot_dict["Rotation"])) + logger.debug("Match time: " + str(match_time)) + logger.debug("Settling timescale: " + str(settling_timescale)) + logger.debug("Lmax: " + str(int(ringdown_ylm_coefs[0][4]))) ringdown_params["MatchTime"] = match_time ringdown_params["ShapeMapLMax"] = int(ringdown_ylm_coefs[0][4]) ringdown_params["PathToAhCCoefsH5File"] = path_to_output_h5 ringdown_params["AhCCoefsSubfilePrefix"] = output_subfile_prefix - ringdown_params["Rotation0"] = rotation_func_with_2_derivs[0][0] - ringdown_params["Rotation1"] = rotation_func_with_2_derivs[0][1] - ringdown_params["Rotation2"] = rotation_func_with_2_derivs[0][2] - ringdown_params["Rotation3"] = rotation_func_with_2_derivs[0][3] - ringdown_params["dtRotation0"] = rotation_func_with_2_derivs[1][0] - ringdown_params["dtRotation1"] = rotation_func_with_2_derivs[1][1] - ringdown_params["dtRotation2"] = rotation_func_with_2_derivs[1][2] - ringdown_params["dtRotation3"] = rotation_func_with_2_derivs[1][3] - ringdown_params["dt2Rotation0"] = rotation_func_with_2_derivs[2][0] - ringdown_params["dt2Rotation1"] = rotation_func_with_2_derivs[2][1] - ringdown_params["dt2Rotation2"] = rotation_func_with_2_derivs[2][2] - ringdown_params["dt2Rotation3"] = rotation_func_with_2_derivs[2][3] - ringdown_params["ExpansionOuterBdry"] = ( - expansion_func_outer_boundary_with_2_derivs[0] - ) - ringdown_params["dtExpansionOuterBdry"] = ( - expansion_func_outer_boundary_with_2_derivs[1] - ) - ringdown_params["dt2ExpansionOuterBdry"] = ( - expansion_func_outer_boundary_with_2_derivs[2] - ) + ringdown_params["Rotation"] = yaml.safe_dump( + evaluated_fot_dict["Rotation"], + default_flow_style=True, + width=float("inf"), + ).strip() + ringdown_params["ExpansionOuterBdry"] = yaml.safe_dump( + evaluated_fot_dict["ExpansionOuterBoundary"], + default_flow_style=True, + width=float("inf"), + ).strip() + ringdown_params["Translation"] = yaml.safe_dump( + evaluated_fot_dict["Translation"], + default_flow_style=True, + width=float("inf"), + ).strip() + # To avoid interpolation errors, put outer boundary of ringdown domain # slightly inside the outer boundary of the inspiral domain ringdown_params["OuterBdryRadius"] = ( @@ -276,7 +276,7 @@ def start_ringdown( ringdown_params["FinalTime"] = ( match_time + ringdown_params["OuterBdryRadius"] + 200.0 ) - logger.info(f"Ringdown parameters: {pretty_repr(ringdown_params)}") + logger.debug(f"Ringdown parameters: {pretty_repr(ringdown_params)}") # Schedule! return schedule( @@ -324,7 +324,7 @@ def start_ringdown( ), default=None, help=( - "Path to reduction file containing AhC coefs, defualts to" + "Path to reduction file containing AhC coefs, defaults to" " 'BbhReductions.h5' in directory given." ), ) @@ -373,7 +373,7 @@ def start_ringdown( default=None, help=( "Output h5 file for shape coefs, defaults to directory where command" - "was run." + " was run." ), ) @click.option( diff --git a/support/Pipelines/Bbh/Ringdown.yaml b/support/Pipelines/Bbh/Ringdown.yaml index 11c8dcfe9ac1..10b882556f0d 100644 --- a/support/Pipelines/Bbh/Ringdown.yaml +++ b/support/Pipelines/Bbh/Ringdown.yaml @@ -16,7 +16,7 @@ InitialData: NumericInitialData: FileGlob: "{{ IdFileGlob }}" Subgroup: "{{ IdFileGlobSubgroup }}" - ObservationValue: &InitialTime "{{ MatchTime }}" + ObservationValue: &InitialTime {{ MatchTime }} ObservationValueEpsilon: Auto ElementsAreIdentical: False Variables: @@ -65,24 +65,17 @@ DomainCreator: # and has not been tested for other configurations. SizeInitialValues: [0.0, -1.0, 0.0] RotationMap: - InitialQuaternions: - - [{{ Rotation0 }}, {{ Rotation1 }}, {{ Rotation2 }}, {{ Rotation3 }}] - - [{{ dtRotation0 }}, {{ dtRotation1 }}, {{ dtRotation2 }}, - {{ dtRotation3 }}] - - [{{ dt2Rotation0 }}, {{ dt2Rotation1 }}, {{ dt2Rotation2}}, - {{ dt2Rotation3 }}] + InitialQuaternions: {{ Rotation }} DecayTimescale: 1.0 ExpansionMap: # During the ringdown, only the outer boundary's expansion map is # applied. InitialValues: [1.0, 0.0, 0.0] - InitialValuesOuterBoundary: [{{ ExpansionOuterBdry }}, - {{ dtExpansionOuterBdry }}, - {{ dt2ExpansionOuterBdry }}] + InitialValuesOuterBoundary: {{ ExpansionOuterBdry }} DecayTimescale: 1.0 DecayTimescaleOuterBoundary: 1.0 TranslationMap: - InitialValues: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] + InitialValues: {{ Translation }} TransitionRotScaleTrans: True OuterBoundaryCondition: ConstraintPreservingBjorhus: diff --git a/tests/Unit/Evolution/Ringdown/Python/Test_ComputeAhCCoefsInRingdownDistortedFrame.py b/tests/Unit/Evolution/Ringdown/Python/Test_ComputeAhCCoefsInRingdownDistortedFrame.py index 3d26f81a7dbd..f699d0a13cf4 100644 --- a/tests/Unit/Evolution/Ringdown/Python/Test_ComputeAhCCoefsInRingdownDistortedFrame.py +++ b/tests/Unit/Evolution/Ringdown/Python/Test_ComputeAhCCoefsInRingdownDistortedFrame.py @@ -76,9 +76,10 @@ def test_compute_ahc_coefs_in_ringdown_distorted_frame(self): ) reduction_file.close_current_object() - exp_inner_func_with_2_derivs = [1.0, 0.0, 0.0] - exp_outer_boundary_func_with_2_derivs = [1.0, -1e-6, 0.0] - rot_func_with_2_derivs = [ + fot_dict = {} + fot_dict["Expansion"] = [1.0, 0.0, 0.0] + fot_dict["ExpansionOuterBoundary"] = [1.0, -1e-6, 0.0] + fot_dict["Rotation"] = [ [0.0, 0.0, 0.0, 1.0], [0.15, 0.0, 0.0, 0.02], [0.06, 0.0, 0.0, 0.03], @@ -87,11 +88,7 @@ def test_compute_ahc_coefs_in_ringdown_distorted_frame(self): compute_ahc_coefs_in_ringdown_distorted_frame( ahc_reductions_path=str(self.inspiral_reduction_data), ahc_subfile="ObservationAhC_Ylm.dat", - exp_func_and_2_derivs=exp_inner_func_with_2_derivs, - exp_outer_bdry_func_and_2_derivs=( - exp_outer_boundary_func_with_2_derivs - ), - rot_func_and_2_derivs=rot_func_with_2_derivs, + evaluated_fot_dict=fot_dict, number_of_ahc_finds_for_fit=5, match_time=time_to_match, settling_timescale=10.0, diff --git a/tests/Unit/IO/H5/Python/CMakeLists.txt b/tests/Unit/IO/H5/Python/CMakeLists.txt index 89e7c962d62a..6c082ce21e10 100644 --- a/tests/Unit/IO/H5/Python/CMakeLists.txt +++ b/tests/Unit/IO/H5/Python/CMakeLists.txt @@ -42,4 +42,10 @@ spectre_add_python_bindings_test( "unit;IO;H5;python" PyH5) +spectre_add_python_bindings_test( + "Unit.IO.H5.Python.FunctionsOfTimeFromVolume" + Test_FunctionsOfTimeFromVolume.py + "unit;IO;H5;python" + PyH5) + diff --git a/tests/Unit/IO/H5/Python/Test_FunctionsOfTimeFromVolume.py b/tests/Unit/IO/H5/Python/Test_FunctionsOfTimeFromVolume.py new file mode 100644 index 000000000000..28a95ea57a1a --- /dev/null +++ b/tests/Unit/IO/H5/Python/Test_FunctionsOfTimeFromVolume.py @@ -0,0 +1,119 @@ +# Distributed under the MIT License. +# See LICENSE.txt for details. + +import logging +import math +import shutil +import unittest +from pathlib import Path + +import numpy as np +import yaml +from click.testing import CliRunner + +import spectre.IO.H5 as spectre_h5 +from spectre import Spectral +from spectre.DataStructures import DataVector +from spectre.Domain import ( + PiecewisePolynomial3, + QuaternionFunctionOfTime, + serialize_functions_of_time, +) +from spectre.Informer import unit_test_build_path +from spectre.IO.H5 import ElementVolumeData, TensorComponent +from spectre.IO.H5.FunctionsOfTimeFromVolume import ( + functions_of_time_from_volume, +) +from spectre.support.Logging import configure_logging + + +class TestFunctionsOfTimeFromVolume(unittest.TestCase): + def setUp(self): + self.test_dir = Path( + unit_test_build_path(), "support/Pipelines/Bbh/Ringdown" + ) + shutil.rmtree(self.test_dir, ignore_errors=True) + self.test_dir.mkdir(parents=True, exist_ok=True) + self.bin_dir = Path(unit_test_build_path(), "../../bin").resolve() + + # Making volume data for functions of time to be extracted + rotation_fot = QuaternionFunctionOfTime( + 0.0, + [DataVector(size=4, fill=1.0)], + 4 * [DataVector(size=3, fill=0.0)], + math.inf, + ) + expansion_fot = PiecewisePolynomial3( + 0.0, 4 * [DataVector(size=1, fill=0.0)], math.inf + ) + expansion_outer_fot = PiecewisePolynomial3( + 0.0, 4 * [DataVector(size=1, fill=0.0)], math.inf + ) + translation_fot = PiecewisePolynomial3( + 0.0, 4 * [DataVector(size=3, fill=0.0)], math.inf + ) + serialized_fots = serialize_functions_of_time( + { + "Expansion": expansion_fot, + "ExpansionOuterBoundary": expansion_outer_fot, + "Rotation": rotation_fot, + "Translation": translation_fot, + } + ) + self.volume_data = self.test_dir / "BbhVolume0.h5" + obs_values = [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] + with spectre_h5.H5File(self.volume_data, "w") as volume_file: + volfile = volume_file.insert_vol("ForContinuation", version=0) + for x in range(0, 5): + volfile.write_volume_data( + observation_id=x, + observation_value=obs_values[x], + elements=[ + ElementVolumeData( + element_name="arthas", + components=[ + TensorComponent( + "menethil", + np.random.rand(3), + ), + ], + extents=[3], + basis=[Spectral.Basis.Legendre], + quadrature=[Spectral.Quadrature.GaussLobatto], + ) + ], + serialized_functions_of_time=serialized_fots, + ) + + def tearDown(self): + shutil.rmtree(self.test_dir, ignore_errors=True) + + def test_functions_of_time_from_volume(self): + expected_rot_fot = [ + [0.5, 0.5, 0.5, 0.5], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ] + expected_exp_fot = [0.0, 0.0, 0.0] + expected_exp_outer_bdry_fot = [0.0, 0.0, 0.0] + expected_translation_fot = [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ] + + fot_dict = functions_of_time_from_volume( + str(self.volume_data), "ForContinuation", 6.0 + ) + + self.assertEqual(fot_dict["Expansion"], expected_exp_fot) + self.assertEqual( + fot_dict["ExpansionOuterBoundary"], expected_exp_outer_bdry_fot + ) + self.assertEqual(fot_dict["Rotation"], expected_rot_fot) + self.assertEqual(fot_dict["Translation"], expected_translation_fot) + + +if __name__ == "__main__": + configure_logging(log_level=logging.DEBUG) + unittest.main(verbosity=2)