pycsamt.forward#

Forward-model configuration, synthetic models, 1-D/2-D/3-D EM forward responses, grids, noise models, batch execution, and plotting helpers.

Physics-based EM forward solvers and synthetic training-data generation.

The package provides 1-D electromagnetic forward solvers and synthetic dataset generation for AI/ML training.

This package has no machine-learning dependencies — only NumPy and SciPy are required. It provides the building blocks consumed by pycsamt.ai for training data generation.

Submodules#

em1d

Three 1-D solvers: MT1DForward, TEM1DForward, CSAMT1DForward.

synthetic

LayeredModel — the central data object for all 1-D models, with random, blocky, smooth, and from_geology constructors.

noise

Noise models for synthetic data: GaussianNoise, FieldRealisticNoise, MultiplicativeNoise.

batch

generate_dataset() — parallelised (model, response) pair generation for large training sets.

Quick start#

>>> import numpy as np
>>> from pycsamt.forward import MT1DForward, LayeredModel
>>> model = LayeredModel([100, 10, 500], [300, 800])
>>> resp = MT1DForward(np.logspace(-3, 4, 30)).run(model)
>>> resp.rho_a.shape
(30,)
class pycsamt.forward.MT1DForward(freqs)#

Bases: _Base1DForward

1-D magnetotelluric forward solver (plane-wave, isotropic earth).

Uses the exact Wait (1954) recursive impedance algorithm. Runs in O(n_freq × n_layers) time — fast enough for generating millions of synthetic training samples.

Parameters:

freqs (array-like) – Frequencies [Hz] at which to evaluate the response. Typical range: 1e-4 – 1e5 Hz for MT/AMT.

Examples

>>> import numpy as np
>>> from pycsamt.forward.em1d import MT1DForward
>>> from pycsamt.forward.synthetic import LayeredModel
>>> freqs = np.logspace(-3, 4, 30)
>>> model = LayeredModel(
...     resistivity=[100, 10, 500],
...     thickness=[500, 1000]
... )
>>> resp = MT1DForward(freqs).run(model)
>>> resp.rho_a.shape
(30,)
run(model)#

Compute the MT 1-D response for model.

Parameters:

model (LayeredModel) – Input earth model.

Returns:

Fields populated: z, rho_a, phase, freqs.

Return type:

ForwardResponse

class pycsamt.forward.TEM1DForward(times, loop_radius=50.0, moment=1.0, n_freqs=64, n_lam=100)#

Bases: _Base1DForward

1-D central-loop TEM forward solver (step-off waveform).

Computes the vertical magnetic field H_z(ω) via a numerical Hankel transform of the TE admittance kernel, then converts to the step-off time-domain dBz/dt via a cosine transform.

Note

This implementation uses scipy.integrate for correctness. It is suitable for generating training datasets of moderate size (up to ~10 000 samples). A Digital Linear Filter (DLF) optimisation yielding 100× speed-up is planned for Phase 2.

Parameters:
  • times (array-like) – Measurement times [s] for the step-off response. Typical range: 1e-6 – 1e-2 s.

  • loop_radius (float) – Transmitter loop radius [m]. Default 50 m.

  • moment (float) – Transmitter magnetic moment [A·m²]. Default 1 A·m².

  • n_freqs (int) – Number of frequency-domain evaluation points used in the cosine transform. Higher → better accuracy at early times.

  • n_lam (int)

References

Ward & Hohmann (1988), Electromagnetic Methods in Applied Geophysics, Vol. 1.

run(model)#

Compute the TEM 1-D step-off response for model.

Parameters:

model (LayeredModel) – Input earth model.

Returns:

Fields populated: dBz_dt, hz_freq, times.

Return type:

ForwardResponse

class pycsamt.forward.CSAMT1DForward(freqs, source_offset=None, dipole_length=1000.0)#

Bases: _Base1DForward

1-D controlled-source AMT forward solver.

In the far-field (source–receiver offset r ≫ skin depth δ) the CSAMT response approximates the MT plane-wave response. A first- order near-field correction factor after Zonge & Hughes (1991) is applied when source_offset is supplied.

Parameters:
  • freqs (array-like) – Frequencies [Hz].

  • source_offset (float or None) – Source–receiver distance [m]. If None, the far-field approximation is used without correction.

  • dipole_length (float) – Electric dipole length [m]. Default 1000 m.

References

Zonge, K.L. & Hughes, L.J. (1991). Controlled source audio- frequency magnetotellurics. In Electromagnetic Methods in Applied Geophysics, 2B, 713-809.

run(model)#

Compute the CSAMT 1-D response for model.

Returns:

Fields populated: z, rho_a, phase.

Return type:

ForwardResponse

class pycsamt.forward.ForwardResponse(method='MT1D', freqs=None, times=None, z=None, rho_a=None, phase=None, dBz_dt=None, hz_freq=None, model=None)#

Bases: object

Container for the output of a 1-D forward solver.

Parameters:
  • method (str) – Solver identifier ('MT1D', 'TEM1D', 'CSAMT1D').

  • freqs (ndarray or None) – Frequencies in Hz (MT/CSAMT).

  • times (ndarray or None) – Times in seconds (TEM).

  • z (ndarray or None) – Complex surface impedance (n_freq,) for MT/CSAMT [V/A].

  • rho_a (ndarray or None) – Apparent resistivity (n_freq,) [Ω·m].

  • phase (ndarray or None) – Impedance phase (n_freq,) [degrees, 0–90° for normal models].

  • dBz_dt (ndarray or None) – dBz/dt step-off response (n_times,) [T/s] for TEM.

  • hz_freq (ndarray or None) – Complex frequency-domain H_z (n_freq,) for TEM.

  • model (LayeredModel or None) – The input model that produced this response.

method: str = 'MT1D'#
freqs: ndarray | None = None#
times: ndarray | None = None#
z: ndarray | None = None#
rho_a: ndarray | None = None#
phase: ndarray | None = None#
dBz_dt: ndarray | None = None#
hz_freq: ndarray | None = None#
model: object = None#
to_array(*, log_rho=True, include_phase=True)#

Flatten to a 1-D feature vector for ML input.

For MT/CSAMT returns [log10(rho_a), phase_deg] concatenated (length 2 × n_freq); for TEM returns log10(|dBz_dt|) (length n_times).

Parameters:
  • log_rho (bool) – Apply log₁₀ to apparent resistivity (recommended).

  • include_phase (bool) – Include phase alongside ρ_a (MT only).

Return type:

ndarray

plot(ax=None, **kwargs)#

Quick diagnostic plot. Returns the Axes used.

class pycsamt.forward.MT2DForward(freqs, grid, *, verbose=True)#

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()#

Run the forward solver for all frequencies.

Return type:

ForwardResponse2D

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

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#
property n_stations: int#
property periods: ndarray#

Periods [s].

station_response(station)#

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)#

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))#

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,)

class pycsamt.forward.LayeredModel(resistivity, thickness, depth=None, name='')#

Bases: object

1-D layered earth model.

The earth has n_layers layers. The last layer is the halfspace (infinite thickness). Thicknesses apply to layers 0 … n−2.

Parameters:
  • resistivity (array-like, shape (n_layers,)) – Layer resistivities in Ω·m, ordered top → bottom.

  • thickness (array-like, shape (n_layers-1,)) – Layer thicknesses in metres. The halfspace has no thickness.

  • depth (ndarray or None) – Top-of-layer depths [m]; computed from thickness if not given.

  • name (str) – Optional label (e.g. geological scenario name).

Examples

>>> from pycsamt.forward.synthetic import LayeredModel
>>> m = LayeredModel(
...     resistivity=[100, 10, 500],
...     thickness=[300, 800],
... )
>>> m.n_layers
3
>>> m.depth
array([   0.,  300., 1100.])
resistivity: ndarray#
thickness: ndarray#
depth: ndarray = None#
name: str = ''#
property n_layers: int#

Number of layers including the halfspace.

property conductivity: ndarray#

Layer conductivities σ = 1/ρ [S/m].

to_vector(*, log_rho=True)#

Flatten to a 1-D parameter vector suitable for ML targets.

The vector layout is [ρ₀, ρ₁, …, ρ_{n-1}, h₀, h₁, …, h_{n-2}] where ρ values are log₁₀(Ω·m) when log_rho is True.

Parameters:

log_rho (bool) – If True (default), resistivities are stored as log₁₀(ρ). This normalises the dynamic range and improves neural network convergence.

Returns:

v

Return type:

ndarray, shape (2 * n_layers - 1,)

classmethod from_vector(v, n_layers, *, log_rho=True, name='')#

Reconstruct a LayeredModel from a flat parameter vector.

Parameters:
  • v (ndarray, shape (2 * n_layers - 1,)) – Parameter vector as produced by to_vector().

  • n_layers (int) – Number of layers.

  • log_rho (bool) – Whether resistivities in v are in log₁₀ space.

  • name (str)

Return type:

LayeredModel

classmethod random(n_layers=5, *, rho_range=(1.0, 10000.0), depth_max=2000.0, seed=None, name='random')#

Generate a random layered model with log-uniform resistivities.

Layer thicknesses are drawn from a Dirichlet-like distribution that sums to depth_max so that the model spans the full target depth range.

Parameters:
  • n_layers (int) – Number of layers (including halfspace).

  • rho_range ((low, high)) – Resistivity bounds in Ω·m.

  • depth_max (float) – Total depth spanned by the first (n-1) layers [m].

  • seed (int, Generator, or None) – Random seed for reproducibility.

  • name (str)

Return type:

LayeredModel

classmethod blocky(n_layers=4, *, rho_background=100.0, rho_anomaly=5.0, anomaly_layer=1, depth_max=1000.0, equal_thickness=True, seed=None, name='blocky')#

Build a model with a single conductive (or resistive) anomaly embedded in a resistive (or conductive) background.

Parameters:
  • rho_background (float) – Background layer resistivity [Ω·m].

  • rho_anomaly (float) – Anomaly layer resistivity [Ω·m].

  • anomaly_layer (int) – Zero-based index of the anomalous layer.

  • n_layers (int)

  • depth_max (float)

  • equal_thickness (bool)

  • seed (int | Generator | None)

  • name (str)

Return type:

LayeredModel

classmethod smooth(n_layers=10, *, rho_surface=100.0, rho_deep=10.0, depth_max=5000.0, perturbation=0.2, seed=None, name='smooth')#

Build a model with a smooth gradient from surface to depth, plus small random perturbations.

Parameters:
  • rho_surface (float) – Resistivity at the surface [Ω·m].

  • rho_deep (float) – Resistivity at depth_max [Ω·m].

  • perturbation (float) – Fractional standard deviation of log₁₀(ρ) noise added to the gradient. 0 = pure gradient.

  • n_layers (int)

  • depth_max (float)

  • seed (int | Generator | None)

  • name (str)

Return type:

LayeredModel

classmethod from_geology(name, *, seed=None)#

Generate a random model using a predefined geological prior.

Parameters:
  • name (str) – One of: 'sedimentary', 'crystalline', 'geothermal', 'marine', 'permafrost'.

  • seed (int | Generator | None)

Raises:

KeyError – If name is not in GEOLOGY_PRIORS.

Return type:

LayeredModel

plot(ax=None, *, log_scale=True, depth_max=None, label=None, **kwargs)#

Plot the 1-D resistivity–depth profile.

Parameters:
  • ax (Axes or None) – Target axes. Created if not given.

  • log_scale (bool) – Use log₁₀ scale on the resistivity axis.

  • depth_max (float or None) – Maximum depth shown. Defaults to 1.2× the deepest interface.

  • label (str or None) – Line label for legend.

Returns:

ax

Return type:

Axes

class pycsamt.forward.Grid2D(dx, dz, resistivity, x_stations, n_pad=0, name='')#

Bases: object

Non-uniform 2-D finite-difference grid for MT forward modelling.

Parameters:
  • dx (array-like, shape (nx,)) – Cell widths in the horizontal (x) direction [m].

  • dz (array-like, shape (nz,)) – Cell heights in the vertical (z, depth) direction [m].

  • resistivity (array-like, shape (nz, nx)) – Cell resistivities [Ω·m], top-to-bottom, left-to-right.

  • x_stations (array-like, shape (n_stations,)) – Horizontal positions of MT stations [m]. Must lie within [x_nodes[0], x_nodes[-1]].

  • n_pad (int) – Number of padding cells on each side (left, right) and at the bottom that were added during construction. Used internally to identify the core model region. Set to 0 if no padding is present.

  • name (str) – Optional label for the model.

Variables:
  • nx (int) – Total number of cells in x (includes padding).

  • nz (int) – Total number of cells in z (includes padding).

  • x_nodes (ndarray, shape (nx+1,)) – x-coordinates of vertical node lines [m].

  • z_nodes (ndarray, shape (nz+1,)) – z-coordinates of horizontal node lines (depth) [m].

  • x_centers (ndarray, shape (nx,)) – x-coordinates of cell centres [m].

  • z_centers (ndarray, shape (nz,)) – z-coordinates (depth) of cell centres [m].

  • core_x_slice (slice) – Slice that selects core (non-padding) columns from any [:, j] array.

  • core_z_slice (slice) – Slice that selects core (non-padding) rows from any [i, :] array.

Examples

Uniform halfspace:

>>> g = Grid2D.halfspace(rho=100.0, nx=30, nz=20,
...                       x_max=5_000.0, z_max=3_000.0,
...                       n_stations=10, station_x_max=4_000.0)
>>> g.resistivity.shape
(20, 30)

One conductive anomaly:

>>> g = Grid2D.with_anomaly(
...     bg_rho=500.0,
...     anomaly_rho=5.0,
...     anomaly_bounds=(1_000.0, 3_000.0, 200.0, 800.0),
...     nx=40, nz=25,
...     x_max=6_000.0, z_max=4_000.0,
...     n_stations=12,
... )

1-D layered model extended horizontally:

>>> from pycsamt.forward.synthetic import LayeredModel
>>> m = LayeredModel([100, 10, 500], [300, 800])
>>> g = Grid2D.from_1d_layers(m, nx=40, x_max=6_000.0, n_stations=12)
dx: ndarray#
dz: ndarray#
resistivity: ndarray#
x_stations: ndarray#
n_pad: int = 0#
name: str = ''#
property nx: int#

Number of cells in x.

property nz: int#

Number of cells in z (depth).

property n_stations: int#

Number of MT stations.

property n_nodes: int#

Total FD node count (nx+1) × (nz+1).

property x_nodes: ndarray#

x-coordinates of vertical node lines [m], shape (nx+1,).

property z_nodes: ndarray#

Depth coordinates of horizontal node lines [m], shape (nz+1,).

property x_centers: ndarray#

x-coordinates of cell centres [m], shape (nx,).

property z_centers: ndarray#

Depth coordinates of cell centres [m], shape (nz,).

property x_extent: float#

Total horizontal extent of the grid [m].

property z_extent: float#

Total depth extent of the grid [m].

property core_x_slice: slice#

Column slice that selects only core (non-padding) cells.

property core_z_slice: slice#

Row slice that selects only core (non-padding) cells.

property core_resistivity: ndarray#

Resistivity array clipped to the core (non-padding) region.

column_profile(col)#

Return the 1-D resistivity/thickness profile of column col.

Used by the FD solver to compute Dirichlet boundary conditions at the left and right edges from the 1-D MT response of the edge columns.

Parameters:

col (int) – Column index (0 = leftmost, nx-1 = rightmost).

Returns:

  • rho (ndarray, shape (nz,)) – Layer resistivities top-to-bottom [Ω·m].

  • thick (ndarray, shape (nz-1,)) – Layer thicknesses [m]. (Bottom layer is a halfspace.)

Return type:

tuple[ndarray, ndarray]

station_cell_indices()#

Return the column index of the cell that contains each station.

Returns:

indices

Return type:

ndarray of int, shape (n_stations,)

station_node_indices()#

Return the index of the nearest surface node for each station.

Surface nodes are at z = 0 and numbered 0, 1, …, nx.

Returns:

indices

Return type:

ndarray of int, shape (n_stations,)

property conductivity: ndarray#

Cell conductivities [S/m], shape (nz, nx).

harmonic_mean_x()#

Harmonic-mean conductivity at x-directed cell interfaces.

Used by the TM-mode FD assembler.

Returns:

sigma_hx[i, j] is the harmonic mean of sigma[i, j] and sigma[i, j+1].

Return type:

ndarray, shape (nz, nx-1)

harmonic_mean_z()#

Harmonic-mean conductivity at z-directed cell interfaces.

Returns:

sigma_hz[i, j] is the harmonic mean of sigma[i, j] and sigma[i+1, j].

Return type:

ndarray, shape (nz-1, nx)

plot(ax=None, *, log_scale=True, cmap='jet_r', clip_core=True, show_stations=True, figsize=(10, 5), vmin=None, vmax=None)#

Plot the 2-D resistivity model.

Parameters:
  • ax (Axes or None) – Target axes. Created when not given.

  • log_scale (bool) – Plot log₁₀(ρ) rather than ρ.

  • cmap (str) – Matplotlib colormap name.

  • clip_core (bool) – Clip to the non-padding core region.

  • show_stations (bool) – Mark station positions on the surface.

  • figsize ((float, float)) – Figure size when ax is not provided.

  • vmin (float or None) – Colormap limits in log₁₀(Ω·m) space when log_scale is True.

  • vmax (float or None) – Colormap limits in log₁₀(Ω·m) space when log_scale is True.

Returns:

ax

Return type:

Axes

classmethod halfspace(rho=100.0, *, nx=40, nz=30, x_max=10000.0, z_max=5000.0, n_pad=8, pad_factor=1.3, n_stations=10, station_x_max=None, name='halfspace')#

Create a uniform resistivity halfspace grid.

Parameters:
  • rho (float) – Background resistivity [Ω·m].

  • nx (int) – Number of core cells in x (padding added on both sides).

  • nz (int) – Number of core cells in z (padding added at the bottom).

  • x_max (float) – Total horizontal extent of the core region [m].

  • z_max (float) – Total depth of the core region [m].

  • n_pad (int) – Number of padding cells on each side (left, right, bottom).

  • pad_factor (float) – Exponential growth factor for padding cell sizes.

  • n_stations (int) – Number of equally spaced stations across the core region.

  • station_x_max (float or None) – Right-most station position [m]. Defaults to x_max.

  • name (str) – Label for the model.

Return type:

Grid2D

classmethod from_1d_layers(model, *, nx=40, x_max=10000.0, n_pad=8, pad_factor=1.3, n_stations=10, station_x_max=None, dz_min=10.0, name='')#

Build a 2-D grid by extending a 1-D LayeredModel.

Every column has the same 1-D layer stack. This is useful as a background model for synthetic anomaly tests and inversion starting models.

Parameters:
  • model (LayeredModel) – Source 1-D model. model.thickness defines the cell thicknesses; the deepest cell becomes the halfspace.

  • nx (int) – Number of core cells in x.

  • x_max (float) – Horizontal extent of the core region [m].

  • n_pad (int) – Padding cells on each side.

  • pad_factor (float) – Padding growth factor.

  • n_stations (int) – Number of equally spaced surface stations.

  • station_x_max (float or None) – Right-most station x [m].

  • dz_min (float) – Minimum cell height [m]; avoids excessively thin cells at depth.

  • name (str) – Model label.

Return type:

Grid2D

classmethod with_anomaly(bg_rho=100.0, anomaly_rho=5.0, anomaly_bounds=(2000.0, 4000.0, 200.0, 800.0), *, nx=50, nz=35, x_max=8000.0, z_max=4000.0, n_pad=8, pad_factor=1.3, n_stations=12, station_x_max=None, name='')#

Create a background halfspace with one rectangular anomaly.

Parameters:
  • bg_rho (float) – Background resistivity [Ω·m].

  • anomaly_rho (float) – Anomaly resistivity [Ω·m].

  • anomaly_bounds ((x_lo, x_hi, z_lo, z_hi)) – Anomaly extent in core coordinates [m]: horizontal from x_lo to x_hi, depth from z_lo to z_hi.

  • nx (int) – Core cell counts.

  • nz (int) – Core cell counts.

  • x_max (float) – Core region extents [m].

  • z_max (float) – Core region extents [m].

  • n_pad (int) – Padding cells per side.

  • pad_factor (float) – Padding growth factor.

  • n_stations (int) – Number of equally spaced surface stations.

  • station_x_max (float or None) – Right-most station x [m].

  • name (str) – Model label.

Return type:

Grid2D

Examples

Resistive body at mid-depth:

>>> g = Grid2D.with_anomaly(
...     bg_rho=50.0, anomaly_rho=2000.0,
...     anomaly_bounds=(2000.0, 4000.0, 500.0, 1500.0),
... )
classmethod random(*, nx=40, nz=30, x_max=8000.0, z_max=4000.0, n_pad=8, pad_factor=1.3, n_stations=10, rho_min=1.0, rho_max=10000.0, n_layers=4, lateral_variation=True, seed=None, name='random')#

Generate a random layered model with optional lateral variation.

Resistivities for n_layers horizontal layers are drawn from a log-uniform prior. When lateral_variation is True, each column’s resistivity is perturbed by ±30 % in log₁₀ space.

Parameters:
  • nx (int) – Core cell counts.

  • nz (int) – Core cell counts.

  • x_max (float) – Core extents [m].

  • z_max (float) – Core extents [m].

  • n_pad (int) – Padding cells per side.

  • rho_min (float) – Resistivity bounds [Ω·m].

  • rho_max (float) – Resistivity bounds [Ω·m].

  • n_layers (int) – Number of horizontal layers.

  • lateral_variation (bool) – Add column-wise log-normal perturbation.

  • seed (int or Generator or None)

  • name (str)

  • pad_factor (float)

  • n_stations (int)

Return type:

Grid2D

pycsamt.forward.make_padding(core_spacing, n_pad, factor=1.3)#

Return cell widths for one padding strip.

The first padding cell has width core_spacing * factor and each subsequent cell is factor times wider.

Parameters:
  • core_spacing (float) – Width/depth of the last core cell adjacent to the padding strip [m].

  • n_pad (int) – Number of padding cells.

  • factor (float) – Growth factor between successive padding cells. Values in [1.2, 1.5] give good results for MT; 1.3 is a safe default.

Returns:

Cell widths ordered from the core edge outward.

Return type:

numpy.ndarray, shape (n_pad,)

class pycsamt.forward.GaussianNoise(level=0.05, apply_to='rho_phase', phase_level=None)#

Bases: _BaseNoiseModel

Add relative Gaussian noise to an EM forward response.

For MT/CSAMT the noise is applied to log₁₀(ρ_a) and the phase independently. For TEM it is applied to log₁₀(|dBz/dt|).

Parameters:
  • level (float) – Relative noise standard deviation (e.g. 0.05 = 5 %).

  • apply_to ({'rho_phase', 'z', 'both'}) – Which quantities to perturb. Default 'rho_phase'.

  • phase_level (float or None) – Separate noise level for phase in degrees. If None, level is used scaled to the typical 45° phase range.

Examples

>>> import numpy as np
>>> from pycsamt.forward.em1d import MT1DForward
>>> from pycsamt.forward.synthetic import LayeredModel
>>> from pycsamt.forward.noise import GaussianNoise
>>> m = LayeredModel([100, 10, 500], [300, 800])
>>> resp = MT1DForward(np.logspace(-3, 4, 20)).run(m)
>>> noisy = GaussianNoise(level=0.05).apply(resp, seed=0)
>>> noisy.rho_a.shape
(20,)
apply(response, *, seed=None)#

Return a new ForwardResponse with noise added.

Parameters:
  • response (ForwardResponse) – Clean forward response.

  • seed (int or None) – Random seed for reproducibility.

Return type:

ForwardResponse

class pycsamt.forward.FieldRealisticNoise(base_level=0.02, powerline_freq=50.0, powerline_level=0.3, dead_band=True, dead_band_freq_range=(0.0003, 0.001), dead_band_level=0.15)#

Bases: _BaseNoiseModel

Frequency-dependent noise model for MT/CSAMT training data.

Simulates three dominant noise sources present in field data:

  1. Power-line harmonics — Gaussian spikes at 50 Hz, 100 Hz, 150 Hz (or 60/120/180 Hz for North American data).

  2. MT dead band — elevated noise at ~1 000–3 000 s period (≈ 3×10⁻⁴ – 10⁻³ Hz) due to reduced natural source energy.

  3. Background floor — minimum noise level applied uniformly.

Parameters:
  • base_level (float) – Background relative noise floor. Default 0.02 (2 %).

  • powerline_freq (float) – Fundamental power-line frequency [Hz]. 50 or 60.

  • powerline_level (float) – Additional noise at power-line harmonics (relative).

  • dead_band (bool) – If True, inflate noise in the MT dead band.

  • dead_band_freq_range ((low, high)) – Frequency range [Hz] of the dead band. Default (3e-4, 1e-3).

  • dead_band_level (float) – Additional noise level in the dead band. Default 0.15.

noise_profile(freqs)#

Return the frequency-dependent noise level array.

Parameters:

freqs (ndarray) – Frequencies [Hz].

Returns:

sigma – Relative noise standard deviation at each frequency.

Return type:

ndarray, same shape as freqs

apply(response, *, seed=None)#

Return a new ForwardResponse with noise added.

Parameters:
  • response (ForwardResponse) – Clean forward response.

  • seed (int or None) – Random seed for reproducibility.

Return type:

ForwardResponse

plot_profile(freqs, ax=None)#

Visualise the noise level vs frequency. Returns Axes.

Parameters:

freqs (ndarray)

class pycsamt.forward.MultiplicativeNoise(sigma_log10=0.05)#

Bases: _BaseNoiseModel

Log-space (multiplicative) Gaussian noise.

Equivalent to a log-normal perturbation on the data value. Appropriate when the data spans many orders of magnitude.

Parameters:

sigma_log10 (float) – Standard deviation of the log₁₀ perturbation. sigma_log10=0.05 corresponds to ≈ ±12 % variation.

apply(response, *, seed=None)#

Return a new ForwardResponse with noise added.

Parameters:
  • response (ForwardResponse) – Clean forward response.

  • seed (int or None) – Random seed for reproducibility.

Return type:

ForwardResponse

pycsamt.forward.add_gaussian_noise(response, level=0.05, *, seed=None)#

Convenience wrapper: add Gaussian noise at a given relative level.

Parameters:
Returns:

New response with noise applied.

Return type:

ForwardResponse

pycsamt.forward.add_noise(response, noise_model='gaussian', level=0.05, *, seed=None, **kwargs)#

Apply a named or pre-built noise model to a forward response.

Parameters:
  • response (ForwardResponse)

  • noise_model (str or noise instance) – 'gaussian', 'multiplicative', 'field', or an already-instantiated noise object.

  • level (float) – Base noise level (used when constructing named models).

  • seed (int or None)

  • **kwargs – Extra keyword arguments forwarded to the noise model constructor.

Return type:

ForwardResponse

pycsamt.forward.generate_dataset(solver='mt1d', n_samples=10000, *, freqs=None, times=None, n_layers=(3, 7), rho_range=(1.0, 10000.0), depth_max=2000.0, loop_radius=50.0, noise_level=0.05, noise_type='gaussian', geology=None, include_phase=True, seed=None, n_jobs=1, output=None, verbose=True)#

Generate a batch of synthetic (data, model) pairs for ML training.

Parameters:
  • solver ({'mt1d', 'tem1d', 'csamt1d'}) – Forward solver to use.

  • n_samples (int) – Total number of samples.

  • freqs (ndarray or None) – Frequencies [Hz] for MT/CSAMT. If None, uses np.logspace(-3, 4, 30) for MT.

  • times (ndarray or None) – Times [s] for TEM. If None, uses np.logspace(-6, -2, 25).

  • n_layers (int or (lo, hi)) – Fixed number of layers, or a range from which the count is drawn uniformly at random per sample.

  • rho_range ((low, high)) – Resistivity bounds in Ω·m.

  • depth_max (float) – Maximum depth of the model [m].

  • loop_radius (float) – TEM transmitter loop radius [m].

  • noise_level (float) – Relative noise standard deviation. 0 = noise-free.

  • noise_type (str) – Noise model: 'gaussian', 'multiplicative', 'field'.

  • geology (str or None) – If given, models are drawn from LayeredModel.from_geology() using this geological scenario name.

  • include_phase (bool) – Include impedance phase in the MT feature vector.

  • seed (int or None) – Base random seed. Worker seeds are derived deterministically.

  • n_jobs (int) – Number of parallel worker processes. -1 uses all CPU cores.

  • output (str or None) – If given, save the dataset to a .npz file at this path.

  • verbose (bool) – Print progress.

Return type:

ForwardDataset

Examples

>>> import numpy as np
>>> from pycsamt.forward.batch import generate_dataset
>>> ds = generate_dataset(n_samples=100, seed=0)
>>> ds.X.shape[0]
100
class pycsamt.forward.ForwardDataset(X, y, freqs=None, times=None, meta=None, solver='mt1d')#

Bases: object

Numpy container for a batch of (features, targets) EM samples.

Parameters:
  • X (ndarray, shape (n_samples, n_features)) – Model responses (log-scaled data).

  • y (ndarray, shape (n_samples, n_params)) – Model parameters (log10 resistivity + thickness).

  • freqs (ndarray or None) – Frequencies used (MT/CSAMT).

  • times (ndarray or None) – Times used (TEM).

  • meta (structured ndarray) – Per-sample metadata (n_layers, noise_level, …).

  • solver (str) – Solver used to generate this dataset.

X: ndarray#
y: ndarray#
freqs: ndarray | None = None#
times: ndarray | None = None#
meta: ndarray | None = None#
solver: str = 'mt1d'#
save(path)#

Save to a compressed .npz file.

Parameters:

path (str)

Return type:

None

classmethod load(path)#

Load from a .npz file produced by save().

Parameters:

path (str)

Return type:

ForwardDataset

split(val_frac=0.1, test_frac=0.1, seed=None)#

Split into train / validation / test sets.

Returns:

(train, val, test)

Return type:

tuple of ForwardDataset

Parameters:
pycsamt.forward.generate_dataset_3d(solver='mt1d', n_surveys=1000, *, n_stations=25, n_layers=4, freqs=None, extent=10000.0, corr_length=2000.0, log_rho_mean=2.0, log_rho_std=0.5, thickness_range=(100.0, 2000.0), station_layout='grid', noise_level=0.03, noise_type='gaussian', include_phase=True, seed=None, n_jobs=1, output=None, verbose=True)#

Generate a pseudo-3D synthetic dataset for GCNInverter3D training.

Each survey realisation consists of n_stations MT soundings whose per-layer log-resistivities are drawn from a spatially correlated Gaussian random field (GRF) with a squared-exponential covariance:

\[C(\mathbf{x}_i,\mathbf{x}_j) = \exp\!\left(-\frac{\|\mathbf{x}_i-\mathbf{x}_j\|^2} {2\,\ell^2}\right)\]

where \(\ell\) is corr_length. Layer thicknesses are drawn log-uniformly per survey but kept spatially constant (flat-layer assumption within one survey). All surveys share the same fixed station grid so that a single adjacency matrix covers the whole training set.

Parameters:
  • solver (str) – Forward solver. Currently only 'mt1d' is supported.

  • n_surveys (int) – Number of independent survey realisations.

  • n_stations (int) – Number of MT stations per survey.

  • n_layers (int) – Fixed number of earth layers (including halfspace).

  • freqs (ndarray or None) – Frequencies [Hz]. Defaults to np.logspace(-3, 4, 30).

  • extent (float) – Side length of the square survey area in metres.

  • corr_length (float) – Spatial correlation length of the GRF in metres. Set smaller than station spacing for uncorrelated models; larger for smooth lateral variation.

  • log_rho_mean (float) – Mean of log₁₀(ρ) for all layers (default 2 → 100 Ω·m).

  • log_rho_std (float) – Marginal standard deviation of the GRF in log₁₀(ρ) units.

  • thickness_range ((lo, hi)) – Bounds [m] for log-uniform layer thickness draws.

  • station_layout ('grid' or 'random') – 'grid' places stations on a regular grid of ⌈√n_stations⌉² points (default). 'random' draws uniform positions within [0, extent]².

  • noise_level (float) – Relative noise standard deviation applied to each response.

  • noise_type (str) – Noise model: 'gaussian', 'multiplicative', 'field'.

  • include_phase (bool) – Include impedance phase in the feature vector.

  • seed (int or None) – Base random seed. Worker seeds are derived deterministically.

  • n_jobs (int) – Number of parallel worker processes. -1 uses all CPU cores.

  • output (str or None) – If given, save the dataset to a compressed .npz file.

  • verbose (bool) – Print progress.

Returns:

Container with arrays X (n_surveys, n_stations, n_features), y (n_surveys, n_stations, n_params), and coords (n_stations, 2).

Return type:

SurveyDataset3D

Examples

>>> import numpy as np
>>> from pycsamt.forward.batch import generate_dataset_3d
>>> from pycsamt.ai.nets.gcn import build_adjacency
>>> ds = generate_dataset_3d(n_surveys=500, n_stations=16,
...                          n_layers=4, corr_length=2000., seed=0)
>>> ds.X.shape
(500, 16, 60)
>>> A = build_adjacency(ds.coords, radius=3000.)
>>> from pycsamt.ai.inversion.inv3d import GCNInverter3D
>>> inv = GCNInverter3D(n_features=ds.n_features, n_layers=4)
>>> inv.fit(ds.X, ds.y, adjacency=A, epochs=5, verbose=False)
class pycsamt.forward.SurveyDataset3D(X, y, coords, freqs=None, meta=None, solver='mt1d')#

Bases: object

Numpy container for a pseudo-3D multi-station survey dataset.

Designed for training GCNInverter3D. All surveys share the same fixed station grid so that a single pre-computed adjacency matrix covers the whole dataset.

Parameters:
  • X (ndarray, shape (n_surveys, n_stations, n_features)) – Per-station MT/CSAMT feature vectors (log-scaled data).

  • y (ndarray, shape (n_surveys, n_stations, n_params)) – Per-station model parameters [log10(ρ), thickness].

  • coords (ndarray, shape (n_stations, 2)) – Station (easting, northing) coordinates in metres.

  • freqs (ndarray or None) – Frequencies [Hz] used by the forward solver.

  • meta (structured ndarray or None) – Per-survey metadata (corr_length, noise_level).

  • solver (str) – Solver used to generate this dataset.

X: ndarray#
y: ndarray#
coords: ndarray#
freqs: ndarray | None = None#
meta: ndarray | None = None#
solver: str = 'mt1d'#
property n_surveys: int#

Number of synthetic survey realisations.

property n_stations: int#

Number of stations per survey.

property n_features: int#

Feature dimensionality per station.

property n_params: int#

Parameter dimensionality per station (2 × n_layers 1).

save(path)#

Save to a compressed .npz file.

Parameters:

path (str)

Return type:

None

classmethod load(path)#

Load from a .npz file produced by save().

Parameters:

path (str)

Return type:

SurveyDataset3D

split(val_frac=0.1, test_frac=0.1, seed=None)#

Split into train / validation / test sets along the survey axis.

Returns:

(train, val, test)

Return type:

tuple of SurveyDataset3D

Parameters:
class pycsamt.forward.Grid3D(dx, dy, dz, resistivity, stations_xy, n_pad=0, name='')#

Bases: object

Non-uniform 3-D finite-difference grid for MT forward modelling.

Parameters:
  • dx (array-like, shape (nx,)) – Cell widths in x (easting) [m], including padding.

  • dy (array-like, shape (ny,)) – Cell widths in y (northing) [m], including padding.

  • dz (array-like, shape (nz,)) – Cell heights in z (depth) [m], including padding.

  • resistivity (array-like, shape (nz, ny, nx)) – Cell resistivities [Ω·m], top→bottom, front→back, left→right.

  • stations_xy (array-like, shape (n_stations, 2)) – Surface station (x, y) coordinates [m]. Must lie within the grid extent.

  • n_pad (int) – Padding cells added on each side in x and y and at the bottom in z during construction.

  • name (str) – Optional label.

Examples

Uniform halfspace:

>>> g = Grid3D.halfspace(rho=100.0, nx=20, ny=20, nz=15,
...     x_max=8_000.0, y_max=8_000.0, z_max=4_000.0,
...     nx_stations=5, ny_stations=5)
>>> g.resistivity.shape   # includes padding
(23, 28, 28)

3-D conductive block:

>>> g = Grid3D.block_anomaly(
...     bg_rho=500.0, anomaly_rho=5.0,
...     bounds=(2_000.0, 6_000.0, 2_000.0, 6_000.0, 300.0, 1_500.0),
...     nx=25, ny=25, nz=18,
...     x_max=8_000.0, y_max=8_000.0, z_max=5_000.0,
...     nx_stations=5, ny_stations=5)
dx: ndarray#
dy: ndarray#
dz: ndarray#
resistivity: ndarray#
stations_xy: ndarray#
n_pad: int = 0#
name: str = ''#
property nx: int#
property ny: int#
property nz: int#
property n_stations: int#
property x_nodes: ndarray#
property y_nodes: ndarray#
property z_nodes: ndarray#
property x_centers: ndarray#
property y_centers: ndarray#
property z_centers: ndarray#
property x_extent: float#
property y_extent: float#
property z_extent: float#
xz_slice(yi)#

Extract an XZ (east-west) 2-D slice at y-cell yi.

Returns a Grid2D whose horizontal axis is x (easting) and vertical axis is z (depth). The station x-positions are those of all stations whose y-coordinate falls in cell yi.

Returns:

  • grid2d (Grid2D)

  • station_indices (ndarray of int) – Global indices (into stations_xy) of stations in this y-row. grid2d.x_stations[k] is the x-coordinate of stations_xy[station_indices[k]].

Parameters:

yi (int)

Return type:

tuple[Grid2D, ndarray]

yz_slice(xi)#

Extract a YZ (north-south) 2-D slice at x-cell xi.

The Grid2D horizontal axis is mapped to y (northing); its dx array contains dy and its resistivity is resistivity[:, :, xi].

Returns:

  • grid2d (Grid2D)

  • station_indices (ndarray of int) – Global indices of stations in this x-column. grid2d.x_stations[k] is the y-coordinate of the station (used as the horizontal axis in the yz-plane solver).

Parameters:

xi (int)

Return type:

tuple[Grid2D, ndarray]

column_profile_3d(xi, yi)#

Return the 1-D resistivity/thickness profile at cell (xi, yi).

Parameters:
  • xi (int Column index (x direction).)

  • yi (int Row index (y direction).)

Returns:

  • rho (ndarray, shape (nz,))

  • thick (ndarray, shape (nz-1,))

Return type:

tuple[ndarray, ndarray]

property conductivity: ndarray#

Cell conductivities [S/m], shape (nz, ny, nx).

plot(*, cmap='jet_r', log_scale=True, clip_core=True, show_stations=True, figsize=(13, 4.5), vmin=None, vmax=None)#

Plot orthogonal slices: XZ (mid-y), YZ (mid-x), XY (mid-z).

Parameters:
Returns:

  • fig (matplotlib.figure.Figure)

  • axes (ndarray of Axes, shape (3,))

classmethod halfspace(rho=100.0, *, nx=20, ny=20, nz=15, x_max=8000.0, y_max=8000.0, z_max=4000.0, n_pad=8, pad_factor=1.3, nx_stations=5, ny_stations=5, name='halfspace')#

Create a uniform resistivity 3-D halfspace with a regular station grid.

Parameters:
  • rho (float) – Background resistivity [Ω·m].

  • nx (int) – Core cell counts (padding added automatically).

  • ny (int) – Core cell counts (padding added automatically).

  • nz (int) – Core cell counts (padding added automatically).

  • x_max (float) – Core horizontal extents [m].

  • y_max (float) – Core horizontal extents [m].

  • z_max (float) – Core depth extent [m].

  • n_pad (int) – Padding cells per side (x, y) and at the bottom (z).

  • pad_factor (float) – Exponential growth factor for padding cells.

  • nx_stations (int) – Regular station grid dimensions.

  • ny_stations (int) – Regular station grid dimensions.

  • name (str)

Return type:

Grid3D

classmethod block_anomaly(bg_rho=100.0, anomaly_rho=5.0, bounds=(2000.0, 6000.0, 2000.0, 6000.0, 300.0, 1500.0), *, nx=25, ny=25, nz=18, x_max=8000.0, y_max=8000.0, z_max=5000.0, n_pad=8, pad_factor=1.3, nx_stations=5, ny_stations=5, name='')#

Create a background halfspace with one rectangular 3-D anomaly.

Parameters:
  • bg_rho (float) – Background resistivity [Ω·m].

  • anomaly_rho (float) – Anomaly resistivity [Ω·m].

  • bounds ((x_lo, x_hi, y_lo, y_hi, z_lo, z_hi)) – Anomaly extents in core coordinates [m].

  • nx (int Core cell counts.)

  • ny (int Core cell counts.)

  • nz (int Core cell counts.)

  • x_max (float Core extents [m].)

  • y_max (float Core extents [m].)

  • z_max (float Core extents [m].)

  • n_pad (int, float)

  • pad_factor (int, float)

  • nx_stations (int)

  • ny_stations (int)

  • name (str)

Return type:

Grid3D

Examples

3-D conductive fault zone:

>>> g = Grid3D.block_anomaly(
...     bg_rho=500.0, anomaly_rho=3.0,
...     bounds=(2_500., 5_500., 2_500., 5_500., 200., 1_800.))
classmethod random_layered(*, n_layers=4, nx=20, ny=20, nz=15, x_max=8000.0, y_max=8000.0, z_max=4000.0, n_pad=8, pad_factor=1.3, nx_stations=5, ny_stations=5, rho_min=1.0, rho_max=10000.0, lateral_variation=True, corr_length=2000.0, seed=None, name='random_3d')#

Generate a random layered 3-D model with optional lateral variation.

Resistivities for n_layers horizontal layers are drawn from a log-uniform prior. When lateral_variation is True, each column’s resistivity is smoothly perturbed using a Gaussian random field with correlation length corr_length.

Parameters:
  • n_layers (int Number of horizontal layers.)

  • nx (as above.)

  • ny (as above.)

  • nz (as above.)

  • x_max (as above.)

  • y_max (as above.)

  • z_max (as above.)

  • n_pad (as above.)

  • pad_factor (as above.)

  • rho_min (float Resistivity bounds [Ω·m].)

  • rho_max (float Resistivity bounds [Ω·m].)

  • lateral_variation (bool)

  • corr_length (float GRF correlation length [m].)

  • seed (int or Generator or None.)

  • name (str)

  • nx_stations (int)

  • ny_stations (int)

Return type:

Grid3D

class pycsamt.forward.MT3DForward(freqs, grid, *, method='quasi3d', verbose=True)#

Bases: object

Quasi-3D magnetotelluric forward solver.

Runs MT2DForward on orthogonal XZ and YZ cross-sections extracted from a Grid3D model and assembles the result into an approximate full impedance tensor.

Parameters:
  • freqs (array-like) – Frequencies [Hz].

  • grid (Grid3D) – 3-D resistivity model with surface station positions.

  • method ({'quasi3d'}) – Forward solver method. Currently only 'quasi3d' is implemented. A true 3-D FD Yee-grid solver ('fd3d') is planned for a future phase.

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

Examples

Halfspace — should recover the 1-D MT response:

>>> import numpy as np
>>> from pycsamt.forward.grid3d import Grid3D
>>> from pycsamt.forward.em3d import MT3DForward

>>> freqs = np.logspace(-1, 2, 8)
>>> g = Grid3D.halfspace(rho=100.0, nx=16, ny=16, nz=12,
...     x_max=5_000.0, y_max=5_000.0, z_max=3_000.0,
...     nx_stations=3, ny_stations=3)
>>> resp = MT3DForward(freqs, g).run()
>>> resp.rho_a_xy.shape
(8, 9)

3-D conductive block:

>>> g = Grid3D.block_anomaly(bg_rho=500.0, anomaly_rho=5.0, nx=20, ny=20, nz=15,
...     x_max=6_000.0, y_max=6_000.0, z_max=4_000.0,
...     nx_stations=4, ny_stations=4)
>>> resp = MT3DForward(freqs, g, verbose=False).run()
>>> resp.rho_a_xy.std(axis=1).max() > 1.0   # lateral variation present
True
run()#

Run the forward solver and return the full impedance tensor.

Return type:

ForwardResponse3D

class pycsamt.forward.ForwardResponse3D(freqs, stations_xy, zxy, zyx, zxx, zyy, rho_a_xy, phase_xy, rho_a_yx, phase_yx, rho_a_xx, phase_xx, rho_a_yy, phase_yy, method='quasi3d', grid=None)#

Bases: object

Full (approximate) impedance tensor from the 3-D MT forward solver.

All arrays have shape (n_freqs, n_stations).

Parameters:
  • freqs (ndarray, shape (n_freqs,))

  • stations_xy (ndarray, shape (n_stations, 2)) – Station (x, y) positions [m].

  • zxy (ndarray of complex) – Impedance tensor components [V/A].

  • zyx (ndarray of complex) – Impedance tensor components [V/A].

  • zxx (ndarray of complex) – Impedance tensor components [V/A].

  • zyy (ndarray of complex) – Impedance tensor components [V/A].

  • rho_a_xy (ndarray) – Apparent resistivities [Ω·m].

  • rho_a_yx (ndarray) – Apparent resistivities [Ω·m].

  • rho_a_xx (ndarray) – Apparent resistivities [Ω·m].

  • rho_a_yy (ndarray) – Apparent resistivities [Ω·m].

  • phase_xy (ndarray) – Impedance phases [degrees].

  • phase_yx (ndarray) – Impedance phases [degrees].

  • phase_xx (ndarray) – Impedance phases [degrees].

  • phase_yy (ndarray) – Impedance phases [degrees].

  • method (str) – Solver method ('quasi3d').

  • grid (Grid3D) – Source model.

freqs: ndarray#
stations_xy: ndarray#
zxy: ndarray#
zyx: ndarray#
zxx: ndarray#
zyy: ndarray#
rho_a_xy: ndarray#
phase_xy: ndarray#
rho_a_yx: ndarray#
phase_yx: ndarray#
rho_a_xx: ndarray#
phase_xx: ndarray#
rho_a_yy: ndarray#
phase_yy: ndarray#
method: str = 'quasi3d'#
grid: Grid3D = None#
property n_freqs: int#
property n_stations: int#
property periods: ndarray#
to_feature_array(*, components='xy_yx', log_rho=True, include_phase=True)#

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

Parameters:
  • components (str) – Comma/underscore-separated component names. E.g. "xy_yx" (default) uses Z_xy and Z_yx; "xy" uses only Z_xy; "all" uses all four.

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

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

Returns:

X

Return type:

ndarray, shape (n_stations, n_features)

to_survey_dataset(y_models=None, *, components='xy_yx')#

Wrap this response as a single-survey SurveyDataset3D.

The result can be concatenated with other surveys to build a training dataset for GCNInverter3D.

Parameters:
  • y_models (ndarray or None) – Per-station model target vectors, shape (n_stations, n_params). When None a zero placeholder is used.

  • components (str) – Passed to to_feature_array().

Returns:

Single-survey dataset (n_surveys = 1).

Return type:

SurveyDataset3D

station_response(station)#

Return all tensor components for one station as a dict.

Parameters:

station (int)

Return type:

dict

class pycsamt.forward.ForwardConfig(solver='mt1d', freq_min=0.0001, freq_max=10000.0, n_freqs=30, time_min=1e-06, time_max=0.01, n_times=25, loop_radius=50.0, n_layers_min=3, n_layers_max=7, rho_min=1.0, rho_max=10000.0, depth_max=2000.0, geology=None, n_samples=10000, noise_level=0.05, noise_type='gaussian', include_phase=True, seed=None, n_jobs=1, output_dir='.', output_name='forward_dataset', verbose=True)#

Bases: object

Collect settings that define a 1-D forward modelling / dataset run.

ForwardConfig is the central configuration object for generate_dataset() and the three 1-D solvers. All fields are plain Python scalars so that the dataclass can be serialised to Python, JSON, and YAML without any numpy dependencies.

The recommended workflow is:

  1. Generate a template with write_template().

  2. Edit the values in the generated file.

  3. Load the edited file with from_file().

  4. Optionally call validate() to catch range errors early.

  5. Pass to_dataset_kwargs() to generate_dataset().

Parameters:
  • solver ({'mt1d', 'csamt1d', 'tem1d'}) – Forward solver.

  • freq_min (float) – Frequency grid bounds [Hz] for MT/CSAMT.

  • freq_max (float) – Frequency grid bounds [Hz] for MT/CSAMT.

  • n_freqs (int) – Number of logarithmically spaced frequency points.

  • time_min (float) – Time-gate grid bounds [s] for TEM.

  • time_max (float) – Time-gate grid bounds [s] for TEM.

  • n_times (int) – Number of logarithmically spaced time-gate points.

  • loop_radius (float) – TEM transmitter loop radius [m].

  • n_layers_min (int) – Layer count range (inclusive). Equal values fix the count.

  • n_layers_max (int) – Layer count range (inclusive). Equal values fix the count.

  • rho_min (float) – Resistivity bounds [Ω·m] for the random prior.

  • rho_max (float) – Resistivity bounds [Ω·m] for the random prior.

  • depth_max (float) – Maximum total depth [m] across all layers except the halfspace.

  • geology (str or None) – Geological prior scenario name; overrides rho/depth bounds when set.

  • n_samples (int) – Number of (model, response) pairs to generate.

  • noise_level (float) – Relative noise standard deviation (0 = noise-free).

  • noise_type (str) – Noise model: 'gaussian', 'multiplicative', 'field'.

  • include_phase (bool) – Include impedance phase in the MT/CSAMT feature vector.

  • seed (int or None) – Global random seed for reproducibility.

  • n_jobs (int) – Parallel worker count (-1 = all cores).

  • output_dir (str or None) – Directory for the saved .npz dataset. None skips saving.

  • output_name (str) – Base file name (without extension) for the saved dataset.

  • verbose (bool) – Print progress and summary.

Examples

Default MT1D configuration:

>>> cfg = ForwardConfig()
>>> cfg.solver
'mt1d'

Fixed 5-layer configuration with geology prior:

>>> cfg = ForwardConfig(
...     solver="mt1d",
...     n_layers_min=5,
...     n_layers_max=5,
...     geology="sedimentary",
...     n_samples=10_000,
...     seed=0,
... )

Generate a template file and round-trip:

>>> path = ForwardConfig.write_template("forward_config.py")
>>> cfg = ForwardConfig.from_file(path)
>>> cfg.solver
'mt1d'
solver: str = 'mt1d'#
freq_min: float = 0.0001#
freq_max: float = 10000.0#
n_freqs: int = 30#
time_min: float = 1e-06#
time_max: float = 0.01#
n_times: int = 25#
loop_radius: float = 50.0#
n_layers_min: int = 3#
n_layers_max: int = 7#
rho_min: float = 1.0#
rho_max: float = 10000.0#
depth_max: float = 2000.0#
geology: str | None = None#
n_samples: int = 10000#
noise_level: float = 0.05#
noise_type: str = 'gaussian'#
include_phase: bool = True#
seed: int | None = None#
n_jobs: int = 1#
output_dir: str | None = '.'#
output_name: str = 'forward_dataset'#
verbose: bool = True#
validate()#

Check parameter ranges and raise ValueError on errors.

Call before a long dataset generation run to catch obvious mistakes (e.g. freq_min >= freq_max) before any compute is spent.

Raises:

ValueError – Descriptive message pointing to the offending parameter.

Return type:

None

freq_grid()#

Return the logarithmically spaced frequency array [Hz].

This is the array that would be passed as freqs to the MT/CSAMT solvers and to generate_dataset().

Return type:

numpy.ndarray, shape (n_freqs,)

time_grid()#

Return the logarithmically spaced time-gate array [s].

This is the array that would be passed as times to the TEM solver and to generate_dataset().

Return type:

numpy.ndarray, shape (n_times,)

to_dataset_kwargs()#

Assemble keyword arguments for generate_dataset().

The returned dict is ready to be unpacked directly:

from pycsamt.forward.batch import generate_dataset
ds = generate_dataset(**cfg.to_dataset_kwargs())
Returns:

All keyword arguments for generate_dataset, with numpy arrays built from the stored scalar parameters.

Return type:

dict

to_template(path='forward_config.py', *, fmt=None)#

Write this configuration to an annotated source-of-truth file.

Parameters:
  • path (path-like, default "forward_config.py") – Destination file. Suffixes .py, .json, .yml, and .yaml select the output format automatically.

  • fmt ({"py", "json", "yml", "yaml"}, optional) – Explicit format override. When omitted, the suffix of path is used. Paths without a suffix default to Python.

Returns:

Path of the generated file.

Return type:

pathlib.Path

classmethod write_template(path='forward_config.py', *, fmt=None)#

Generate a documented source-of-truth configuration file.

Creates a file with default parameter values and an inline comment for every parameter explaining its role. Edit the generated file, then load it with from_file().

Parameters:
  • path (path-like, default "forward_config.py") – Destination file. The suffix determines the output format (.py, .json, .yml).

  • fmt ({"py", "json", "yml", "yaml"}, optional) – Explicit format override.

Returns:

Path of the generated file.

Return type:

pathlib.Path

Examples

>>> from pycsamt.forward.config import ForwardConfig
>>> path = ForwardConfig.write_template("my_forward.yml")
>>> path.suffix
'.yml'
classmethod from_file(path, *, strict=True)#

Load a configuration from a source-of-truth file.

Parameters:
  • path (path-like) – Python, JSON, YML, or YAML file generated by write_template() or following the same structure.

  • strict (bool, default True) – If True, unknown keys raise ValueError. If False, unknown keys are silently ignored.

Returns:

Configuration populated from the file values.

Return type:

ForwardConfig

Examples

>>> ForwardConfig.write_template("forward_config.json")
PosixPath('forward_config.json')
>>> cfg = ForwardConfig.from_file("forward_config.json")
>>> cfg.solver
'mt1d'
classmethod read(path, *, strict=True)#

Alias — matches the convention used by ModEmConfig and OccamConfig.

Parameters:
Return type:

ForwardConfig

summary()#

Return a human-readable multi-line summary of the configuration.

Return type:

str

class pycsamt.forward.ForwardConfig2D(freq_min=0.001, freq_max=1000.0, n_freqs=20, nx=40, nz=30, x_max=10000.0, z_max=6000.0, n_pad=8, pad_factor=1.3, bg_rho=100.0, model_type='halfspace', anomaly_rho=5.0, anomaly_x_lo=2000.0, anomaly_x_hi=6000.0, anomaly_z_lo=300.0, anomaly_z_hi=1500.0, n_stations=10, station_x_max=None, verbose=True)#

Bases: object

Collect settings for a 2-D MT finite-difference forward run.

The configuration covers four areas: frequency grid, FD grid geometry, starting earth model, and station layout.

Parameters:
  • freq_min (float) – Frequency range [Hz].

  • freq_max (float) – Frequency range [Hz].

  • n_freqs (int) – Number of logarithmically spaced frequencies.

  • nx (int) – Core cell counts (x, z).

  • nz (int) – Core cell counts (x, z).

  • x_max (float) – Core region extents [m].

  • z_max (float) – Core region extents [m].

  • n_pad (int) – Padding cells per side.

  • pad_factor (float) – Padding growth factor.

  • bg_rho (float) – Background resistivity [Ω·m].

  • model_type ({'halfspace', 'anomaly', 'random'}) – Grid constructor to use.

  • anomaly_rho (float) – Anomaly resistivity [Ω·m] (model_type=’anomaly’ only).

  • anomaly_x_lo (float) – Horizontal anomaly bounds [m].

  • anomaly_x_hi (float) – Horizontal anomaly bounds [m].

  • anomaly_z_lo (float) – Depth anomaly bounds [m].

  • anomaly_z_hi (float) – Depth anomaly bounds [m].

  • n_stations (int) – Number of equally spaced surface stations.

  • station_x_max (float or None) – Right-most station position [m].

  • verbose (bool)

Examples

Default halfspace:

>>> cfg = ForwardConfig2D()
>>> cfg.model_type
'halfspace'
>>> cfg.validate()

Template round-trip:

>>> import tempfile, os
>>> with tempfile.NamedTemporaryFile(suffix='.yml', delete=False) as f:
...     path = f.name
>>> _ = ForwardConfig2D.write_template(path)
>>> cfg2 = ForwardConfig2D.from_file(path)
>>> os.unlink(path)
freq_min: float = 0.001#
freq_max: float = 1000.0#
n_freqs: int = 20#
nx: int = 40#
nz: int = 30#
x_max: float = 10000.0#
z_max: float = 6000.0#
n_pad: int = 8#
pad_factor: float = 1.3#
bg_rho: float = 100.0#
model_type: str = 'halfspace'#
anomaly_rho: float = 5.0#
anomaly_x_lo: float = 2000.0#
anomaly_x_hi: float = 6000.0#
anomaly_z_lo: float = 300.0#
anomaly_z_hi: float = 1500.0#
n_stations: int = 10#
station_x_max: float | None = None#
verbose: bool = True#
validate()#

Raise ValueError on invalid parameter values.

Return type:

None

freq_grid()#

Return the logarithmically spaced frequency array [Hz].

Return type:

ndarray

to_grid(seed=None)#

Construct a Grid2D from this config.

Parameters:

seed (int or None) – Random seed (used only for model_type='random').

Return type:

Grid2D

to_solver_kwargs()#

Return kwargs for MT2DForward.

Return type:

dict[str, Any]

to_template(path='forward_config_2d.py', *, fmt=None)#

Write to an annotated source-of-truth file.

Parameters:
Return type:

Path

classmethod write_template(path='forward_config_2d.py', *, fmt=None)#

Generate a documented source-of-truth file with default values.

Parameters:
  • path (path-like)

  • fmt ({"py", "json", "yml", "yaml"}, optional)

Return type:

pathlib.Path

classmethod from_file(path, *, strict=True)#

Load from a generated source-of-truth file.

Parameters:
  • path (path-like)

  • strict (bool)

Return type:

ForwardConfig2D

classmethod read(path, *, strict=True)#

Load from a generated source-of-truth file.

Parameters:
  • path (path-like)

  • strict (bool)

Return type:

ForwardConfig2D

summary()#
Return type:

str

class pycsamt.forward.ForwardConfig3D(freq_min=0.01, freq_max=1000.0, n_freqs=15, method='quasi3d', nx=20, ny=20, nz=15, x_max=8000.0, y_max=8000.0, z_max=4000.0, n_pad=8, pad_factor=1.3, bg_rho=100.0, model_type='halfspace', anomaly_rho=5.0, anomaly_x_lo=2000.0, anomaly_x_hi=6000.0, anomaly_y_lo=2000.0, anomaly_y_hi=6000.0, anomaly_z_lo=300.0, anomaly_z_hi=1500.0, n_layers=4, lateral_variation=True, corr_length=2000.0, nx_stations=5, ny_stations=5, verbose=True)#

Bases: object

Collect settings for a quasi-3D MT forward modelling run.

Parameters:
  • freq_min (float) – Frequency range [Hz].

  • freq_max (float) – Frequency range [Hz].

  • n_freqs (int)

  • method (str) – Forward method (‘quasi3d’).

  • nx (int) – Core cell counts.

  • ny (int) – Core cell counts.

  • nz (int) – Core cell counts.

  • x_max (float) – Core extents [m].

  • y_max (float) – Core extents [m].

  • z_max (float) – Core extents [m].

  • n_pad (int)

  • pad_factor (float)

  • bg_rho (float)

  • model_type ({'halfspace', 'block_anomaly', 'random_layered'})

  • anomaly_rho (float)

  • anomaly_x_lo (float)

  • anomaly_x_hi (float)

  • anomaly_y_lo (float)

  • anomaly_y_hi (float)

  • anomaly_z_lo (float)

  • anomaly_z_hi (float)

  • n_layers (int)

  • lateral_variation (bool)

  • corr_length (float)

  • nx_stations (int)

  • ny_stations (int)

  • verbose (bool)

Examples

Default halfspace:

>>> cfg = ForwardConfig3D()
>>> cfg.validate()
>>> grid = cfg.to_grid()

Block anomaly:

>>> cfg = ForwardConfig3D(
...     model_type='block_anomaly',
...     anomaly_rho=5.0,
...     anomaly_x_lo=2000., anomaly_x_hi=6000.,
...     anomaly_y_lo=2000., anomaly_y_hi=6000.,
...     anomaly_z_lo=300.,  anomaly_z_hi=1500.,
... )
freq_min: float = 0.01#
freq_max: float = 1000.0#
n_freqs: int = 15#
method: str = 'quasi3d'#
nx: int = 20#
ny: int = 20#
nz: int = 15#
x_max: float = 8000.0#
y_max: float = 8000.0#
z_max: float = 4000.0#
n_pad: int = 8#
pad_factor: float = 1.3#
bg_rho: float = 100.0#
model_type: str = 'halfspace'#
anomaly_rho: float = 5.0#
anomaly_x_lo: float = 2000.0#
anomaly_x_hi: float = 6000.0#
anomaly_y_lo: float = 2000.0#
anomaly_y_hi: float = 6000.0#
anomaly_z_lo: float = 300.0#
anomaly_z_hi: float = 1500.0#
n_layers: int = 4#
lateral_variation: bool = True#
corr_length: float = 2000.0#
nx_stations: int = 5#
ny_stations: int = 5#
verbose: bool = True#
validate()#

Raise ValueError on invalid parameters.

Return type:

None

freq_grid()#

Return the logarithmically spaced frequency array [Hz].

Return type:

ndarray

to_grid(seed=None)#

Construct a Grid3D from this config.

Parameters:

seed (int or None) – Random seed (used only for model_type='random_layered').

Return type:

Grid3D

to_solver_kwargs()#

Return kwargs for MT3DForward.

Return type:

dict[str, Any]

to_template(path='forward_config_3d.py', *, fmt=None)#

Write an annotated source-of-truth file.

Parameters:
Return type:

Path

classmethod write_template(path='forward_config_3d.py', *, fmt=None)#

Generate a documented source-of-truth configuration file.

Parameters:
  • path (path-like)

  • fmt ({"py", "json", "yml", "yaml"}, optional)

Return type:

pathlib.Path

classmethod from_file(path, *, strict=True)#

Load from a source-of-truth file.

Parameters:
  • path (path-like)

  • strict (bool)

Return type:

ForwardConfig3D

classmethod read(path, *, strict=True)#

Load from a source-of-truth file.

Parameters:
  • path (path-like)

  • strict (bool)

Return type:

ForwardConfig3D

summary()#
Return type:

str

pycsamt.forward.plot_response_1d(response, *, modes='both', show_te=<object object>, show_tm=<object object>, color_te=<object object>, color_tm=<object object>, lw=<object object>, marker_te=<object object>, marker_tm=<object object>, ms=<object object>, label_te=<object object>, label_tm=<object object>, title='', figsize=(7, 5.5), axes=None)#

Plot 1-D MT/CSAMT apparent resistivity and phase vs period (or frequency).

Reads visual defaults from PYCSAMT_STYLE and axis behaviour from PYCSAMT_CONTROL.

Parameters:
  • response (ForwardResponse) – Output of MT1DForward or CSAMT1DForward.

  • modes ({'te', 'tm', 'both'}) – Which modes to plot. For a 1-D response response.rho_a and response.phase hold a single polarisation; pass 'both' to show both ρ_a curves with TE/TM styling on the same axes.

  • show_te (bool) – Override visibility of each mode independently.

  • show_tm (bool) – Override visibility of each mode independently.

  • color_te (colour spec) – Line colours. Default: PYCSAMT_STYLE.mt.te.color / PYCSAMT_STYLE.mt.tm.color.

  • color_tm (colour spec) – Line colours. Default: PYCSAMT_STYLE.mt.te.color / PYCSAMT_STYLE.mt.tm.color.

  • lw (float) – Line width.

  • marker_te (str) – Marker styles.

  • marker_tm (str) – Marker styles.

  • ms (float) – Marker size.

  • label_te (str) – Legend labels.

  • label_tm (str) – Legend labels.

  • title (str) – Figure suptitle.

  • figsize ((float, float))

  • axes (array-like of Axes or None) – Two pre-existing axes (rho, phase). Created when not given.

Returns:

axes[ax_rho, ax_phase]

Return type:

ndarray of Axes, shape (2,)

pycsamt.forward.plot_model_1d(models, labels=None, *, log_rho=True, depth_max=None, lw=<object object>, alpha=<object object>, title='', figsize=(3.8, 5.5), ax=None)#

Plot one or more 1-D layered earth models as resistivity-depth profiles.

Multiple models are coloured with PYCSAMT_STYLE.multiline so the gradient or cycle palette matches all other multi-model plots.

Parameters:
  • models (LayeredModel or list of LayeredModel) – One model or a list to overlay.

  • labels (list of str, optional) – Legend labels; defaults to model name attributes.

  • log_rho (bool) – Use log₁₀ scale on the resistivity axis.

  • depth_max (float or None) – Maximum depth shown [m]. Defaults to the deepest interface × 1.2.

  • lw (float) – Line width. Default: PYCSAMT_STYLE.multiline.lw.

  • alpha (float) – Line alpha. Default: PYCSAMT_STYLE.multiline.alpha.

  • title (str)

  • figsize ((float, float))

  • ax (Axes or None)

Returns:

ax

Return type:

Axes

pycsamt.forward.plot_response_and_model_1d(response, model=None, *, title='', figsize=(10, 5), gridspec_kw=None)#

3-panel figure combining model depth profile, ρ_a, and phase.

This is the canonical “validate and save” view for a 1-D forward run.

Parameters:
Return type:

Figure

pycsamt.forward.plot_model_2d(grid, *, cmap='jet_r', log_scale=True, clip_core=True, vmin=None, vmax=None, show_stations=True, station_preset='inversion', title='', figsize=(11, 4), ax=None)#

Plot the 2-D resistivity model on a colour map.

Station markers and labels are rendered using PYCSAMT_STATION_RENDERING.

Parameters:
  • grid (Grid2D)

  • cmap (str) – Colourmap name. "jet_r" is the geophysical convention (blue = conductive, red = resistive).

  • log_scale (bool) – Display log₁₀(ρ) rather than ρ.

  • clip_core (bool) – Clip to the non-padding core region.

  • vmin (float or None) – Colour limits in log₁₀(Ω·m) when log_scale is True.

  • vmax (float or None) – Colour limits in log₁₀(Ω·m) when log_scale is True.

  • show_stations (bool) – Render station markers and labels on the surface.

  • station_preset (str) – "inversion" or "pseudosection" or "survey".

  • title (str)

  • figsize ((float, float))

  • ax (Axes or None)

Returns:

ax

Return type:

Axes

pycsamt.forward.plot_pseudosection_2d(response, *, mode='te', quantity='rho_a', cmap=<object object>, vmin=None, vmax=None, n_contours=0, show_stations=True, station_preset='pseudosection', title='', figsize=(11, 5), ax=None)#

Plot a 2-D MT pseudo-section (period × station distance).

The colour shows log₁₀(ρ_a) or phase at each (period, station) point. Station markers are rendered via PYCSAMT_STATION_RENDERING.

Parameters:
  • response (ForwardResponse2D)

  • mode ({'te', 'tm'}) – Which polarisation mode to display.

  • quantity ({'rho_a', 'phase'}) – Quantity to colour.

  • cmap (str) – Colour map. Defaults to "jet_r" for ρ_a and "RdBu_r" for phase.

  • vmin (float or None) – Colour limits.

  • vmax (float or None) – Colour limits.

  • n_contours (int) – Number of contour lines overlaid on the colour map (0 = none).

  • show_stations (bool) – Add station axis with markers.

  • station_preset (str)

  • title (str)

  • figsize ((float, float))

  • ax (Axes or None)

Returns:

ax

Return type:

Axes

pycsamt.forward.plot_response_profiles(response, *, mode='te', quantity='rho_a', freq_indices=None, n_freqs_shown=5, lw=<object object>, alpha=<object object>, title='', figsize=(9, 4), ax=None)#

Plot ρ_a (or phase) vs station distance at selected frequencies.

Each frequency is a separate line coloured by PYCSAMT_STYLE.multiline, making it easy to see how the lateral anomaly signature changes with depth (period).

Parameters:
  • response (ForwardResponse2D)

  • mode ({'te', 'tm'})

  • quantity ({'rho_a', 'phase'})

  • freq_indices (sequence of int or None) – Indices into response.freqs to display. When None, n_freqs_shown equally spaced indices are chosen automatically.

  • n_freqs_shown (int) – Number of frequency curves when freq_indices is None.

  • lw (float) – Line width. Default: PYCSAMT_STYLE.multiline.lw.

  • alpha (float) – Line alpha. Default: PYCSAMT_STYLE.multiline.alpha.

  • title (str)

  • figsize ((float, float))

  • ax (Axes or None)

Returns:

ax

Return type:

Axes

pycsamt.forward.plot_model_3d(grid3d, *, cmap='jet_r', log_scale=True, clip_core=True, vmin=None, vmax=None, show_stations=True, title='', figsize=(13, 4.5))#

Three orthogonal slice panels for a 3-D resistivity model.

Displays the XZ (mid-y), YZ (mid-x), and XY (mid-z) cross-sections of grid3d as colour maps. Station positions are overlaid on the XY (map-view) panel.

Parameters:
  • grid3d (Grid3D)

  • cmap (str)

  • log_scale (bool)

  • clip_core (bool)

  • vmin (float or None) – Colour limits in log₁₀(Ω·m) when log_scale is True.

  • vmax (float or None) – Colour limits in log₁₀(Ω·m) when log_scale is True.

  • show_stations (bool)

  • title (str)

  • figsize ((float, float))

Returns:

axes[ax_xz, ax_yz, ax_xy]

Return type:

ndarray of Axes, shape (3,)

pycsamt.forward.plot_response_map_3d(response3d, *, freq_idx=0, component='xy', quantity='rho_a', cmap=<object object>, vmin=None, vmax=None, show_labels=True, marker_size=120.0, title='', figsize=(7, 6), ax=None)#

Map-view scatter of ρ_a or phase at one frequency.

Each station is drawn as a coloured symbol at its (x, y) surface position.

Parameters:
Returns:

ax

Return type:

Axes

pycsamt.forward.plot_response_section_3d(response3d, *, component='xy', quantity='rho_a', y_row=None, cmap=<object object>, vmin=None, vmax=None, n_contours=0, show_stations=True, station_preset='pseudosection', title='', figsize=(11, 5), ax=None)#

Period × station pseudo-section for one 3-D response component.

Stations are sorted along x and projected onto a profile at a selected y-row (default: mid-y row).

Parameters:
  • response3d (ForwardResponse3D)

  • component ({'xy', 'yx', 'xx', 'yy'})

  • quantity ({'rho_a', 'phase'})

  • y_row (int or None) – Index of the y-row. None → midpoint row.

  • cmap (str or _UNSET)

  • vmin (float or None)

  • vmax (float or None)

  • n_contours (int)

  • show_stations (bool)

  • station_preset (str)

  • title (str)

  • figsize ((float, float))

  • ax (Axes or None)

Returns:

ax

Return type:

Axes

pycsamt.forward.plot_tensor_components_3d(response3d, *, freq_idx=0, quantity='rho_a', cmap=<object object>, vmin=None, vmax=None, marker_size=100.0, title='', figsize=(12, 10))#

2 × 2 map panel showing all four impedance tensor components.

Panels are arranged as: [[Z_xx, Z_xy], [Z_yx, Z_yy]]

Parameters:
Returns:

axes

Return type:

ndarray of Axes, shape (2, 2)

Forward Modules#

pycsamt.forward.config

Configuration for pyCSAMT 1-D forward modelling and dataset generation.

pycsamt.forward.config2d

Configuration for pyCSAMT 2-D MT forward modelling.

pycsamt.forward.config3d

Configuration for pyCSAMT quasi-3D MT forward modelling.

pycsamt.forward.em1d

1-D electromagnetic forward solvers.

pycsamt.forward.em2d

2-D magnetotelluric finite-difference forward solver.

pycsamt.forward.em3d

Quasi-3D magnetotelluric forward solver.

pycsamt.forward.grid2d

2-D resistivity grid for MT forward modelling.

pycsamt.forward.grid3d

3-D resistivity grid for MT forward modelling.

pycsamt.forward.synthetic

Synthetic 1-D earth model generators.

pycsamt.forward.noise

Noise models for synthetic EM training data.

pycsamt.forward.batch

Parallelised synthetic EM dataset generator.

pycsamt.forward.plot

Visualisation for pyCSAMT 1-D and 2-D forward models and responses.