SWATGenXSWATGenX
Watershed ExplorerExample modelsCloud calibrationDocsAccess
SWATGenXDocs

MODFLOW coupling

Applies to SWATGenX engine extensions · Updated August 2026

MODFLOW_250m package contents, the one-way steady-state MODFLOW 6 build from SWAT+ percolation, and research 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)

  • Standard deliverable: sequential one-way steady-state. SWAT+ builds first; a sibling MODFLOW_250m grid is then built from annual-mean percolation (perc). Heads and baseflow are not fed back into SWAT+ in this mode. Transient MODFLOW is out of scope for standard builds.
  • Research path: live daily two-way BMI/XMI coupling inside the SWAT+ day loop. Activated only when TxtInOut contains mf6.con plus map files; the engine loads libmf6 at run time. Not included in standard packages.
Ordinary coupled downloads are the one-way steady-state sibling grid. If the unzipped site has MODFLOW_250m next to the SWAT+ project and no mf6.con in TxtInOut, it is the standard deliverable.

Build pipeline (one-way steady state)

  1. Order a coupled SWAT+/MODFLOW build (or attach MODFLOW to a finished SWAT+ workspace).
  2. After the SWAT+ package is ready, a 250 m MODFLOW 6 grid is built from annual-mean SWAT+ percolation.
  3. 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.
  4. 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, Wisconsin, and Ohio. The request point / HUC12 centroid must fall in coverage; sparse well density can refuse a build.
  • 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

  1. Install USGS MODFLOW 6 (mf6). FloPy is optional for inspection/edits; the platform already ran MF6 at build time.
  2. Unzip the MODFLOW_* package; keep the tree intact (mfsim.nam at the root of that folder).
  3. From that directory, run mf6 (or point your runner at mfsim.nam). Re-read heads (.hds), budget (.cbc), and listing files.
  4. 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)

Live coupling is built into the public SWAT+ fork. Each SWAT+ day: percolation is pushed to MF6 recharge; SFR groundwater exchange is aggregated back to SWAT+ channels (replacing native aquifer return to avoid double counting). 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.con in TxtInOut. Convention: MF6 workspace at TxtInOut/mf6/ containing mfsim.nam. Absent mf6.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.con or the exchange maps; assemble them only for the research daily-coupling path.

Failure modes

  • Expected mf6.con missingstandard archives intentionally omit it; the BMI path requires adding con + maps + a coupler binary.
  • MF6 fails to open packagesrun 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

FileDescriptionUnits / key values
mfsim.namSimulation namefile: TDIS + GWF model + IMS solver
{name}.tdisSingle steady stress periodTIME_UNITS days; period (1.0, 1, 1.0)
{name}.imsNewton / BiCGSTAB solver settingsouter head close 0.1 m; inner 0.01 m
{name}.namGWF package listdis, ic, npf, sto, ghb, rcha, sfr/riv, drn, wel, oc
{name}.disStructured grid (delr/delc/top/botm/idomain)LENGTH_UNITS meters
{name}.npfNode property flow: k, k33, icelltypeK in m d⁻¹
{name}.icStarting heads = land surface (top), all layersm
{name}.stoStorage; stress period 0 steady-state
{name}.rchaArray recharge from SWAT+ annual-mean percolationm d⁻¹ (mm yr⁻¹ ÷ 1000 ÷ 365.25); default 5.5e-4
{name}.ghbPerimeter general-head boundary to kriged water tablehead m; conductance m² d⁻¹ (K × thickness)
{name}.sfrStreamflow routing (default stream representation)lengths m; bed K m d⁻¹; inflow m³ d⁻¹; TIME_CONVERSION 86400
{name}.rivRIV fallback only if the SFR build failsstage/rbot m; conductance m² d⁻¹
{name}.drnSurface-seepage drains (default lake representation)elevation m; conductance m² d⁻¹ (capped 1e5)
{name}.welPumping wells from the wells inventoryflux m³ d⁻¹ (gpm × 5.678, negative = extraction)
{name}.ocOutput controlwrites {name}.hds + {name}.cbc
{name}.hds / .cbc / .lstRun outputs: heads, cell budgets, listingheads m; budgets m³ (per day)
{name}.sfr.stage / .sfr.cbcSFR stage and budget outputsstage m; flows m³ d⁻¹

Companion files (not MF6 packages)

FileDescription
Grids_MODFLOW_centroids.parquetCell centroids (row, col, geometry) in the projected CRS — used for well placement and GIS joins
Grids_MODFLOW.geojson / Grids_MODFLOW/*.shpCell polygons (GeoJSON only when cell count ≤ 120,000; shapefile alongside)
obs_vs_sim.csvHead observations vs simulated: wellid, row, col, obs_head_m, sim_head_m (obs = land surface − 0.3048 × SWL_ft)
obs_vs_sim.pngObserved-vs-simulated head scatter
head_calibration_report.jsonDifferential-evolution head calibration report (multipliers, NSE, cal/val metrics) — present only after the head-calibration pass, not the initial build
{name}_overview.pngModel overview figure
lake_raster.tif, swat_river.tif, rasters_input/Intermediate build rasters (included because the ZIP archives the whole folder)
The standard folder intentionally contains no mf6.con and no exchange-map files: it is a one-way steady-state deliverable, not the research daily BMI/XMI coupling. 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
LineDescriptionTypeDefault
1MF6 workspace path relative to TxtInOut (folder holding mfsim.nam)path"." (required in practice)
2Groundwater FLOW step cadence in days (clamped to ≥ 1)integer1
3Groundwater TRANSPORT step cadence in days (< 1 falls back to the flow cadence)integer30
4 (optional)Recharge multiplier rch_mult applied to every pushed recharge valuereal1.0
5 (optional)Full path to libmf6.sopathbin/libmf6.so on the default search path
Some example 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).

FieldDescriptionTypeUnits
N_ENTRIESHeader: number of overlap linksinteger
N_CELLSHeader: RECHARGE array size (NROW × NCOL)integer
NCOL / N_HRUHeader: grid columns and max HRU id (written by the builder; unused by the coupler)integers
cell_indexRow value 1: 0-based cell index (row × NCOL + col)integer
hruRow value 2: SWAT+ HRU id (1-based)integer
weightRow value 3: overlap area ÷ cell arearealdimensionless

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, replacing native aquifer return to avoid double counting.

FieldDescriptionTypeUnits
N_LINKSHeader: number of reach→channel linksinteger
N_REACHESHeader: SFR GWFLOW array lengthinteger
reach_indexRow value 1: 0-based SFR reach indexinteger
gis_channelRow value 2: SWAT+ channel GIS idinteger

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.

FieldDescriptionTypeUnits
N_ENTRIESHeader: number of HRU→source linksinteger
N_SRCCELLSHeader: SRC BOUND array lengthinteger
src_indexRow value 1: 0-based SRC list indexinteger
hruRow value 2: SWAT+ HRU idinteger
overlap_haRow value 3: HRU–cell overlap arearealha

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.
  • Ordinary website packages ship none of these coupling files; only the one-way sibling MODFLOW_250m archive is standard.