pycsamt.forward.em2d#

2-D magnetotelluric finite-difference forward solver.

MT2DForward solves the 2-D MT boundary-value problem for both the TE and TM polarisation modes on a non-uniform staggered grid using the finite-difference (FD) method.

Physics#

For a 2-D earth with conductivity σ(x, z) and a plane electromagnetic wave incident from above, the governing scalar PDEs (time convention e^{+iωt}) are:

TE mode (electric field parallel to strike, E_y):

∂²E_y/∂x² + ∂²E_y/∂z² − iωμ₀σ(x,z) E_y = 0

TM mode (magnetic field parallel to strike, H_y):

∂/∂x[σ⁻¹ ∂H_y/∂x] + ∂/∂z[σ⁻¹ ∂H_y/∂z] − iωμ₀ H_y = 0

Grid and node numbering#

The FD grid has (nx+1) × (nz+1) nodes. Node at column j, row i (depth) has global index k = i*(nx+1) + j. The surface is row i = 0, the bottom is row i = nz.

Boundary conditions#

Dirichlet conditions are applied at all four boundaries using the analytic 1-D MT response of the edge column profiles (left/right) or the halfspace (top/bottom). For the TE mode the normalised plane-wave source E_y = 1 at the surface is the natural starting point; the BC values at depth follow from the 1-D recursion. For the TM mode the analogous 1-D H_y field is used.

Each frequency requires two independent sparse solves (one per mode). With scipy.sparse.linalg.spsolve and grids of order 50 × 40 nodes (~2000 unknowns) each solve takes < 0.1 s on a single CPU core.

References

Wannamaker, P.E., Stodt, J.A., Rijo, L. (1987). A stable finite element solution for two-dimensional magnetotelluric modelling. Geophys. J. Int. 88, 277-296.

de Groot-Hedlin, C., Constable, S. (1990). Occam’s inversion to generate smooth, two-dimensional models from magnetotelluric data. Geophysics 55, 1613-1624.

Wait, J.R. (1954). On the relation between telluric currents and the Earth’s magnetic field. Geophysics 19, 281-289.

Classes

ForwardResponse2D(freqs, stations_x, zxy, ...)

Output of the 2-D MT forward solver.

MT2DForward(freqs, grid, *[, verbose])

2-D magnetotelluric finite-difference forward solver.

class pycsamt.forward.em2d.MT2DForward(freqs, grid, *, verbose=True)[source]#

Bases: object

2-D magnetotelluric finite-difference forward solver.

Solves both TE and TM modes for a list of frequencies on the provided Grid2D and returns a ForwardResponse2D with apparent resistivity and phase at all station positions.

Parameters:
  • freqs (array-like) – Frequencies [Hz] at which to evaluate the response.

  • grid (Grid2D) – 2-D resistivity model and station layout.

  • verbose (bool) – Print per-frequency progress.

Examples

Uniform halfspace — should recover the 1-D MT response:

>>> import numpy as np
>>> from pycsamt.forward.grid2d import Grid2D
>>> from pycsamt.forward.em2d import MT2DForward

>>> freqs = np.logspace(-2, 3, 10)
>>> g = Grid2D.halfspace(rho=100.0, nx=30, nz=20,
...                       x_max=5_000.0, z_max=3_000.0,
...                       n_stations=5)
>>> fwd = MT2DForward(freqs, g)
>>> resp = fwd.run()
>>> resp.rho_a_te.shape
(10, 5)

2-D model with conductive anomaly:

>>> g2 = Grid2D.with_anomaly(bg_rho=100.0, anomaly_rho=2.0,
...     anomaly_bounds=(1500.0, 3500.0, 300.0, 900.0),
...     nx=40, nz=25, x_max=6000.0, z_max=3000.0, n_stations=10)
>>> resp2 = MT2DForward(freqs, g2).run()
run()[source]#

Run the forward solver for all frequencies.

Return type:

ForwardResponse2D

class pycsamt.forward.em2d.ForwardResponse2D(freqs, stations_x, zxy, zyx, rho_a_te, phase_te, rho_a_tm, phase_tm, grid)[source]#

Bases: object

Output of the 2-D MT forward solver.

All impedance and apparent-resistivity arrays have shape (n_freqs, n_stations).

Parameters:
freqs: ndarray#
stations_x: ndarray#
zxy: ndarray#
zyx: ndarray#
rho_a_te: ndarray#
phase_te: ndarray#
rho_a_tm: ndarray#
phase_tm: ndarray#
grid: Grid2D#
property n_freqs: int[source]#
property n_stations: int[source]#
property periods: ndarray[source]#

Periods [s].

station_response(station)[source]#

Return all response arrays for one station as a dict.

Parameters:

station (int)

Return type:

dict

to_feature_array(*, mode='both', log_rho=True, include_phase=True)[source]#

Flatten to a 2-D feature matrix for ML training.

Parameters:
  • mode ({'te', 'tm', 'both'}) – Which mode(s) to include.

  • log_rho (bool) – Return log₁₀(ρ_a) instead of ρ_a.

  • include_phase (bool) – Concatenate phase alongside ρ_a.

Return type:

ndarray, shape (n_stations, n_features)

plot(station=0, ax=None, *, figsize=(9, 5))[source]#

Quick diagnostic plot of ρ_a and phase for one station.

Parameters:
  • station (int) – Station index.

  • ax (array of Axes or None) – Two axes (rho, phase). Created when not provided.

  • figsize (tuple)

Returns:

axes

Return type:

ndarray of Axes, shape (2,)