Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
that negated codameter output to get physical dv/v must remove that
negation.

- **The stretching-family trial-epsilon search now resamples `current`, not
`reference`.** `stretching_cc`, `measure_stretching_trailing`, and
`measure_wts` previously interpolated the *reference* waveform at trial
positions `t/(1+eps)` and held `current` fixed; they now interpolate
*current* at `(1+eps)*t` and hold `reference` fixed, matching the field's
usual convention (the reference is the stable, often multi-day-averaged
anchor; the current trace is the one being tested against it). **The exact
conversion `dv/v = -eps/(1+eps)` is unchanged** — both conventions give
the identical exact map (see the derivation in the PR), so this is not a
second sign-convention flip; it is an internal numerics change with a
small (single-digit-percent) shift in finite-sample results, since a
different (per-day, typically noisier) trace is now the one being
resampled. Added `synthetic_demo.dvv_to_epsilon` (the exact inverse of
`eps_to_dvv`) and `synthetic_demo._stretch_window`, a common
valid-support window shared across the whole epsilon grid so no trial
epsilon is silently extrapolated and every candidate is scored on an
identical sample count (warns and shrinks the window if the requested
one would need extrapolation at the edges of `eps_max`; none of the
packaged `use_cases.py` configs hit this).
`tests/data/golden/manifest.json` regenerated against the new numerics
(`golden.MANIFEST_VERSION` bumped 2 → 3 so stale per-user caches
regenerate); a hidden/private golden corpus built with `private_golden.py`
before this change should be regenerated too.

### Added

- `synthetic_demo.eps_to_dvv`: the exact stretch-to-velocity map.
Expand All @@ -43,13 +67,14 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
the estimators whose band usage is that one linear filter (stretching, WCC,
DTW, MWCS — the wavelet estimators raise).
- **`measure_stretching_trailing`** — vectorized stretching against a trailing
(moving) reference. The stretched sample positions `t/(1+eps)` are
(moving) reference. The stretched sample positions `(1+eps)*t` are
data-independent, so the interpolation gather indices/weights are computed
once per epsilon and applied to all days at once; trailing references come
from a cumulative sum and the band-pass runs once over the whole matrix.
`deviations._moving_reference` dispatches to it for the stretching
estimator (~3x on the 3-year volcano synthetic, observed 3-4.5x across
repeated runs), keeping the generic per-day loop for the other estimators.
(Updated below: the resampled trace is `current`, not `reference`.)

### Changed

Expand Down
Binary file modified literature/figs/demo_10_deviations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_11_multiverse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_12_bayes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_13_branch_asymmetry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_14_network_pairs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_15_window_envelope.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/demo_16_band_sensitivity.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/demo_17_reference_schemes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/demo_18_stack_coherence.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_1_methods.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_2_aggregation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_3_uncertainty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_4_frequency_depth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_5_window_band.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_6_stacking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_7_reference.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_8_artifacts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified literature/figs/demo_9_multiverse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/realdata_1_validation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/realdata_2_interferograms.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added literature/figs/realdata_3_warmup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
749 changes: 489 additions & 260 deletions paper/manuscript_marine.qmd

Large diffs are not rendered by default.

992 changes: 618 additions & 374 deletions paper/manuscript_marine.tex

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions paper/references.bib
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
@article{poupinet84,
author = {Poupinet, G. and Ellsworth, W. L. and Frechet, J.},
title = {Monitoring velocity variations in the crust using earthquake doublets: An application to the {Calaveras} Fault, {California}},
journal = {Journal of Geophysical Research: Solid Earth},
volume = {89}, number = {B7}, pages = {5719--5731}, year = {1984},
doi = {10.1029/jb089ib07p05719}
}

@article{lobkis03,
author = {Lobkis, Oleg I. and Weaver, Richard L.},
title = {Coda-Wave Interferometry in Finite Solids: Recovery of {P}-to-{S} Conversion Rates in an Elastodynamic Billiard},
journal = {Physical Review Letters},
volume = {90}, number = {25}, pages = {254302}, year = {2003},
doi = {10.1103/PhysRevLett.90.254302}
}

@article{SensSchonfelder2006,
author = {Sens-Sch{\"o}nfelder, Christoph and Wegler, Ulrich},
title = {Passive image interferometry and seasonal variations of seismic velocities at {Merapi} Volcano, {Indonesia}},
Expand Down Expand Up @@ -203,6 +219,19 @@ @article{Okubo2024
doi = {10.1029/2023JB028084}
}

@article{Denolle25b,
author = {Denolle, Marine A. and Shi, Qibin and Clements, Tim and Viens, Lo{\"\i}c and Rodriguez-Tribaldos, Veronica and Cotton, Fabrice},
title = {Ambient field seismology in critical zone hydrological sciences},
journal = {Comptes Rendus. G\'eoscience},
pages = {425--451},
year = {2025},
publisher = {Acad\'emie des sciences, Paris},
volume = {357},
doi = {10.5802/crgeos.310},
language = {en}
}


@article{Kidiwela2026,
author = {Kidiwela, Maleen and Denolle, Marine A. and Wilcock, William S. D. and Feng, K. F.},
title = {Active protothrusts and fluid highways: Seismic noise reveals hidden subduction dynamics in Cascadia},
Expand All @@ -229,3 +258,47 @@ @book{Mavko2009
year = {2009},
doi = {10.1017/CBO9780511626753}
}

% Deployment examples cited narratively in the Introduction (not part of
% the 103-study processing-choice survey, so kept here rather than in the
% auto-generated survey.bib).
@article{CubukSabuncu2021,
author = {Cubuk-Sabuncu, Ye{\c s}im and J{\'o}nsd{\'o}ttir, Kristín and Caudron, Corentin and Lecocq, Thomas and Parks, Michelle and Geirsson, Halld{\'o}r and Mordret, Aur{\'e}lien},
title = {Temporal Seismic Velocity Changes During the 2020 Rapid Inflation at Mt. {\th}orbj{\"o}rn-Svartsengi, Iceland, Using Seismic Ambient Noise},
journal = {Geophysical Research Letters},
year = {2021},
volume = {48},
pages = {e2020GL092265},
doi = {10.1029/2020GL092265}
}

@article{Ouellet2022,
author = {Ouellet, Susanne M. and Dettmer, Jan and Olivier, Gerrit and de Wit, Tjaart and Lato, Matt},
title = {Advanced monitoring of tailings dam performance using seismic noise and stress models},
journal = {Communications Earth \& Environment},
year = {2022},
volume = {3},
pages = {301},
doi = {10.1038/s43247-022-00629-w}
}

@article{Planes2016,
author = {Plan{\`e}s, Thomas and Mooney, Michael A. and Rittgers, Jacob B. R. and Parekh, Malcolm L. and Behm, Michael and Snieder, Roel},
title = {Time-lapse monitoring of internal erosion in earthen dams and levees using ambient seismic noise},
journal = {G{\'e}otechnique},
year = {2016},
volume = {66},
number = {4},
pages = {301--312},
doi = {10.1680/jgeot.14.P.268}
}

@article{Tsuji2021,
author = {Tsuji, Takeshi and Ikeda, Tatsunori and Matsuura, Ryosuke and Mukumoto, Kota and Hutapea, Fernando Lawrens and Kimura, Tsunehisa and Yamaoka, Koshun and Shinohara, Masanao},
title = {Continuous monitoring system for safe managements of {CO2} storage and geothermal reservoirs},
journal = {Scientific Reports},
year = {2021},
volume = {11},
pages = {19120},
doi = {10.1038/s41598-021-97881-5}
}
38 changes: 21 additions & 17 deletions src/codameter/deviations.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
YEAR_D,
C,
Synth,
_boost_fonts,
_days,
_trailing_stack,
daily_ccfs,
Expand Down Expand Up @@ -134,10 +135,11 @@ def run_pipeline(ccfs, t, fs, cfg, *, eps_max=0.05, return_cc=False, prefiltered

**Sign convention (v0.4.0, physical dv/v)**: a velocity *increase* is
positive. All estimators return ``dv/v = -eps / (1 + eps)`` where
``eps`` is the stretch factor that maps the reference onto the current
waveform (a coda that must be dilated to match means the medium slowed
down). Before v0.4.0 this function returned ``eps`` itself, labeled
dv/v — anticorrelated with the physical convention.
``eps`` is the stretch factor that resamples the *current* waveform to
match the fixed reference (a current trace that must be dilated to
match means the medium slowed down). Before v0.4.0 this function
returned ``eps`` itself, labeled dv/v — anticorrelated with the
physical convention.

Returns ``(dvv, valid)``: the per-day series and a boolean mask of epochs the
pipeline actually produced (moving/inversion references have a warm-up gap;
Expand Down Expand Up @@ -410,9 +412,9 @@ def fig_deviation_ranking(rows=None):
xlabel="RMS error vs truth (dv/v, %, log)",
title="(a) Bias injected by each deviation",
)
ax[0].set_yticklabels(labels, fontsize=8.5)
ax[0].set_yticklabels(labels, fontsize=10.5)
ax[0].invert_yaxis()
ax[0].legend(fontsize=8.5, frameon=False, loc="lower right")
ax[0].legend(fontsize=10.5, frameon=False, loc="lower right")
drop = [r.drop_err * PCT for r in items]
ax[1].barh(y, drop, color=cols)
ax[1].axvline(0, color=C["truth"], lw=1)
Expand All @@ -424,13 +426,15 @@ def fig_deviation_ranking(rows=None):
title="(b) Distortion of the drop",
)
ax[1].invert_yaxis()
_boost_fonts(ax[0], ax[1], tick=10.5, label=12, title=13)
fig.tight_layout()
return fig


def fig_multiverse_full(mv=None):
"""The ultimate multiverse: every pipeline + the variance attribution."""
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

if mv is None:
mv = multiverse()
Expand All @@ -444,7 +448,7 @@ def fig_multiverse_full(mv=None):
# (a) fan of pipelines, coloured by RMS error with a colourblind-safe,
# perceptually uniform sequential map (dark = accurate, bright = biased).
order = np.argsort(-np.nan_to_num(rms))
norm = plt.Normalize(np.nanpercentile(rms, 5), np.nanpercentile(rms, 95))
norm = Normalize(np.nanpercentile(rms, 5), np.nanpercentile(rms, 95))
cmap = plt.cm.viridis_r
for i in order:
ax[0].plot(yrs, curves[i] * PCT, color=cmap(norm(rms[i])), lw=0.3, alpha=0.16)
Expand All @@ -463,28 +467,27 @@ def fig_multiverse_full(mv=None):
)
ax[0].plot(yrs, truth * PCT, color=C["truth"], lw=2.6, label="ground truth")
ax[0].axvline(2.0, color="0.6", ls="--", lw=1)
# Clip tightly to the truth scale; the cycle-skipping pipelines run off-axis
# (that is the point the colourbar flags them) but would otherwise swamp the
# Fixed, symmetric range: the cycle-skipping pipelines run off-axis (that is
# the point -- the colourbar flags them) but would otherwise swamp the
# signal and make the panel unreadable.
span = (np.nanmax(truth) - np.nanmin(truth)) * PCT
ax[0].set_ylim(
(np.nanmin(truth) * PCT - 0.35 * span, np.nanmax(truth) * PCT + 0.35 * span)
)
ax[0].set_ylim((-0.8, 0.8))
ax[0].set(
xlabel="time (years)",
ylabel="dv/v (%)",
title=f"(a) {mv['n_pipelines']} pipelines (colour = RMS error)",
)
leg = ax[0].legend(fontsize=8.5, loc="lower left", frameon=True)
leg = ax[0].legend(fontsize=10.5, loc="lower left", frameon=True)
leg.get_frame().set_facecolor("white")
leg.get_frame().set_alpha(0.9)
leg.get_frame().set_edgecolor("0.7")
fig.colorbar(
cbar = fig.colorbar(
plt.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax[0],
fraction=0.046,
label="RMS vs truth",
)
cbar.set_label("RMS vs truth", fontsize=12)
cbar.ax.tick_params(labelsize=10.5)

# (b) first-order variance attribution.
axes = mv["axes"]
Expand All @@ -498,8 +501,9 @@ def fig_multiverse_full(mv=None):
ylabel="first-order variance fraction",
title="(b) Which choice controls the answer",
)
ax[1].set_xticklabels(axes, rotation=30, ha="right", fontsize=8.5)
ax[1].legend(fontsize=8.5, frameon=False)
ax[1].set_xticklabels(axes, rotation=30, ha="right", fontsize=10.5)
ax[1].legend(fontsize=10.5, frameon=False)
_boost_fonts(ax[0], ax[1], tick=10.5, label=12, title=13)
fig.tight_layout()
return fig

Expand Down
Loading