Skip to content

Conversation

@AlexCarpenter46
Copy link
Contributor

@AlexCarpenter46 AlexCarpenter46 commented Aug 11, 2025

Proposed changes

First pr of 3 adding the rest of the transition to ringdown script from SpEC to SpECTRE.

This pr adds the tracking of the geometric center of the common horizon which will then be used to make the translation function of time used in the ringdown. This is necessary for unequal mass simulations to fully ringdown.

Upgrade instructions

Code review checklist

  • The code is documented and the documentation renders correctly. Run
    make doc to generate the documentation locally into BUILD_DIR/docs/html.
    Then open index.html.
  • The code follows the stylistic and code quality guidelines listed in the
    code review guide.
  • The PR lists upgrade instructions and is labeled bugfix or
    new feature if appropriate.

Further comments

@AlexCarpenter46 AlexCarpenter46 marked this pull request as draft August 11, 2025 20:45
@AlexCarpenter46 AlexCarpenter46 force-pushed the ringdown_translation branch 2 times, most recently from cb37705 to 3a24d16 Compare August 11, 2025 23:12
@AlexCarpenter46 AlexCarpenter46 force-pushed the ringdown_translation branch 2 times, most recently from eb5ca91 to aa50963 Compare October 8, 2025 19:09
@AlexCarpenter46 AlexCarpenter46 marked this pull request as ready for review October 8, 2025 21:11
Copy link
Contributor

@markscheel markscheel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have missed it, but I don't see comments corresponding to lines 1209-1237 of SpEC's ConstructPostMergerDataFromAhC.pl, where the translation map is corrected to account for translation/rotation in the inspiral. This correction is easy to overlook; are you doing the correction?

} // namespace

void bind_strahlkorper_transformations(py::module& m) { // NOLINT
// Only instantiating for Grid->Inertial because the Py functions are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update dox here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This binding was not needed and left in by mistake

false,
std::nullopt,
{100.0},
{50.0},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments as to why 50 and not 100 (or some other number). Same for other magic numbers here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what "Radial partition used in current ringdowns" means or why it is 50.

Comment on lines +197 to +242
if "Translation" not in evaluated_fot_dict:
evaluated_fot_dict["Translation"] = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this so that we don't try to read in the history of the translation map from the inspiral if there wasn't one used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, pls add comment.

/*!
* \brief Transform `Strahlkorper` coefs to ringdown distorted frame.
* \brief Transforms `Strahlkorper` coefs to ringdown distorted frame and tracks
* the center of mass.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it track the center of mass, or does it track the geometric center of AhC? I think the latter.
Maybe Reads inertial-frame Strahlkorper coefs from a file, returns the ringdown-distorted-frame coefs and the Strahlkorper's inertial-frame geometric center ?

Comment on lines 24 to 40
* ringdown distorted frame defined by the expansion, rotation, and translation
* maps specified by `exp_func_and_2_derivs`,
* `exp_outer_bdry_func_and_2_derivs`, `rot_func_and_2_derivs`, and
* `trans_func_and_2_derivs`. The expansion and rotation functions of time
* correspond to the ringdown frame's expansion and rotation maps at the time
* given by `match_time`, and by `settling_timescale`, the timescale for the
* maps to settle to constant values. The translation function of time supplied
* does not correspond to the ringdown frame's translation function of time. The
* ringdown's translation function of time needs to be built by tracking the
* position of the center of mass at multiple times. Only Strahlkorpers and
* center of mass points within `requested_number_of_times_from_end` times from
* the final time are returned. This function is used to transition from
* inspiral to ringdown; in this case, the inertial-frame Strahlkorper is the
* common apparent horizon from a binary-black-hole inspiral; the
* ringdown-distorted-frame coefficients are used to initialize the shape map
* for the ringdown domain. The center of mass points are used to initialize the
* translation map for the ringdown domain.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the translation function of time that is passed into this function? Is it the translation function of time of the inspiral? (You say what it is not, but not what it is).

And what are "center of mass points"? Does the center of mass actually matter here?

Also, should say that the AhC center is returned in the inertial frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the translation function of time is from the inspiral. And no, the center of mass doesn't actually matter here, I originally assumed that the center of mass and geometric center of the strahlkorper were the same.

tnsr::I<DataVector, 3, ::Frame::Inertial> inertial_center_point{
DataVector{3, 0.0}};
// The center point is mapped back to the inspiral inertial frame so that
// the center of mass is the same at the match time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

center of mass -> center of AhC

*/
std::vector<DataVector> strahlkorper_coefs_in_ringdown_distorted_frame(
std::pair<std::vector<DataVector>, std::vector<std::array<double, 3>>>
strahlkorper_coefs_in_ringdown_distorted_frame(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename? The function name sounds like it is returning only the coefs.

expansion_map = ExpansionMapOptions([1.0, 1e-4, 0.0], 100.0, 1e-6)
rotation_map = RotationMapOptions([[0.0, 0.0, 0.0, 1.0]], 100.0)
translation_map = TranslationMapOptions(
[[1.0, -1.0, 0.5], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to test with nonzero velocity?

Copy link
Contributor Author

@AlexCarpenter46 AlexCarpenter46 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I believe this correction is being applied to account for the inspirals rotation, expansion, and translation. This is done by transforming the geometric center from the ringdown-distorted-frame EDIT: back to the inspiral-inertial-frame to the ringdown-inertial-frame. Those center points are then used to fit to a cubic polynomial. I added some comments in the details, but let me know if I missed anything or if more should be added :)

make_not_null(&distorted_ahc), 1e-7);
ahc_ringdown_distorted_coefs.push_back(distorted_ahc.coefficients());

tnsr::I<DataVector, 3, ::Frame::Grid> grid_center_point{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to point out that I changed these lines in this fixup because doing tnsr::I<DataVector, 3, ::Frame::Grid> {distorted_ahc.expansion_center()} was not constructing the tensor correctly. It was producing a tensor with a DataVector with 3 component at each index which is not what I was trying to do there.

@AlexCarpenter46 AlexCarpenter46 force-pushed the ringdown_translation branch 2 times, most recently from bab84f6 to 1978a2d Compare October 30, 2025 15:16
@AlexCarpenter46
Copy link
Contributor Author

AlexCarpenter46 commented Oct 31, 2025

So I had assumed that with all the pieces added (automatically choosing an excision radius and rescaling the shape coefficients) that the ringdown would just work. However, I noticed that the translation still looks off even when rescaling. This can be seen in the two images below,
This first image is the domain for the ringdown and common horizon from the inspiral at the match time.
Common_Horizon_Match_time
So I thought okay maybe the shape is incorrect, but in paraview I just transformed the domain around a bit and the shape actually looks really good after being rescaled.
Common_Horizon_Match_time_corrected
So there must be something I've implemented incorrectly or maybe I'm not accounting for the inspiral rotation, expansion and translation correctly or at all. I'm not sure, but just wanted to share, cause I don't think this should be merged in this state.

Edit for more context: The images above show the apparent horizon of the common horizon at the match time in black. I've turned the opacity down so that we can see where the excision is relative to the horizon (the off-white/grayish ring inside the apparent horizon).

// the center of AhC is the same at the match time.
coords_to_different_frame(
make_not_null(&inertial_center_point), grid_center_point,
ringdown_domain, ringdown_functions_of_time, gsl::at(ahc_times, i));
Copy link
Contributor Author

@AlexCarpenter46 AlexCarpenter46 Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to highlight this change, that was causing the center to be placed incorrectly. I misread what the SpEC script was doing and thought it was taking this center point back to the inspiral inertial frame, but it actually maps it to the ringdown inertial frame instead. Doing this placed the excision center correctly for the 2 mass ratio ringdown as can be seen below.
image

@AlexCarpenter46
Copy link
Contributor Author

@markscheel and @nilsvu I've pushed a fixup adding some more comments, so I think this is ready for another round of reviews :)

Copy link
Contributor

@markscheel markscheel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In SpEC's ConstructPostMergerDataFromAhC, there's a 28-line detailed comment, including matrix algebra, that explains why all of this works even though translation and rotation don't commute and the center of AhC is not the origin. In particular, it explains why you can use the coefficients of AhC as-is except for a minus sign, and how you compute the coefficients of the translation map. Please add a comment that is at least as detailed as the SpEC comment.

There is also a 32-line detailed comment in ConstructPostMergerFromAhC explaining what the 'ringdown distorted frame' is (in SpEC this is sometimes called the 'intermediate frame'), and how it is constructed, and explains details like "The ringdown translation map is different than the plunge one because it is tracking a different center, so translation is discontinuous in time". I think all of that still applies here (but let me know if I am wrong). Please add a comment that is at least as detailed as the SpEC comment.

translation function of time for the ringdown using the functions of time
and the AhC coefficients in the Inspiral inertial frame.
Arugments:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: spelling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping on this

Comment on lines 170 to 184
(
fit_ahc_translation_coefs,
fit_ahc_dt_translation_coefs,
fit_ahc_dt2_translation_coefs,
) = fit_to_a_cubic(
ahc_times_for_fit,
ahc_inertial_centers_for_fit,
match_time,
zero_coefs_eps,
)
ahc_translation_fot = [
fit_ahc_translation_coefs,
fit_ahc_dt_translation_coefs,
fit_ahc_dt2_translation_coefs,
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just asking: is there a reason this can't be

ahc_translation_fot = fit_to_a_cubic(...)

instead of doing it in two steps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no reason, I'll swap it to that

translation_map_options,
translation_fot_from_volume,
true};
const domain::creators::Sphere domain_creator{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to make a fake Domain that is different from the actual Domain that will be used for the final ringdown. Below you used to call it temporary_domain, so I think my interpretation is correct, but now it's no longer called temporary_domain (why)? Please add a (long, at least one paragraph, probably several paragraphs) comment of why you are doing this in the first place, what will this fake domain be used for, and what assumptions are being made about the fake domain (e.g. why is the inner radius so tiny as to make the domain extremely distorted [I don't think SpEC does this]? Why is the outer radius only 200M? Do you assume that AhC in the ringdown must have r < 200M [and if so, in what frame?] Why only 5 grid points?).

false,
std::nullopt,
{100.0},
{50.0},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what "Radial partition used in current ringdowns" means or why it is 50.

translation function of time for the ringdown using the functions of time
and the AhC coefficients in the Inspiral inertial frame.
Arugments:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping on this

None,
)
shape_and_translation_coefs = Ringdown.strahlkorper_coefs_and_centers(
str(path_to_volume_data),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use named arguments. Makes it clearer what each argument means and prevents bugs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants