Inversion#
Inversion turns processed electromagnetic observations into a resistivity model. In pyCSAMT this guide is the decision point between three related but different paths:
the backend-neutral
pycsamt.inversionAPI for built-in and adapter workflows;the classical engine integrations in
pycsamt.modelsfor Occam2D, ModEM, and MARE2DEM native projects;the learned workflows in
pycsamt.ai, documented separately as AI inversion.
Forward modelling is not an inversion path. It predicts responses from a known model and is documented in Forward Modelling; it is often used to design, test, or validate inversion choices.
Choose Your Path#
Use InversionConfig and InversionWorkflow when you want one
Python interface for built-in 1-D/2-D runs, external adapters, results,
plotting, and export.
Use Occam2D, ModEM, or MARE2DEM when the native solver, file format, mesh, covariance, response files, or existing project structure matters.
Train, run, validate, and report learned 1-D/2-D/3-D inversion tools when a calibrated model family is part of the workflow.
Before Any Inversion#
Do not start with a solver. Start with evidence that the data and modelling assumptions are suitable. A reproducible inversion package should retain:
the EDI or processed observation source and the exact processing steps;
frequency/period band, components, units, station order, and coordinates;
QC tables, confidence decisions, and any frequencies recovered or masked;
static-shift, noise-removal, tensor-rotation, and dimensionality evidence;
error floors or uncertainty model, with justification;
chosen dimensionality: 1-D sounding, stitched 2-D profile, true 2-D, 2.5-D, or 3-D;
starting model, bounds, regularization, mesh/grid, and covariance controls;
executable identity for external solvers and whether external execution was explicitly requested;
residual, convergence, response-fit, and model-appraisal products.
Useful preparation pages are Data processing, EM Tools Guide, Choosing A Model Backend, and Inversion Concepts.
Backend-Neutral Workflow#
pycsamt.inversion separates configuration, execution, results, and export:
InversionConfigDescribes method, dimension, backend, data arrays, starting model, solver limits, error settings, backend options, and output policy.
InversionWorkflowResolves the selected backend and runs the workflow. For external engines, execution remains explicit through the backend configuration.
InversionResultStores recovered model values, diagnostics, uncertainty, history, native files, and conversion helpers such as
to_resistivity_model().pycsamt.inversion.exportandpycsamt.inversion.plotWrite common products and quick-look figures from a result object.
At a glance, backend names accepted by the common API include:
Backend |
Main use |
Notes |
|---|---|---|
|
Lightweight local inversion |
MT/AMT/CSAMT layered 1-D, TDEM 1-D, stitched 2-D profiles, and optional finite-difference 2-D profile experiments. |
|
Smooth 2-D profile inversion |
Prepares/validates native Occam2D files and can run an external executable when configured. |
|
2-D or 3-D ModEM workflow |
Manages native ModEM data/model/control/covariance conventions and completed-run loading. |
|
Optional SimPEG adapter |
Imported only when selected and installed. |
|
Optional pyGIMLi adapter |
Useful for 1-D EM modelling/inversion and stitched profile experiments. |
MARE2DEM is documented under MARE2DEM. It is a rich native model integration for 2.5-D MT/CSEM projects; use it directly when the MARE2DEM file set and finite-element workflow are the scientific target.
Minimal MT 1-D#
This synthetic example uses the built-in backend so it can run without an external solver:
import numpy as np
from pycsamt.forward import LayeredModel, MT1DForward
from pycsamt.inversion import (
InversionConfig,
InversionWorkflow,
StartingModel,
)
freqs = np.logspace(-2, 2, 12)
truth = LayeredModel([80.0, 25.0, 600.0], [250.0, 900.0])
response = MT1DForward(freqs=freqs).run(truth)
cfg = InversionConfig(
method="mt",
dimension="1d",
backend="builtin",
data={
"freqs": freqs,
"rho_a": response.rho_a,
"phase": response.phase,
},
starting_model=StartingModel(
resistivities=[100.0, 50.0, 500.0],
thicknesses=[300.0, 1000.0],
),
max_iter=12,
)
result = InversionWorkflow(cfg).run()
print(result.summary())
Minimal TDEM 1-D#
The same pattern works for TDEM when the data vector is a time-domain decay:
import numpy as np
from pycsamt.forward import LayeredModel, TEM1DForward
from pycsamt.inversion import (
InversionConfig,
InversionWorkflow,
StartingModel,
)
times = np.logspace(-5, -3, 7)
truth = LayeredModel([60.0, 250.0, 900.0], [120.0, 700.0])
forward_options = {"loop_radius": 25.0, "n_freqs": 10, "n_lam": 16}
response = TEM1DForward(times=times, **forward_options).run(truth)
cfg = InversionConfig(
method="tdem",
dimension="1d",
backend="builtin",
data={"times": times, "values": response.dBz_dt},
starting_model=StartingModel(
resistivities=[80.0, 200.0, 700.0],
thicknesses=[150.0, 800.0],
),
backend_options=forward_options,
max_iter=8,
)
result = InversionWorkflow(cfg).run()
Profile Inversion#
For a profile where each station has responses on a common frequency grid, pass station-by-frequency arrays:
cfg = InversionConfig(
method="mt",
dimension="2d",
backend="builtin",
data={
"freqs": freqs,
"rho_a": rho_by_station, # (n_stations, n_frequencies)
"phase": phase_by_station, # (n_stations, n_frequencies)
"station_x": [0.0, 400.0, 800.0],
"station_names": ["S00", "S01", "S02"],
},
starting_model=StartingModel(
resistivities=[100.0, 50.0, 600.0],
thicknesses=[300.0, 900.0],
),
max_iter=10,
)
result = InversionWorkflow(cfg).run()
model = result.to_resistivity_model()
The built-in dimension="2d" path may represent either stitched station
inversions or an opt-in finite-difference profile experiment, depending on
backend_options:
cfg.backend_options.update(
{
"profile_mode": "fd2d",
"nx": 12,
"n_pad": 2,
"components": ("te", "tm"),
}
)
For production smooth 2-D profile inversion, review Occam2D. For 3-D MT/AMT projects, review ModEM. For 2.5-D MT/CSEM finite-element projects, review MARE2DEM.
Classical Engine Pages#
Compare built-in, Occam2D, ModEM, MARE2DEM, SimPEG, and pyGIMLi paths against geometry, physics, files, and compute requirements.
Create run folders, templates, validation checks, native-file archives, and reproducible provenance records.
Build and review smooth 2-D MT/AMT/CSAMT profile inversions.
Prepare, validate, run, and load 2-D/3-D ModEM projects.
Manage 2.5-D finite-element MT/CSEM projects and native MARE2DEM files.
Exports And Review#
All common export helpers accept an InversionResult:
from pycsamt.inversion import export, plot
export.to_csv(result, "model.csv")
export.to_npz(result, "model.npz")
export.to_geojson(result, "model.geojson")
export.to_vtk(result, "model.vtk")
export.to_archive(result, "snapshot.zip")
# Requires rasterio.
export.to_geotiff(result, "model.tif")
plot.plot_model(result)
plot.plot_rms(result)
Archive the configuration and review products together with these exports. The final color section is not enough for scientific reproducibility.
Hydrogeophysical Handoff#
Any inversion result that can be converted to ResistivityModel can enter
the pycsamt.interp hydrogeophysical workflow:
from pycsamt.interp import EMHydroModel, PetrophysicalConfig
from pycsamt.interp.petrophysics import ArchieModel
resistivity_model = result.to_resistivity_model()
hydro_cfg = PetrophysicalConfig(
petro=ArchieModel(m=1.8, n=2.0),
rho_w=20.0,
porosity_prior=0.28,
)
hydro = EMHydroModel(resistivity_model, hydro_cfg, method_tag="MT").fit()
print(hydro.water_table)
Next Steps#
Use these pages depending on the work in front of you:
Classical model integrations for classical Occam2D, ModEM, and MARE2DEM projects.
Choosing A Model Backend before committing to a solver.
Inversion Concepts for objective functions, RMS, regularization, uncertainty, resolution, and non-uniqueness.
AI inversion for learned inversion workflows.
Interpretation when moving from a model to geological or hydrogeophysical interpretation.
Inversion for runnable gallery examples.