======================= Meteorological Forcing ======================= Cocoa supports atmospheric forcing from wind fields and surface pressure data for storm surge and other weather-driven simulations. Forcing data is read from external files, interpolated onto the computational mesh, and applied at each timestep. .. contents:: On This Page :local: :depth: 2 Overview -------- Meteorological forcing in Cocoa includes two components: - **Wind stress**: Surface drag from 10-meter wind velocity, computed via the Garratt (1977) bulk drag law - **Atmospheric pressure gradient**: Barotropic forcing from spatially varying surface pressure Both components are read from the same input file(s) and share a common temporal interpolation framework. See :doc:`../theory/meteorological_forcing` for the mathematical formulation. Supported File Formats ---------------------- Cocoa supports three meteorological file formats through the ``cocoa_meteo`` library: .. list-table:: :header-rows: 1 :widths: 20 15 15 50 * - Format - Config Value - Domains - Description * - CF-compliant NetCDF - ``cf_netcdf`` - Single - Standard climate/forecast NetCDF with configurable variable names * - OWI ASCII - ``owi_ascii`` - Multiple - ADCIRC-compatible paired pressure/wind ASCII files * - OWI NetCDF - ``owi_netcdf`` - Multiple - NetCDF variant of OWI with support for moving (vortex-tracking) grids The synonyms ``cf`` and ``netcdf`` (for ``cf_netcdf``) and ``owi`` (for ``owi_ascii``) are also accepted. Configuration ------------- Meteorological forcing is configured in the ``forcing.meteorological`` section of the YAML configuration file. Enabling Meteorological Forcing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To enable meteorological forcing, set ``enabled: true`` and specify the file format and path(s): .. code-block:: yaml forcing: meteorological: enabled: true format: cf_netcdf filename: "path/to/meteo_data.nc" ramp: enabled: true duration: 1d The ``ramp`` section controls the global spinup ramp applied to both tidal and meteorological forcing. To use a different ramp for meteorological forcing, add an optional ``ramp`` subsection under ``forcing.meteorological``: .. code-block:: yaml forcing: ramp: enabled: true duration: 5d # Applied to tidal forcing meteorological: enabled: true format: cf_netcdf filename: "path/to/meteo_data.nc" ramp: # Optional: overrides forcing.ramp for met enabled: true duration: 1d # Shorter met ramp When the ``forcing.meteorological.ramp`` section is absent, the global ramp is used for both tidal and meteorological forcing. CF NetCDF Format ^^^^^^^^^^^^^^^^ .. code-block:: yaml forcing: meteorological: enabled: true format: cf_netcdf filename: "path/to/meteo_data.nc" **Optional variable name overrides:** By default, Cocoa expects the following NetCDF variable names. Override them under a nested ``variables`` map if your data uses different conventions: .. list-table:: :header-rows: 1 :widths: 25 25 50 * - Key - Default - Description * - ``pressure`` - ``mslp`` - Mean sea level pressure variable name * - ``wind_u`` - ``wind_u`` - Eastward 10-m wind component * - ``wind_v`` - ``wind_v`` - Northward 10-m wind component * - ``time`` - ``time`` - Time coordinate variable * - ``lon`` - ``lon`` - Longitude coordinate variable * - ``lat`` - ``lat`` - Latitude coordinate variable Example with custom variable names: .. code-block:: yaml forcing: meteorological: enabled: true format: cf_netcdf filename: "era5_data.nc" variables: pressure: "sp" wind_u: "u10" wind_v: "v10" time: "time" lon: "longitude" lat: "latitude" OWI ASCII Format ^^^^^^^^^^^^^^^^ OWI ASCII uses paired pressure and wind files per domain. This is the traditional ADCIRC meteorological forcing format. **Single domain:** .. code-block:: yaml forcing: meteorological: enabled: true format: owi_ascii filenames: - pressure: "path/to/fort.221" wind: "path/to/fort.222" **Multiple nested domains:** .. code-block:: yaml forcing: meteorological: enabled: true format: owi_ascii filenames: - pressure: "path/to/basin.pre" wind: "path/to/basin.wnd" - pressure: "path/to/region.pre" wind: "path/to/region.wnd" Domain 0 (first entry) is the outer coarse grid. Subsequent entries are progressively finer inner grids. Where grids overlap, the innermost valid domain takes priority. OWI NetCDF Format ^^^^^^^^^^^^^^^^^ OWI NetCDF stores all domains in a single NetCDF file using group-based organization. It additionally supports moving (vortex-tracking) grids where the grid coordinates change at each time step. .. code-block:: yaml forcing: meteorological: enabled: true format: owi_netcdf filename: "path/to/meteo_owi.nc" Drag Law ^^^^^^^^ The wind drag law used to convert 10-m wind velocity to surface stress is selected with ``forcing.meteorological.drag_law``. The only accepted value is ``garratt`` (the Garratt 1977 bulk drag law), which is also the default: .. code-block:: yaml forcing: meteorological: enabled: true format: cf_netcdf filename: "data.nc" drag_law: garratt # default; only accepted value Scale Factors ^^^^^^^^^^^^^ Cocoa applies configurable scale factors to convert raw file values to SI units (Pa for pressure, m/s for wind): .. list-table:: :header-rows: 1 :widths: 25 15 60 * - Parameter - Default - Description * - ``pressure_scale`` - ``100.0`` - Multiplier for pressure values. Default converts hectopascals (hPa) to pascals (Pa). * - ``wind_scale`` - ``1.0`` - Multiplier for wind velocity values. Default assumes m/s input. Example for a dataset with pressure in Pa and wind in knots: .. code-block:: yaml forcing: meteorological: enabled: true format: cf_netcdf filename: "data.nc" pressure_scale: 1.0 # Already in Pa wind_scale: 0.514444 # Convert knots to m/s .. _meteo-file-formats: File Format Details ------------------- CF-Compliant NetCDF ^^^^^^^^^^^^^^^^^^^ The CF NetCDF reader expects a regular rectangular grid with the following structure: **Required dimensions and variables:** .. code-block:: text dimensions: time = UNLIMITED ; lat = ; lon = ; variables: double time(time) ; time:units = "hours since 2026-01-01 00:00:00" ; time:calendar = "standard" ; double lat(lat) ; double lon(lon) ; float mslp(time, lat, lon) ; // Surface pressure float wind_u(time, lat, lon) ; // Eastward 10-m wind float wind_v(time, lat, lon) ; // Northward 10-m wind - The time variable must use CF-compliant units (e.g., ``"hours since ..."`` or ``"seconds since ..."``) - Longitude and latitude are 1D coordinate arrays defining the grid - Global grids (360\ |deg| longitude span) are detected automatically; the reader handles wrap-around OWI ASCII ^^^^^^^^^ OWI ASCII files use a fixed-width format with one pressure file and one wind file per domain. **File header** (line 1): .. code-block:: text Oceanweather WIN/PRE Format YYYYMMDDHH YYYYMMDDHH The header line contains a format identifier, the start time, and the end time. **Snapshot header** (one per time step): .. code-block:: text iLat= NNNiLong= NNNdx=D.DDDDdy=D.DDDDSWLat=LL.LLLLLSWLon=LLL.LLLLDT=YYYYMMDDHHNN .. list-table:: :header-rows: 1 :widths: 20 20 60 * - Field - Position - Description * - ``iLat`` - cols 5-8 - Number of latitude points (NY) * - ``iLong`` - cols 15-18 - Number of longitude points (NX) * - ``dx`` - cols 22-27 - Longitude grid spacing [degrees] * - ``dy`` - cols 31-36 - Latitude grid spacing [degrees] * - ``SWLat`` - cols 43-50 - Southwest corner latitude [degrees] * - ``SWLon`` - cols 57-64 - Southwest corner longitude [degrees] * - ``DT`` - cols 68-79 - Snapshot time (YYYYMMDDHHNN) **Data records:** Following each snapshot header, ``NX * NY`` floating-point values are written in free format. Pressure files contain one field per snapshot; wind files contain two fields (eastward U, then northward V). OWI NetCDF ^^^^^^^^^^ OWI NetCDF files use NetCDF groups to organize multi-domain data: .. code-block:: text root group: dimensions: time = UNLIMITED ; variables: double time(time) ; group: domain_0 { dimensions: node = ; variables: double longitude(time, node) ; double latitude(time, node) ; float pressure(time, node) ; float wind_u(time, node) ; float wind_v(time, node) ; } group: domain_1 { ... } The per-domain coordinate arrays (``longitude``, ``latitude``) vary with time, enabling vortex-tracking grids that follow a storm center. For stationary grids, the coordinates are the same at each time step. Combining Meteorological and Tidal Forcing ------------------------------------------ Meteorological forcing is commonly used alongside tidal forcing for storm surge simulations. Both forcing types operate independently and can be configured together: .. code-block:: yaml forcing: ramp: enabled: true duration: 2d meteorological: enabled: true format: cf_netcdf filename: "hurricane_met.nc" tide: potential: enabled: true type: astronomical boundary: enabled: true constituents: - name: M2 frequency: 1.405189028e-04 nodal_factor: 0.964 equilibrium_arg: 23.06 boundary_values: - { amplitude: 0.50, phase: 340.0 } The ramp function is applied independently to tidal and meteorological components. If the simulation starts from a pre-spun-up tidal state, a shorter meteorological ramp avoids unnecessary delay: .. code-block:: yaml forcing: ramp: enabled: true duration: 5d # Long tidal spinup meteorological: enabled: true format: cf_netcdf filename: "hurricane_met.nc" ramp: enabled: true duration: 12h # Short met ramp Wind Reduction -------------- Cocoa supports two complementary wind reduction mechanisms that modify wind velocity over land before computing wind stress. These are particularly important for storm surge simulations where overland wind fields need to account for surface roughness and canopy sheltering. Both reductions are configured in the ``physics`` section and require spatially-varying data from the mesh file. See :ref:`wind-reduction-config` for configuration details. Directional Roughness Reduction ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When ``surface_directional_roughness: mesh`` is specified, Cocoa applies a direction-dependent wind reduction based on upwind land surface roughness. This reproduces ADCIRC's ``ApplyDirectionalWindReduction`` subroutine. The algorithm: 1. Determines the wind direction at each node 2. Interpolates the land roughness length from the two nearest directional bins (12 bins at 30-degree spacing) 3. Computes the marine roughness from the current drag coefficient 4. Applies a reduction factor based on the roughness ratio An overland flooding correction reduces the effective land roughness when the total water depth exceeds twice the minimum depth threshold (``h0``), accounting for the reduced influence of land surface features when they are submerged. **Configuration:** .. code-block:: yaml physics: surface_directional_roughness: mesh # Read from mesh file The mesh file must contain the ``surface_directional_effective_roughness_length`` variable with shape ``[num_nodes, 12]``. See :doc:`mesh_preparation` for details on the mesh variable format. Canopy Coefficient ^^^^^^^^^^^^^^^^^^ When ``surface_canopy_coefficient: mesh`` is specified, wind velocity components are multiplied by a per-node canopy sheltering factor before stress computation. This represents wind attenuation under forest canopy. **Configuration:** .. code-block:: yaml physics: surface_canopy_coefficient: mesh # Read from mesh file The mesh file must contain the ``surface_canopy_coefficient`` variable with shape ``[num_nodes]`` and values in the range [0, 1]. Processing Order ^^^^^^^^^^^^^^^^ When meteorological forcing is active, the wind processing pipeline at each node follows this order: 1. **Directional roughness** (if enabled): Reduce wind based on upwind land roughness, using the drag coefficient computed from the pre-reduction wind speed 2. **Canopy coefficient** (if enabled): Multiply wind components by the canopy factor 3. **Ramp**: Scale wind by the meteorological ramp factor 4. **Wind stress**: Compute kinematic stress from the final (reduced, ramped) wind using the Garratt drag law This ordering ensures that the directional roughness reduction uses the marine drag coefficient from the unreduced wind, the canopy reduction is applied as a simple multiplicative factor, and the ramp is applied last before stress computation. Diagnostics ----------- Cocoa tracks peak wind speed and minimum atmospheric pressure at each node over the course of the simulation. These peak values are written to the output file alongside the standard elevation and velocity fields, which is useful for post-processing storm surge maxima. Complete Example ---------------- A storm surge simulation with OWI ASCII forcing on a regional mesh: .. code-block:: yaml mesh: filename: "gulf_mesh.nc" projection: type: "EquidistantCylindrical" center: [-90.0, 25.0] simulation: start_time: 2026-08-01 end_time: 2026-08-10 time_step: 10s initial_conditions: water_level: 0.0 physics: manning_n: mesh tau0: mesh cf_lower_limit: 0.001 smagorinsky_coefficient: 0.2 numeric: solver: explicit gwce_coefficients: [0.0, 1.0, 0.0] forcing: ramp: enabled: true duration: 2d meteorological: enabled: true format: owi_ascii filenames: - pressure: "basin_scale.pre" wind: "basin_scale.wnd" - pressure: "inner_region.pre" wind: "inner_region.wnd" tide: potential: enabled: true type: astronomical boundary: enabled: true constituents: - name: M2 frequency: 1.405189028e-04 nodal_factor: 0.964 equilibrium_arg: 23.06 boundary_values: - { amplitude: 0.50, phase: 340.0 } - { amplitude: 0.48, phase: 342.0 } output: filename: "surge_output.nc" step_interval: 60 diagnostics: screen_interval: 3600