MODFLOW-NWT Contracts#
This page documents the internal contracts that HydroModPy honors before instantiating MODFLOW-NWT packages. Two contracts are covered:
Spatial and temporal discretization (DIS package).
Boundary activation and initialization (BAS package,
iboundandstrtarrays).
1. Discretization contract#
Source: hydromodpy/solver/modflow_nwt/nwt/discretization.py.
Two typed dataclasses carry the contract:
TemporalDiscretizationResultSpatialDiscretizationResult
1.1 Temporal contract#
Fields of TemporalDiscretizationResult:
Field |
Type |
Role |
|---|---|---|
|
|
MODFLOW time-unit code passed to DIS |
|
|
Number of stress periods, strictly positive |
|
1D float |
Duration of each period in |
|
1D int |
Number of time steps per period |
|
1D bool |
Steady-vs-transient flag per period |
|
|
Optional start-date metadata |
Required invariants:
nper == perlen.sizenstp.size == npersteady.size == npernper > 0
Conversion to FloPy kwargs goes through
TemporalDiscretizationResult.as_dis_kwargs(), which exposes the keys
itmuni, nper, perlen, nstp, steady, start_datetime.
1.2 Spatial contract#
Fields of SpatialDiscretizationResult:
Field |
Type |
Role |
|---|---|---|
|
grid object |
Output of |
|
2D float |
Validated topographic support |
|
|
Number of layers |
|
|
Number of rows |
|
|
Number of columns |
|
3D float |
Bottom elevations |
|
2D float |
|
Required invariants:
zbot.shape == (nlay, nrow, ncol)bottom_layer.shape == (nrow, ncol)The domain provides
surface_topoandsubstratumof typeSurface, consistent with the DEM shape.
1.3 Upstream inputs#
The temporal builder consumes:
tgrid_config.to_builder_kwargs()flow_regimedefault_itmuni
The spatial builder consumes:
the
domainwithsurface_topoandsubstratumthe active DEM shape
vertical_config
1.4 Why this contract#
Make the DIS payload explicit and testable.
Prevent any shape or unit drift between runtime objects and the solver configuration.
Keep the DIS conventions out of the orchestration code.
2. BAS contract (ibound, strt)#
These two arrays are the most sensitive at MODFLOW startup. An inconsistency can silently destabilize the simulation.
2.1 MODFLOW semantics honored#
HydroModPy follows the standard sign-based BAS contract:
ibound > 0: active cell, head is computed.ibound = 0: inactive cell, no-flow.ibound < 0: imposed-head cell (constant head).
strt is a 3D array (nlay, nrow, ncol). For ibound < 0
cells, strt provides the imposed head used by BAS.
2.2 Where the arrays are built#
Main source:
hydromodpy/solver/modflow_nwt/nwt/flow_to_modflow_adapter.pyFlowToModflowAdapter._build_initial_heads_and_sidesFlowToModflowAdapter._build_ocean_chdFlowToModflowAdapter._validate_ibound_strt_contract
Assembly point:
hydromodpy/solver/modflow_nwt/nwt/nwt_solver.pycallsflopy.modflow.ModflowBas(..., ibound=..., strt=...).
2.3 Application order#
The strt initialization policy comes from
flow.initial_conditions.h.type:
top: initialize from the DEM.bottom: initialize from the bottom-layer elevation.custom: initialize from a user scalar value.
Then lateral Dirichlet conditions (west, east, north,
south) are applied:
face cells flipped to
ibound = -1,matching
strtvalues overwritten by the boundary head.
Then the no-data mask:
DEM cells below the sentinel threshold flip to
ibound = 0.
Then the optional ocean condition:
a scalar ocean level can flip submerged cells to
ibound < 0and overwritestrt;a transient ocean forcing produces a CHD payload per stress period and can locally disable drainage.
2.4 Validations applied#
Before assembly continues, the adapter checks:
ibound.shape == (nlay, nrow, ncol)strt.shape == (nlay, nrow, ncol)drain_array.shape == (nrow, ncol)all values are finite
drain_arrayis binary (0or1)
The validation enforces sign-based semantics, not just
{-1, 0, 1}.
2.5 Practical debugging#
Check the assignment order (initial conditions, then lateral boundaries, then ocean).
Inspect
iboundsign masks (>0,=0,<0) before launching the solver.Plot
strtslices on imposed-head faces and ocean-influenced areas.Any non-finite value in
iboundorstrtis a hard error.
See also#
Solver Architecture for the solver package architecture.
Structured Grid Architecture for the grid object that feeds the DIS contract.
Design Patterns (item 1) for the adapter pattern that wraps these contracts.