| Field | Value | |----------------|-------------------------------------------------------------| | **Package** | SimPEG KI v1.0 | | **Model** | SimPEG (Simulation and Parameter Estimation in Geophysics) | | **Domain** | Geophysics (forward modeling and inversion) | | **Language** | Python (>=3.11) | | **Authors...
Scanned 9/11/2026
Install to Claude Code
npx -y skills add lzwei196/KISS---Knowledge-Infrastructure-for-Scientific-Simulation --skill SimPEG --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of SimPEG?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/lzwei196-simpeg)More formats (shields.io, HTML) on the badges page.
> **MANDATORY EXECUTION POLICY** — READ BEFORE PROCEEDING
>
> You MUST run the **actual model binary or package** described in this document.
> If the model fails to import, compile, or execute, you MUST:
> 1. Check `diagnostics/triplets.yaml` for a matching error pattern
> 2. Try the fix suggested in the triplet's `remedy` section
> 3. If still failing, report the error to the user with full details
>
> You MUST NOT substitute a simplified Python formula, regression equation,
> or hand-coded approximation in place of the real model.
>
>
> Before starting, run: `python preflight_check.py` (in this KI directory)
> to verify that the model binary/package and required data are available.
>
> **DEBUGGING PROTOCOL** — When something goes wrong, follow this order:
> 1. **Check triplets** — `diagnostics/triplets.yaml` may already cover this error
> 2. **Read official docs** — The model's own documentation for expected formats/units
> 3. **Find working examples** — Check `outputs/` or the model's shipped test data
> 4. **Fix the tool** — With knowledge of what "correct" looks like
>
> Do NOT write custom debug scripts. The answers are in the docs and examples.
<!-- KI-MAP:BEGIN (projected by generate_skill_map.py — edit the KI, not this table) -->
## KI map — what to read, and when
| when you need | read | why |
|---|---|---|
| FIRST, always | `preflight_check.py` | run it (`python preflight_check.py`): proves env/binary/data are usable and emits a machine-readable `PREFLIGHT_REPORT=` line. Do not debug a run that never had a healthy environment. |
| to run the pipeline stages | `tools/` (4 tools) | the executable pipeline. Read each tool's argparse (`--help`) before composing a command; SKILL.md's stage table says which tool serves which stage. |
| before running a stage | `docs/s*_*.md` (5 stage docs) | per-stage procedure, verification and traps — the how-to that SKILL.md's overview compresses. |
| on ANY error, before debugging | `diagnostics/triplets.yaml` (18 entries) | symptom → diagnosis → remedy for this model's known failure modes. Check here FIRST; the answer usually exists. Never renumber or rewrite entries. |
| to know what an output IS | `dag.yaml` | the model's identity: every output's medium, units, `validation_rank` (1 = the headline variable) and observability. Scoring and obs-binding read THIS — when asked 'what does this model predict', the dag is the answer, not a guess. |
| when building inputs / parsing outputs | `docs/format_spec.yaml` | exact I/O shapes + `known_issues`, projected from dag + triplets. Regenerate with `ki_tools_common/generate_format_spec.py` after changing either — never hand-edit. |
| to judge a run's skill | `docs/validation_convention.yaml` | how this model's field judges it validated: per-`dag_variable` metrics, directions and CITED pass-bands. A run is graded against these, not against intuition. |
| for claims and thresholds | `docs/gathered_papers.json` (7 papers) + `docs/papers_index.md` | the literature this KI is judged by; each entry's `text_path` is fetched full text in the central paper cache. `role: benchmark` marks the model's own skill paper. |
| for a machine-readable summary | `knowledge_infrastructure.yaml` | the manifest (package, pipeline, validation tier, counts) — projected by `ki_tools_common/generate_ki_manifest.py`; regenerate after structural changes, never hand-edit. |
*Projected 2026-08-17 from the KI's actual contents — 9 components present. Refresh: `python3 ki_tools_common/generate_skill_map.py --ki_dir <this KI>`.*
<!-- KI-MAP:END -->
<!-- KI-TOOL-INDEX:BEGIN (projected by generate_skill_map.py — the discoverability contract: every public tool, exact path; PURPOSE stays human-authored elsewhere) -->
### Executable tool index (projected — complete by construction)
Every public tool in this KI, by exact path. What each is FOR lives in the
human-written Tool Inventory above; `--help` on any of these prints its arguments.
| tool (exact path) | invocation |
|---|---|
| `tools/build_mesh.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/build_mesh.py --help` |
| `tools/initialize_model.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/initialize_model.py --help` |
| `tools/parse_results.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/parse_results.py --help` |
| `tools/run_simpeg.py` | `KISSPATH_PYTHON_ENV/bin/python {KI}/tools/run_simpeg.py --help` |
*4 public tools; `_`-prefixed helpers and packaging files excluded.*
<!-- KI-TOOL-INDEX:END -->
# SimPEG Knowledge Infrastructure
| Field | Value |
|----------------|-------------------------------------------------------------|
| **Package** | SimPEG KI v1.0 |
| **Model** | SimPEG (Simulation and Parameter Estimation in Geophysics) |
| **Domain** | Geophysics (forward modeling and inversion) |
| **Language** | Python (>=3.11) |
| **Authors** | Cockett, Kang, Heagy, Pidlisecky, Oldenburg |
| **License** | MIT |
| **Repository** | https://github.com/simpeg/simpeg |
| **Tools** | 4 scripts, ~1200 lines |
| **Skill docs** | 5 markdown documents |
| **Triplets** | 18 diagnostic entries |
---
## Data Preparation
### Forcing data
**Data Sources**: Use `from ki_tools_common.load_forcing import load_daily_forcing` for CMFD/MSWX/NASA POWER.
**Data Validation Reference**: See `data_ki/DTB/SKILL.md` for depth-to-bedrock data.
## 1. Overview
SimPEG is an open-source Python framework for **simulation and gradient-based parameter
estimation** in geophysical applications. It provides a modular architecture where meshes,
forward simulations, data misfits, regularization, optimization, and inversion directives
are composable objects.
### Supported Geophysical Methods
| Method | Module | Dimension |
|-------------------------------|---------------------------------------------|------------|
| Gravity | `simpeg.potential_fields.gravity` | 1D/2D/3D |
| Magnetics | `simpeg.potential_fields.magnetics` | 1D/2D/3D |
| DC Resistivity | `simpeg.electromagnetics.static.resistivity`| 1D/2D/3D |
| Induced Polarization (IP) | `simpeg.electromagnetics.static.induced_polarization` | 1D/2D/3D |
| Spectral IP (SIP) | `simpeg.electromagnetics.static.spectral_induced_polarization` | 1D/2D/3D |
| Self-Potential (SP) | `simpeg.electromagnetics.static.self_potential` | 2D/3D |
| Frequency-Domain EM (FDEM) | `simpeg.electromagnetics.frequency_domain` | 1D/3D |
| Time-Domain EM (TDEM) | `simpeg.electromagnetics.time_domain` | 1D/3D |
| Natural Source EM / MT | `simpeg.electromagnetics.natural_source` | 1D/3D |
| VRM | `simpeg.electromagnetics.viscous_remanent_magnetization` | 3D |
| Seismic Ray Tomography | `simpeg.seismic.straight_ray_tomography` | 2D |
| Richards Equation (flow) | `simpeg.flow.richards` | 1D/2D/3D |
### Key Differences from Other Geophysics Codes
- **Inverse-first design**: every simulation exposes `Jvec`, `Jtvec` for gradient-based inversion.
- **Mesh-agnostic**: works with `discretize` TensorMesh, TreeMesh, CylindricalMesh, SimplexMesh.
- **Composable maps**: chain parameter transformations (log, exponential, injection, tile, etc.).
- **Dask support**: distributed forward and sensitivity computations for large-scale 3D problems.
---
## 2. Installation
### Quick Install (pip)
```bash
python -m venv venv && source venv/bin/activate
pip install simpeg
# or with all optional dependencies:
pip install "simpeg[dask,choclo,plotting,sklearn,pandas]"
```
### Developer Install
```bash
git clone https://github.com/simpeg/simpeg.git
cd simpeg
pip install -e ".[tests,docs,style]"
```
### Core Dependencies
| Package | Version | Purpose |
|--------------|-----------|----------------------------------|
| numpy | >= 1.22 | Array operations |
| scipy | >= 1.12 | Sparse matrices, linear algebra |
| discretize | >= 0.12 | Mesh generation and operators |
| pymatsolver | >= 0.3 | Linear solver wrapper |
| geoana | >= 0.8.1 | Analytical geophysical functions |
| libdlf | any | Hankel/digital-linear-filter |
| matplotlib | any | Plotting |
### Verify Installation
```python
import simpeg
print(simpeg.__version__)
from simpeg import simulation, maps, data_misfit, inversion
print("Core modules loaded OK")
```
---
## 3. Pipeline Stages
| Stage | Name | Tool | Description |
|-------|---------------------|-----------------------------|-----------------------------------------------------|
| S1 | Mesh & Survey Setup | `tools/build_mesh.py` | Create discretize mesh + survey geometry |
| S2 | Model & Parameters | `tools/initialize_model.py` | Build starting model, define maps and properties |
| S3 | Forward Modeling | (API) | Run forward simulation to predict data |
| S4 | Data Preparation | (API) | Load/create observed data, assign uncertainties |
| S5 | Inversion Setup | `tools/run_simpeg.py` | Combine misfit + regularization + optimization |
| S6 | Inversion Execution | `tools/run_simpeg.py` | Run `BaseInversion.run(m0)` |
| S7 | Output Parsing | `tools/parse_results.py` | Extract recovered model, predicted data, metrics |
| S8 | Visualization | `tools/parse_results.py` | Plot model slices, data comparison, convergence |
| S9 | Validation | (manual) | Compare to analytical solutions or known models |
---
## 4. Tools Reference
| # | Script | Lines | Purpose |
|----|---------------------------|-------|----------------------------------------------------|
| T1 | `tools/build_mesh.py` | ~330 | Mesh generation and survey geometry builder |
| T2 | `tools/initialize_model.py`| ~300 | Physical property model initializer with unit maps |
| T3 | `tools/run_simpeg.py` | ~320 | Forward + inversion execution wrapper |
| T4 | `tools/parse_results.py` | ~280 | Output parser: model to CSV, convergence metrics |
All tools follow the **validate → process → validate** pattern:
1. `validate_inputs()` — check files exist, types correct, units sane
2. `process()` — main computation
3. `validate_outputs()` — verify results are physically reasonable
4. Output: JSON on stdout with `{"status": "success"|"error", ...}`
---
## 5. Unit Trap Table — Critical Domain Knowledge
These are **silent failures** — the model runs but produces wrong results.
| ID | Trap | Wrong | Correct | Effect |
|--------|---------------------------------------|----------------------------|--------------------------|-------------------------------------|
| dt_001 | Gravity density units | g/cm^3 directly | kg/m^3 or g/cc→SI via map| Factor-of-1000 anomaly error |
| dt_002 | Magnetic susceptibility vs SI | CGS susceptibility | SI susceptibility (×4π) | Amplitude off by 4π ≈ 12.57 |
| dt_003 | DC resistivity vs conductivity | Resistivity (Ω·m) | Conductivity (S/m) | Inverted model is reciprocal |
| dt_004 | FDEM frequency vs angular frequency | ω (rad/s) | f (Hz) | Phase/amplitude completely wrong |
| dt_005 | Topography elevation datum | Depth below surface | Elevation (m above ref) | Air cells miscategorized |
| dt_006 | Receiver component mismatch | Survey measures Bz | Simulation returns Hx | Silently wrong data predicted |
| dt_007 | nC (nanoTesla) vs T for magnetics | Data in Tesla | Data in nanoTesla | Misfit 10^9 too large |
| dt_008 | Regularization alpha ratios | Default alpha_s=alpha_x | Tune for cell-size ratio | Over-smooth or blocky model |
| dt_009 | InjectActiveCells background value | 0.0 for conductivity | ln(σ) or actual σ_air | Singular system or air artifacts |
| dt_010 | Data uncertainty floor too small | noise_floor=0 | >1-5% of |d| | Overfit noise, model artifacts |
| dt_011 | Mesh cell count vs memory | 1M cells, dense J | Use TreeMesh or Dask | OOM crash at sensitivity stage |
| dt_012 | TileMap index mismatch | Wrong local-to-global map | Match tile cell indices | Corrupted global sensitivity |
---
## 6. Skill Knowledge by Stage
### S1 — Mesh & Survey Setup
The mesh discretizes the Earth volume. Survey defines source and receiver locations.
**Mesh types** (from `discretize`):
- `TensorMesh` — regular grid, fast, memory-heavy for 3D
- `TreeMesh` (OcTree) — adaptive refinement near data, recommended for 3D
- `CylindricalMesh` — axially symmetric problems (boreholes, TEM loops)
- `SimplexMesh` — unstructured tetrahedral, complex geometry
**Common pitfall**: Mesh must extend far enough beyond the survey footprint
(≥2–3× target depth) to avoid boundary effects. Padding cells should
grow geometrically (factor 1.3–1.5).
### S2 — Model & Physical Properties
The model vector `m` is mapped to physical properties via `simpeg.maps`:
```python
# Example: log-conductivity model with active cells
model_map = maps.ExpMap(nP=n_active) * maps.InjectActiveCells(mesh, active_ind, np.log(1e-8))
simulation.sigma_map = model_map
```
**Key maps and when to use them:**
| Map | Use case |
|--------------------|----------------------------------------|
| `IdentityMap` | Model IS the physical property |
| `ExpMap` | Model in log-space, property positive |
| `LogMap` | Property in log-space |
| `ReciprocalMap` | Resistivity ↔ conductivity |
| `InjectActiveCells`| Exclude air/inactive cells |
| `TileMap` | Map local tile model to global mesh |
| `ChiMap` | Susceptibility → permeability |
| `Wires` | Split model vector for multiple props |
### S3 — Forward Modeling
Every simulation has `sim.dpred(m)` → predicted data vector and
`sim.fields(m)` → full field solution on the mesh.
**Performance considerations:**
- Gravity/magnetics: integral formulation, no PDE solve, but dense J matrix
- DC/EM: PDE-based, sparse systems, factorization dominates cost
- Use `store_sensitivities="forward_only"` to avoid storing full J
### S4 — Data Preparation
```python
data_obj = data.Data(survey, dobs=observed_data,
relative_error=0.05, # 5% of |d|
noise_floor=1e-3) # absolute floor
```
**Uncertainty formula**: `std_dev = sqrt(noise_floor^2 + (relative_error * |dobs|)^2)`
### S5 — Inversion Setup
```python
dmis = data_misfit.L2DataMisfit(data=data_obj, simulation=sim)
reg = regularization.WeightedLeastSquares(mesh, active_cells=active_ind)
opt = optimization.InexactGaussNewton(maxIter=20, maxIterCG=30)
inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)
```
**Trade-off parameter β**: controls data-fit vs model-smoothness.
Use `directives.BetaEstimate_ByEig` for automatic initial estimate.
### S6 — Inversion Execution
```python
directives_list = [
directives.BetaEstimate_ByEig(beta0_ratio=1e0),
directives.TargetMisfit(),
directives.BetaSchedule(coolingFactor=5, coolingRate=1),
]
inv = inversion.BaseInversion(inv_prob, directiveList=directives_list)
m_recovered = inv.run(m0)
```
### S7 — Output Parsing
Recovered model is a numpy array matching the mesh cells.
Map it back to physical property space:
```python
physical_property = model_map * m_recovered
mesh.plot_slice(physical_property, normal='Y', ind=slice_index)
```
---
## 6. Output Description — dag.yaml Restatement
**Source of truth**: `dag.yaml`. The dag wins over this prose if any wording drifts.
**Headline output** (dag `validation_rank: 1`):
> `recovered_model` — Recovered subsurface model vector, one value per active mesh cell, in model space; returned by the inversion. (model space (e.g. ln(S/m); kg/m^3 under identity map))
| Output variable (dag `var`) | Rank | Unit | Description / role |
|-----------------------------|------|------|--------------------|
| `recovered_model` | 1 | model space (e.g. ln(S/m); kg/m^3 under identity map) | Recovered subsurface model vector, one value per active mesh cell, in model space; returned by the inversion. |
| `physical_property` | dag output | see `dag.yaml` | Physical-property output listed by the dag. |
| `predicted_data` | dag output | see `dag.yaml` | Predicted-data output listed by the dag. |
| `fields` | dag output | see `dag.yaml` | Fields output listed by the dag. |
SimPEG's `inv.run(m0)` returns the recovered model vector as a numpy array with one value per active mesh cell in model space. The predicted data vector is obtained via `sim.dpred(m_recovered)`. Use `model_map * m_recovered` to transform from model space back to physical property space. The `parse_results.py` tool exports: (1) the recovered model as a CSV with columns `x, y, z, property_value`, (2) a convergence log with iteration number, data misfit (phi_d), regularization (phi_m), and trade-off parameter (beta), and (3) optional model-slice plots and observed-vs-predicted data comparisons.
## 8. Unit Table — Pipeline Units and Output Units
**Source of truth**: output units are restated from `dag.yaml`; conversion behavior comes from the stage docs and tool contracts. Do not infer a physical-property unit for `recovered_model`: the dag defines it as model space.
| Variable | Source unit / representation | Model or output unit | Conversion / mapping |
|----------|------------------------------|----------------------|----------------------|
| `recovered_model` | SimPEG inversion result from `inv.run(m0)` | model space (e.g. ln(S/m); kg/m^3 under identity map) | None at return time; values remain in model space. |
| `physical_property` | `recovered_model` | see `dag.yaml` | Apply `model_map * m_recovered` to transform from model space to physical-property space. |
| `predicted_data` | simulation response from `sim.dpred(m_recovered)` | see `dag.yaml` | Simulation-dependent; preserve survey data units used by the configured SimPEG method. |
| `fields` | simulation field solution from `sim.fields(m)` | see `dag.yaml` | Simulation-dependent; preserve field units from the configured SimPEG method. |
Method-specific unit traps remain in the critical domain table above. The most common silent failures are density in `g/cm^3` instead of `kg/m^3`, CGS susceptibility instead of SI susceptibility, resistivity supplied where conductivity is expected, and angular frequency supplied where frequency in Hz is expected.
## 11. Validated Results — validation_convention.yaml Restatement
**Source of truth**: `docs/validation_convention.yaml`. A null convention band is written as `no cited threshold`; no pass/fail threshold is inferred when the convention does not cite one.
| Output variable | Metric | Direction | Very good band | Good band | Satisfactory band | Citation key(s) |
|-----------------|--------|-----------|----------------|-----------|-------------------|-----------------|
| `recovered_model` | `csi` | maximize | no cited threshold | no cited threshold | no cited threshold | none listed |
| `recovered_model` | `pbias` | zero_centered | no cited threshold | no cited threshold | no cited threshold | none listed |
| `physical_property` | `csi` | maximize | no cited threshold | no cited threshold | no cited threshold | none listed |
No achieved calibration or validation metric values are stated in the supplied KI facts. Treat the body validation campaign as pending until a real SimPEG run is executed and scored against `docs/validation_convention.yaml`.
---
## 7. Calibration / Tuning Parameters
| Priority | Parameter | Typical Range | Effect |
|----------|---------------------------|-----------------------|-------------------------------------|
| 1 | `beta0_ratio` | 1e-2 – 1e2 | Initial trade-off aggressiveness |
| 2 | `coolingFactor` | 2 – 10 | How fast β decreases per iteration |
| 3 | `alpha_s / alpha_x,y,z` | 1e-4 – 1e2 | Smallness vs smoothness weighting |
| 4 | `maxIter` | 10 – 50 | Total inversion iterations |
| 5 | `maxIterCG` | 10 – 100 | CG iterations per Gauss-Newton step |
| 6 | `irls_threshold` | 1e-2 – 1e-4 | IRLS convergence threshold |
| 7 | `reference_model` | problem-specific | Drives model toward known geology |
| 8 | `upper_bound/lower_bound` | physical constraints | Prevent non-physical values |
---
## 8. Diagnostic Triplets Summary
18 triplets organized by failure domain:
| Domain | Count | IDs |
|---------------------|-------|------------------------|
| unit_conversion | 5 | dt_001 – dt_004, dt_007|
| parameter_format | 3 | dt_005, dt_006, dt_012 |
| numerical_stability | 3 | dt_009, dt_010, dt_011 |
| convergence | 3 | dt_013, dt_014, dt_015 |
| silent_error | 2 | dt_008, dt_016 |
| runtime | 2 | dt_017, dt_018 |
See `diagnostics/triplets.yaml` for full symptom → diagnosis → remedy chains.
---
## 9. Quick Start — Gravity Inversion Example
```bash
# 1. Create venv and install
python -m venv simpeg_env && source simpeg_env/bin/activate
pip install simpeg discretize matplotlib
# 2. Build mesh and survey
python tools/build_mesh.py \
--method gravity \
--survey-file survey_locs.csv \
--nx 40 --ny 40 --nz 20 \
--padding 6 --pad-factor 1.3 \
--output mesh_config.json
# 3. Initialize model
python tools/initialize_model.py \
--mesh-config mesh_config.json \
--property density \
--background 0.0 \
--bounds "-1.0,1.0" \
--map-type identity \
--output model_config.json
# 4. Run inversion
python tools/run_simpeg.py \
--mode inversion \
--method gravity \
--mesh-config mesh_config.json \
--model-config model_config.json \
--data-file gravity_data.csv \
--relative-error 0.02 \
--noise-floor 0.001 \
--max-iter 30 \
--output results/
# 5. Parse and plot results
python tools/parse_results.py \
--results-dir results/ \
--mesh-config mesh_config.json \
--output-csv recovered_model.csv \
--plot convergence,model_slice
```
---
## 10. Coupling Points
SimPEG interfaces with:
| External Package | Purpose | Notes |
|------------------|--------------------------------------|------------------------------|
| `discretize` | Mesh generation and operators | Required, co-developed |
| `geoana` | Analytical solutions for validation | Dipole, sphere, layered |
| `pymatsolver` | Linear system solvers | Wraps Pardiso, Mumps, scipy |
| `choclo` | Optimized gravity/magnetic kernels | Numba-compiled |
| `dask` | Distributed computing | Parallel tiles/frequencies |
---
## 11. Data Requirements
| Data Type | Format | Units | Notes |
|----------------------|-------------------------|-------------------------|----------------------------|
| Survey locations | CSV (x, y, z) | meters (SI) | Elevation, not depth |
| Gravity observations | CSV or numpy array | mGal (1e-5 m/s^2) | Free-air or Bouguer |
| Magnetic observations| CSV or numpy array | nT (1e-9 T) | Total field anomaly |
| DC apparent resist. | UBC format or CSV | Ω·m (observed) | Transmitter-receiver pairs |
| EM data (FDEM) | CSV (freq, real, imag) | A/m or V/m | Per-frequency |
| EM data (TDEM) | CSV (time, dB/dt) | V/m^2 or T/s | Per-time-gate |
| Topography | CSV (x, y, z) | meters elevation | Reference datum matters |
---
## 12. File Structure
```
ki/
├── SKILL.md # This file — main entry point
├── tools/
│ ├── build_mesh.py # S1: mesh + survey builder
│ ├── initialize_model.py # S2: model parameter setup
│ ├── run_simpeg.py # S5-S6: execution wrapper
│ └── parse_results.py # S7-S8: output parser + plots
├── docs/
│ ├── s1_mesh_survey_setup.md # Mesh and survey design
│ ├── s2_model_parameters.md # Physical properties and maps
│ ├── s3_forward_modeling.md # Forward simulation details
│ ├── s4_inversion_setup.md # Inversion configuration
│ └── s5_output_analysis.md # Parsing, visualization, QC
└── diagnostics/
└── triplets.yaml # 18 symptom→diagnosis→remedy entries
```
---
## 13. References
- Cockett, R., Kang, S., Heagy, L. J., Pidlisecky, A., & Oldenburg, D. W. (2015).
SimPEG: An open source framework for simulation and gradient based parameter
estimation in geophysical applications. *Computers & Geosciences*, 85, 166–176.
- https://simpeg.xyz — official documentation and tutorials
- https://discretize.simpeg.xyz — discretize mesh documentation
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!