GWForge.fisher.stepsize¶
Choosing finite-difference steps, and measuring what limits them.
Two things bound a usable step from opposite sides. Too large and the difference stops being local; too small and it drowns in the waveform model’s own numerical noise. The constants here are measured rather than guessed, and the measurements are recorded beside them because they are the whole justification.
calibrate_step() handles the upper bound by targeting a fixed fractional
change in the waveform. estimate_noise() handles the lower one, using the
ECNoise procedure of Moré and Wild, Estimating Computational Noise, SIAM J.
Sci. Comput. 33(3):1292–1314 (2011): a smooth function’s k-th finite differences
shrink like \(h^k\) while noise does not shrink at all, so the level at which
the difference table stops changing is the noise.
Attributes¶
Functions¶
|
Estimate the numerical noise of a computed function from its values. |
|
Evaluate a function at equally spaced points centred on zero. |
|
Rescale a step so one displacement changes the waveform by |
Module Contents¶
- GWForge.fisher.stepsize.estimate_noise(values)[source]¶
Estimate the numerical noise of a computed function from its values.
Implements the ECNoise procedure of Moré and Wild, Estimating Computational Noise, SIAM J. Sci. Comput. 33(3):1292–1314 (2011), which is the standard way to measure how much of a simulated function’s output is numerical scatter rather than signal.
The idea is that for a smooth \(f\) the \(k\)-th finite difference over a spacing \(h\) shrinks like \(h^k\), while iid noise does not shrink at all – it merely gets amplified by a known binomial factor. So build the difference table and look for the level at which the estimates stop changing:
\[\sigma_k^2 = \frac{\gamma_k}{m + 1 - k} \sum_i \big(\Delta^k f_i\big)^2, \qquad \gamma_k = \frac{(k!)^2}{(2k)!}.\]- Parameters:
values (array_like) – Function values at equally spaced points. At least four, preferably
NOISE_SAMPLE_POINTS. The spacing itself never enters.- Returns:
(noise, status).statusis1when the noise was detected,2when the spacing was too small (half the first differences came out exactly zero – widen it by ~100), and3when it was too large (no level settled, or the values already differ in their first digit – narrow it by ~100).noiseis0.0unlessstatusis1.- Return type:
tuple
- GWForge.fisher.stepsize.sample_around(evaluate, half_width, points=NOISE_SAMPLE_POINTS)[source]¶
Evaluate a function at equally spaced points centred on zero.
The spacing convention follows Moré and Wild’s driver:
half_widthis the half-width of the span, not the gap between points.- Parameters:
evaluate (callable) –
evaluate(offset) -> float.half_width (float) – Half the total span.
points (int) – Number of evaluations.
- Return type:
numpy.ndarray
- GWForge.fisher.stepsize.calibrate_step(evaluate, name, value, initial, target=TARGET_FRACTIONAL_CHANGE)[source]¶
Rescale a step so one displacement changes the waveform by
target.The fractional change is linear in the step over many decades, so a single probe fixes the scale; a second probe confirms it and catches the non-linear case. See
TARGET_FRACTIONAL_CHANGEfor why the target is what it is.- Parameters:
evaluate (callable) –
evaluate(step) -> floatreturning \(\lVert\Delta h\rVert / \lVert h\rVert\) for that displacement.name (str) – Parameter name, used for the bound check and for logging.
value (float) – Fiducial value.
initial (float) – Starting step.
target (float) – Desired fractional change.
- Returns:
(step, noise_ratio). The step is bounded. The noise ratio is always0.0here – measuring it isWaveformDerivatives._apply_noise_estimate()’s job, which usesestimate_noise(). Falls back toinitialif the waveform does not depend on the parameter at all.- Return type:
tuple