Skip to content

Instantly share code, notes, and snippets.

@kevinrosa
Last active May 23, 2025 13:36
Show Gist options
  • Save kevinrosa/4a51c4040b5a82d665b48a558b980db6 to your computer and use it in GitHub Desktop.
Save kevinrosa/4a51c4040b5a82d665b48a558b980db6 to your computer and use it in GitHub Desktop.
ROMS notes

ROMS

The model described in this document is the three-dimensional, hydrostatic primitive-equation Regional Ocean Modeling System. It is a free-surface, finite-difference circulation model, formulated in a vertical terrain-following sigma-coordinate. The horizontal discretization is by an orthogonal curvilinear Arakawa-C grid. (taken from He and Wilkin 2006)

On restarts

Perfect restart uses multiple time steps in order to calculate the derivatives (unlike a single time step initialization)

For new solutions, or to use analytical initial conditions, must set NRREC == 0 (in addition to compiling with #define ANA_INITIAL in the cpp header file.

To restart, if you used #define ANA_INITIALthen you need to recompile with #undef ANA_INITIAL.

If using perfect restart from a previous solution, make sure that AVGNAME and DIANAME correspond to existing files (from the previous solution), do not rename these.

Another potential source of error is in regards to NTIMES. When restarting, this is not how many timesteps to take in the current run, it is related to the start time of the restart file. Have not yet investigated how it handles changes in DT.

On surface boundary forcing

https://www.myroms.org/index.php?page=forcing

BULK_FLUXES:

If the ocean-atmosphere boundary layer is activated, the User needs to provide the following atmospheric fields:

  • Surface U-wind component.
  • Surface V-wind component.
  • Surface air temperature.
  • Surface air pressure.
  • Surface air relative humidity.
  • Cloud fraction.
  • Rain fall rate.
  • Shortwave radiation flux.

Here, surface means near surface sea level and it is usually at 10 m. If some of the above fields are not available, the User can set them internally in the model using the analytical options.

Provide Fluxes Directly (no BULK_FLUXES):

https://www.myroms.org/forum/viewtopic.php?f=30&t=3003
"In some applications with open boundary conditions like T/S radiation, the recommendation is to not use BULK_FLUXES"

  • surface wind stress sustr and svstr
  • surface freshwater flux swflux
  • surface net heat flux shflux
  • surface shortwave radiation flux swrad
    • Why would we need swrad if we already have shflux?: "If the water is clear, not all incoming light will enter as a surface boundary heating. It will instead penetrate down some distance and be absorbed as heat there." [source]

Note that surface heat flux depends on SST. Likely the SST used in the heat flux calculations were from climatology but it would be useful to examine the sensitivity of heat flux on SST.

Note for variables such as evaporation, the input ECMWF data is a cumulative integral in forecast cycle from hour zero. Be aware of this when converting to instantaneous flux.

Shortwave, longwave

https://www.myroms.org/forum/viewtopic.php?f=1&t=2621
The total net surface heat flux shflux... is always the sum of four terms: shortwave radiation flux, longwave radiation flux, latent heat flux, and sensible heat flux. Its sign can be both positive (downward flux, heating) or negative (upward flux, cooling). The net heat flux is a vertical boundary condition to the temperature diffusion equation.

On rotating velocity output

ROMS ticket #539 added the capability to output momentum components rotated to geographical eastward/northward and interpolated to rho-points.

To include this output, add to ocean.in:

Hout(idu3dE) == T       ! u_eastward         3D U-eastward  at RHO-points
Hout(idv3dN) == T       ! v_northward        3D V-northward at RHO-points

Hout(idu2dE) == T       ! ubar_eastward      2D U-eastward  at RHO-points
Hout(idv2dN) == T       ! vbar_northward     2D V-northward at RHO-points

Note that the above will include these output in the history files. For averages and stations, follow the same format but replace Hout with Aout and Sout respectively.

Rotating vectors in curvilinear coordinates

Grid dimensions

ξ - xi (pronounced like "sigh") East-West
η - eta North-South

Converting forcing units

Field FVCOM ROMS
wind stress Pa Newton meter-2
precip/evap m/s kg m-2 s-1
radiation flux W m-2 W m-2
air pressure Pa millibar
  • Pay careful attention to freshwater flux directions. In FVCOM, negative evap and negative precip both correspond to the ocean losing water. In ROMS, negative swflux means ocean gaining water.

Vertical S-coordinate

vertical grid

Stations file

The horizontal location for a particular station may be specified in terms (longitude,latitude) grid pairs (FLAG=1) or fractional (I,J) grid pairs (FLAG=0).

The positions (I,J) specified in stations.in are located at rho-points. These points begin at 0. Since MATLAB cannot handle 0 indices, you must be careful of off-by-one mistakes when defining station locations. https://www.myroms.org/forum/viewtopic.php?f=30&t=2478

Similarly, when analyzing the stations output in Matlab, the fields Ipos and Jpos will be off by 1 in relation to Matlab matrices.

Interpolating to the open boundary

u and v at the roms boundary is not the same as the u and v fvcom values interpolated along the boundary. fvcom output is true northward and eastward. For velocities, will just calculate u_eastward and v_northward along the boundaries (at rho-points of course) and then rotate and solve for roms u and v at the u- and v-points.

Editing grid mask

Use matlab function editmask

Smoothing grid

To smooth from grd_375x450_v5.nc to grd_375x450_v6.nc, I applied fourth order shapiro function, calling the ROMS MATLAB utility shapiro2 as follows: h_smooth = shapiro2(h,4,1).

	grid			|	rx0		|	rx1

:------------------:|:-------:|:-------: grd_375x450_v5.nc | 0.817 | 1.304 grd_375x450_v6.nc | 0.671 | 1.079

Open boundaries

In ocean.in, be sure to check the nudging time scales. The following correspond to the passive (outflow) nudging time scales: TNUDG, ZNUDG, M2NUDG, and M3NUDG for active tracer variables (temp and salinity), free-surface, 2-D momentum, and 3-D momentum respectively.

OBCFAC is factor bewtween passive (outflow) and active (inflow) open boundary conditions. Nudging time scales for inflow conditions are obtained by multiplying the passive values by OBFAC. (If OBFAC>1, nudging on inflow is stronger than on outflow).

Assorted boundary problems
  • RADIATION: for fsg150, tried using Rad for zeta, ubar, vbar. Kept blowing up in the upper bay, even down to 15 sec DT. Changed to Chapman and Flathers and increased DT to 30 and it worked fine. Could probably have gone higher on DT

Rivers

USGS Blackstone River stream site near the Bay (USGS 01113895) was not installed until 2003. USGS 01112500 is available since 1929 but is near the northern border of RI (42°00'22"N 71°30'13"W). Should look into how different the readings are at the two locations.

Tidal forcing

John Wilkin [source]:

On the US East Coast our experience is that both ADCIRC and TPX0 tide models work quite well as regional model boundary conditions. Or if you're keen, you can consider using a data assimilative approach to tuning the tide boundary conditions to better fit data in the model interior. See for example (shameless pitch for my own work): He, R. and J. L. Wilkin, (2006), Barotropic tides on the southeast New England shelf: A view from a hybrid data assimilative modeling approach. Journal of Geophysical Research, 111, C08002, doi:10.1029/2005JC003254. pdf of paper

A note on forcing tides at the boundaries, from the above He and Wilkin 2006 paper:

"In limited area coastal domains the tides can be treated as being entirely remotely forced, i.e., the influence of the gravitational tide generating forces within the domain are negligible. The principal challenge to modeling tides accurately is the proper representation of tidal elevation and velocity boundary conditions around the entire model perimeter."

More on tides and boundaries

Initially, it was my understanding that tides in ROMS were applied at every grid point (since that is how they are stored in the netcdf file). This does not appear to be the case though. For most applications, the tidal fields (period, amplitude, phase angle) are only applied at the open boundaries.
arango: "it is not obvious to many users why we built the tidal forcing in the full grid. We did this because of sponge layers and nudging bands next to the open boundaries. The interior tidal field maybe needed for such application."

Special cases, such as global models in which there are no boundaries, can apply tides at each grid point but for a case like Rhode Island Sound, the interior points can be set to 0 and it will not change the solution.
See this discussion. Also, another potentially useful discussion about tidal forcing vs. bry (zeta,u,v,ubar,vbar) forcing and the associated flags and boundary conditions.

From the FAQs

What are the ways that ROMS can receive tides on the boundaries?

  1. You can specify a time-dependent boundary condition file that temporally resolves the tides and skip the tides file entirely.
  2. You can specify SSH_TIDES and/or UV_TIDES and provide a tides file and skip the boundary condition file entirely - though this option might require you to tell ROMS in globaldefs.h that you really, really don't need an OBC_FILE. Usual practice is to provide both surface elevation and currents in the tidal file and to use FSCHAPMAN and M2FLATHER on the open sides of your domain.
  3. You can specify other 2-d currents and surface elevation signals as coming in, plus have tides and use the ADD_M2OBC and ADD_FSOBC options.

To do: figure out when analytical boundary conditions are necessary and whether they must accompany ADD_*OBC.

source:
To use tidal forcing in your south open boundary, you would specify Chapman for free-surface boundary condition and Flather for 2D U/V-momentum in ocean_yourproject.in. The corresponding CPP options are SSH_TIDES, which indicates ROMS to use tidal elevation (from your tidal forcing file) as the free-surface open boundary condition and UV_TIDES for 2D momentum open boundary conditions.

Kate:
If you are getting your tides from the XX_TIDES options, you leave that on when adding tides to the subtidal flows coming from your FSOBC and M2OBC. The only domain in which I don't have ADD_FSOBC, SSH_TIDES and so forth is when my boundary file temporally resolves the tides and brings the tides in directly.

Making tides file

Download TPXO2ROMS_v4pt0 here. Reads from the TPXO 8 atlas (download netcdfs of the harmonics as well as the bathymetry here).

Run in 2D (barotropic) mode

  • undefine SOLVE3d in *.h file
  • set NDTFAST == 1 in *.in file
  • decrease DT. If 3D configuration, DT is the size of the baroclinic time-step. If only 2D configuration, DT is the size of the barotropic time-step.

Compiling error: stflx(i,j,itemp)=wetdry(i,j)*stflx(i,j,itemp)
Used cppdefs_2D.h from here as a template.

Aug 5, 2016 update: Compiling with ROMS source code set as /home/rosa/roms/new_trunk-3.7 instead of /home/rosa/large_grid/ROMS_trunk did not return an error

Storm surge

Reduced-physics 2d momentum, Chapman free surface, ANA_M2OBC => no tidal elevation.
Reduced-physics 2d momentum, Reduced-physics free surface, ANA_M2OBC => no tidal elevation.
Reduced-physics 2d momentum, Reduced-physics free surface, undef ANA_M2OBC => no tidal elevation.
Flather 2d momentum, Reduced-physics free surface, undef ANA_M2OBC => no tidal elevation. Actually may not be true, did not run long enough for ramptide to be felt

CPP Header file

ROMS wiki

Bottom stress

Three main ways to add bottom stress in ROMS:

  1. Linear -- RDRG > 0, RDRG2 = 0, Zob = 0
  2. Quadratic -- RDRG = 0, RDRG2 > 0, Zob = 0
  3. Logarithmic -- RDRG = 0, RDRG2 = 0, Zob > 0
    *Note that the logarithmic "law of the wall" only applies to 3d configurations.

Nesting

Run f79a was instructional. I had not written the salt and temp to the initialization file for the nested grid so those fields were just filled with fill values. Two things happened: the temp was initalized to 0°C throughout the nested grid and then that temperature was assigned to the parent grid. This run also provides an interesting look at what happens if you suddenly make the Prov River very cold during the summer.

Wetting and Drying

Finding a test case with wetting and drying: grep WET_DRY ~/nesttest/test/*/*.h. Showed that the test_head test case uses wetting and drying.

discussion 1

  • WET_DRY
  • DCRIT == 0.1
  • use LIMIT_BSTRESS

Rivers/Dyes

https://www.myroms.org/wiki/River_Runoff

In ocean.in, activate one (and only one) of the following:

  • LuvSrc - imposes sources via a horizontal velocity. The river's u- or v-face should be a land/sea mask boundary.
    • river_Xposition and river_Eposition refer to the i,j index of the u-face or v-face the flow crosses
  • LwSrc - does not add momentum to the system; adds directly to the volume and tracer divergence terms.

Define TS_PSOURCE. Update: it looks like this flag is no longer used.

For passive tracers, set #define T_PASSIVE and update LtracerSrc. For example, LtracerSrc == F F 5*T Will need river_dye_01, river_dye_02, etc. in river forcing NetCDF.

Note: Avoid using LwSrc for now

John Wilkin:

Hernan and I have looked in to this a bit further, and this has raised concerns that the LwSrc option is not implemented correctly... Until we (or someone else in the user community) resolves this, I would strongly caution against using the LwSrc option for river sources.

Starting passive tracers from analytical initial conditions
  • Define ANA_PASSIVE, ANA_BPFLUX, and ANA_SPFLUX
  • Update ana_passive.h

If you're going to do a run with no rivers, must set LuvSrc and LwSrc both to false as well as all LtracerSrc to false, otherwise ROMS will look for an SSF file.

Averages files

In order to write to averages file, must #define AVERAGES in cppdefs.h file.

ROMS intro descriptions

  • Warner et al. 2005: A general class of three-dimensional, free surface, terrain following numerical models appli- cable to oceanographic and estuarine studies includes POM, ECOM, and ROMS. These models solve the Reynolds-averaged Navier–Stokes equations (RANS) using the hydrostatic and Bous- sinesq assumptions (Blumberg and Mellor, 1983, 1987; Haidvogel and Beckmann, 1999; Kantha and Clayson, 2000).
    • The diversity of three-dimensional ocean models reflects various choices involving numerics (e.g., how best to discretize and solve the RANS equations, which grid method to use, what programming language to use, and how to structure the model) and physics (e.g., what boundary conditions to use for the RANS equations, and which turbulence closure methods to use).

Nice command line tricks

  • watch -n5 qstat will execute qstat every 5 seconds, forever. Use Ctrl-C to stop.

_

_
_

Assorted error sources

  • Non-space (TAB) characters in the ocean.in file
    • Test for their existence using grep $'\t' ocean.in
  • in cppdefs.h, cannot start a variable with a number
    • also it turns out TIDES is a reserved name
  • messing up the variable attributes on the netcdf forcing files can return very unhelpful errors that look as if it's an MPI issue.
  • if LtracerSrc has any Ts, must provide a SSFNAME file
  • "dye_west_01 not found...". I don't understand this bug but basically when NPT==1 it fails with this error but works when NPT==2.

_

_
_

Motivations

From Li et al. (2006):
Given warmer-than-normal global sea-surface temperature, both the number and proportion of intense TCs have increased notably since 1970 [Emanuel, 2005; Webster et al., 2005]. Thus, more hurricanes with stronger intensity might hit bays and generate storm surges as seen during the passage of Isabel. The problem of storm surge is exacerbated by the prospect of accelerated global sea-level rise in the 21st century [Church et al., 2001], and compounded by continuing subsidence of low-lying lands surrounding bays and estuaries [Kearney and Stevenson, 1991]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment