Common Workflow Patterns#

This document describes common workflow patterns for using the PyHydroGeophysX multi-agent system, from basic ERT processing to advanced multi-method fusion.

Pattern A: Basic ERT Processing#

Use Case: Single ERT dataset, no constraints

Agents: Context → Loader → Inversion → Evaluation → WaterContent → Report

Workflow Diagram:

User Input
    │
    ▼
ContextInputAgent (parse natural language)
    │
    ▼
ERTLoaderAgent (load data)
    │
    ▼
ERTInversionAgent (invert)
    │
    ▼
InversionEvaluationAgent (evaluate & optimize)
    │
    ▼
WaterContentAgent (convert to WC)
    │
    ▼
ReportAgent (generate report)

Example Code:

from PyHydroGeophysX.agents import (
    ERTLoaderAgent,
    ERTInversionAgent,
    InversionEvaluationAgent,
    WaterContentAgent,
    ReportAgent
)

# Load data
loader = ERTLoaderAgent(api_key)
data = loader.execute({
    'data_file': 'field_ert.ohm',
    'instrument': 'E4D',
    'quality_check': True
})

# Invert
inverter = ERTInversionAgent(api_key)
inv_result = inverter.execute({
    'ert_data': data['ert_data'],
    'inversion_mode': 'standard',
    'inversion_params': {'lambda': 20}
})

# Evaluate and optimize
evaluator = InversionEvaluationAgent(api_key)
eval_result = evaluator.execute({
    'inversion_results': inv_result,
    'ert_data': data['ert_data'],
    'auto_adjust': True
})

# Convert to water content
converter = WaterContentAgent(api_key)
wc = converter.execute({
    'inversion_results': eval_result['final_results'],
    'petrophysical_params': {'porosity': 0.35, 'n': 2.0}
})

Pattern B: Time-Lapse Monitoring#

Use Case: Multiple ERT datasets over time

Agents: Context → Loader (xN) → Climate → Inversion (time-lapse) → Evaluation → WaterContent → Report

Special Features:

  • Temporal regularization

  • Climate data integration

  • Difference/ratio/joint methods

Workflow Diagram:

User Input
    │
    ▼
ContextInputAgent (identify time-lapse)
    │
    ▼
ERTLoaderAgent (load multiple datasets)
    │
    ▼
ClimateDataAgent (fetch climate data) [optional]
    │
    ▼
ERTInversionAgent (time-lapse inversion)
    │
    ├─ difference method
    ├─ ratio method
    └─ joint inversion
    │
    ▼
InversionEvaluationAgent (evaluate quality)
    │
    ▼
WaterContentAgent (temporal conversion)
    │
    ▼
ReportAgent (temporal analysis + climate integration)

Example Code:

from PyHydroGeophysX.agents import (
    ERTLoaderAgent,
    ClimateDataAgent,
    ERTInversionAgent,
    WaterContentAgent
)

# Load multiple time-lapse datasets
loader = ERTLoaderAgent(api_key)
datasets = []
for file in ['ert_t1.ohm', 'ert_t2.ohm', 'ert_t3.ohm']:
    result = loader.execute({'data_file': file, 'instrument': 'E4D'})
    datasets.append(result['ert_data'])

# Fetch climate data
climate = ClimateDataAgent(api_key)
climate_data = climate.execute({
    'geometry': {'lat': 41.5, 'lon': -91.5},
    'start_date': '2024-01-01',
    'end_date': '2024-03-31',
    'variables': ['precipitation', 'temperature']
})

# Time-lapse inversion
inverter = ERTInversionAgent(api_key)
inv_result = inverter.execute({
    'time_lapse_data': datasets,
    'inversion_mode': 'time-lapse',
    'time_lapse_method': 'ratio',
    'temporal_regularization': 10.0
})

Pattern C: Structure-Constrained Fusion#

Use Case: Seismic + ERT with layer identification

Agents: Context → DataFusion → Seismic → Structure → Petrophysics → Report

Special Features:

  • Interface extraction from seismic velocity

  • Layer-specific petrophysical parameters

  • Monte Carlo uncertainty (10,000 realizations)

Workflow Diagram:

User Input
    │
    ▼
ContextInputAgent (parse multi-method request)
    │
    ▼
DataFusionAgent (recommend fusion pattern)
    │
    ├─────────────────┬─────────────────┐
    │                 │                 │
    ▼                 ▼                 ▼
SeismicAgent    ERTLoaderAgent     (other methods)
(velocity)          │
    │               │
    └───────┬───────┘
            │
            ▼
  StructureConstraintAgent
  (extract interfaces → constrained mesh → constrained inversion)
            │
            ▼
    PetrophysicsAgent
    (layer-specific conversion with MC uncertainty)
            │
            ▼
      ReportAgent

Example Code:

from PyHydroGeophysX.agents import (
    DataFusionAgent,
    SeismicAgent,
    ERTLoaderAgent,
    StructureConstraintAgent,
    PetrophysicsAgent
)

# Recommend fusion pattern
fusion = DataFusionAgent(api_key)
plan = fusion.execute({
    'fusion_pattern': 'auto',
    'methods': ['seismic', 'ert'],
    'data': {
        'seismic': 'seismic.sgt',
        'ert': 'ert.ohm'
    }
})

# Process seismic data
seismic = SeismicAgent(api_key)
seis_result = seismic.execute({
    'seismic_data': 'seismic.sgt',
    'velocity_threshold': 1200
})

# Load ERT data
ert_loader = ERTLoaderAgent(api_key)
ert_data = ert_loader.execute({
    'data_file': 'ert.ohm',
    'instrument': 'E4D'
})

# Structure-constrained inversion
structure = StructureConstraintAgent(api_key)
constrained = structure.execute({
    'ert_data': ert_data['ert_data'],
    'velocity_model': seis_result['velocity_model'],
    'velocity_thresholds': [1000, 1950],
    'lambda': 20
})

# Layer-specific petrophysics
petro = PetrophysicsAgent(api_key)
wc = petro.execute({
    'resistivity_model': constrained['resistivity_model'],
    'mesh': constrained['mesh'],
    'cell_markers': constrained['cell_markers'],
    'n_realizations': 10000
})

Pattern D: Full Field-Scale Analysis#

Use Case: Complete hydrogeophysical characterization

Agents: Context → DataFusion → Seismic → ERTLoader → Structure → Evaluation → Petrophysics → Report

Special Features:

  • Multi-method integration

  • Quality optimization loop

  • Comprehensive uncertainty quantification

  • Publication-ready reports

Workflow Diagram:

User Natural Language Request
        │
        ▼
ContextInputAgent
        │
        ▼
DataFusionAgent
        │
        ├─────────────────────────────┐
        │                             │
        ▼                             ▼
SeismicAgent                    ERTLoaderAgent
        │                             │
        └───────────┬─────────────────┘
                    │
                    ▼
        StructureConstraintAgent
                    │
                    ▼
        InversionEvaluationAgent
                    │
                ┌───┴───┐
                │       │
                ▼       ▼
            Adjust   Accept
                    │
                    ▼
        PetrophysicsAgent (MC uncertainty)
                    │
                    ▼
            ReportAgent

TDEM Workflow#

Use Case: Time-Domain Electromagnetic sounding from hydrological models

Workflow Diagram:

MODFLOW/ParFlow Data
        │
        ▼
Extract 1D Vertical Profile
        │
        ▼
WS_Model (Waxman-Smits Petrophysics)
        │
        ▼
TDEMForwardModeling
        │
        ▼
Add Synthetic Noise
        │
        ▼
TDEMInversion
        │
        ▼
Compare True vs Recovered

Example Code:

from PyHydroGeophysX.forward.tdem_forward import (
    TDEMForwardModeling,
    TDEMSurveyConfig
)
from PyHydroGeophysX.inversion.tdem_inversion import TDEMInversion
from PyHydroGeophysX.petrophysics.resistivity_models import WS_Model
import numpy as np

# Convert water content to conductivity
conductivity = 1.0 / WS_Model(
    saturation, porosity, sigma_w=0.05, m=1.5, n=2.0, sigma_s=0.001
)

# Configure TDEM survey
times = np.logspace(-5, -2, 31)
survey = TDEMSurveyConfig(
    source_location=np.array([0.0, 0.0, 0.0]),
    source_radius=10.0,
    times=times
)

# Forward modeling
fwd = TDEMForwardModeling(thicknesses, survey)
dobs, dpred, uncertainties = fwd.forward_with_noise(
    conductivity, noise_level=0.05
)

# Inversion
inv = TDEMInversion(
    times=times,
    dobs=dobs,
    uncertainties=uncertainties,
    source_radius=10.0,
    n_layers=20,
    use_irls=True
)
result = inv.run()

3D ERT Workflow#

Use Case: 3D ERT forward modeling with MODFLOW integration

Workflow Diagram:

MODFLOW 3D Data
        │
        ▼
Analyze Active Cells (find optimal domain)
        │
        ▼
Create Surface Electrode Array
        │
        ▼
Apply Topography to Electrodes
        │
        ▼
Create 3D Mesh with Topography
        │
        ▼
Interpolate Hydrological Properties
        │
        ▼
Waxman-Smits Conversion
        │
        ▼
3D ERT Forward Modeling
        │
        ▼
PyVista Visualization

Example Code:

from PyHydroGeophysX.core.mesh_3d import (
    Mesh3DCreator,
    create_3d_ert_data_container
)
from PyHydroGeophysX.petrophysics.resistivity_models import WS_Model
from pygimli.physics import ert

# Initialize mesh creator
creator = Mesh3DCreator(
    mesh_directory='./meshes',
    elec_refinement=0.3
)

# Create electrodes with topography
electrodes = creator.create_surface_electrode_array(
    nx=5, ny=5, dx=4.0, dy=4.0
)
electrodes = creator.apply_topography_to_electrodes(
    electrodes, topography_function
)

# Create 3D mesh
mesh = creator.create_3d_mesh_with_topography(
    electrode_positions=electrodes,
    topography_func=topography_function,
    para_depth=14.0,
    use_prism_mesh=True
)

# Create data container
data = create_3d_ert_data_container(
    electrodes, scheme='dd', dimension=3
)

# Forward modeling
fop = ert.ERTModelling()
fop.setData(data)
fop.setMesh(mesh)
response = fop.response(resistivity_mesh)

Best Practices#

  1. Start Simple: Begin with Pattern A before moving to more complex workflows

  2. Validate Data: Always enable quality_check=True in ERTLoaderAgent

  3. Iterate on Inversion: Use InversionEvaluationAgent with auto_adjust=True

  4. Quantify Uncertainty: Use PetrophysicsAgent with n_realizations >= 1000

  5. Document Results: Always include ReportAgent for reproducibility

  6. Check Chi-Squared: Target chi2 between 0.8 and 1.5 for good data fit

  7. Use Appropriate Constraints: Structure constraints improve resolution but require seismic data