=================== Boundary Conditions =================== 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: .. list-table:: :header-rows: 1 :widths: 15 25 60 * - Code(s) - Type - Description * - ``-1`` - Open - Open ocean boundary. Water surface elevation is prescribed (e.g., tidal forcing). * - ``0, 1, 10, 20`` - Land - Land boundary. No normal flow is permitted (natural coastline). * - ``22`` - Specified Flux - Flux-specified boundary (e.g., river inflow). Normal flow per unit width is prescribed from a time series. * - ``32``, ``52`` - Flux + Radiation - Specified flow with Sommerfeld radiation. Combines prescribed inflow with a radiation condition that allows outgoing waves to pass through. * - ``30`` - Radiation - Sommerfeld radiation boundary. Allows outgoing waves to exit the domain. * - ``3, 13, 23`` - External Weir - External weir/barrier boundary. Overflow computed from the head above a one-sided weir crest. * - ``4, 24`` - Internal Weir - Internal weir/barrier boundary with paired nodes. Overflow computed independently on both sides of the crest. Any code not listed is treated as a land boundary. A malformed boundary table stops the run at startup with a message naming the problem: a boundary string whose start or end index falls outside the ``boundary_nodes`` table, a weir boundary missing a required weir column, an optional boundary column that is present but shorter than the boundary, or a flux boundary chord of zero length. 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 :doc:`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. As in ADCIRC, codes 0 through 19 (which include the weir codes 3, 4 and 13) are *essential* boundaries: the momentum solve at each of their nodes is rotated into tangential and normal components and the normal velocity is set to zero. The normal is the physical one, so the condition is exact on any map projection (see the land boundary section of :doc:`../theory/momentum`). Codes 20 and above are *natural* boundaries, where no normal flow enters only weakly, through the GWCE boundary integral. .. _flow-boundaries: 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 user specifies a total volumetric flow rate :math:`Q` (m\ :sup:`3`/s) for each boundary segment via a time series file. Cocoa converts this to a normal flux per unit width :math:`q_n` (m\ :sup:`2`/s) that is applied uniformly at every node on the segment: .. math:: q_n = \frac{Q}{L_{\text{total}}} where :math:`L_{\text{total}} = \sum_j L_j` is the total length of the boundary segment. Each node's contributing length :math:`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 :math:`q_n` is assigned to every node, the total flux across the segment recovers the prescribed :math:`Q`. The recovery depends on two details. The lengths :math:`L_j` are measured in physical metres, not in the mesh's projected coordinates: the two differ by the map scale factors everywhere except at the projection's reference latitude, and measuring them projected would realize :math:`Q \cdot L_{\text{phys}} / L_{\text{proj}}` instead of :math:`Q`. And the GWCE boundary integral that consumes :math:`q_n` carries the projection's continuity-form map factors, described under :ref:`the map-factor weight `; without them the realized discharge is :math:`Q / \text{SFCX}`, which on a Mercator mesh at 29 degrees is 1.31 times what was asked for. This weight is exact at any latitude and any boundary orientation, because it combines the endpoint's own scale factors with its projected chord normal as a Euclidean norm; ADCIRC instead pre-multiplies an approximation of it into :math:`q_n` itself in its cylindrical-mapping modes, and applies nothing at all in classic spherical mode (the note under that reference gives the exact comparison). On a boundary string that spans MPI ranks, :math:`L_{\text{total}}` is summed over the whole string across all ranks (owned nodes only) rather than over each rank's own fragment. **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 Sommerfeld radiation boundary with no prescribed flow. Outgoing waves exit the domain. Configuration """"""""""""" Flow boundaries are configured in the ``forcing.flow_boundary`` section: .. code-block:: yaml 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): .. code-block:: yaml 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: .. code-block:: yaml 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 m\ :sup:`3`/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. Each ``segment_index`` may appear only once and must name an existing flow boundary; a repeated or out-of-range index stops the run at startup. .. _weir-boundaries: 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: .. math:: h_f = \tfrac{2}{3}(\eta - z_{\text{crest}}) .. math:: 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} where :math:`\eta` is the water surface elevation at the boundary node, :math:`z_{\text{crest}}` is the crest elevation, :math:`R` is the ramp factor, :math:`C_p` is the supercritical discharge coefficient, :math:`g` is gravitational acceleration, and :math:`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 :math:`q_n^{n+1}` is determined, the standard QFORCE formula applies: .. math:: 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 :math:`N` node pairs lists :math:`2N` nodes: the first :math:`N` are "side 1" and the second :math:`N` are "side 2". Each node on one side is paired with the corresponding node on the other side. .. figure:: ../_static/images/diagrams/weir_cross_section.svg :alt: Cross-section of an internal weir showing paired nodes on opposite sides :width: 550px :align: center Cross-section of an internal weir. Node A and Node B are on opposite sides of the crest. The overflow flux :math:`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 :ref:`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: .. figure:: ../_static/images/diagrams/weir_flow_regimes.svg :alt: Six overflow regimes for internal weir computation :width: 650px :align: center 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:** - :math:`z_{\text{crest}}`: crest elevation, from the mesh file. - :math:`C_p`: supercritical (free overflow) discharge coefficient, used by both external and internal weirs. - :math:`C_s`: subcritical (submerged overflow) discharge coefficient, internal weirs only. - :math:`h_{\min}` = 0.04 m: no overflow occurs while the head above the crest is below this value. - Equal-level tolerance, 0.01 m: no overflow occurs while the head difference between the two sides is smaller than this value (internal weirs 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, so isolated wet nodes cannot generate 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. The wet/dry algorithm keeps a flagged node wet while it receives overflow. **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: the ghost exchange that runs before the overflow computation supplies the elevation and wet/dry status of ghost pair nodes. See :doc:`parallel_execution`. 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: .. code-block:: yaml 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.