Flow Boundary Conditions#

Scope#

This page documents the runtime contract used for groundwater flow boundary conditions.

The public TOML grammar remains under [flow.bc] and flow.active_bc. The runtime architecture now adds one explicit middle layer:

  • FlowBoundaryConditionConfig stores one normalized boundary payload.

  • FLOW_BOUNDARY_DEFINITIONS is the canonical registry of known boundary identifiers and backend capabilities.

  • BoundaryConditionBundle groups configured and active boundaries for solver adapters.

This keeps the user-facing contract stable while making backend support and future extensions easier to inspect.

Quick Access#

Question

Primary code location

What to look for

Which ids can appear in flow.active_bc?

hydromodpy.physics.flow.FLOW_BOUNDARY_DEFINITIONS

Canonical id, family, support kind, and backend support.

How is TOML normalized?

hydromodpy.physics.flow.boundary_conditions_config

Accepted [flow.bc] shapes before typed validation.

What does a solver adapter consume?

hydromodpy.physics.flow.BoundaryConditionBundle

Configured boundary payloads plus explicit active ids.

Where is MF6 assembly handled?

hydromodpy.solver.modflow6.builders.boundary_conditions

CHD and DRN package payload construction.

Where is MODFLOW-NWT assembly handled?

hydromodpy.solver.modflow_nwt.nwt._chd_payloads

BAS / CHD boundary-head payloads.

Where is Boussinesq assembly handled?

hydromodpy.solver.boussinesq.forcing

Prescribed-head support and drainage operator resolution.

Which tests cover the registry contract?

tests/unit/physics/test_flow_boundary_condition_registry.py

Registry ids, backend support, bundle behavior, and Flow integration.

Code Map#

  • hydromodpy.physics.flow.boundary_conditions: normalized boundary-condition payload model.

  • hydromodpy.physics.flow.boundary_conditions_config: TOML shape normalization.

  • hydromodpy.physics.flow.boundary_condition_registry: canonical boundary registry and runtime bundle helpers.

  • hydromodpy.physics.flow.flow: runtime Flow object storing the boundary bundle.

  • hydromodpy.solver.modflow6.builders.boundary_conditions: MF6 CHD / DRN translation.

  • hydromodpy.solver.modflow_nwt.nwt._chd_payloads and _well_drainage_payloads: MODFLOW-NWT BAS / CHD / DRN translation.

  • hydromodpy.solver.boussinesq.forcing: prescribed-head and drainage operator resolution.

Current Boundary Ids#

Id

Family

Support kind

Backend package/operator

west_side

dirichlet

side

MF6 CHD; NWT BAS/CHD; Boussinesq prescribed_head.

east_side

dirichlet

side

MF6 CHD; NWT BAS/CHD; Boussinesq prescribed_head.

north_side

dirichlet

side

MF6 CHD; NWT BAS/CHD; Boussinesq prescribed_head.

south_side

dirichlet

side

MF6 CHD; NWT BAS/CHD; Boussinesq prescribed_head.

stream

dirichlet

stream

MF6 CHD; Boussinesq prescribed_head. Not implemented for NWT.

ocean

dirichlet

ocean_stage

MF6 CHD; NWT BAS/CHD; Boussinesq prescribed_head.

drainage

head_dependent_exchange

top

MF6 DRN; NWT DRN; Boussinesq top_drainage.

Diagram 1: Component View#

@startuml
title Flow Boundary Conditions - Component View

package "physics.flow" {
  component "TOML [flow.bc]" as Toml
  component "normalize_flow_boundary_conditions" as Normalizer
  component "FlowBoundaryConditionConfig" as BoundaryConfig
  component "FLOW_BOUNDARY_DEFINITIONS" as Registry
  component "BoundaryConditionBundle" as Bundle
  component "Flow" as FlowRuntime
}

package "solver.modflow6" {
  component "CHD builder" as Mf6Chd
  component "DRN builder" as Mf6Drn
}

package "solver.modflow_nwt" {
  component "BAS/CHD payloads" as NwtChd
  component "DRN payloads" as NwtDrn
}

package "solver.boussinesq" {
  component "Dirichlet support resolver" as BoussDirichlet
  component "Drainage resolver" as BoussDrainage
}

Toml --> Normalizer
Normalizer --> BoundaryConfig
BoundaryConfig --> FlowRuntime
Registry --> Bundle
FlowRuntime --> Bundle

Bundle --> Mf6Chd : dirichlet ids
Bundle --> Mf6Drn : drainage
Bundle --> NwtChd : side/ocean ids
Bundle --> NwtDrn : drainage
Bundle --> BoussDirichlet : prescribed heads
Bundle --> BoussDrainage : top drainage

note right of Registry
  Central inventory:
  id, family, units,
  support kind,
  backend support.
end note

note bottom of Bundle
  Runtime view:
  configured boundaries
  plus active ids.
end note
@enduml

Listing 1 PlantUML (.wsd) source - flow boundary-condition component view#
@startuml
title Flow Boundary Conditions - Component View

package "physics.flow" {
  component "TOML [flow.bc]" as Toml
  component "normalize_flow_boundary_conditions" as Normalizer
  component "FlowBoundaryConditionConfig" as BoundaryConfig
  component "FLOW_BOUNDARY_DEFINITIONS" as Registry
  component "BoundaryConditionBundle" as Bundle
  component "Flow" as FlowRuntime
}

package "solver.modflow6" {
  component "CHD builder" as Mf6Chd
  component "DRN builder" as Mf6Drn
}

package "solver.modflow_nwt" {
  component "BAS/CHD payloads" as NwtChd
  component "DRN payloads" as NwtDrn
}

package "solver.boussinesq" {
  component "Dirichlet support resolver" as BoussDirichlet
  component "Drainage resolver" as BoussDrainage
}

Toml --> Normalizer
Normalizer --> BoundaryConfig
BoundaryConfig --> FlowRuntime
Registry --> Bundle
FlowRuntime --> Bundle

Bundle --> Mf6Chd : dirichlet ids
Bundle --> Mf6Drn : drainage
Bundle --> NwtChd : side/ocean ids
Bundle --> NwtDrn : drainage
Bundle --> BoussDirichlet : prescribed heads
Bundle --> BoussDrainage : top drainage

note right of Registry
  Central inventory:
  id, family, units,
  support kind,
  backend support.
end note

note bottom of Bundle
  Runtime view:
  configured boundaries
  plus active ids.
end note
@enduml

Diagram 2: Runtime Sequence#

@startuml
title Flow Boundary Conditions - Runtime Sequence

actor User
participant "FlowConfig" as FlowConfig
participant "BC normalizer" as Normalizer
participant "Flow" as Flow
participant "BoundaryConditionBundle" as Bundle
participant "Solver adapter" as Adapter
participant "Backend package/operator" as Backend

User -> FlowConfig: define [flow.bc]\nand flow.active_bc
FlowConfig -> Normalizer: validate and normalize sections
Normalizer --> FlowConfig: flat mapping keyed by bc id

User -> Flow: Flow(config)
Flow -> Flow: set_boundary_conditions(...)
Flow -> Bundle: from_flow(flow)
Bundle --> Flow: active/configured runtime view

Adapter -> Bundle: active_side_dirichlet_ids()\nget_active("ocean")\nget_active("drainage")
Bundle --> Adapter: typed payloads or None

alt MODFLOW 6
  Adapter -> Backend: CHD / DRN stress-period data
else MODFLOW-NWT
  Adapter -> Backend: BAS/CHD / DRN payloads
else Boussinesq
  Adapter -> Backend: prescribed-head cells\nand drainage conductance
end

Backend --> User: solver-ready boundary representation
@enduml

Listing 2 PlantUML (.wsd) source - flow boundary-condition runtime sequence#
@startuml
title Flow Boundary Conditions - Runtime Sequence

actor User
participant "FlowConfig" as FlowConfig
participant "BC normalizer" as Normalizer
participant "Flow" as Flow
participant "BoundaryConditionBundle" as Bundle
participant "Solver adapter" as Adapter
participant "Backend package/operator" as Backend

User -> FlowConfig: define [flow.bc]\nand flow.active_bc
FlowConfig -> Normalizer: validate and normalize sections
Normalizer --> FlowConfig: flat mapping keyed by bc id

User -> Flow: Flow(config)
Flow -> Flow: set_boundary_conditions(...)
Flow -> Bundle: from_flow(flow)
Bundle --> Flow: active/configured runtime view

Adapter -> Bundle: active_side_dirichlet_ids()\nget_active("ocean")\nget_active("drainage")
Bundle --> Adapter: typed payloads or None

alt MODFLOW 6
  Adapter -> Backend: CHD / DRN stress-period data
else MODFLOW-NWT
  Adapter -> Backend: BAS/CHD / DRN payloads
else Boussinesq
  Adapter -> Backend: prescribed-head cells\nand drainage conductance
end

Backend --> User: solver-ready boundary representation
@enduml

Notes#

  • active_bc remains explicit: declared boundaries are not assembled unless their id is active.

  • The registry is deliberately small. It describes the current canonical ids and backend support; it does not hide backend-specific package semantics.

  • Adding a new canonical boundary should start in the registry, then each backend should either implement it or explicitly leave it unsupported.