Improve handling of precessing reference frame - #101
Merged
Conversation
The surrogate is told (q, chiA, chiB) *at a reference frequency*. A precessing
binary's spins swing continuously, so "the spins" is meaningless without saying
when, and an epoch read at the wrong instant does not describe the same binary
imprecisely -- it describes a different binary precisely. That distinction
carries any comparison built on it: if the model waveform is not the same
physical system as the NR waveform, parameter-mismatch error and NR-intrinsic
error mix and cannot be separated again.
reference_frame.py replaces an epoch rule that was wrong in four ways:
- It searched FORWARD for the first sample reaching the target frequency,
which lands inside the junk-radiation burst, where the phase derivative is
large and erratic and crosses any threshold spuriously. The GW frequency
rises monotonically through the inspiral, so the last crossing before merger
is the secular one; searching back from the peak never enters the transient.
- It compared against a hardcoded omega_0. omega_0 is an output of the
surrogate's own dynamics and varies by 17% at q=1 and 28% at q=6 between
maximal alignment and anti-alignment; over the population analysed here it
spans 0.0150 to 0.0218. A fixed threshold rejects valid simulations at one
end of that range and accepts invalid epochs at the other.
- Taking omega_0 from the model creates a circularity -- omega_0 depends on
the spins, the spins are read at the epoch, the epoch is where the frequency
reaches omega_0/pi. Broken by fixed-point iteration, which converges in one
step for three simulations in five and within six for 99%. The one
pathology is a two-cycle, where the epoch implies spins whose omega_0 sends
it back; both endpoints are valid references, so the later one is taken.
- It trusted the published relaxation time. Junk radiation leaves the domain
in about a light-crossing time and the domain is ~800 M in code units, so a
value far above that is not measuring the transient. Clamped to 800 M --
which bites: 97% of the precessing SXS simulations here publish more, median
1409 M.
Two frame conventions are implemented so they can be measured against each
other rather than argued about: A takes Lhat from the catalog's own dynamics,
B from the waveform's coprecessing frame. B needs no metadata, so it is the
only option for MAYA. Its branch ambiguity is resolved from the sign of
d(arg h22)/dt; the obvious alternative of comparing power in h_{2,2} against
h_{2,-2} is invalid, because equatorial symmetry makes those equal by
construction. validate_frame() gates the reconstruction against the published
SXS reference_orbital_frequency, where both exist.
Also here: the sharded campaign drivers, and the durability fixes a 13.5-hour
silent hang forced. Two shards slept inside an SXS download because urllib3
inherits the (absent) default socket timeout; common.py now sets one, retries
transient failures after dropping the partial cache entry, resumes a restarted
shard from its own output, and writes results by atomic rename -- json.dump
truncates before writing, and these runners rewrite the whole file after every
simulation, so a kill was destroying a day's work most of the time.
Campaign OUTPUT is deliberately not tracked; see analysis/.gitignore. Its
merged form is committed in catalog-comparison-paper, which is where analysis
inputs to a manuscript belong.
Same policy as the rest of analysis/.gitignore: campaign output belongs with the manuscript, not in the library repo.
The rule already covered *.png, but the plotting scripts also emit PDF, so a figure left over from a run showed up as untracked. Same policy either way: campaign output belongs with the manuscript.
Both match paths located the peak of an inverse FFT by taking its largest sample, quantizing the time shift to the sample spacing. The error that introduces grows as the mismatch shrinks -- a better match is a sharper peak, and a sharper peak is worse approximated by its nearest sample -- which is backwards for work whose subject is mismatches between 1e-4 and 1e-2. This is the mechanism behind findings 5k in the catalog-comparison-paper repo, where the SXS (2,2) median moved by a factor of 2.5 between 4096 Hz and 16384 Hz on simulations with nothing near Nyquist, non-monotonically. pycbc.filter.match already offers the correction; it was left at its False default. The sphere-averaged and BMS-maximized matches do their own time maximization rather than calling pycbc, so that flag would not have reached them -- and those are the paths the precessing campaign runs on. Hence _interpolated_peak_abs(), applied at both hand-rolled peaks, doing the same quadratic interpolation pycbc does. Measured on the three findings-5k simulations across 4096..32768 Hz: the converged values move by 0.06%, 1.5% and 0.07%, so this corrects discretization error rather than changing the answer, while 16384 Hz now agrees with 32768 Hz to 0.2% instead of 1.5-33%. One caveat, recorded because it decides how the existing data must be treated: at 4096 Hz the parabola overshoots a peak that coarse, and two of the three simulations then read an order of magnitude low. Data at that rate has to be re-run, not reprocessed.
They now live in catalog-comparison-paper under project/scripts/precessing_campaign/ and project/results/precessing_campaign/, with the manuscript whose numbers they produce and under the same reproducibility guard as the rest of them. Deleted rather than left in place: a second copy is a second source of truth, and the two would drift the first time one was edited. The paper repo's copy reproduces every figure and table that cites it, verified before this removal.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.