pycsamt.ai.inversion.pinn1d#

Physics-informed 1-D MT/CSAMT inversion.

PINNInverter1D fits a layered Earth model to observed EM data without labelled training examples. Model parameters (log-resistivity and log-thickness) are optimised with Adam by minimising:

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

where \(\rho_a^{\rm pred}\) comes from the Wait (1954) 1-D MT recursion. The recursion is implemented in both PyTorch and TensorFlow; the active backend is selected automatically via pycsamt.backends.

Example

>>> from pycsamt.ai.inversion import PINNInverter1D
>>> inv = PINNInverter1D(
...     "edi/",
...     n_layers=10,
...     depth_max=2000.0,
...     smoothness_weight=0.01,
... )
>>> inv.fit(epochs=500)
PINNInverter1D(n_stations=5, fitted)
>>> models = inv.predict()

Classes

PINNInverter1D(sites, *[, solver, n_layers, ...])

Physics-informed 1-D EM inversion.

class pycsamt.ai.inversion.pinn1d.PINNInverter1D(sites, *, solver='mt1d', n_layers=10, depth_max=2000.0, smoothness_weight=0.01, lr=0.01, device=None, comp='xy', recursive=True, on_dup='replace', verbose=0)[source]

Bases: BasePINNInverter

Physics-informed 1-D EM inversion.

Fits a layered Earth model to observed MT/CSAMT apparent resistivity and phase by gradient descent. No labelled training data is required.

Parameters:
  • sites (Any) – Path, EDIFile, EDICollection, Site, Sites, APISurvey, or iterable. Station data are extracted at construction time.

  • solver ({'mt1d', 'csamt1d'}) – EM physics solver (TEM not supported).

  • n_layers (int, default 10) – Number of earth layers including the halfspace.

  • depth_max (float, default 2000.0) – Approximate investigation depth in metres, used to set equal initial layer thicknesses.

  • smoothness_weight (float, default 0.01) – Regularisation weight \(\lambda\) on the first-difference of log-resistivity.

  • lr (float, default 1e-2) – Adam learning rate.

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

  • comp ({'xy', 'yx', 'xx', 'yy'}, default 'xy') – Impedance tensor component to use.

  • recursive (bool, default True) – Passed to ensure_sites.

  • on_dup (str, default 'replace') – Passed to ensure_sites.

  • verbose (int, default 0) – Verbosity level for site loading.

fit(epochs=500, *, verbose=True, log_every=100)[source]

Run the physics-informed optimisation.

Parameters:
  • epochs (int, default 500) – Number of Adam iterations per station.

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

  • log_every (int, default 100) – Print epoch detail every this many steps.

Return type:

self

predict()[source]

Return fitted layered models for all stations.

Returns:

models – One per station, same order as stations.

Return type:

list of LayeredModel

residuals()[source]

Compute observed vs predicted data for all sites.

Returns:

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

Return type:

pandas.DataFrame

loss_curves()[source]

Return the Adam loss history for all stations.

Returns:

Columns: station, epoch, loss.

Return type:

pandas.DataFrame

property stations: list[str][source]

Station names in order.

property n_sites: int[source]

Number of loaded stations.