pycsamt.ai.inversion.hybrid1d#

Hybrid AI + physics 1-D MT/CSAMT inversion.

HybridInverter1D combines a pre-trained EMInverter1D (Option 1, supervised AI) with a physics-informed refinement step (Option 2 gradient descent).

Stage 1 — AI initial model

The supervised inverter maps the observed EM response directly to a layered Earth model:

d_obs --> EMInverter1D --> m_0  (fast, per-station)

Stage 2 — Physics refinement

Starting from m_0, Adam minimises the same physics-informed loss as PINNInverter1D:

\[\mathcal{L}(\theta) = \frac{1}{F}\sum_{f} \left[ \left( \log_{10}\frac{\rho_a^{\rm pred}} {\rho_a^{\rm obs}} \right)^2 + \left( \frac{\phi^{\rm pred} - \phi^{\rm obs}}{90} \right)^2 \right] + \lambda\sum_k(\rho_k - \rho_{k-1})^2\]

Because m_0 is physically plausible, Stage 2 converges faster and more reliably than a PINN started from a naive initialisation.

Example

>>> from pycsamt.ai.inversion import (
...     EMInverter1D,
...     HybridInverter1D,
... )
>>> ai = EMInverter1D.load(
...     "checkpoints/mt1d_resnet.npz"
... )
>>> inv = HybridInverter1D(
...     "edi/",
...     ai_inverter=ai,
...     max_iter=200,
...     smoothness_weight=0.005,
... )
>>> inv.fit()
HybridInverter1D(n_stations=5, fitted)
>>> models = inv.predict()
>>> df = inv.convergence_curves()

Classes

HybridInverter1D(sites, ai_inverter, *[, ...])

Two-stage hybrid AI + physics 1-D inversion.

class pycsamt.ai.inversion.hybrid1d.HybridInverter1D(sites, ai_inverter, *, solver='mt1d', max_iter=200, smoothness_weight=0.005, lr=0.005, device=None, comp='xy', n_freqs=32, recursive=True, on_dup='replace', verbose=0)[source]

Bases: BaseHybridInverter

Two-stage hybrid AI + physics 1-D inversion.

Parameters:
  • sites (Any) – Path, EDIFile, EDICollection, Site, Sites, APISurvey, or iterable.

  • ai_inverter (EMInverter1D or str or Path) – Pre-trained supervised inverter (fitted EMInverter1D) or path to a saved .npz checkpoint.

  • solver ({'mt1d', 'csamt1d'}, default 'mt1d') – EM physics used in the refinement step.

  • max_iter (int, default 200) – Adam iterations for the physics refinement.

  • smoothness_weight (float, default 0.005) – Regularisation weight on log-resistivity first differences.

  • lr (float, default 5e-3) – Adam learning rate for Stage 2.

  • device (str or None) – Torch device. Auto-detects CUDA/CPU if None.

  • comp ({'xy', 'yx', 'xx', 'yy'}, default 'xy') – Impedance component for observed data.

  • n_freqs (int, default 32) – Frequency-grid size for EMInverter1D input.

  • recursive (bool, default True)

  • on_dup (str, default 'replace')

  • verbose (int, default 0)

fit(*, verbose=True, log_every=50)[source]

Run both inversion stages.

Parameters:
  • verbose (bool, default True) – Print per-station progress.

  • log_every (int, default 50) – Epoch-detail print frequency for Stage 2.

Return type:

self

predict()[source]

Return Stage-2 refined layered models.

Return type:

list of LayeredModel

stage1_models()[source]

Return Stage-1 (AI-only) layered models.

These are the AI starting points before physics refinement.

Return type:

list of LayeredModel

convergence_curves()[source]

Return Stage-2 Adam loss history.

Returns:

Columns: station, epoch, loss.

Return type:

pandas.DataFrame

residuals(stage=2)[source]

Observed vs predicted data fit.

Parameters:

stage ({1, 2}, default 2) – Which stage’s models to evaluate.

Returns:

Columns: station, freq, rho_obs, rho_pred, phase_obs, phase_pred.

Return type:

pandas.DataFrame

property stations: list[str][source]

Station names in order.

property n_sites: int[source]

Number of loaded stations.