8#include <AMReX_FArrayBox.H>
9#include <AMReX_ParmParse.H>
10#include <AMReX_Utility.H>
19#ifdef REMORA_USE_BIOLOGY_DIAG
34AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
35void remora_fennel_tag (
const char* tag,
int iter,
int i,
int j,
int k,
36 const char* var, Real val)
noexcept
38 printf(
"FENNEL-CPP %-10s iter=%3d i=%5d j=%5d k=%4d %-4s %26.17E\n",
39 tag, iter, i, j, k, var,
double(val));
43AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
44Real fennel_pco2_water (Real T, Real S, Real TIC, Real TAlk)
noexcept
46 constexpr Real
zero = Real(0.0);
47 constexpr int IbrackMax = 30;
50 const Real Tk = T + Real(273.15);
51 const Real centiTk = Real(0.01) * Tk;
52 const Real invTk = Real(1.0) / Tk;
53 const Real logTk = std::log(Tk);
54 const Real sqrtS = std::sqrt(S);
55 const Real SO4 = Real(19.924) * S / (Real(1000.0) - Real(1.005) * S);
56 const Real sqrtSO4 = std::sqrt(SO4);
57 const Real scl = S / Real(1.80655);
59 const Real alk = TAlk * Real(0.000001);
60 const Real dic = TIC * Real(0.000001);
61 const Real phos =
zero;
62 const Real sili =
zero;
66 const Real ff = std::exp(-Real(162.8301) +
67 Real(218.2968) / centiTk +
68 std::log(centiTk) * Real(90.9241) -
69 centiTk * centiTk * Real(1.47696) +
71 centiTk * (Real(0.025225) -
72 centiTk * Real(0.0049867))));
80 const Real K1 = std::pow(Real(10.0), Real(62.008) -
81 invTk * Real(3670.7) -
82 logTk * Real(9.7944) +
83 S * (Real(0.0118) - S * Real(0.000116)));
84 const Real K2 = std::pow(Real(10.0), -Real(4.777) -
85 invTk * Real(1394.7) +
86 S * (Real(0.0184) - S * Real(0.000118)));
90 const Real Kb = std::exp(-invTk * (Real(8966.90) +
91 sqrtS * (Real(2890.53) +
92 sqrtS * (Real(77.942) -
93 sqrtS * (Real(1.728) -
94 sqrtS * Real(0.0996))))) -
95 logTk * (Real(24.4344) +
96 sqrtS * (Real(25.085) + sqrtS * Real(0.2474))) +
97 Tk * (sqrtS * Real(0.053105)) +
99 sqrtS * (Real(137.1942) + sqrtS * Real(1.62142)));
108 const Real K1p = std::exp(Real(115.525) -
109 invTk * Real(4576.752) -
110 logTk * Real(18.453) +
111 sqrtS * (Real(0.69171) - invTk * Real(106.736)) -
112 S * (Real(0.01844) + invTk * Real(0.65643)));
113 const Real K2p = std::exp(Real(172.0883) -
114 invTk * Real(8814.715) -
115 logTk * Real(27.927) +
116 sqrtS * (Real(1.3566) - invTk * Real(160.340)) -
117 S * (Real(0.05778) - invTk * Real(0.37335)));
118 const Real K3p = std::exp(-Real(18.141) -
119 invTk * Real(3070.75) +
120 sqrtS * (Real(2.81197) + invTk * Real(17.27039)) -
121 S * (Real(0.09984) + invTk * Real(44.99486)));
125 const Real Ksi = std::exp(Real(117.385) -
126 invTk * Real(8904.2) -
127 logTk * Real(19.334) +
128 sqrtSO4 * (Real(3.5913) - invTk * Real(458.79)) -
129 SO4 * (Real(1.5998) - invTk * Real(188.74) -
130 SO4 * (Real(0.07871) - invTk * Real(12.1652))) +
131 std::log(Real(1.0) - Real(0.001005) * S));
135 const Real Kw = std::exp(Real(148.9652) -
136 invTk * Real(13847.26) -
137 logTk * Real(23.6521) -
138 sqrtS * (Real(5.977) - invTk * Real(118.67) -
139 logTk * Real(1.0495)) -
144 const Real Ks = std::exp(Real(141.328) -
145 invTk * Real(4276.1) -
146 logTk * Real(23.093) +
147 sqrtSO4 * (Real(324.57) - invTk * Real(13856.0) -
148 logTk * Real(47.986) - SO4 * invTk * Real(2698.0)) -
149 SO4 * (Real(771.54) - invTk * Real(35474.0) -
150 logTk * Real(114.723) - SO4 * invTk * Real(1776.0)) +
151 std::log(Real(1.0) - Real(0.001005) * S));
155 const Real Kf = std::exp(-Real(12.641) +
156 invTk * Real(1590.2) +
157 sqrtSO4 * Real(1.525) +
158 std::log(Real(1.0) - Real(0.001005) * S) +
159 std::log(Real(1.0) + Real(0.1400) * scl / (Real(96.062) * Ks)));
163 const Real borate = Real(0.000232) * scl / Real(10.811);
164 const Real sulfate = Real(0.14) * scl / Real(96.062);
165 const Real fluoride = Real(0.000067) * scl / Real(18.9984);
168 Real X_lo = std::pow(Real(10.0), -Real(10.0));
169 Real X_hi = std::pow(Real(10.0), -Real(5.0));
170 Real X_mid = Real(0.5) * (X_lo + X_hi);
172 const Real K12 = K1 * K2;
173 const Real K12p = K1p * K2p;
174 const Real K123p = K12p * K3p;
175 const Real invKb = Real(1.0) / Kb;
176 const Real invKs = Real(1.0) / Ks;
177 const Real invKsi = Real(1.0) / Ksi;
181 for (
int Ibrack = 0; Ibrack < IbrackMax; ++Ibrack) {
182 for (
int Hstep = 1; Hstep <= 3; ++Hstep) {
183 if (Hstep == 1) { X = X_hi; }
184 if (Hstep == 2) { X = X_lo; }
185 if (Hstep == 3) { X = X_mid; }
189 const Real X2 = X * X;
190 const Real X3 = X2 * X;
191 const Real invX = Real(1.0) / X;
192 const Real A = X * (K12p + X * (K1p + X)) + K123p;
193 const Real B = X * (K1 + X) + K12;
194 const Real C = Real(1.0) / (Real(1.0) + sulfate * invKs);
197 const Real fni = dic * (K1 * X + Real(2.0) * K12) / B +
198 borate / (Real(1.0) + X * invKb) +
200 phos * (K12p * X + Real(2.0) * K123p - X3) / A +
201 sili / (Real(1.0) + X * invKsi) -
203 sulfate / (Real(1.0) + Ks * invX * C) -
204 fluoride / (Real(1.0) + Kf * invX) - alk;
205 if (Hstep == 1) { fni1 = fni; }
206 if (Hstep == 3) { fni3 = fni; }
213 const Real ftest = fni1 / fni3;
219 X_mid = Real(0.5) * (X_lo + X_hi);
226 const Real Htotal = X;
227 const Real Htotal2 = Htotal * Htotal;
232 const Real CO2star = dic * Htotal2 / (Htotal2 + K1 * Htotal + K1 * K2);
235 return CO2star * Real(1000000.0) / ff;
249 Real pco2air_constant)
noexcept
252 return pco2air_constant;
255 constexpr Real pi2 = Real(6.2831853071796);
258 Real yday = Real(0.0);
259 remora_caldate(time_ref, time_seconds / Real(86400.0), year, yday);
263 return Real(380.464) + Real(9.321) *
264 std::sin(pi2 * yday / Real(365.25) + Real(1.068));
270 constexpr Real D0 = Real(282.6);
271 constexpr Real D1 = Real(0.125);
272 constexpr Real D2 = Real(-7.18);
273 constexpr Real D3 = Real(0.86);
274 constexpr Real D4 = Real(-0.99);
275 constexpr Real D5 = Real(0.28);
276 constexpr Real D6 = Real(-0.80);
277 constexpr Real D7 = Real(0.06);
279 const Real pmonth = Real(year) - Real(1951.0) + yday / Real(365.0);
280 return D0 + D1 * pmonth * Real(12.0) +
281 D2 * std::sin(pi2 * pmonth + D3) +
282 D4 * std::sin(pi2 * pmonth + D5) +
283 D6 * std::sin(pi2 * pmonth + D7);
293 ParmParse pp(remora_prefix +
".fennel");
295 pp.queryAdd(
"BioIter",
BioIter);
296 pp.queryAdd(
"AttSW",
AttSW);
297 pp.queryAdd(
"AttChl",
AttChl);
298 pp.queryAdd(
"PARfrac",
PARfrac);
299 pp.queryAdd(
"Vp0",
Vp0);
300 pp.queryAdd(
"I_thNH4",
I_thNH4);
301 pp.queryAdd(
"D_p5NH4",
D_p5NH4);
302 pp.queryAdd(
"NitriR",
NitriR);
303 pp.queryAdd(
"K_NO3",
K_NO3);
304 pp.queryAdd(
"K_NH4",
K_NH4);
305 pp.queryAdd(
"K_PO4",
K_PO4);
306 pp.queryAdd(
"K_Phy",
K_Phy);
307 pp.queryAdd(
"Chl2C_m",
Chl2C_m);
308 pp.queryAdd(
"ChlMin",
ChlMin);
309 pp.queryAdd(
"PhyCN",
PhyCN);
310 pp.queryAdd(
"R_P2N",
R_P2N);
311 pp.queryAdd(
"PhyIP",
PhyIP);
312 pp.queryAdd(
"PhyIS",
PhyIS);
313 pp.queryAdd(
"PhyMin",
PhyMin);
314 pp.queryAdd(
"PhyMR",
PhyMR);
315 pp.queryAdd(
"ZooAE_N",
ZooAE_N);
316 pp.queryAdd(
"ZooCN",
ZooCN);
317 pp.queryAdd(
"ZooBM",
ZooBM);
318 pp.queryAdd(
"ZooER",
ZooER);
319 pp.queryAdd(
"ZooGR",
ZooGR);
320 pp.queryAdd(
"ZooMin",
ZooMin);
321 pp.queryAdd(
"ZooMR",
ZooMR);
322 pp.queryAdd(
"LDeRRN",
LDeRRN);
323 pp.queryAdd(
"LDeRRC",
LDeRRC);
324 pp.queryAdd(
"CoagR",
CoagR);
325 pp.queryAdd(
"SDeRRN",
SDeRRN);
326 pp.queryAdd(
"SDeRRC",
SDeRRC);
327 pp.queryAdd(
"RDeRRN",
RDeRRN);
328 pp.queryAdd(
"RDeRRC",
RDeRRC);
329 pp.queryAdd(
"wPhy",
wPhy);
330 pp.queryAdd(
"wLDet",
wLDet);
331 pp.queryAdd(
"wSDet",
wSDet);
332 pp.queryAdd(
"pCO2air",
pCO2air);
333 pp.queryAdd(
"po4",
po4);
334 pp.queryAdd(
"carbon",
carbon);
335 pp.queryAdd(
"oxygen",
oxygen);
336 pp.queryAdd(
"odu",
odu);
346 amrex::Abort(
"remora.fennel.talk_nonconserv requires remora.fennel.carbon: "
347 "alkalinity is a carbon-block tracer");
350 static std::string pco2air_type_string =
"constant";
351 pp.queryAdd(
"pco2air_type", pco2air_type_string);
352 const std::string pco2air_type_ci = amrex::toLower(pco2air_type_string);
353 if (pco2air_type_ci ==
"constant") {
355 }
else if (pco2air_type_ci ==
"data") {
357 }
else if (pco2air_type_ci ==
"secular") {
360 amrex::Abort(
"Unknown remora.fennel.pco2air_type: " + pco2air_type_string +
361 ". Expected constant, data, or secular.");
364 static std::string co2_schmidt_string =
"wanninkhof1992";
365 pp.queryAdd(
"co2_schmidt", co2_schmidt_string);
366 const std::string co2_schmidt_ci = amrex::toLower(co2_schmidt_string);
367 if (co2_schmidt_ci ==
"wanninkhof1992" || co2_schmidt_ci ==
"w92") {
369 }
else if (co2_schmidt_ci ==
"wanninkhof2014" || co2_schmidt_ci ==
"rw14") {
372 amrex::Abort(
"Unknown remora.fennel.co2_schmidt: " + co2_schmidt_string +
373 ". Expected wanninkhof1992 or wanninkhof2014.");
376 static std::string o2_schmidt_string =
"wanninkhof1992";
377 pp.queryAdd(
"oxygen_schmidt", o2_schmidt_string);
378 const std::string o2_schmidt_ci = amrex::toLower(o2_schmidt_string);
379 if (o2_schmidt_ci ==
"wanninkhof1992" || o2_schmidt_ci ==
"w92") {
381 }
else if (o2_schmidt_ci ==
"wanninkhof2014" || o2_schmidt_ci ==
"rw14") {
383 }
else if (o2_schmidt_ci ==
"ocmip") {
386 amrex::Abort(
"Unknown remora.fennel.oxygen_schmidt: " + o2_schmidt_string +
387 ". Expected wanninkhof1992, wanninkhof2014, or ocmip.");
394 const std::string model = amrex::toLower(name);
395 if (model ==
"none" || model ==
"off") {
398 if (model ==
"fennel") {
401 amrex::Abort(
"Unknown remora.biology_model: " + name);
414 amrex::Abort(
"Invalid biology model");
421 std::string lower = amrex::toLower(name);
422 if (lower ==
"follow" || lower ==
"follow_ic_type" || lower ==
"default") {
424 }
else if (lower ==
"analytic") {
426 }
else if (lower ==
"netcdf") {
429 amrex::Abort(
"remora.biology_ic_type must be one of: follow, analytic, netcdf");
444 amrex::Abort(
"Invalid biology IC type");
461 Vector<std::string> names = {
"NO3",
"NH4",
"chlorophyll",
"phytoplankton",
462 "zooplankton",
"LdetritusN",
"SdetritusN"};
464 names.emplace_back(
"RdetritusN");
466 if (fennel_parameters.
po4) {
467 names.emplace_back(
"PO4");
469 if (fennel_parameters.
carbon) {
470 names.emplace_back(
"LdetritusC");
471 names.emplace_back(
"SdetritusC");
472 names.emplace_back(
"TIC");
473 names.emplace_back(
"alkalinity");
475 names.emplace_back(
"RdetritusC");
478 if (fennel_parameters.
oxygen) {
479 names.emplace_back(
"oxygen");
481 if (fennel_parameters.
odu) {
482 names.emplace_back(
"ODU");
487 amrex::Abort(
"Invalid biology model");
504 amrex::Abort(
"advance_biology only supports fennel");
507#ifdef REMORA_USE_FENNEL_FORT
512 advance_biology_fortran(lev, mf_cons_old, mf_cons_new, N, dt_lev);
526 amrex::Abort(
"Fennel biology requires Hz, z_w, rmask, srflx, and, when carbon or "
527 "oxygen is active, either uwind/vwind (bulk_fluxes) or sustr/svstr");
531 const Real dtdays = dt_lev / Real(86400.0) /
static_cast<Real
>(parms.BioIter);
533 const bool use_po4 = parms.po4;
534 const bool use_carbon = parms.carbon;
535 const bool use_oxygen = parms.oxygen;
536 const bool use_odu = parms.odu;
537 const bool use_denitrification = parms.denitrification;
538 const bool use_river_don = parms.river_don;
539 const bool use_river_don_c = parms.river_don && parms.carbon;
540 const bool use_talk_nonconserv = parms.talk_nonconserv;
541 const bool use_salt = use_oxygen || use_carbon;
552 Real A_O2 = Real(1953.4);
553 Real B_O2 = Real(128.0);
554 Real C_O2 = Real(3.9918);
555 Real D_O2 = Real(0.050091);
556 Real E_O2 = Real(0.0);
557 Real o2_rate = Real(0.31);
562 D_O2 = Real(0.10939);
563 E_O2 = Real(0.00093777);
564 o2_rate = Real(0.251);
571 D_O2 = Real(0.008004);
575 Real A_CO2 = Real(2073.1);
576 Real B_CO2 = Real(125.62);
577 Real C_CO2 = Real(3.6276);
578 Real D_CO2 = Real(0.043219);
579 Real E_CO2 = Real(0.0);
580 Real co2_rate = Real(0.31);
582 A_CO2 = Real(2116.8);
583 B_CO2 = Real(136.25);
584 C_CO2 = Real(4.7353);
585 D_CO2 = Real(0.092307);
586 E_CO2 = Real(0.0007555);
587 co2_rate = Real(0.251);
594 t_old[lev], parms.pCO2air);
599 if (use_carbon && pco2air <=
zero) {
601 amrex::Abort(
"remora.fennel.pCO2air must be a positive partial pressure; got "
602 + std::to_string(pco2air) +
" ppmv.");
608 amrex::Abort(
"remora.fennel.pco2air_type gives a non-positive atmospheric pCO2 ("
609 + std::to_string(pco2air) +
" ppmv) at this model time. The secular"
610 " trend is fitted around 1951, so put the run in a real year: set"
611 " remora.time_ref to the reference date and remora.start_time to the"
616#ifdef REMORA_USE_BIOLOGY_DIAG
629 const int sc_no3 = ncell++;
630 const int sc_nh4 = ncell++;
631 const int sc_chlo = ncell++;
632 const int sc_phyt = ncell++;
633 const int sc_zoop = ncell++;
634 const int sc_lden = ncell++;
635 const int sc_sden = ncell++;
636 const int sc_rden = use_river_don ? ncell++ : -1;
637 const int sc_po4 = use_po4 ? ncell++ : -1;
638 const int sc_ldec = use_carbon ? ncell++ : -1;
639 const int sc_sdec = use_carbon ? ncell++ : -1;
640 const int sc_tic = use_carbon ? ncell++ : -1;
641 const int sc_talk = use_carbon ? ncell++ : -1;
642 const int sc_rdec = use_river_don_c ? ncell++ : -1;
643 const int sc_oxyg = use_oxygen ? ncell++ : -1;
644 const int sc_odu = use_odu ? ncell++ : -1;
645 const int sc_temp = ncell++;
646 const int sc_salt = use_salt ? ncell++ : -1;
647 const int sc_inv_hz = ncell++;
648 const int sc_inv_hz2 = ncell++;
649 const int sc_inv_hz3 = ncell++;
650 const int sc_qc = ncell++;
651 const int sc_bR = ncell++;
652 const int sc_bL = ncell++;
653 const int sc_WR = ncell++;
654 const int sc_WL = ncell++;
657 const int sw_FC = nw++;
659 for (MFIter mfi(mf_cons_new, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
660 Box bx = mfi.tilebox();
663 Box wbx = surroundingNodes(bx, 2);
665 FArrayBox fab_cell(bx, ncell, amrex::The_Async_Arena());
667 FArrayBox
fab_w(
wbx,
nw, amrex::The_Async_Arena());
747 constexpr Real
zero = Real(0.0);
756 constexpr Real
one = Real(1.0);
757 constexpr Real
two = Real(2.0);
758 constexpr Real
eps = Real(1.0e-20);
759 constexpr Real
minval = Real(1.0e-6);
760 constexpr Real
cff_weno = Real(1.0e-14);
762 constexpr Real
OA0 = Real(2.00907);
763 constexpr Real
OA1 = Real(3.22014);
764 constexpr Real
OA2 = Real(4.05010);
765 constexpr Real
OA3 = Real(4.94457);
766 constexpr Real
OA4 = Real(-0.256847);
767 constexpr Real
OA5 = Real(3.88767);
768 constexpr Real
OB0 = Real(-0.00624523);
769 constexpr Real
OB1 = Real(-0.00737614);
770 constexpr Real
OB2 = Real(-0.0103410);
771 constexpr Real
OB3 = Real(-0.00817083);
772 constexpr Real
OC0 = Real(-0.000000488682);
773 constexpr Real
rOxNO3 = Real(8.625);
774 constexpr Real
rOxNH4 = Real(6.625);
775 constexpr Real
rOxNH4Denit = Real(115.0) / Real(16.0);
777 constexpr Real
l2mol = Real(1000.0) / Real(22.3916);
779 constexpr Real
A1 = Real(-60.2409);
780 constexpr Real
A2 = Real(93.4517);
781 constexpr Real
A3 = Real(23.3585);
782 constexpr Real
B1 = Real(0.023517);
783 constexpr Real
B2 = Real(-0.023656);
784 constexpr Real
B3 = Real(0.0047036);
793 for (
int k = 0;
k <=
N; ++
k) {
812 tic(
i,
j,
k) = amrex::min(tic(
i,
j,
k), Real(3000.0));
813 tic(
i,
j,
k) = amrex::max(tic(
i,
j,
k), Real(400.0));
831 for (
int k = 0;
k <
N; ++
k) {
834 for (
int k = 1;
k <
N; ++
k) {
851#ifndef REMORA_USE_BIOLOGY_DIAG
852 auto tag_state = [] (
const char*, int)
noexcept {};
858 for (
int k = 0;
k <=
N; ++
k) {
918 for (
int k =
N;
k >= 0; --
k) {
930 const Real
cff =
parms.PhyCN * Real(12.0);
936 const Real
Vp =
parms.Vp0 * Real(0.59) * std::pow(Real(1.066),
temp(
i,
j,
k));
1043 for (
int k =
N;
k >= 0; --
k) {
1065 for (
int k = 0;
k <=
N; ++
k) {
1100 for (
int k = 0;
k <=
N; ++
k) {
1141 for (
int k = 0;
k <=
N; ++
k) {
1160 for (
int k = 0;
k <=
N; ++
k) {
1161 const Real
fac1 = amrex::max(oxyg(
i,
j,
k) - Real(6.0),
zero);
1201 for (
int k = 0;
k <=
N; ++
k) {
1233 const Real
cff1 =
rho0 * Real(550.0);
1240 u10squ = uwind(
i,
j,0) * uwind(
i,
j,0) + vwind(
i,
j,0) * vwind(
i,
j,0);
1243 std::sqrt((Real(0.5) * (sustr(
i,
j,0) + sustr(
i+1,
j,0))) *
1244 (Real(0.5) * (sustr(
i,
j,0) + sustr(
i+1,
j,0))) +
1245 (Real(0.5) * (svstr(
i,
j,0) + svstr(
i,
j+1,0))) *
1246 (Real(0.5) * (svstr(
i,
j,0) + svstr(
i,
j+1,0))));
1256 const Real
TS = std::log((Real(298.15) -
temp(
i,
j,
k)) /
1257 (Real(273.15) +
temp(
i,
j,
k)));
1281 for (
int k = 0;
k <=
N; ++
k) {
1299 for (
int k = 0;
k <=
N; ++
k) {
1300 talk(
i,
j,
k) = Real(587.05) + Real(50.56) *
salt(
i,
j,
k);
1312 tic(
i,
j,
k), talk(
i,
j,
k));
1315 const Real
cff1 =
rho0 * Real(550.0);
1321 u10squ = uwind(
i,
j,0) * uwind(
i,
j,0) + vwind(
i,
j,0) * vwind(
i,
j,0);
1324 std::sqrt((Real(0.5) * (sustr(
i,
j,0) + sustr(
i+1,
j,0))) *
1325 (Real(0.5) * (sustr(
i,
j,0) + sustr(
i+1,
j,0))) +
1326 (Real(0.5) * (svstr(
i,
j,0) + svstr(
i,
j+1,0))) *
1327 (Real(0.5) * (svstr(
i,
j,0) + svstr(
i,
j+1,0))));
1337 const Real
TempK = Real(0.01) * (
temp(
i,
j,
k) + Real(273.15));
1366 }
else if (
isink == 2) {
1369 }
else if (
isink == 3) {
1372 }
else if (
isink == 4) {
1376 }
else if (
isink == 5) {
1384 for (
int k = 0;
k <=
N; ++
k) {
1391 for (
int k = 0;
k <=
N + 1; ++
k) {
1400 for (
int k = 1;
k <
N; ++
k) {
1412 }
else if (std::abs(
dltR) > std::abs(
cffL)) {
1414 }
else if (std::abs(
dltL) > std::abs(
cffR)) {
1431 for (
int k = 1;
k <
N - 1; ++
k) {
1448 for (
int k = 0;
k <=
N; ++
k) {
1456 }
else if (std::abs(
dltR) > std::abs(
cffL)) {
1458 }
else if (std::abs(
dltL) > std::abs(
cffR)) {
1473 for (
int k = 0;
k <=
N; ++
k) {
1479 for (
int k = 0;
k <=
N; ++
k) {
1498 for (
int k = 0;
k <=
N; ++
k) {
1551 for (
int k = 0;
k <=
N; ++
k) {
1552 tic(
i,
j,
k) = amrex::min(tic(
i,
j,
k), Real(3000.0));
1553 tic(
i,
j,
k) = amrex::max(tic(
i,
j,
k), Real(400.0));
1567 const Real rmask =
mskr(
i,
j,0);
1568 for (
int k = 0;
k <=
N; ++
k) {
1639#ifdef REMORA_USE_BIOLOGY_DIAG
1647 for (
int k = 0;
k <=
N; ++
k) {
constexpr amrex::Real two
constexpr amrex::Real one
constexpr amrex::Real zero
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void remora_caldate(amrex::Real time_ref, amrex::Real current_time_days, int &year, int &month, int &day, amrex::Real &yday) noexcept
Model time in days to calendar date. ROMS caldate.
mf_h setVal(geomdata.ProbHi(2))
int biology_debug_i
Target column i index for biology_debug = 1.
REMORABiology::BiologyModel biology_model
Active biology package.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vwind
Wind in the v direction, defined at rho-points.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr
land/sea mask at cell centers (2D)
int biology_debug
Biology diagnostic verbosity: 0 off, 1 target column, 2 all columns. See Source/Biology/Fortran/tag_m...
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_sustr
Surface stress in the u direction.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Hz
Width of cells in the vertical (z-) direction (3D, Hz in ROMS)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
int Bio_comp
First cons component of the biology block, i.e. Tracer_comp + nscalar. The state is laid out as temp,...
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_svstr
Surface stress in the v direction.
static SolverChoice solverChoice
Container for algorithmic choices.
int biology_debug_j
Target column j index for biology_debug = 1.
void advance_biology(int lev, amrex::MultiFab const &mf_cons_old, amrex::MultiFab &mf_cons_new, int N, amrex::Real dt_lev)
Apply biological tracer source/sink terms.
REMORABiology::FennelParameters fennel_params
Runtime parameters for the Fennel biology package.
int use_biology_cpp_answer
Select the native C++ biology kernel (1) or the ROMS Fortran bridge oracle (0). Only meaningful when ...
amrex::Vector< amrex::Real > t_old
old time at each level
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_srflx
Shortwave radiation flux [W/m²], defined at rho-points.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_z_w
z coordinates at w points (faces between z-cells)
Components components(FennelParameters const ¶meters, int base) noexcept
Map the Fennel tracers onto cons components starting at base.
Vector< std::string > tracer_names(BiologyModel model, FennelParameters const &fennel_parameters)
std::string biology_ic_type_name(BiologyICType type)
bool has_biology(BiologyModel model) noexcept
BiologyICType parse_biology_ic_type(const std::string &name)
@ secular
secular trend plus harmonics, referenced to 1951
@ constant
remora.fennel.pCO2air, unchanging
@ data
annual climatology of Laurent et al. (2017)
@ follow_ic_type
default: NetCDF when ic_type is netcdf, else analytic
BiologyModel parse_biology_model(const std::string &name)
std::string biology_model_name(BiologyModel model)
CO2SchmidtType co2_schmidt
void init_params(const std::string &remora_prefix)