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, withrandom,blocky,smooth, andfrom_geologyconstructors.- 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:
_Base1DForward1-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:
- class pycsamt.forward.TEM1DForward(times, loop_radius=50.0, moment=1.0, n_freqs=64, n_lam=100)#
Bases:
_Base1DForward1-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.integratefor 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:
- class pycsamt.forward.CSAMT1DForward(freqs, source_offset=None, dipole_length=1000.0)#
Bases:
_Base1DForward1-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:
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:
- 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:
objectContainer 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.
- 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 returnslog10(|dBz_dt|)(length n_times).
- plot(ax=None, **kwargs)#
Quick diagnostic plot. Returns the Axes used.
- class pycsamt.forward.MT2DForward(freqs, grid, *, verbose=True)#
Bases:
object2-D magnetotelluric finite-difference forward solver.
Solves both TE and TM modes for a list of frequencies on the provided
Grid2Dand returns aForwardResponse2Dwith apparent resistivity and phase at all station positions.- Parameters:
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:
- class pycsamt.forward.ForwardResponse2D(freqs, stations_x, zxy, zyx, rho_a_te, phase_te, rho_a_tm, phase_tm, grid)#
Bases:
objectOutput of the 2-D MT forward solver.
All impedance and apparent-resistivity arrays have shape
(n_freqs, n_stations).- Parameters:
freqs (ndarray, shape (n_freqs,)) – Evaluation frequencies [Hz].
stations_x (ndarray, shape (n_stations,)) – Station x-positions [m].
zxy (ndarray, shape (n_freqs, n_stations), complex) – TE-mode surface impedance Z_xy = E_y / H_x [V/A].
zyx (ndarray, shape (n_freqs, n_stations), complex) – TM-mode surface impedance Z_yx = E_x / H_y [V/A] (negative by convention: Z_yx = −Z_xy for a 1-D earth).
rho_a_te (ndarray, shape (n_freqs, n_stations)) – TE apparent resistivity [Ω·m].
phase_te (ndarray, shape (n_freqs, n_stations)) – TE impedance phase [degrees, 0–90° for a normal model].
rho_a_tm (ndarray, shape (n_freqs, n_stations)) – TM apparent resistivity [Ω·m].
phase_tm (ndarray, shape (n_freqs, n_stations)) – TM impedance phase [degrees].
grid (Grid2D) – The model grid used for the forward run.
- station_response(station)#
Return all response arrays for one station as a dict.
- to_feature_array(*, mode='both', log_rho=True, include_phase=True)#
Flatten to a 2-D feature matrix for ML training.
- Parameters:
- Return type:
ndarray, shape (n_stations, n_features)
- class pycsamt.forward.LayeredModel(resistivity, thickness, depth=None, name='')#
Bases:
object1-D layered earth model.
The earth has
n_layerslayers. 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.])
- 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 isTrue.
- classmethod from_vector(v, n_layers, *, log_rho=True, name='')#
Reconstruct a
LayeredModelfrom 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:
- 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:
- Return type:
- 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:
- Return type:
- 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:
- Return type:
- classmethod from_geology(name, *, seed=None)#
Generate a random model using a predefined geological prior.
- Parameters:
- Raises:
KeyError – If name is not in
GEOLOGY_PRIORS.- Return type:
- plot(ax=None, *, log_scale=True, depth_max=None, label=None, **kwargs)#
Plot the 1-D resistivity–depth profile.
- class pycsamt.forward.Grid2D(dx, dz, resistivity, x_stations, n_pad=0, name='')#
Bases:
objectNon-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)
- 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.
- 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 = 0and numbered0, 1, …, nx.- Returns:
indices
- Return type:
ndarray of int, shape (n_stations,)
- harmonic_mean_x()#
Harmonic-mean conductivity at x-directed cell interfaces.
Used by the TM-mode FD assembler.
- harmonic_mean_z()#
Harmonic-mean conductivity at z-directed cell interfaces.
- 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:
- 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.thicknessdefines 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:
- 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:
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_layershorizontal layers are drawn from a log-uniform prior. When lateral_variation isTrue, 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:
- 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 * factorand each subsequent cell isfactortimes wider.- Parameters:
- 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:
_BaseNoiseModelAdd 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:
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
ForwardResponsewith noise added.- Parameters:
response (ForwardResponse) – Clean forward response.
seed (int or None) – Random seed for reproducibility.
- Return type:
- 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:
_BaseNoiseModelFrequency-dependent noise model for MT/CSAMT training data.
Simulates three dominant noise sources present in field data:
Power-line harmonics — Gaussian spikes at 50 Hz, 100 Hz, 150 Hz (or 60/120/180 Hz for North American data).
MT dead band — elevated noise at ~1 000–3 000 s period (≈ 3×10⁻⁴ – 10⁻³ Hz) due to reduced natural source energy.
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
ForwardResponsewith noise added.- Parameters:
response (ForwardResponse) – Clean forward response.
seed (int or None) – Random seed for reproducibility.
- Return type:
- class pycsamt.forward.MultiplicativeNoise(sigma_log10=0.05)#
Bases:
_BaseNoiseModelLog-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.05corresponds to ≈ ±12 % variation.
- apply(response, *, seed=None)#
Return a new
ForwardResponsewith noise added.- Parameters:
response (ForwardResponse) – Clean forward response.
seed (int or None) – Random seed for reproducibility.
- Return type:
- pycsamt.forward.add_gaussian_noise(response, level=0.05, *, seed=None)#
Convenience wrapper: add Gaussian noise at a given relative level.
- Parameters:
response (ForwardResponse)
level (float) – Relative noise standard deviation.
seed (int or None)
- Returns:
New response with noise applied.
- Return type:
- 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:
- 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.
-1uses all CPU cores.output (str or None) – If given, save the dataset to a
.npzfile at this path.verbose (bool) – Print progress.
- Return type:
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:
objectNumpy 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.
- 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
GCNInverter3Dtraining.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.
-1uses all CPU cores.output (str or None) – If given, save the dataset to a compressed
.npzfile.verbose (bool) – Print progress.
- Returns:
Container with arrays
X(n_surveys, n_stations, n_features),y(n_surveys, n_stations, n_params), andcoords(n_stations, 2).- Return type:
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:
objectNumpy 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.
- class pycsamt.forward.Grid3D(dx, dy, dz, resistivity, stations_xy, n_pad=0, name='')#
Bases:
objectNon-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)
- xz_slice(yi)#
Extract an XZ (east-west) 2-D slice at y-cell yi.
Returns a
Grid2Dwhose 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 ofstations_xy[station_indices[k]].
- Parameters:
yi (int)
- Return type:
- yz_slice(xi)#
Extract a YZ (north-south) 2-D slice at x-cell xi.
The
Grid2Dhorizontal axis is mapped to y (northing); itsdxarray containsdyand its resistivity isresistivity[:, :, xi].
- column_profile_3d(xi, yi)#
Return the 1-D resistivity/thickness profile at cell (xi, yi).
- 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).
- 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:
- 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].)
nx_stations (int)
ny_stations (int)
name (str)
- Return type:
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:
- class pycsamt.forward.MT3DForward(freqs, grid, *, method='quasi3d', verbose=True)#
Bases:
objectQuasi-3D magnetotelluric forward solver.
Runs
MT2DForwardon orthogonal XZ and YZ cross-sections extracted from aGrid3Dmodel 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:
- 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:
objectFull (approximate) impedance tensor from the 3-D MT forward solver.
All arrays have shape
(n_freqs, n_stations).- Parameters:
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.
- to_feature_array(*, components='xy_yx', log_rho=True, include_phase=True)#
Flatten to a 2-D feature matrix for ML input.
- Parameters:
- 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). WhenNonea zero placeholder is used.components (str) – Passed to
to_feature_array().
- Returns:
Single-survey dataset (
n_surveys = 1).- Return type:
- 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:
objectCollect settings that define a 1-D forward modelling / dataset run.
ForwardConfigis the central configuration object forgenerate_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:
Generate a template with
write_template().Edit the values in the generated file.
Load the edited file with
from_file().Optionally call
validate()to catch range errors early.Pass
to_dataset_kwargs()togenerate_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
.npzdataset.Noneskips 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'
- validate()#
Check parameter ranges and raise
ValueErroron 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:
- 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:
- 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:
- 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.yamlselect 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:
- 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:
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 raiseValueError. IfFalse, unknown keys are silently ignored.
- Returns:
Configuration populated from the file values.
- Return type:
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:
- 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:
objectCollect 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)
- validate()#
Raise
ValueErroron invalid parameter values.- Return type:
None
- to_solver_kwargs()#
Return kwargs for
MT2DForward.
- to_template(path='forward_config_2d.py', *, fmt=None)#
Write to an annotated source-of-truth file.
- 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:
- classmethod from_file(path, *, strict=True)#
Load from a generated source-of-truth file.
- Parameters:
path (path-like)
strict (bool)
- Return type:
- 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:
objectCollect 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., ... )
- validate()#
Raise
ValueErroron invalid parameters.- Return type:
None
- to_solver_kwargs()#
Return kwargs for
MT3DForward.
- to_template(path='forward_config_3d.py', *, fmt=None)#
Write an annotated source-of-truth file.
- 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:
- classmethod from_file(path, *, strict=True)#
Load from a source-of-truth file.
- Parameters:
path (path-like)
strict (bool)
- Return type:
- 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_STYLEand axis behaviour fromPYCSAMT_CONTROL.- Parameters:
response (ForwardResponse) – Output of
MT1DForwardorCSAMT1DForward.modes ({'te', 'tm', 'both'}) – Which modes to plot. For a 1-D response
response.rho_aandresponse.phasehold 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.
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.multilineso 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)
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:
response (ForwardResponse)
model (LayeredModel or None) – If given, plotted in the left panel. When
None, only the two response panels are shown.title (str) – Figure suptitle.
gridspec_kw (dict or None) – Passed to
subplots().
- 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)
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)
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.freqsto display. WhenNone, 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)
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:
- 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)
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]]
Forward Modules#
Configuration for pyCSAMT 1-D forward modelling and dataset generation. |
|
Configuration for pyCSAMT 2-D MT forward modelling. |
|
Configuration for pyCSAMT quasi-3D MT forward modelling. |
|
1-D electromagnetic forward solvers. |
|
2-D magnetotelluric finite-difference forward solver. |
|
Quasi-3D magnetotelluric forward solver. |
|
2-D resistivity grid for MT forward modelling. |
|
3-D resistivity grid for MT forward modelling. |
|
Synthetic 1-D earth model generators. |
|
Noise models for synthetic EM training data. |
|
Parallelised synthetic EM dataset generator. |
|
Visualisation for pyCSAMT 1-D and 2-D forward models and responses. |