MODFLOW coupling
MODFLOW_250m package contents, the steady-state MODFLOW 6 build from SWAT+ percolation, and the engine's two-way BMI/XMI files (mf6.con).
“SWAT+MODFLOW-6” refers to two related but different deliverables. Establish which one a given package contains before working with exchange files or BMI.
Two coupling modes (do not conflate)
- Automatic build: SWAT+ builds first; a sibling MODFLOW_250m steady-state grid is then built from annual-mean percolation (perc). This model runs on its own: heads and baseflow return to SWAT+ only in the engine's daily coupling, switched on by
mf6.con(below). Automatic builds do not yet produce a transient MODFLOW model. - Research path (research work, not a product capability): daily two-way BMI/XMI coupling inside the SWAT+ day loop. Activated only when TxtInOut contains
mf6.conplus map files; the engine loads libmf6 at run time. Not included in standard packages.
mf6.con in TxtInOut, it is that build.Build pipeline (steady-state MODFLOW 6)
- Order a SWAT+ build with a steady-state MODFLOW 6 model (or attach one to a finished SWAT+ workspace).
- After the SWAT+ package is ready, a 250 m MODFLOW 6 grid is built from annual-mean SWAT+ percolation.
- Percolation is mapped HRU→cell (area-weighted); the grid is assembled with standard MF6 packages (RCHA, SFR/DRN/GHB/WEL, …), solved steady-state, then optionally head-calibrated when observations exist.
- Artifacts land as a sibling folder MODFLOW_{resolution}m under the same site directory — not inside Scenarios/.../TxtInOut.
{site}/
├── SWAT_MODEL_Web_Application/ # (or resolved model name) — SWAT+ package
│ └── Scenarios/Default/TxtInOut/
└── MODFLOW_250m/ # sibling steady-state MF6 grid (not inside TxtInOut)
├── mfsim.nam
├── MODFLOW_250m.nam
├── *.dis *.npf *.ic *.ims *.oc *.sto *.tdis
├── *.rcha *.sfr *.drn *.ghb *.wel …
├── Grids_MODFLOW*
├── obs_vs_sim.csv / .png # when head obs exist
└── head_calibration_report.json- SWAT+ and MODFLOW download as separate archives. The standard MODFLOW folder has no README and no
mf6.con/ exchange maps. - Default grid spacing for chained builds is 250 m. You can also attach MODFLOW to an existing finished SWAT+ workspace from the product UI/API.
- Groundwater coverage for hosted coupled builds: Michigan Lower Peninsula, Indiana, Minnesota, Ohio, Wisconsin. The request point / HUC12 centroid must fall in coverage; sparse well density can refuse a build.
Units and the recharge link
- MF6 lengths in meters; time in days. Recharge is derived from SWAT+ percolation (often converted mm/yr → m/day). Well elevations commonly convert feet→meters (× 0.3048).
- Spatial link: an HRU↔cell area-weighted map places recharge on the grid. No daily exchange loop in the shipped archive.
- The stock SWAT+ gwflow module is a different mechanism and is not this external-MF6 path.
Running the MODFLOW package locally
- Install USGS MODFLOW 6 (mf6). FloPy is optional for inspection/edits; the platform already ran MF6 at build time.
- Unzip the MODFLOW_* package; keep the tree intact (
mfsim.namat the root of that folder). - From that directory, run mf6 (or point your runner at
mfsim.nam). Re-read heads (.hds), budget (.cbc), and listing files. - SWAT+ still runs from Scenarios/Default/TxtInOut with a SWAT+ executable — independently of mf6 unless you assemble the research coupling below.
Daily two-way BMI/XMI coupling (research)
Daily two-way coupling is research work in the public SWAT+ fork. Its design, each SWAT+ day: percolation is pushed to MF6 recharge; SFR groundwater exchange is aggregated back to SWAT+ channels, meant to replace the native aquifer return. The current engine still adds that exchange on top of the native return (a double count being fixed), and no model we deliver runs this mode. An optional PFAS leach map feeds groundwater transport when present.
./mf6 ! 1: folder (inside TxtInOut) holding mfsim.nam
1 ! 2: groundwater FLOW step, in days (1 = daily)
30 ! 3: groundwater TRANSPORT step, in days (30 = monthly)
1.0 ! 4: (optional) recharge multiplier for calibration
! 5: (optional) full path to libmf6 if not on the default search path- Place
mf6.conin TxtInOut. Convention: MF6 workspace at TxtInOut/mf6/ containingmfsim.nam. Absentmf6.con⇒ plain SWAT+ (no-op). - Maps next to
mf6.con: mf6_recharge.map (HRU→cell), mf6_baseflow.map (SFR reach→channel), optional pfas_leach.map. - Needs a coupler-enabled swatplus binary (see Compile the SWAT+ fork) plus libmf6.so / libmf6.dll on the library path.
- Standard packages do not ship
mf6.conor the exchange maps; assemble them only for the research daily-coupling path.
Failure modes
- Expected
mf6.conmissing — standard archives intentionally omit it; the BMI path requires adding con + maps + a coupler binary. - MF6 fails to open packages — run from the MODFLOW_* directory; do not nest it inside TxtInOut unless assembling research daily coupling.
MODFLOW_250m package contents
File-by-file contents of the sibling MODFLOW_{resolution}m folder a coupled build produces. Assembled as a standard MODFLOW 6 simulation; the archive contains the entire folder.
The standard deliverable is a standalone steady-state MODFLOW 6 model built from SWAT+ annual-mean percolation. Lengths are meters, time is days. Run it locally with mf6 from the folder root (mfsim.nam). The archive (MODFLOW_Model_{site}_{res}m.zip) contains the whole tree, including intermediate rasters and grids.
MODFLOW 6 packages in the archive
| File | Description | Units / key values |
|---|---|---|
| mfsim.nam | Simulation namefile: TDIS + GWF model + IMS solver | — |
| {name}.tdis | Single steady stress period | TIME_UNITS days; period (1.0, 1, 1.0) |
| {name}.ims | Newton / BiCGSTAB solver settings | outer head close 0.1 m; inner 0.01 m |
| {name}.nam | GWF package list | dis, ic, npf, sto, ghb, rcha, sfr/riv, drn, wel, oc |
| {name}.dis | Structured grid (delr/delc/top/botm/idomain) | LENGTH_UNITS meters |
| {name}.npf | Node property flow: k, k33, icelltype | K in m d⁻¹ |
| {name}.ic | Starting heads = land surface (top), all layers | m |
| {name}.sto | Storage; stress period 0 steady-state | — |
| {name}.rcha | Array recharge, designed to come from SWAT+ annual-mean percolation; today automatic builds carry the uniform default | m d⁻¹ (mm yr⁻¹ ÷ 1000 ÷ 365.25); default 5.5e-4 (about 200 mm/yr), the value builds use today |
| {name}.ghb | Perimeter general-head boundary to kriged water table | head m; conductance m² d⁻¹ (K × thickness) |
| {name}.sfr | Streamflow routing (default stream representation) | lengths m; bed K m d⁻¹; inflow m³ d⁻¹; TIME_CONVERSION 86400 |
| {name}.riv | RIV fallback only if the SFR build fails | stage/rbot m; conductance m² d⁻¹ |
| {name}.drn | Surface-seepage drains (default lake representation) | elevation m; conductance m² d⁻¹ (capped 1e5) |
| {name}.wel | Pumping wells from the wells inventory | flux m³ d⁻¹ (gpm × 5.678, negative = extraction) |
| {name}.oc | Output control | writes {name}.hds + {name}.cbc |
| {name}.hds / .cbc / .lst | Run outputs: heads, cell budgets, listing | heads m; budgets m³ (per day) |
| {name}.sfr.stage / .sfr.cbc | SFR stage and budget outputs | stage m; flows m³ d⁻¹ |
Companion files (not MF6 packages)
| File | Description |
|---|---|
| Grids_MODFLOW_centroids.parquet | Cell centroids (row, col, geometry) in the projected CRS — used for well placement and GIS joins |
| Grids_MODFLOW.geojson / Grids_MODFLOW/*.shp | Cell polygons (GeoJSON only when cell count ≤ 120,000; shapefile alongside) |
| obs_vs_sim.csv | Head observations vs simulated: wellid, row, col, obs_head_m, sim_head_m, restricted_source (obs = land surface − 0.3048 × SWL_ft). Where the source agency restricts public display of its records, obs_head_m is left empty and restricted_source names that source; those wells are not plotted in obs_vs_sim.png. |
| obs_vs_sim.png | Observed-vs-simulated head scatter |
| head_calibration_report.json | Differential-evolution head calibration report (multipliers, NSE, cal/val metrics) — present only after the head-calibration pass, not the initial build |
| {name}_overview.png | Model overview figure |
| lake_raster.tif, swat_river.tif, rasters_input/ | Intermediate build rasters (included because the ZIP archives the whole folder) |
mf6.con and no exchange-map files: it is an automatic build's steady-state model; the engine's daily two-way coupling needs mf6.con and the exchange maps. See mf6.con and exchange maps below.mf6.con and exchange maps
The four TxtInOut files that activate daily two-way SWAT+/MODFLOW 6 BMI/XMI coupling: mf6.con and the mf6_recharge.map, mf6_baseflow.map, pfas_leach.map exchange maps.
Coupling activates when TxtInOut contains mf6.con and a coupler-enabled swatplus binary can dlopen libmf6.so. Absent mf6.con → plain SWAT+ (no-op). Comments after ! are stripped on every line of every coupling file.
mf6.con
./mf6 ! 1: folder (inside TxtInOut) holding mfsim.nam
1 ! 2: groundwater FLOW step, in days (1 = daily)
30 ! 3: groundwater TRANSPORT step, in days (30 = monthly)
1.0 ! 4: (optional) recharge multiplier for calibration
! 5: (optional) full path to libmf6 if not on the default search path| Line | Description | Type | Default |
|---|---|---|---|
| 1 | MF6 workspace path relative to TxtInOut (folder holding mfsim.nam) | path | "." (required in practice) |
| 2 | Groundwater FLOW step cadence in days (clamped to ≥ 1) | integer | 1 |
| 3 | Groundwater TRANSPORT step cadence in days (< 1 falls back to the flow cadence) | integer | 30 |
| 4 (optional) | Recharge multiplier rch_mult applied to every pushed recharge value | real | 1.0 |
| 5 (optional) | Full path to libmf6.so | path | bin/libmf6.so on the default search path |
mf6.con comments mislabel line 4 as the library path. The engine parser is the authority: line 4 is the recharge multiplier; line 5 is the optional library path.mf6_recharge.map — HRU → cell (down-coupling)
Optional; absent → MF6 keeps its own recharge. Header line, then one row per HRU–cell overlap link. Each day the coupler overwrites MF6 RECHARGE with Σ sepbtm(hru)/1000 × weight × rch_mult (SWAT+ mm/day → MF6 m/day).
| Field | Description | Type | Units |
|---|---|---|---|
| N_ENTRIES | Header: number of overlap links | integer | — |
| N_CELLS | Header: RECHARGE array size (NROW × NCOL) | integer | — |
| NCOL / N_HRU | Header: grid columns and max HRU id (written by the builder; unused by the coupler) | integers | — |
| cell_index | Row value 1: 0-based cell index (row × NCOL + col) | integer | — |
| hru | Row value 2: SWAT+ HRU id (1-based) | integer | — |
| weight | Row value 3: overlap area ÷ cell area | real | dimensionless |
mf6_baseflow.map — SFR reach → channel (up-coupling)
Optional; absent → up-coupling off. Header N_LINKS N_REACHES, then one row per link. The coupler reads SFR GWFLOW (m³/day; positive = stream→aquifer) and adds −GWFLOW as baseflow to the mapped SWAT+ channel. It is meant to replace the native aquifer return; the current engine still adds it on top (a double count being fixed).
| Field | Description | Type | Units |
|---|---|---|---|
| N_LINKS | Header: number of reach→channel links | integer | — |
| N_REACHES | Header: SFR GWFLOW array length | integer | — |
| reach_index | Row value 1: 0-based SFR reach index | integer | — |
| gis_channel | Row value 2: SWAT+ channel GIS id | integer | — |
pfas_leach.map — HRU → GWT source cell (PFAS down-coupling)
Optional; requires the PFAS module and a GWT model with an SRC package. Daily push: SRC load = Σ perc(kg/ha) × overlap_ha × 1e9 (µg/day); GWT concentrations are treated as ng/L on the way back.
| Field | Description | Type | Units |
|---|---|---|---|
| N_ENTRIES | Header: number of HRU→source links | integer | — |
| N_SRCCELLS | Header: SRC BOUND array length | integer | — |
| src_index | Row value 1: 0-based SRC list index | integer | — |
| hru | Row value 2: SWAT+ HRU id | integer | — |
| overlap_ha | Row value 3: HRU–cell overlap area | real | ha |
How maps are produced, and coupled-run outputs
- Exchange maps are assembled offline from the SWAT+ HRU geometry and the MF6 grid (area-weighted HRU→cell for recharge / PFAS leach; SFR reach→channel for baseflow). They are not written by a standard website order.
- A research daily-coupling workspace also needs a daily-TDIS MF6 (and optional GWT+SRC) model next to
mf6.con— typically under TxtInOut/mf6/. - Coupled-run outputs under TxtInOut/mf6/: pfas.ucn (groundwater PFAS concentration per cell over time), pfas.lst (transport mass budget + percent discrepancy), MODFLOW_sfr.lst (flow budget incl. stream–aquifer exchange) — standard MODFLOW 6 formats.
- An automatic build's package holds none of these coupling files; it carries the steady-state sibling MODFLOW_250m archive.
