Boundary Conditions

Cocoa supports various boundary condition types for different simulation scenarios. Boundary conditions are defined in the mesh file (NetCDF UGRID format), not in the YAML configuration file. Flow boundary forcing is configured separately in the YAML configuration.

Boundary Types

Boundary types are specified in the mesh file via the boundary_types variable. The following boundary type codes are recognized:

Code(s)

Type

Status

Description

-1

Open

Implemented

Open ocean boundary. Water surface elevation is prescribed (e.g., tidal forcing).

0, 1, 10, 20

Land

Implemented

Land boundary. No normal flow is permitted (natural coastline).

22

Specified Flux

Implemented

Flux-specified boundary (e.g., river inflow). Normal flow per unit width is prescribed from a time series.

32, 52

Flux + Radiation

Implemented

Specified flow with Sommerfeld radiation. Combines prescribed inflow with a radiation condition that allows outgoing waves to pass through.

30

Radiation

Implemented

Sommerfeld radiation boundary. Allows outgoing waves to exit the domain.

3, 13, 23

External Weir

Implemented

External weir/barrier boundary. Overflow computed from head difference across a one-sided weir crest.

4, 24

Internal Weir

Implemented

Internal weir/barrier boundary with paired nodes. Overflow computed independently on both sides of the crest.

Open Ocean Boundaries

Open boundaries allow water to flow in and out of the domain. These are typically used at the ocean-facing edges of the mesh. Tidal elevation forcing is applied at open boundary nodes via the forcing.tide.boundary configuration section.

See Tidal Forcing for configuring tidal boundary conditions.

Land Boundaries

Land boundaries represent coastlines where no normal flow is permitted. Multiple ADCIRC-compatible boundary codes (0, 1, 10, 20) are all mapped to the Land type internally.

Flow Boundaries

Flow boundaries prescribe the normal flow along a boundary segment. They are used to represent river inflows, controlled discharges, or other sources where the total volumetric flow rate is known.

Boundary code 22 (Specified Flux):

The simplest flow boundary. The user specifies a total volumetric flow rate \(Q\) (m3/s) for each boundary segment via a time series file. Cocoa converts this to a normal flux per unit width \(q_n\) (m2/s) that is applied uniformly at every node on the segment:

\[q_n = \frac{Q}{L_{\text{total}}}\]

where \(L_{\text{total}} = \sum_j L_j\) is the total length of the boundary segment. Each node’s contributing length \(L_j\) is computed using a trapezoidal rule: interior nodes receive half the distance to the previous neighbor plus half the distance to the next neighbor, while endpoints receive only a single half-edge length. Because the same \(q_n\) is assigned to every node, the total flux across the segment recovers the prescribed \(Q\).

Boundary code 32/52 (Flux + Sommerfeld Radiation):

Combines specified flux with a Sommerfeld radiation condition. In addition to prescribing the inflow, this boundary type allows outgoing long waves (e.g., tidal signals propagating upstream) to pass through the boundary without reflection. Both flow and elevation are specified in the time series file.

Boundary code 30 (Radiation):

A pure Sommerfeld radiation boundary with no prescribed flow. Allows outgoing waves to exit the domain cleanly.

Configuration

Flow boundaries are configured in the forcing.flow_boundary section:

forcing:
  flow_boundary:
    enabled: true
    ramp:
      enabled: true
      duration: 2d
    segments:
      - segment_index: 0
        time_series_file: "flow_segment0.yaml"

Each segment references a YAML time series file. For type 22 (flow only):

time_series:
  - { datetime: "2026-01-01 00:00:00", flow: 10000.0 }
  - { datetime: "2026-02-01 00:00:00", flow: 10000.0 }

For type 32/52 (flow + radiation), an elevation field is also required:

time_series:
  - { datetime: "2026-01-01 00:00:00", flow: 10000.0, elevation: 0.012 }
  - { datetime: "2026-02-01 00:00:00", flow: 10000.0, elevation: 0.012 }

The flow value is the total volumetric flow rate in m3/s for the entire boundary segment. The elevation value is the prescribed water surface elevation in meters at the boundary (used by the radiation term).

Ramping:

The flow boundary ramp is independent of the tidal ramp. Both flow and elevation values are multiplied by the ramp factor, which uses a hyperbolic tangent function over the specified ramp duration. This prevents impulsive startup transients.

Segment indexing:

The segment_index refers to the zero-based index of flow boundary groups in the mesh file, in the order they appear. Only non-weir flow boundary groups with codes 22, 30, 32, or 52 are counted; weir groups (codes 3, 13, 23, 4, 24) are excluded from this indexing.

Weir Boundaries

Weir boundaries model flow over elevated structures such as levees, barriers, and flood walls. Unlike flow boundaries where the flux is prescribed from a time series, weir boundaries compute the flux dynamically from the water elevation difference across the weir crest.

External Weir (codes 3, 13, 23):

An external weir has nodes on one side only. The overflow formula computes a supercritical free-overflow discharge based on the head above the crest at the boundary node, with no consideration of the water level on the opposite side (which is outside the domain). External weirs are typically used at the domain boundary to represent structures like levees where overflow exits the computational domain.

The external weir overflow formula:

\[h_f = \tfrac{2}{3}(\eta - z_{\text{crest}})\]
\[\begin{split}q_n = \begin{cases} -R \cdot C_p \cdot h_f \sqrt{h_f \cdot g} & \text{if } h_f > h_{\min} \\ 0 & \text{otherwise} \end{cases}\end{split}\]

where \(\eta\) is the water surface elevation at the boundary node, \(z_{\text{crest}}\) is the crest elevation, \(R\) is the ramp factor, \(C_p\) is the supercritical discharge coefficient, \(g\) is gravitational acceleration, and \(h_{\min}\) = 0.04 m is the minimum head threshold below which no overflow occurs.

The factor of 2/3 converts the total head above the crest to the free-overflow head, following standard weir hydraulics. The negative sign indicates outward flow (out of the domain). Once \(q_n^{n+1}\) is determined, the standard QFORCE formula applies:

\[Q_{\text{force}} = \frac{q_n^{n+1} - q_n^{n-1}}{2\Delta t} + \tau_0 \, q_n^n\]

Internal Weir (codes 4, 24):

An internal weir connects paired nodes on opposite sides of a weir crest. In the mesh file, an internal weir boundary with \(N\) node pairs lists \(2N\) nodes: the first \(N\) are “side 1” and the second \(N\) are “side 2”. Each node on one side is paired with the corresponding node on the other side.

Cross-section of an internal weir showing paired nodes on opposite sides

Fig. 2 Cross-section of an internal weir. Node A and Node B are on opposite sides of the crest. The overflow flux \(Q_N\) depends on the head above the crest on each side.

Unlike external weirs, internal weirs consider the water level on both sides of the crest. The head difference determines both the direction and regime (subcritical vs supercritical) of the overflow. Both nodes in each pair independently compute overflow from the six-regime formula (see weir overflow formula in the theory guide). Each paired node receives its own QFORCE value, which is applied to the GWCE RHS through the standard boundary segment integration.

Internal weir overflow regimes:

The overflow is classified into six regimes based on the head above the crest on each side:

Six overflow regimes for internal weir computation

Fig. 3 The six overflow regimes. Cases 1-2 produce zero flow. Cases 3-4 are outward (A to B), cases 5-6 are inward (B to A). The transition between subcritical and supercritical flow occurs at a head ratio of 2/3.

Key parameters:

  • Crest elevation (\(z_{\text{crest}}\)): Height of the weir crest (from mesh file)

  • Supercritical coefficient (\(C_p\)): Discharge coefficient for free overflow (used by both external and internal weirs)

  • Subcritical coefficient (\(C_s\)): Discharge coefficient for submerged overflow (internal weir only)

  • Minimum head threshold (\(h_{\min}\) = 0.04 m): No overflow occurs if the head above the crest is below this value

  • Equal level tolerance (0.01 m): No overflow occurs if the head difference between sides is smaller than this value (internal weir only)

Wet-edge neighbor check:

Before allowing overflow, Cocoa checks that the source side of the weir has at least one wet edge adjacent to the boundary node. This prevents isolated wet nodes from generating spurious overflow. For each weir node, the previous and next nodes along the same side of the boundary are checked for wet status. If neither neighbor is wet, flow is blocked regardless of elevation.

Barrier node flag (internal weir only):

When an internal weir has active overflow, the receiving node (the node on the lower side) is flagged as a barrier receiver. This flag is used by the wet/dry algorithm to force-wet receiving nodes, preventing them from being incorrectly dried while they are actively receiving overflow from the weir.

Weir boundaries and MPI:

Unlike ADCIRC, which requires internal weir pair nodes to be in the same MPI subdomain, Cocoa allows pair nodes to be on different ranks. This is possible because the standard ghost exchange (which runs before the overflow computation) provides the necessary elevation and wet/dry status for ghost pair nodes. See Parallel Execution for details on how this works.

Weir Configuration

Weir boundary parameters (crest elevation, discharge coefficients, pair node mapping) are defined in the mesh file. No additional YAML configuration is needed for weir boundaries beyond the standard flow boundary ramp:

forcing:
  flow_boundary:
    enabled: true
    ramp:
      enabled: true
      duration: 2d

The ramp factor is applied to all weir overflow fluxes. Weir boundaries do not use time series files; the flow is computed dynamically from the overflow formula at each timestep.