Fennel Biology
The Fennel biology module adds biological tracers to REMORA’s conserved scalar state and applies biological source and sink terms during the three-dimensional time step. The biology update is called after the GLS corrector when a biology model is enabled.
Turning Fennel On
Enable the module in the inputs file with:
remora.biology_model = fennel
The values none and off disable biology. The biology tracer count is set by
the active Fennel tracer set and is independent of remora.nscalar, which counts
passive (dye) scalars only. A run may carry both: the state is laid out as
temperature, salinity, the passive scalars, then the biology tracers.
remora.nscalar defaults to 0, so a Fennel run carries no dye unless it asks for
some.
Warning
remora.nscalar previously had to equal the biology tracer count and was a
consistency check. It now counts dye scalars in addition to biology, so an
input file carrying remora.nscalar = 11 alongside Fennel will now allocate
eleven dye tracers on top of the biology ones. Remove the setting to get the
previous state layout. REMORA prints the full component list whenever a run
carries both dye and biology.
A minimal nitrogen-only configuration is:
remora.biology_model = fennel
remora.fennel.po4 = false
remora.fennel.carbon = false
remora.fennel.oxygen = false
remora.fennel.odu = false
remora.fennel.denitrification = false
Runtime Options
All Fennel options use the remora.fennel prefix.
Option |
Default |
Effect |
|---|---|---|
|
false |
Adds phosphate and phosphate limitation and recycling terms. |
|
false |
Adds carbon detritus, TIC, alkalinity, carbon cycling, and surface CO2 exchange. |
|
false |
Adds dissolved oxygen, oxygen source/sink terms, and surface O2 exchange. |
|
false |
Adds the optional |
|
false |
Changes bottom nitrogen remineralization when
|
|
true |
Returns sinking particulate material at the bottom. |
|
false |
Adds a river dissolved organic nitrogen pool
that remineralizes to |
|
false |
Makes alkalinity prognostic instead of a
function of salinity. Requires |
|
constant |
Source of the atmospheric CO2 partial
pressure: |
|
|
Schmidt-number relation for the CO2 transfer
velocity: |
|
|
Same for O2, with the additional choice
|
The core nitrogen tracers are always present, in this order:
NO3NH4chlorophyllphytoplanktonzooplanktonLdetritusNSdetritusN
When river_don is true, RdetritusN is appended after SdetritusN.
When po4 is true, PO4 follows it.
When carbon is true, the following tracers are appended after optional
PO4: LdetritusC, SdetritusC, TIC, and alkalinity, then
RdetritusC if river_don is also true.
When oxygen is true, oxygen is appended after the carbon tracers, if
present. When odu is true, ODU is appended last. This is the order ROMS
uses in initialize_biology, so a NetCDF file written for either code reads
into the same tracers.
The tracer count is additive:
nbio = 7 + (po4 ? 1 : 0) + (carbon ? 4 : 0) + (oxygen ? 1 : 0) + (odu ? 1 : 0)
+ (river_don ? 1 : 0) + (river_don && carbon ? 1 : 0)
ncons = Tracer_comp + remora.nscalar + nbio
For example, nitrogen-only Fennel uses 7 biology tracers, PO4-only Fennel uses 8, carbon+oxygen+ODU uses 13, and every optional tracer group at once uses 16.
The oxygen and carbon options use surface gas-exchange terms and therefore
require surface forcing fields for the transfer velocity: 10-m winds
(Uwind/Vwind) when remora.bulk_fluxes is true, and surface stress
(sustr/svstr) otherwise. The base nitrogen-only configuration does not
require those fields for biology.
Biology Parameters
The following parameters can be overridden in the inputs file as
remora.fennel.<name> = <value>.
Parameter |
Default |
Meaning |
|---|---|---|
|
1 |
Iterations for the nonlinear biology update |
|
0.04 |
Seawater light attenuation [1/m] |
|
0.02486 |
Chlorophyll light attenuation |
|
0.43 |
Shortwave fraction available for biology |
|
1.0 |
Phytoplankton growth tuning parameter |
|
0.0095 |
Radiation threshold for nitrification |
|
0.1 |
Half-saturation radiation for nitrification |
|
0.05 |
Nitrification rate [day-1] |
|
2.0 |
NO3 uptake inverse half-saturation |
|
2.0 |
NH4 uptake inverse half-saturation |
|
32.0 |
PO4 uptake inverse half-saturation |
|
1.0 |
Zooplankton ingestion half-saturation |
|
0.0535 |
Maximum chlorophyll-to-carbon ratio |
|
0.01 |
Chlorophyll minimum threshold |
|
6.625 |
Phytoplankton carbon-to-nitrogen ratio |
|
0.0625 |
Phytoplankton phosphate-to-nitrogen ratio |
|
1.5 |
Phytoplankton NH4 inhibition parameter |
|
0.025 |
Phytoplankton P-I curve initial slope |
|
0.01 |
Phytoplankton minimum threshold |
|
0.15 |
Phytoplankton mortality rate [day-1] |
|
0.75 |
Zooplankton nitrogen assimilation fraction |
|
6.625 |
Zooplankton carbon-to-nitrogen ratio |
|
0.1 |
Zooplankton basal metabolism [day-1] |
|
0.1 |
Zooplankton excretion rate [day-1] |
|
0.6 |
Zooplankton maximum growth rate [day-1] |
|
0.01 |
Zooplankton minimum threshold |
|
0.025 |
Zooplankton mortality rate [day-1] |
|
0.01 |
Large nitrogen detritus remineralization |
|
0.01 |
Large carbon detritus remineralization |
|
0.005 |
Coagulation rate [day-1] |
|
0.1 |
Small nitrogen detritus remineralization |
|
0.03 |
Small carbon detritus remineralization |
|
0.03 |
River nitrogen detritus remineralization
[day-1]. Used only with |
|
0.03 |
River carbon detritus remineralization
[day-1]. Used only with |
|
0.1 |
Phytoplankton sinking velocity [m/day] |
|
1.0 |
Large detritus sinking velocity [m/day] |
|
0.1 |
Small detritus sinking velocity [m/day] |
|
370.0 |
Atmospheric CO2 partial pressure [ppmv].
Used when |
Alkalinity
By default alkalinity is diagnostic: at every biology iteration it is overwritten with \(587.05 + 50.56\,S\) following Brewer et al. (1986), so it is a relabelled salinity field and carries no memory of the biology.
With remora.fennel.talk_nonconserv = true it becomes prognostic. The
overwrite is dropped and alkalinity instead responds to nitrate uptake
(\(+\)), ammonium uptake (\(-\)), nitrification (\(-2\) per mole of
\(NH_4\)), zooplankton metabolism and excretion (\(+\)),
remineralization (\(+\)), and the sediment return (\(+\), except under
denitrification). Alkalinity feeds the pCO2 solver, so this changes the
air-sea CO2 flux and hence TIC; it changes nothing else.
Atmospheric CO2
remora.fennel.pco2air_type selects where the atmospheric CO2 partial
pressure used by the surface gas exchange comes from:
constantremora.fennel.pCO2air, unchanging. The default.dataThe annual climatology of Laurent et al. (2017), \(380.464 + 9.321 \sin(2\pi\, \mathrm{yday}/365.25 + 1.068)\).
secularA linear trend plus three harmonics, referenced to 1951.
The two time-dependent forms need a calendar. REMORA dates the model clock with
remora_caldate in Source/Utils/REMORA_DateClock.H, a port of ROMS
caldate: remora.time_ref gives the reference date and selects the
calendar, and model time is elapsed time from there. See Reference date and calendar.
Either of these places a run on 1 January 2020, the first by naming the date and the second by offsetting the default 0001-01-01 epoch:
remora.fennel.pco2air_type = secular
remora.time_ref = 20200101
remora.fennel.pco2air_type = secular
remora.start_time = 63713433600 # 2020-01-01, with time_ref = 0
Getting this right matters for secular. Its fit is anchored to 1951, and
extrapolating far back from there gives a negative partial pressure – at the
0001-01-01 epoch it returns about -2648 ppmv, which would draw CO2 out of the
ocean for the whole run. REMORA aborts on a non-positive value rather than
running with it. data is an annual climatology with no year dependence, so it
is unaffected, though it still needs the calendar to know the season.
Gas transfer
remora.fennel.co2_schmidt and remora.fennel.oxygen_schmidt select the
Schmidt-number relation for the transfer velocity. Each choice also carries its
own leading rate coefficient – 0.31 for Wanninkhof (1992), 0.251 for
Wanninkhof (2014) – so the two move together and are not settable separately.
ocmip, available for oxygen only, is Keeling et al. (1998) and pairs with
the 1992 rate coefficient, as it does in ROMS.
Initial Data and Restarts
The source of the biology initial condition is selected independently of
remora.ic_type:
Option |
Default |
Description |
|---|---|---|
|
|
|
Note this option has no remora.fennel prefix; it is a biology-wide setting
rather than a Fennel parameter.
The two are decoupled because a NetCDF initial file supplies only the tracers it
happens to contain. Setting remora.biology_ic_type = analytic keeps physical
fields coming from NetCDF while biology comes from the problem’s analytic
profile, which is useful when the initial file lacks a tracer that an enabled
option requires.
For NetCDF biology initialization, REMORA reads one variable per active tracer, using the tracer names listed under Runtime Options above. A missing variable is an error. For analytic biology initialization, the problem must provide an analytic biology routine; problems that enable biology without one abort during initialization rather than starting from uninitialized tracers.
BioToy and Upwelling ship with such a routine, both using the profile from
ROMS ana_biology.h: nitrate follows a cubic in a temperature-derived silicate
proxy, and the remaining tracers start uniform. To add one for another problem, write
a Source/Prob/REMORA_InitAnalyticBiology_<Problem>.H and give it a branch in
Problem::init_analytic_biology in Exec/REMORA_Prob.cpp. Because that profile
is a function of temperature alone, it carries over unchanged to any problem that
stratifies temperature.
When initial data is specified on a high-resolution level and averaged down
(remora.hires_init_level), biology is initialized on that level before the
average-down, using the same remora.biology_ic_type selection.
Checkpoints contain the active conserved state, including Fennel tracers. Restart
with the same Fennel component options used to create the checkpoint. Changing
po4, carbon, oxygen, or odu across a restart changes the scalar
layout and is not supported unless the checkpoint was produced with a compatible
layout.
Boundary conditions for the Fennel tracers offer the same options as temperature
and salinity, including the file-driven clamped and orlanski_rad_nudg
conditions. When per-variable boundary conditions are enabled, each tracer can be
addressed by its own name – remora.bc.NO3.type, remora.bc.oxygen.type,
and so on – and a tracer with no entry of its own falls back to
remora.bc.scalar.type. A tracer clamped or nudged to file data reads
<name>_west, <name>_east, <name>_south, and <name>_north from the
boundary NetCDF file, following the ROMS naming convention, and only for the sides
that need it. A per-side keyword applies the file-driven condition to every
tracer alike, Fennel tracers included, so a per-side clamped run needs
NO3_west and the rest in the boundary file; per-variable mode is what lets a
biology tracer keep a local condition such as outflow while temperature and
salinity are clamped. See Boundary conditions for individual tracers for details.
Validation Against ROMS
REMORA can optionally build the original ROMS Fennel kernel alongside the native C++ implementation and select between them at run time, so the two can be compared without rebuilding. This is validation infrastructure; production runs need none of it, and both features are compiled out by default.
Build flags:
GNUmake |
CMake |
|---|---|
|
|
|
|
The first builds the ROMS reference kernel; the second compiles in the
per-block diagnostic output used to compare the two. They are independent: the
native kernel carries the diagnostic instrumentation whether or not the
reference kernel is built. REMORA_ENABLE_FENNEL_FORT must be given on the
initial CMake configure line, because it determines whether the Fortran language
is enabled for the project.
Runtime options:
Option |
Default |
Description |
|---|---|---|
|
1 |
|
|
0 |
|
|
2 |
Target column index for |
|
2 |
Target column index for |
Requesting something that was not compiled in aborts with a message naming the flag to rebuild with. Neither option degrades silently: selecting the reference kernel without it present does not fall back to the native kernel, and enabling diagnostics without them present does not produce an empty log.
Because ROMS selects its biology options at compile time while REMORA selects
them at run time, the reference kernel is built for one option set at a time.
That set is pinned in Source/Biology/Fortran/remora_bio_cppdefs.h and is
checked against the runtime options on every call, so a mismatched build stops
rather than producing an invalid comparison.
Diagnostic output volume grows as tags times levels times active tracers, so
biology_debug = 2 is only practical on very small grids.
See Source/Biology/Fortran/README.md for the full build-and-run procedure
and Source/Biology/Fortran/validation_lanes.md for current validation
coverage.
Output
Fennel tracers are output by requesting fennel in
remora.plot_vars_3d, which expands to all active biology tracers. Individual
active tracer names may also be requested. Do not use scalar for Fennel
output; scalar is the passive tracer name used when biology is disabled.
Nitrogen-only output example:
remora.plot_vars_3d = temp salt fennel
PO4 output example:
remora.fennel.po4 = true
remora.plot_vars_3d = temp salt NO3 NH4 chlorophyll phytoplankton zooplankton LdetritusN SdetritusN PO4
Carbon and oxygen output example:
remora.fennel.carbon = true
remora.fennel.oxygen = true
remora.plot_vars_3d = temp salt NO3 NH4 chlorophyll phytoplankton zooplankton LdetritusN SdetritusN LdetritusC SdetritusC TIC alkalinity oxygen
Only active tracer names are available. If an inactive or unknown name is listed
in remora.plot_vars_3d, REMORA warns and omits it. Native AMReX plotfiles
and NetCDF plotfiles use the same active tracer names. NetCDF output requires
building REMORA with PnetCDF enabled; see Plotfiles.
Biology diagnostic variables such as primary productivity, nitrification flux, air-sea CO2 flux, air-sea O2 flux, and denitrification flux are not currently implemented as separate output variables.
Regression Coverage
One CI test carries biology: Upwelling_Fennel
(Tests/test_files/Upwelling_Fennel/Upwelling_Fennel.i), 41x80x16 for ten
baroclinic steps with analytic physics and analytic biology, so it needs no
NetCDF input. Its option set is deliberately wide, since one gold file is all
the coverage there is:
Option |
Value in the test |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Where an option has a default and an alternative, the test generally takes the
alternative. The defaults are the settings the Fortran-bridge comparison in
Source/Biology/Fortran runs on, so they are already checked against ROMS
itself; the gold file is more useful covering the paths that comparison does
not reach. denitrification is the exception, and is off for a reason: the
alkalinity increment from the sediment remineralization return only exists in
the branch ROMS takes when BIO_SEDIMENT is on and DENITRIFICATION is
off, so turning it on would leave that increment untested.
Because pco2air_type = secular reads the model clock, the test also sets
remora.time_ref = 20200301. That places the run just after 29 February of a
leap year, so the day-of-year handed to the trend depends on the leap-day branch
of the calendar; moving the run one day changes the gold file by about 3e-8
relative, comfortably above the test’s 1e-11 tolerance.
Not covered by any gold file, and left to the Fortran-bridge lanes:
po4, odu, denitrification, bio_sediment = false,
BioIter > 1, the data form of pco2air_type, the w92 and
ocmip Schmidt sets, and NetCDF biology initialization.