Skip to content

WP7: the integrated loop, discrepancy register, multiples and the Fig. 2/4/5 analogues - #8

Merged
ingehap merged 1 commit into
mainfrom
claude/blissful-gauss-3y1u5w
Oct 15, 2026
Merged

ingehap merged 1 commit into
mainfrom
claude/blissful-gauss-3y1u5w

Conversation

@ingehap

@ingehap ingehap commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Summary

Work package 7 of docs/IMPLEMENTATION_PLAN.md. This runs the article's integrated loop (Lewis et al., 2016, Fig. 1) end to end on the synthetic well, using estimated models only:

  • logs → ZO-VSP → walkaway → surface seismic;
  • each step is recorded in an auditable register of model versions, discrepancies and pre-fixed acceptance criteria.

New code

  • iwt/welltie.py:
    • least-squares multi-trace wavelet estimation (Walden & White, 1998);
    • constant phase rotation;
    • tie metrics (White & Simm, 2003). The time shift and the phase come from the complex cross-correlation of the analytic signals, because a real cross-correlation mistakes one for the other.
  • iwt/workflow.py:
    • model_from_logs: sonic and dipole moved to the seismic frequency with Q (Kjartansson, 1979); ε, δ, γ and Q curves; a gap layer above the logs, with its velocity from the VSP;
    • Register: versions, discrepancies, criteria, Markdown output.
  • iwt/multiples.py: CMP gathers with the physics switched off step by step (full, primaries with conversions, no mode conversion, P primaries, Born).
  • iwt/avo.py: linear_resolution for the identifiability study.
  • iwt/synthetic.py: dipping_reservoir_models (wedge, dipping reservoir, flat OWC, all-brine twin).
  • iwt/modeling/reflection.py: exact_pp_slowness.
  • iwt/raytrace.py: an exact zero-offset fast path in reflection_table.
  • examples/reproduce_paper.py: the loop (about 6 min with 4 workers). It writes docs/discrepancy_register.md and docs/figures/wp7_{tie,ava,section}.png.
  • tests/test_workflow.py (11 tests), README and plan updates, version 0.7.0.

Results (synthetic well)

criterion (fixed before tuning) value threshold passed
VSP first-break residual 0.22 ms ≤ 1 ms yes
corridor stack vs synthetic 0.93 ≥ 0.8 yes
reservoir event time shift 0.02 ms ≤ 2 ms yes
Stø AVA gradient, contamination-free 0.40 ≤ 0.10 no
Stø AVA gradient, as acquired 0.73 ≤ 0.10 no

The time tie closes:

  • the ZO-VSP Q and drift calibration do most of the work;
  • filling the 52 m blind gap above the logs from the VSP lifts the corridor correlation from −0.06 to 0.93.

The AVA does not close, as in the article. After migration:

  • the full-physics contamination is 0.9–1.5 × Born, and it grows with angle;
  • without mode conversion, P-wave interbed multiples are small (0.14–0.23 × Born);
  • with mode conversion, the converted primaries and the multiples largely cancel, so an acoustic demultiple would not repair the AVA.

Synthetic-only attribution:

  • the true earth itself predicts 2–14 % too much amplitude. That is the Q model above the first VSP receiver; with the true Q the misfit falls from 0.088 to 0.040;
  • swapping one part of v2 into the truth is not additive. The 5 m-smoothed γ gives the isotropic stringers shale anisotropy.

Identifiability:

  • the reservoir AVA constrains ρ and the overburden Q, barely the Vs and not δ;
  • reservoir Vs and overburden Q correlate +0.59.

Fig. 5 analogue: VTI places the fluid signal inside the oil column, while isotropic imaging puts it 17 m deep. Q compensation barely sharpens the signal in 1D.

Deviations from the plan (documented in the plan's as-built notes)

  • Predictions use full reflectivity. A ray-Born prototype failed beyond about 27° with the thin stringers.
  • The AVA criterion uses 20–44°, not 30–50°, because the seabed reflection crosses the reservoir.
  • Not built: hold-out validation, Monte Carlo ensembles, free-surface multiples.

Test plan

  • pytest -q -W error::RuntimeWarning -W error::DeprecationWarning (Python 3.13 venv): 154 passed
  • pytest -q (Python 3.9 venv): 150 passed, 1 skipped (no matplotlib)
  • pyflakes iwt tests examples
  • python examples/reproduce_paper.py --workers 4 completes and regenerates the register and figures
  • README quick start runs

🤖 Generated with Claude Code

https://claude.ai/code/session_019vaUDUPicoFeQaUhfhnoYq


Generated by Claude Code

…. 2/4/5 analogues

- iwt.welltie: least-squares wavelet estimation, phase rotation, tie metrics from the
  complex cross-correlation of analytic signals (shift and constant phase separated)
- iwt.workflow: model_from_logs (dispersion with Q, anisotropy and Q curves, gap layer
  from the VSP), versioned models, discrepancy register, acceptance criteria, Markdown
- iwt.multiples: CMP gathers with physics switched off step by step
- iwt.avo.linear_resolution: identifiability (posterior std, data weight, correlation)
- iwt.synthetic.dipping_reservoir_models: wedge, dipping reservoir, flat OWC
- iwt.modeling.reflection.exact_pp_slowness; zero-offset fast path in reflection_table
- examples/reproduce_paper.py runs logs -> ZO-VSP -> walkaway -> surface seismic on
  estimated models and writes docs/discrepancy_register.md and docs/figures/wp7_*.png
- tests/test_workflow.py (11 tests); README, plan; version 0.7.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vaUDUPicoFeQaUhfhnoYq
@ingehap
ingehap marked this pull request as ready for review October 15, 2026 06:04
Copilot AI balanced review requested due to automatic review settings October 15, 2026 06:04
@ingehap
ingehap merged commit a7f5530 into main Oct 15, 2026
4 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Numerical errors, ground-truth leakage, and inconsistent model history and scoring undermine the workflow’s reliability.

8 open findings
What changed in this PR

Implements WP7, connecting the existing modelling and calibration tools into an integrated synthetic-well workflow with an auditable discrepancy register.

Changes:

  • Adds well-tie metrics, model versioning, physics comparisons, and identifiability analysis.
  • Adds the reproduction script and dipping-reservoir experiment.
  • Documents results, adds regression tests, and bumps the package version.
File Description
tests/​test_workflow.py Tests WP7 helpers and numerical behaviour.
README.md Documents workflow, results, and limitations.
pyproject.toml Bumps version to 0.7.0.
iwt/​workflow.py Adds log-derived models and discrepancy register.
iwt/​welltie.py Adds wavelet estimation and tie metrics.
iwt/​synthetic.py Adds dipping-reservoir model pairs.
iwt/​raytrace.py Optimizes zero-offset reflection tables.
iwt/​multiples.py Compares physics variants and relative errors.
iwt/​modeling/​reflection.py Exposes PP reflection coefficients by slowness.
iwt/​avo.py Adds linear parameter-resolution analysis.
iwt/​__init__.py Exports new modules and updates version.
examples/​reproduce_paper.py Runs the integrated workflow and generates outputs.
docs/​IMPLEMENTATION_PLAN.md Records WP7 completion and deviations.
docs/​discrepancy_register.md Records generated discrepancies and acceptance results.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread iwt/workflow.py
criteria: List[Criterion] = field(default_factory=list)

def new_version(self, name: str, model: ElasticModel1D, changes: str) -> ModelVersion:
v = ModelVersion(len(self.versions), name, model, changes)
Comment on lines +147 to +148
reg.check("VSP first-break residual after calibration", 1e3 * np.sqrt(np.nanmean(d1 ** 2)), 1.0,
"<=", "ms")

def anisotropy_step(model, logs, reg, zo):
z = logs.depth
g_sonic, g_up = wp5.sonic_gamma(model, logs)
Comment thread iwt/multiples.py
Comment on lines +71 to +74
a, b = np.asarray(a, dtype=float), np.asarray(b, dtype=float)
if mask is not None:
a, b = a[mask], b[mask]
return float(np.sqrt(np.nanmean((a - b) ** 2) / np.nanmean(b * b)))
Comment thread iwt/synthetic.py
Comment on lines +294 to +297
units.sort(key=lambda u: u.top)
below = units[units.index(water) + 1:]
if below and below[0].top <= water.top:
raise ValueError("the dip moves the base of the reservoir above the contact")
Comment thread iwt/welltie.py
L = int(round(max_shift / dt))
lags = np.arange(-L, L + 1)
# |analytic| norms are twice the real ones (equal energy in the quadrature part)
cc = np.array([np.vdot(np.roll(sa, k), oa) for k in lags]) / (2.0 * no * ns)
Comment thread iwt/welltie.py
a, b, c = env[i - 1], env[i], env[i + 1]
den = a - 2 * b + c
off = 0.5 * (a - c) / den if den != 0 else 0.0
phi = float(-np.angle(cc[i]))
Comment thread iwt/workflow.py
Comment on lines +71 to +72
curves = {k: mid(_at(v, n)) for k, v in (("eps", eps), ("delta", delta), ("gamma", gamma),
("qp", qp), ("qs", qs))}
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