| name | geophysical-inversion |
| skill_type | workflow |
| description | Geophysical data inversion workflow from data loading through mesh
creation, forward modelling, inversion, and result visualization.
Use when inverting ERT, magnetics, gravity, or EM survey data.
|
| version | 1.0.0 |
| author | Geoscience Skills |
| license | MIT |
| tags | ["Geophysical Inversion","ERT","Magnetics","Gravity","EM","Workflow"] |
| dependencies | ["simpeg","pygimli","verde","pyvista"] |
| complements | ["simpeg","pygimli","verde","pyvista"] |
| workflow_role | modelling |
Geophysical Inversion Workflow
End-to-end pipeline for inverting geophysical data, from survey data loading
through mesh creation, forward modelling, inversion, gridding, and 3D
visualization of recovered physical property models.
Skill Chain
simpeg / pygimli verde pyvista
[Mesh + Inversion] --> [Gridding] --> [3D Visualization]
| | |
Survey geometry Interpolate Volume render
Forward model Grid to raster Slice views
Misfit + reg Trend removal Overlay data
Recover model Cross-validate Export mesh
Decision Points: SimPEG vs pyGIMLi
| Criterion | SimPEG | pyGIMLi |
|---|
| DC resistivity / ERT | Yes | Yes (simpler API) |
| Magnetics | Yes | Limited |
| Gravity | Yes | Limited |
| Electromagnetics (TDEM, FDEM) | Yes | No |
| Seismic refraction (SRT) | No | Yes |
| Induced polarization | Yes | Yes |
| Built-in electrode arrays | Manual setup | Built-in (Wenner, Schlumberger, etc.) |
| Mesh types | TensorMesh, TreeMesh, CurvilinearMesh | Triangular, tetrahedral, structured |
| Joint inversion | Yes (Wires maps) | Limited |
| API complexity | More boilerplate, more flexible | Less boilerplate, opinionated |
Rule of thumb: Use pyGIMLi for standard near-surface ERT/SRT surveys with
conventional arrays. Use SimPEG for multi-physics, EM methods, potential fields,
or research-grade custom inversions.
Step-by-Step Orchestration
Stage 1a: Inversion with SimPEG (DC Resistivity Example)
import numpy as np
from discretize import TensorMesh
from simpeg.electromagnetics.static import resistivity as dc
from simpeg import maps, data, data_misfit, regularization
simpeg optimization, inverse_problem, inversion, directives
hx = np.ones() *
hz = np.ones() *
mesh = TensorMesh([hx, hz], origin=)
n_electrodes =
electrode_spacing =
elec_x = np.arange(n_electrodes) * electrode_spacing
elec_locs = np.c_[elec_x, np.zeros(n_electrodes)]
source_list = []
i (n_electrodes - ):
rx = dc.receivers.Dipole(elec_locs[[i+]], elec_locs[[i+]])
src = dc.sources.Dipole([rx], elec_locs[i], elec_locs[i+])
source_list.append(src)
survey = dc.Survey(source_list)
sigma_true = np.ones(mesh.nC) *
sigma_true[mesh.cell_centers[:, ] < -] =
simulation = dc.Simulation2DNodal(
mesh, survey=survey, sigmaMap=maps.ExpMap(mesh)
)
dobs = simulation.dpred(np.log(sigma_true))
dobs += * np.(dobs) * np.random.randn((dobs))
obs_data = data.Data(survey, dobs=dobs,
standard_deviation= * np.(dobs))
dmis = data_misfit.L2DataMisfit(data=obs_data, simulation=simulation)
reg = regularization.WeightedLeastSquares(
mesh, alpha_s=, alpha_x=, alpha_z=
)
opt = optimization.InexactGaussNewton(maxIter=)
inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)
dir_list = [
directives.BetaSchedule(coolingFactor=),
directives.TargetMisfit()
]
inv = inversion.BaseInversion(inv_prob, directiveList=dir_list)
m0 = np.log(np.ones(mesh.nC) * )
mrec = inv.run(m0)
sigma_rec = np.exp(mrec)