2.26.5.21. pycsamt.agents.inv3d_agent#
pycsamt.agents.inv3d_agent#
Inv3DAgent — Graph-convolutional 3-D MT spatial inversion.
Wraps GCNInverter3D:
Represents the survey network as a spatial graph whose edges connect stations within a configurable radius. Spectral GCN message-passing propagates information between neighbouring stations so the resulting 3-D resistivity volume is spatially coherent — artefacts from station-by-station 1-D inversion are suppressed.
Trains on synthetic 3-D profiles, using one of two
physicsmodes (see below), then predicts on the observedSitesdataset.Outputs log₁₀ρ per depth layer and log₁₀h per interface for every station, giving a full layered earth model that can be gridded into a 3-D resistivity volume.
Optionally runs MC-dropout uncertainty (
n_mcstochastic passes) to produce depth-resolved confidence maps alongside the main prediction.
Physics modes#
physics="mt1d"(default)Tiles independent 1-D forward models across the real station positions (
generate_dataset()). This is the original smoke/demo path from the AI-inversion implementation plan: nothing enforces genuine lateral/3-D coupling between the tiled 1-D columns beyond what the GCN’s spatial smoothing adds after the fact, so the plan explicitly does not call this genuine 3-D inversion. Kept unconditionally as the default and as an explicit fallback, per the plan’s requirement.physics="mt3d"Generates genuinely 3-D correlated geological volumes at the survey’s own real station
(x, y)positions and solves them with the research-only, small-gridMT3DAdapter(generate_3d_maxwell_dataset()). UnlikeInv2DAgent(physics="mt2d"), this uses the survey’s actual station geometry rather than a synthetic uniform spacing, since the real coordinates are already needed to build the GCN adjacency graph. Each training profile’s per-station target is the true 3-D volume’s own vertical resistivity column at that station, resampled onto the agent’s display depth grid (nearest-cell; the geological grid’s own resolution is coarser than most production sections, perMT3DAdapter’s small-cell-budget research-only status). Only the TE-likezxyresponse is requested and used, matching the observed feature pipeline (_z_to_features(), which is[log10(rho_a_xy), phase_xy]only, zero-padded to this agent’s 4-wide feature slot — using the unusedzyx/diagonal slots for synthetic data would create a train/observation distribution mismatch, not add information). When a held-out synthetic split is available, a genuine (non-fabricated) recovery check against known-truth resistivity is added to the result viarecovery_report(), since the field survey has no ground truth to check against. This mode is far more expensive per training profile than"mt1d"(a real 3-D Maxwell solve vs. an independent 1-D solve per station) — lowern_train_profilesaccordingly. Mesh accuracy degrades at higher frequencies (~10% error by 20-50 Hz vs ~1-2% at 1-2 Hz, at this agent’s defaultcells_per_skin_depth=None); passing an explicitcells_per_skin_depth(e.g. 8.0) narrows this to ~5-9% at the same cell budget but does not fully close it — seedataset3d’s module docstring for measured numbers and the cost/accuracy trade-off raising it together withmax_mesh_cellsbuys. Prefer afreqsgrid concentrated in the low-frequency range this solver’s own benchmark validates when accuracy matters more than matching a specific field acquisition band.
Requires PyTorch or TensorFlow.
Architecture#
GCNNet — spectral graph convolutional network
(Kipf & Welling 2017). No external graph library is required.
References
Classes
|
3-D MT profile inversion using a graph-convolutional network (GCN). |
- class pycsamt.agents.inv3d_agent.Inv3DAgent(*, api_key=None, model=None, llm_provider='claude', n_layers=5, n_freqs=32, freqs=None, depth_max=None, n_train_profiles=150, epochs=30, patience=None, radius=5000.0, hidden=(256, 128, 64), dropout=0.1, n_mc=20, physics='mt1d', correlation_length_x_m=(500.0, 2000.0), correlation_length_y_m=(500.0, 2000.0), correlation_length_z_m=(100.0, 500.0), log_resistivity_mean=2.0, log_resistivity_std=0.5, mesh_safety_factor=3.0, max_mesh_cells=6000, cells_per_skin_depth=None, geology_grid_nx_ny=6, geology_grid_nz=None, verbose=False)[source]
Bases:
BaseAgent3-D MT profile inversion using a graph-convolutional network (GCN).
- Parameters:
api_key (str)
model (str)
llm_provider (str)
n_layers (int) – Number of depth layers per station (default 5).
n_freqs (int) – Number of frequencies used for feature extraction (default 32).
freqs (array-like, optional — execution-time frequency-grid override.) – Explicit positive frequency grid in hertz. When supplied, it replaces the legacy
10^-4–10^3Hz grid and determinesn_freqs.depth_max (float, optional — cumulative finite-layer depth in metres.) – Maximum cumulative model depth in metres. When supplied, layer thicknesses are geometrically graded and normalized to this depth.
Nonepreserves the legacy Bostick-derived display parameterization.n_train_profiles (int) – Number of synthetic 3-D training profiles (default 150). With
physics="mt3d", each profile costs a real 3-D Maxwell solve, not a cheap independent 1-D solve — lower this substantially (e.g. 20-40) for that mode.epochs (int) – Training epochs (default 30).
patience (int or None) – Early-stopping patience measured in epochs.
Noneuses one fifth ofepochswith a minimum of five.radius (float) – Maximum inter-station edge distance in metres for the adjacency graph (default 5 000 m). Stations farther apart than radius are disconnected in the graph.
hidden (tuple of int) – GCN hidden-layer sizes (default (256, 128, 64)).
dropout (float) – Dropout probability (default 0.1); also used for MC uncertainty.
n_mc (int) – Number of Monte-Carlo dropout passes for uncertainty estimation. Set to 0 to skip uncertainty (faster, default 20).
physics ({"mt1d", "mt3d"}, default "mt1d") – Synthetic training-data physics; see the module docstring.
correlation_length_x_m (tuple[float, float]) – : (float, float)
physics="mt3d"only: horizontal/horizontal/vertical correlation length ranges forwarded toMaxwell3DDatasetConfig.correlation_length_y_m (tuple[float, float]) – : (float, float)
physics="mt3d"only: horizontal/horizontal/vertical correlation length ranges forwarded toMaxwell3DDatasetConfig.correlation_length_z_m (tuple[float, float]) – : (float, float)
physics="mt3d"only: horizontal/horizontal/vertical correlation length ranges forwarded toMaxwell3DDatasetConfig.log_resistivity_mean (float) –
physics="mt3d"only: affine map from the standardized correlated field tolog10(resistivity_ohm_m).log_resistivity_std (float) –
physics="mt3d"only: affine map from the standardized correlated field tolog10(resistivity_ohm_m).mesh_safety_factor (float, int) –
physics="mt3d"only: forwarded toMaxwell3DDatasetConfig.max_mesh_cellsalso builds the matchingMT3DAdapter(max_cells=...)used to solve.max_mesh_cells (float, int) –
physics="mt3d"only: forwarded toMaxwell3DDatasetConfig.max_mesh_cellsalso builds the matchingMT3DAdapter(max_cells=...)used to solve.cells_per_skin_depth (float or None, default None) –
physics="mt3d"only: opt-in frequency-aware solver core resolution, forwarded toMaxwell3DDatasetConfig— see its docstring for the accuracy-vs-cell-cost trade-off this exists to address.None(the default) preserves this agent’s original behavior (core resolution = the geological grid’s own spacing); this agent’s defaultfreqsgrid spans up to ~1000 Hz (_DEFAULT_FREQS), so enabling this without also raisingmax_mesh_cellsand/or narrowingfreqsrisks a “needs N solver cells” error at high frequencies.geology_grid_nx_ny (int, int or None) –
physics="mt3d"only: resolution of the geological training grid (how finely the true 3-D resistivity volumes are drawn), independent of the solver mesh’s own frequency-aware resolution above.geology_grid_nz=None(default) usesmin(max(n_layers, 4), 8). Raising these increases realism at the cost of more solver cells per realization; seemax_mesh_cellsfor the resulting budget.geology_grid_nz (int, int or None) –
physics="mt3d"only: resolution of the geological training grid (how finely the true 3-D resistivity volumes are drawn), independent of the solver mesh’s own frequency-aware resolution above.geology_grid_nz=None(default) usesmin(max(n_layers, 4), 8). Raising these increases realism at the cost of more solver cells per realization; seemax_mesh_cellsfor the resulting budget.keys (Output data)
----------
path (sites /)
coords (ndarray (n_stations, 2), optional — station (x, y) in metres.) – Auto-extracted from EDI lat/lon when absent.
adjacency (ndarray (n_stations, n_stations), optional — pre-computed) – normalised adjacency; overrides radius when supplied.
output_dir (str, optional)
freqs
depth_max
topography (bool or dict, optional) –
Trueextracts elevation and chainage fromsitesand adds a terrain-draped section. A mapping may instead provideelevation_mand optionallychainage_km, plusexaggerationandinterp_methodrendering options. This is a geometry/visualisation contract; it does not alter the MT forward solver or GCN prediction.period_range ([T_min, T_max], optional)
keys
----------------
(n_sta (adjacency ndarray)
log₁₀ρ (n_layers) —)
(n_sta
(metres) (n_layers-1) — log₁₀h)
(n_sta
std (n_layers) or None — MC-dropout)
(km) (depths_km ndarray — depth axis at station midpoints)
grid (frequency_grid_hz ndarray — effective feature/forward frequency)
contract (configured_depth_max_m float or None — explicit depth)
metadata (topography dict or None — resolved terrain)
list[str] (station_names)
(n_sta
metres (2) —)
(n_sta
n_sta)
float (rms_global)
GCNInverter3D (inverter)
dict (figure_paths)
dict
"mt3d" (physics str — "mt1d" or)
used (mode)
known-truth (mt3d_recovery dict or None — held-out) – recovery metrics (
physics="mt3d"only)losses (training_history dict -- per-epoch training and validation)
stopping (epochs_completed int -- epochs actually completed before)
loss (best_validation_loss float -- minimum finite validation)
Examples
>>> agent = Inv3DAgent(n_layers=5, epochs=20, n_mc=10) >>> result = agent.execute( ... { ... "path": "/data/WILLY_EDIs", ... "output_dir": "/out/inv3d", ... } ... ) >>> result["rms_global"] 0.28
- SYSTEM_PROMPT: str = 'You are an expert in 3-D MT inversion using graph-convolutional deep learning.\nGiven a GCN-based 3-D inversion result, write 4-5 sentences that:\n1. Describe the survey geometry (station count, spatial extent, adjacency radius).\n2. Interpret the dominant 3-D resistivity structures and their spatial continuity.\n3. Assess prediction quality (RMS, depth range) relative to station spacing.\n4. Compare the GCN spatial result to independent 1-D predictions where possible.\n5. Recommend geological follow-up and areas with highest uncertainty.\nReply in plain scientific English.\n'
Override in subclasses to give the LLM its domain expertise.
- execute(input_data)[source]
Run this agent on input_data and return an
AgentResult.Subclasses must implement this method. The contract:
Reset
self._last_cost = 0.0at the top.Record wall-clock time with
t0 = time.time().Return
AgentResult(elapsed_seconds=time.time()-t0, cost_estimate_usd=self._last_cost, ...).
- Parameters:
- Return type: