Skip to main content

pyiwfm

CI Coverage

Python package for reading, writing, visualizing, and comparing IWFM (Integrated Water Flow Model) models.

Installation

# Basic installation (includes matplotlib, geopandas, shapely, h5py)
pip install pyiwfm

# With mesh generation (triangle, gmsh)
pip install "pyiwfm[mesh]"

# With VTK 3D export
pip install "pyiwfm[viz]"

# With web viewer (FastAPI + React + vtk.js + deck.gl)
pip install "pyiwfm[webapi]"

# With PEST++ integration (scipy)
pip install "pyiwfm[pest]"

# With all optional dependencies
pip install "pyiwfm[all]"

# Development (editable install with dev tools)
pip install -e ".[dev]"

Windows install pitfalls

These are environmental issues we've seen in the wild — none are pyiwfm bugs, but the fixes aren't always obvious.

1. Use a clean virtual environment. Layering [webapi] on top of an interpreter that already has matplotlib / numpy / vtk installed is the most common source of import errors on Windows. Start from a fresh venv and install the extras you need in one shot:

py -3.13 -m venv .venv
.venv\Scripts\activate
pip install "pyiwfm[webapi]"

2. ImportError: cannot import name '_c_internal_utils' from matplotlib. This is a known matplotlib-on-Windows install corruption (often after antivirus or OneDrive interferes with a .pyd write). Reinstall matplotlib:

pip install --force-reinstall matplotlib

3. WinError 206 The filename or extension is too long. Windows limits paths to 260 characters by default. Models nested under OneDrive-synced or deeply-named user directories can exceed this. Two fixes:

  • System-wide (recommended): enable Windows long-path support, then reboot. Affects every tool on the system, not just pyiwfm:
    reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f
    
  • Per-model workaround: move the model to a shallower path such as C:\iwfm\<model_name>, away from OneDrive-synced or deeply-nested user paths.

4. Install extras upfront, not incrementally. pip install pyiwfm followed later by pip install pyiwfm[webapi] should work in theory, but the second resolver pass can leave half-installed state if anything errors mid-stream (Windows AV, OneDrive latency). Prefer a single pip install "pyiwfm[webapi]" in a fresh venv.

Budget Post-Processing

Export IWFM budget and zone budget results to Excel workbooks:

# Export budgets from a control file (one .xlsx per budget spec)
pyiwfm budget C2VSimFG_Budget_xlsx.in

# Export zone budgets from a control file
pyiwfm zbudget C2VSimFG_ZBudget_xlsx.in

Or use the Python API directly:

from pyiwfm.io import BudgetReader, budget_to_excel

reader = BudgetReader("GW_Budget.hdf")
budget_to_excel(
    reader, "GW_Budget.xlsx",
    volume_factor=2.29568e-05, volume_unit="AC.FT.",
)

Quick Start

from pyiwfm import AppGrid, Node, Element, Stratigraphy
import numpy as np

# Create a simple mesh
nodes = {
    1: Node(id=1, x=0.0, y=0.0),
    2: Node(id=2, x=100.0, y=0.0),
    3: Node(id=3, x=100.0, y=100.0),
    4: Node(id=4, x=0.0, y=100.0),
}

elements = {
    1: Element(id=1, vertices=(1, 2, 3, 4), subregion=1),
}

grid = AppGrid(nodes=nodes, elements=elements)
grid.compute_areas()
grid.compute_connectivity()

print(f"Grid: {grid.n_nodes} nodes, {grid.n_elements} elements")

Model I/O Example

from pathlib import Path
from pyiwfm.io import load_complete_model, save_complete_model

# Load a complete IWFM model from simulation main file
model = load_complete_model("Simulation/Simulation.in")

print(f"Loaded model with {model.grid.n_nodes} nodes")
print(f"Groundwater wells: {len(model.groundwater.wells) if model.groundwater else 0}")

# Save model to new directory
save_complete_model(model, Path("output_model"))

# Write time series to HEC-DSS (bundled C library)
from pyiwfm.io.dss import DSSTimeSeriesWriter, DSSPathnameTemplate

template = DSSPathnameTemplate(a_part="IWFM", c_part="HEAD", e_part="1DAY")
with DSSTimeSeriesWriter("output.dss") as writer:
    writer.write_timeseries(head_timeseries, template.make_pathname(location="WELL_1"))

Web Visualization

pyiwfm includes an interactive web viewer built with FastAPI (backend) and React + vtk.js + deck.gl (frontend). Launch it with:

# CRS is optional — defaults to C2VSimFG UTM Zone 10N for most models
pyiwfm viewer --model-dir /path/to/model

# Specify CRS explicitly if needed
pyiwfm viewer --model-dir /path/to/model --crs "+proj=utm +zone=10 +datum=NAD83 +units=us-ft +no_defs"

The viewer provides six tabs:

  • Overview: Model summary, metadata, and mesh quality metrics
  • 3D Mesh: Interactive vtk.js 3D rendering with layer visibility, cross-section slicing, stream network overlay, and z-exaggeration
  • Results Map: deck.gl + MapLibre map showing head contours, drawdown with diverging color scale, subsidence surface, hydrograph locations, head statistics, and observation upload/comparison (CSV, TSV, SMP formats)
  • Diagnostics: Convergence iteration charts, mass balance error timeseries, filterable message table
  • Budgets: Plotly charts of water budget time series with location/column selection
  • Z-Budgets: Zone budget visualization organized by spatial zones

Additional API endpoints:

  • Data Export: CSV (heads, budgets, hydrographs), GeoJSON mesh, GeoPackage (multi-layer), and publication-quality matplotlib plots (PNG/SVG)
  • Model Comparison: Load a second model and compare meshes/stratigraphy via the ModelDiffer engine
  • Head Statistics: Time-aggregated min/max/mean/std per node across all timesteps

The frontend is pre-built into src/pyiwfm/visualization/webapi/static/. To rebuild from source:

cd frontend && npm install && npm run build

Calibration Tools

pyiwfm provides calibration tools that mirror and extend IWFM's Fortran utilities (IWFM2OBS, CalcTypHyd):

# Explicit SMP mode: interpolate simulated heads to observation times
pyiwfm iwfm2obs --obs observed.smp --sim simulated.smp --output interp.smp

# Model discovery mode: auto-discover .out files from simulation main file
pyiwfm iwfm2obs --model C2VSimFG.in --obs-gw gw_obs.smp --output-gw gw_out.smp

# With multi-layer T-weighted averaging and PEST instruction file
pyiwfm iwfm2obs --model C2VSimFG.in \
    --obs-gw gw_obs.smp --output-gw gw_out.smp \
    --well-spec obs_wells.txt \
    --multilayer-out GW_MultiLayer.out \
    --multilayer-ins GWHMultiLayer.ins
# CalcTypHyd with Fortran config file (produces PEST .out/.ins files)
pyiwfm calctyphyd --config CalcTypeHyd.in

# Deduplicate per-layer SMP output (strip %N suffixes)
pyiwfm iwfm2obs --deduplicate-smp GW_OUT.smp --output GW_OUT_dedup.smp

Or use the Python API:

from pyiwfm.calibration import iwfm2obs_from_model, discover_hydrograph_files

# Auto-discover .out files and interpolate to observation times
results = iwfm2obs_from_model(
    simulation_main_file="C2VSimFG.in",
    obs_smp_paths={"gw": "GW_Obs.smp"},
    output_paths={"gw": "GW_OUT.smp"},
)

PEST++ Calibration CLI

Set up, run, and analyze PEST++ calibration from the command line:

# Generate PEST++ files from an IWFM model
pyiwfm pest setup --model-dir /path/to/model --case-name c2vsim_cal

# Run PEST++ (requires pestpp-glm or pestpp-ies on PATH)
pyiwfm pest run --pst-file ./pest_setup/c2vsim_cal.pst --num-workers 8

# Analyze results
pyiwfm pest analyze --pst-file ./pest_setup/c2vsim_cal.pst --format json

Features

  • Core Data Structures: Node, Element, Face, AppGrid, Stratigraphy, TimeSeries
  • BaseComponent ABC: Common interface (validate(), n_items) for all model components (groundwater, streams, lakes, root zone, small watersheds, unsaturated zone)
  • Complete Model I/O: Full roundtrip support for reading and writing IWFM models
    • ASCII files (nodes, elements, stratigraphy, time series)
    • Binary files (Fortran unformatted)
    • HDF5 files (efficient large model storage)
    • HEC-DSS 7 files (bundled C library)
  • Budget Post-Processing: Parse IWFM budget/zbudget control files and export to Excel
    • One sheet per location/zone with title lines, bold headers, and auto-fitted columns
    • Unit conversion factors (FACTLTOU, FACTAROU, FACTVLOU) applied per column type
    • CLI commands: pyiwfm budget and pyiwfm zbudget
  • Component Writers: Write complete IWFM input files with shared BaseComponentWriterConfig
    • Groundwater: wells, pumping, boundary conditions, aquifer parameters
    • Streams: nodes, reaches, diversions, bypasses, rating curves
    • Lakes: definitions, elements, rating curves, outflows
    • Root Zone: crop types, soil parameters, land use
    • Small Watersheds: watershed units, root zone/aquifer parameters
    • Unsaturated Zone: element layers, soil moisture
    • Simulation: main control file
  • PreProcessor Integration: Load/save complete models from IWFM file structure
  • Model Factory: Extracted construction helpers (reach building, coordinate resolution, parametric grids, binary loading) into pyiwfm.core.model_factory
  • Mesh Generation: Triangle and Gmsh wrappers
  • Calibration Tools: IWFM2OBS time interpolation with automatic model file discovery and Fortran-verified timestamp alignment, multi-layer T-weighted observation well processing (GW_MultiLayer.out + PEST .ins), fuzzy c-means well clustering, typical hydrograph computation (CalcTypHyd) with Fortran-format config file parsing and PEST output, and publication-quality calibration figures
  • Visualization: GIS export (GeoPackage download), VTK 3D export, matplotlib plot generation (PNG/SVG), interactive web viewer with budget charts, head maps, hydrograph comparison, drawdown animation, and head statistics
  • Model Comparison: Diff and comparison metrics, including web viewer comparison endpoint
  • Drawdown Analysis: Compute drawdown relative to reference timesteps with per-node, per-element, max-map, and robust range calculations
  • Stream Depletion: Compare baseline and pumping model runs to quantify stream flow depletion per reach
  • Budget Checks: Mass balance sanity checks to detect timestep-level inflow/outflow/storage imbalance
  • Mesh Quality: Element-level quality metrics (aspect ratio, skewness, min/max angle) with aggregate statistics
  • Simulation Diagnostics: Parse SimulationMessages.out for convergence tracking, mass balance errors, and spatial hotspot analysis
  • PEST++ CLI: pyiwfm pest setup/run/analyze for end-to-end calibration from the command line

Versioning

The package version is derived automatically from git tags using hatch-vcs. There is no hardcoded version string to maintain — pyiwfm.__version__, pyproject.toml metadata, and the Sphinx docs all read from the same source.

Scenario Version produced
On a tagged commit (v1.0.4) 1.0.4
3 commits after a tag 1.0.5.dev3+gabcdef1
Uncommitted changes (dirty) 1.0.5.dev3+gabcdef1.d20260228

Release workflow:

git tag -a v1.0.4 -m "Release v1.0.4"
git push && git push origin v1.0.4
# CI builds and publishes automatically

Building locally:

pip install -e ".[dev]"          # editable install — version from git
python -m build                  # sdist + wheel — version baked into _version.py
python -c "import pyiwfm; print(pyiwfm.__version__)"

The auto-generated src/pyiwfm/_version.py is gitignored and should not be committed.

License

GPL-2.0 - Same as IWFM

Metadata

Release files for pyiwfm 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyiwfm 1.3.0
File Size Uploaded
pyiwfm-1.3.0.tar.gz 4.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyiwfm 1.3.0
File Interpreter ABI Platform
pyiwfm-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 8.1 MB

Release files / pyiwfm-1.3.0.tar.gz

Download URL pyiwfm-1.3.0.tar.gz
Size 4.5 MB
Tags Source
SHA-256 checksum
How to use checksums
1cd579319489384f44083cbd0c6305ebcedb378480d8e3bef2d789dac4964d2e
BLAKE2b-256 checksum
How to use checksums
d32784a01deb2c06408e529b12a4f087c67a53c4abd32f3c4d56eed2b4e0e049
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / pyiwfm-1.3.0-py3-none-any.whl

Download URL pyiwfm-1.3.0-py3-none-any.whl
Size 3.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
d63495a2183f21a5726d25356ea1c0f422b9ec90b56ff0e51edb30dfa4a85fbc
BLAKE2b-256 checksum
How to use checksums
c9ee12ed0af786120f50c1652a3ce4db89bd84519ac5008415a40b1aa5b10b2d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page