455#ifdef REMORA_USE_FENNEL_FORT
457 advance_fortran(context);
461 auto const& mf_cons_old = context.
old_state;
466 const Real dt_lev = context.
dt;
469 const bool need_wind = (parms.oxygen || parms.carbon) && solverChoice.bulk_fluxes;
470 const bool need_stress = (parms.oxygen || parms.carbon) && !solverChoice.bulk_fluxes;
472 if (context.
hz ==
nullptr || context.
z_w ==
nullptr || context.
mask ==
nullptr ||
474 (need_stress && (context.
stress_u ==
nullptr || context.
stress_v ==
nullptr)) ||
475 (need_wind && (context.
wind_u ==
nullptr || context.
wind_v ==
nullptr))) {
476 amrex::Abort(
"Fennel biology requires Hz, z_w, rmask, srflx, and, when carbon or "
477 "oxygen is active, either uwind/vwind (bulk_fluxes) or sustr/svstr");
481 const Real dtdays = dt_lev / Real(86400.0) /
static_cast<Real
>(parms.BioIter);
482 const Real
rho0 = solverChoice.rho0;
483 const bool use_po4 = parms.po4;
484 const bool use_carbon = parms.carbon;
485 const bool use_oxygen = parms.oxygen;
486 const bool use_odu = parms.odu;
487 const bool use_denitrification = parms.denitrification;
488 const bool use_river_don = parms.river_don;
489 const bool use_river_don_c = parms.river_don && parms.carbon;
490 const bool use_talk_nonconserv = parms.talk_nonconserv;
491 const bool use_salt = use_oxygen || use_carbon;
492 const bool do_bulk_flux = solverChoice.bulk_fluxes;
502 Real A_O2 = Real(1953.4);
503 Real B_O2 = Real(128.0);
504 Real C_O2 = Real(3.9918);
505 Real D_O2 = Real(0.050091);
506 Real E_O2 = Real(0.0);
507 Real o2_rate = Real(0.31);
512 D_O2 = Real(0.10939);
513 E_O2 = Real(0.00093777);
514 o2_rate = Real(0.251);
521 D_O2 = Real(0.008004);
525 Real A_CO2 = Real(2073.1);
526 Real B_CO2 = Real(125.62);
527 Real C_CO2 = Real(3.6276);
528 Real D_CO2 = Real(0.043219);
529 Real E_CO2 = Real(0.0);
530 Real co2_rate = Real(0.31);
532 A_CO2 = Real(2116.8);
533 B_CO2 = Real(136.25);
534 C_CO2 = Real(4.7353);
535 D_CO2 = Real(0.092307);
536 E_CO2 = Real(0.0007555);
537 co2_rate = Real(0.251);
543 const Real pco2air = fennel_pco2_air(parms.pco2air_type, solverChoice.time_ref,
549 if (use_carbon && pco2air <=
zero) {
551 amrex::Abort(
"remora.fennel.pCO2air must be a positive partial pressure; got "
552 + std::to_string(pco2air) +
" ppmv.");
558 amrex::Abort(
"remora.fennel.pco2air_type gives a non-positive atmospheric pCO2 ("
559 + std::to_string(pco2air) +
" ppmv) at this model time. The secular"
560 " trend is fitted around 1951, so put the run in a real year: set"
561 " remora.time_ref to the reference date and remora.start_time to the"
566#ifdef REMORA_USE_BIOLOGY_DIAG
579 const int sc_no3 = ncell++;
580 const int sc_nh4 = ncell++;
581 const int sc_chlo = ncell++;
582 const int sc_phyt = ncell++;
583 const int sc_zoop = ncell++;
584 const int sc_lden = ncell++;
585 const int sc_sden = ncell++;
586 const int sc_rden = use_river_don ? ncell++ : -1;
587 const int sc_po4 = use_po4 ? ncell++ : -1;
588 const int sc_ldec = use_carbon ? ncell++ : -1;
589 const int sc_sdec = use_carbon ? ncell++ : -1;
590 const int sc_tic = use_carbon ? ncell++ : -1;
591 const int sc_talk = use_carbon ? ncell++ : -1;
592 const int sc_rdec = use_river_don_c ? ncell++ : -1;
593 const int sc_oxyg = use_oxygen ? ncell++ : -1;
594 const int sc_odu = use_odu ? ncell++ : -1;
595 const int sc_temp = ncell++;
596 const int sc_salt = use_salt ? ncell++ : -1;
597 const int sc_inv_hz = ncell++;
598 const int sc_inv_hz2 = ncell++;
599 const int sc_inv_hz3 = ncell++;
600 const int sc_qc = ncell++;
601 const int sc_bR = ncell++;
602 const int sc_bL = ncell++;
603 const int sc_WR = ncell++;
604 const int sc_WL = ncell++;
607 const int sw_FC = nw++;
609 for (MFIter mfi(mf_cons_new, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
610 Box bx = mfi.tilebox();
613 Box wbx = surroundingNodes(bx, 2);
615 FArrayBox fab_cell(bx, ncell, amrex::The_Async_Arena());
616 fab_cell.template setVal<RunOn::Device>(
zero);
617 FArrayBox fab_w(wbx, nw, amrex::The_Async_Arena());
618 fab_w.template setVal<RunOn::Device>(
zero);
620 auto no3 = fab_cell.array(sc_no3);
621 auto nh4 = fab_cell.array(sc_nh4);
622 auto chlo = fab_cell.array(sc_chlo);
623 auto phyt = fab_cell.array(sc_phyt);
624 auto zoop = fab_cell.array(sc_zoop);
625 auto lden = fab_cell.array(sc_lden);
626 auto sden = fab_cell.array(sc_sden);
629 rden = fab_cell.array(sc_rden);
633 po4 = fab_cell.array(sc_po4);
640 ldec = fab_cell.array(sc_ldec);
641 sdec = fab_cell.array(sc_sdec);
642 tic = fab_cell.array(sc_tic);
643 talk = fab_cell.array(sc_talk);
646 if (use_river_don_c) {
647 rdec = fab_cell.array(sc_rdec);
651 oxyg = fab_cell.array(sc_oxyg);
655 odu = fab_cell.array(sc_odu);
657 auto temp = fab_cell.array(sc_temp);
660 salt = fab_cell.array(sc_salt);
662 auto inv_hz = fab_cell.array(sc_inv_hz);
663 auto inv_hz2 = fab_cell.array(sc_inv_hz2);
664 auto inv_hz3 = fab_cell.array(sc_inv_hz3);
665 auto qc = fab_cell.array(sc_qc);
666 auto bR = fab_cell.array(sc_bR);
667 auto bL = fab_cell.array(sc_bL);
668 auto WR = fab_cell.array(sc_WR);
669 auto WL = fab_cell.array(sc_WL);
670 auto FC = fab_w.array(sw_FC);
672 Array4<Real const>
const& state_old = mf_cons_old.const_array(mfi);
673 Array4<Real>
const& state_new = mf_cons_new.array(mfi);
674 Array4<Real const>
const& Hz = context.
hz->const_array(mfi);
675 Array4<Real const>
const& z_w = context.
z_w->const_array(mfi);
676 Array4<Real const>
const& srflx = context.
shortwave->const_array(mfi);
677 Array4<Real const>
const& mskr = context.
mask->const_array(mfi);
681 Array4<Real const> sustr;
682 Array4<Real const> svstr;
683 Array4<Real const> uwind;
684 Array4<Real const> vwind;
685 if (use_oxygen || use_carbon) {
687 uwind = context.
wind_u->const_array(mfi);
688 vwind = context.
wind_v->const_array(mfi);
690 sustr = context.
stress_u->const_array(mfi);
691 svstr = context.
stress_v->const_array(mfi);
695 ParallelFor(bx2d, [=] AMREX_GPU_DEVICE (
int i,
int j,
int)
noexcept
697 constexpr Real
zero = Real(0.0);
704 if (mskr(i,j,0) ==
zero)
return;
706 constexpr Real
one = Real(1.0);
707 constexpr Real
two = Real(2.0);
708 constexpr Real eps = Real(1.0e-20);
709 constexpr Real minval = Real(1.0e-6);
710 constexpr Real cff_weno = Real(1.0e-14);
712 constexpr Real OA0 = Real(2.00907);
713 constexpr Real OA1 = Real(3.22014);
714 constexpr Real OA2 = Real(4.05010);
715 constexpr Real OA3 = Real(4.94457);
716 constexpr Real OA4 = Real(-0.256847);
717 constexpr Real OA5 = Real(3.88767);
718 constexpr Real OB0 = Real(-0.00624523);
719 constexpr Real OB1 = Real(-0.00737614);
720 constexpr Real OB2 = Real(-0.0103410);
721 constexpr Real OB3 = Real(-0.00817083);
722 constexpr Real OC0 = Real(-0.000000488682);
723 constexpr Real rOxNO3 = Real(8.625);
724 constexpr Real rOxNH4 = Real(6.625);
725 constexpr Real rOxNH4Denit = Real(115.0) / Real(16.0);
726 constexpr Real denitrification_NH4_fraction = Real(4.0) / Real(16.0);
727 constexpr Real l2mol = Real(1000.0) / Real(22.3916);
729 constexpr Real A1 = Real(-60.2409);
730 constexpr Real A2 = Real(93.4517);
731 constexpr Real A3 = Real(23.3585);
732 constexpr Real B1 = Real(0.023517);
733 constexpr Real B2 = Real(-0.023656);
734 constexpr Real B3 = Real(0.0047036);
743 for (
int k = 0; k <= N; ++k) {
744 inv_hz(i,j,k) =
one / Hz(i,j,k);
745 no3(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.no3));
746 nh4(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.nh4));
747 chlo(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.chlo));
748 phyt(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.phyt));
749 zoop(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.zoop));
750 lden(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.lden));
751 sden(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.sden));
753 rden(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.rden));
756 po4(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.po4));
759 ldec(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.ldec));
760 sdec(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.sdec));
761 tic(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.tic));
762 tic(i,j,k) = amrex::min(
tic(i,j,k), Real(3000.0));
763 tic(i,j,k) = amrex::max(
tic(i,j,k), Real(400.0));
764 talk(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.talk));
766 rdec(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.rdec));
770 oxyg(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.oxyg));
773 odu(i,j,k) = amrex::max(
zero, state_old(i,j,k,bio_comp.odu));
776 temp(i,j,k) = amrex::min(state_old(i,j,k,
Temp_comp), Real(35.0));
781 for (
int k = 0; k < N; ++k) {
782 inv_hz2(i,j,k) =
one / (Hz(i,j,k) + Hz(i,j,k+1));
784 for (
int k = 1; k < N; ++k) {
785 inv_hz3(i,j,k) =
one / (Hz(i,j,k-1) + Hz(i,j,k) + Hz(i,j,k+1));
791 const Real PARsur = parms.PARfrac * srflx(i,j,0);
801#ifndef REMORA_USE_BIOLOGY_DIAG
802 auto tag_state = [] (
const char*, int)
noexcept {};
804 auto tag_state = [=] (
const char* tag,
int it)
noexcept
806 if (dbg_level <= 0)
return;
807 if (dbg_level == 1 && (i != dbg_i || j != dbg_j))
return;
808 for (
int k = 0; k <= N; ++k) {
809 remora_fennel_tag(tag, it, i, j, k,
"NO3 ",
no3(i,j,k));
810 remora_fennel_tag(tag, it, i, j, k,
"NH4 ",
nh4(i,j,k));
811 remora_fennel_tag(tag, it, i, j, k,
"CHLO",
chlo(i,j,k));
812 remora_fennel_tag(tag, it, i, j, k,
"PHYT",
phyt(i,j,k));
813 remora_fennel_tag(tag, it, i, j, k,
"ZOOP",
zoop(i,j,k));
814 remora_fennel_tag(tag, it, i, j, k,
"LDEN",
lden(i,j,k));
815 remora_fennel_tag(tag, it, i, j, k,
"SDEN",
sden(i,j,k));
817 remora_fennel_tag(tag, it, i, j, k,
"RDEN",
rden(i,j,k));
820 remora_fennel_tag(tag, it, i, j, k,
"PO4 ",
po4(i,j,k));
823 remora_fennel_tag(tag, it, i, j, k,
"LDEC",
ldec(i,j,k));
824 remora_fennel_tag(tag, it, i, j, k,
"SDEC",
sdec(i,j,k));
825 remora_fennel_tag(tag, it, i, j, k,
"TIC ",
tic(i,j,k));
826 remora_fennel_tag(tag, it, i, j, k,
"TALK",
talk(i,j,k));
828 remora_fennel_tag(tag, it, i, j, k,
"RDEC",
rdec(i,j,k));
832 remora_fennel_tag(tag, it, i, j, k,
"OXYG",
oxyg(i,j,k));
835 remora_fennel_tag(tag, it, i, j, k,
"ODU ",
odu(i,j,k));
841 tag_state(
"G00_PRE ", 0);
858 for (
int iter = 0; iter < parms.BioIter; ++iter) {
868 for (
int k = N; k >= 0; --k) {
872 const Real thickness = z_w(i,j,k+1) - z_w(i,j,k);
873 const Real Att = (parms.AttSW + parms.AttChl *
chlo(i,j,k)) * thickness;
874 const Real ExpAtt = std::exp(-Att);
875 const Real Itop = PAR;
876 const Real PARavg = Itop * (
one - ExpAtt) / Att;
880 const Real cff = parms.PhyCN * Real(12.0);
881 const Real Chl2C = amrex::min(
chlo(i,j,k) / (
phyt(i,j,k) * cff + eps), parms.Chl2C_m);
886 const Real Vp = parms.Vp0 * Real(0.59) * std::pow(Real(1.066), temp(i,j,k));
887 const Real fac1_light = PARavg * parms.PhyIS;
888 const Real Epp = Vp / std::sqrt(Vp * Vp + fac1_light * fac1_light);
889 const Real t_PPmax = Epp * fac1_light;
893 const Real
cff1 =
nh4(i,j,k) * parms.K_NH4;
894 const Real
cff2 =
no3(i,j,k) * parms.K_NO3;
898 const Real LTOT = L_NO3 + L_NH4;
901 const Real cff3 =
po4(i,j,k) * parms.K_PO4;
902 const Real L_PO4 = cff3 / (
one + cff3);
903 LMIN = amrex::min(LTOT, L_PO4);
911 const Real mu = dtdays * t_PPmax * LMIN;
912 cff4 = mu *
phyt(i,j,k) * L_NO3 /
913 amrex::max(minval, LTOT) / amrex::max(minval,
no3(i,j,k));
914 cff5 = mu *
phyt(i,j,k) * L_NH4 /
915 amrex::max(minval, LTOT) / amrex::max(minval,
nh4(i,j,k));
916 cff6 = parms.R_P2N * mu *
phyt(i,j,k) /
917 amrex::max(minval,
po4(i,j,k));
919 const Real fac1 = dtdays * t_PPmax;
920 cff4 = fac1 * parms.K_NO3 * inhNH4 / (
one +
cff2) *
phyt(i,j,k);
921 cff5 = fac1 * parms.K_NH4 / (
one +
cff1) *
phyt(i,j,k);
928 const Real N_Flux_NewProd =
no3(i,j,k) * cff4;
929 const Real N_Flux_RegProd =
nh4(i,j,k) * cff5;
930 phyt(i,j,k) += N_Flux_NewProd + N_Flux_RegProd;
931 chlo(i,j,k) += (dtdays * t_PPmax * t_PPmax * LMIN * LMIN *
932 parms.Chl2C_m *
chlo(i,j,k)) /
933 (parms.PhyIS * amrex::max(Chl2C, eps) * PARavg + eps);
935 oxyg(i,j,k) += N_Flux_NewProd * rOxNO3 + N_Flux_RegProd * rOxNH4;
940 const Real cff1_carbon = parms.PhyCN *
941 (N_Flux_NewProd + N_Flux_RegProd);
942 tic(i,j,k) -= cff1_carbon;
943 if (use_talk_nonconserv) {
945 talk(i,j,k) += N_Flux_NewProd - N_Flux_RegProd;
964 Real nitri_fac = dtdays * parms.NitriR;
966 const Real fac2 = amrex::max(
oxyg(i,j,k),
zero);
967 const Real fac3 = amrex::max(fac2 / (Real(3.0) + fac2),
zero);
970 const Real light_ratio = (PARavg - parms.I_thNH4) /
971 (parms.D_p5NH4 + PARavg -
two * parms.I_thNH4);
972 const Real light_inhibit =
one - amrex::max(
zero, light_ratio);
973 const Real nitri = nitri_fac * light_inhibit;
975 const Real N_Flux_Nitrifi =
nh4(i,j,k) * nitri;
976 no3(i,j,k) += N_Flux_Nitrifi;
978 oxyg(i,j,k) -=
two * N_Flux_Nitrifi;
980 if (use_talk_nonconserv) {
981 talk(i,j,k) -=
two * N_Flux_Nitrifi;
992 const Real nitri = dtdays * parms.NitriR;
993 for (
int k = N; k >= 0; --k) {
995 const Real N_Flux_Nitrifi =
nh4(i,j,k) * nitri;
996 no3(i,j,k) += N_Flux_Nitrifi;
998 oxyg(i,j,k) -=
two * N_Flux_Nitrifi;
1000 if (use_talk_nonconserv) {
1001 talk(i,j,k) -=
two * N_Flux_Nitrifi;
1006 tag_state(
"G01_LIGHT ", iter + 1);
1013 const Real grazing_fac = dtdays * parms.ZooGR;
1014 const Real phyt_mort_fac = dtdays * parms.PhyMR;
1015 for (
int k = 0; k <= N; ++k) {
1017 const Real phy2 =
phyt(i,j,k) *
phyt(i,j,k);
1018 const Real graze = grazing_fac *
zoop(i,j,k) *
phyt(i,j,k) /
1019 (parms.K_Phy + phy2);
1020 const Real consume =
one / (
one + graze);
1021 phyt(i,j,k) *= consume;
1022 chlo(i,j,k) *= consume;
1025 const Real N_Flux_Assim = graze *
phyt(i,j,k) * parms.ZooAE_N;
1026 const Real N_Flux_Egest =
phyt(i,j,k) * graze * (
one - parms.ZooAE_N);
1027 zoop(i,j,k) += N_Flux_Assim;
1028 sden(i,j,k) += N_Flux_Egest;
1032 const Real N_Flux_Pmortal = phyt_mort_fac * amrex::max(
phyt(i,j,k) - parms.PhyMin,
zero);
1033 phyt(i,j,k) -= N_Flux_Pmortal;
1034 chlo(i,j,k) -= phyt_mort_fac * amrex::max(
chlo(i,j,k) - parms.ChlMin,
zero);
1035 sden(i,j,k) += N_Flux_Pmortal;
1037 sdec(i,j,k) += parms.PhyCN * (N_Flux_Egest + N_Flux_Pmortal) +
1038 (parms.PhyCN - parms.ZooCN) * N_Flux_Assim;
1042 tag_state(
"G02_GRAZE ", iter + 1);
1047 const Real zoo_metab_fac = dtdays * parms.ZooBM;
1048 const Real zoo_mort_fac = dtdays * parms.ZooMR;
1049 const Real zoo_excrete_fac = dtdays * parms.ZooER;
1050 for (
int k = 0; k <= N; ++k) {
1051 const Real phy2 =
phyt(i,j,k) *
phyt(i,j,k);
1052 const Real ingestion_excretion = zoo_excrete_fac * phy2 /
1053 (parms.K_Phy + phy2);
1054 const Real
cff2 = zoo_mort_fac *
zoop(i,j,k);
1055 const Real cff3 = ingestion_excretion * parms.ZooAE_N;
1058 const Real N_Flux_Zmortal =
cff2 *
zoop(i,j,k);
1059 const Real N_Flux_Zexcret = cff3 *
zoop(i,j,k);
1060 nh4(i,j,k) += N_Flux_Zexcret;
1062 po4(i,j,k) += parms.R_P2N * N_Flux_Zexcret;
1064 sden(i,j,k) += N_Flux_Zmortal;
1068 const Real N_Flux_Zmetabo = zoo_metab_fac * amrex::max(
zoop(i,j,k) - parms.ZooMin,
zero);
1069 zoop(i,j,k) -= N_Flux_Zmetabo;
1070 nh4(i,j,k) += N_Flux_Zmetabo;
1072 po4(i,j,k) += parms.R_P2N * N_Flux_Zmetabo;
1075 oxyg(i,j,k) -= rOxNH4 * (N_Flux_Zmetabo + N_Flux_Zexcret);
1078 sdec(i,j,k) += parms.ZooCN * N_Flux_Zmortal;
1079 tic(i,j,k) += parms.ZooCN * (N_Flux_Zmetabo + N_Flux_Zexcret);
1080 if (use_talk_nonconserv) {
1081 talk(i,j,k) += N_Flux_Zmetabo + N_Flux_Zexcret;
1086 tag_state(
"G03_ZMETAB", iter + 1);
1090 const Real coag_fac = dtdays * parms.CoagR;
1091 for (
int k = 0; k <= N; ++k) {
1092 const Real coag = coag_fac * (
sden(i,j,k) +
phyt(i,j,k));
1093 const Real consume =
one / (
one + coag);
1094 phyt(i,j,k) *= consume;
1095 chlo(i,j,k) *= consume;
1096 sden(i,j,k) *= consume;
1097 const Real N_Flux_CoagP =
phyt(i,j,k) * coag;
1098 const Real N_Flux_CoagD =
sden(i,j,k) * coag;
1099 lden(i,j,k) += N_Flux_CoagP + N_Flux_CoagD;
1101 sdec(i,j,k) -= parms.PhyCN * N_Flux_CoagD;
1102 ldec(i,j,k) += parms.PhyCN * (N_Flux_CoagP + N_Flux_CoagD);
1106 tag_state(
"G04_COAG ", iter + 1);
1110 for (
int k = 0; k <= N; ++k) {
1111 const Real fac1 = amrex::max(
oxyg(i,j,k) - Real(6.0),
zero);
1112 const Real fac2 = amrex::max(fac1 / (Real(3.0) + fac1),
zero);
1113 const Real remin_s = dtdays * parms.SDeRRN * fac2;
1114 const Real remin_s_consume =
one / (
one + remin_s);
1115 const Real remin_l = dtdays * parms.LDeRRN * fac2;
1116 const Real remin_l_consume =
one / (
one + remin_l);
1117 sden(i,j,k) *= remin_s_consume;
1118 lden(i,j,k) *= remin_l_consume;
1119 const Real N_Flux_RemineS =
sden(i,j,k) * remin_s;
1120 const Real N_Flux_RemineL =
lden(i,j,k) * remin_l;
1121 nh4(i,j,k) += N_Flux_RemineS + N_Flux_RemineL;
1123 po4(i,j,k) += parms.R_P2N * (N_Flux_RemineS + N_Flux_RemineL);
1125 oxyg(i,j,k) -= (N_Flux_RemineS + N_Flux_RemineL) * rOxNH4;
1126 if (use_talk_nonconserv) {
1127 talk(i,j,k) += N_Flux_RemineS + N_Flux_RemineL;
1129 if (use_river_don) {
1130 const Real remin_r = dtdays * parms.RDeRRN * fac2;
1131 const Real remin_r_consume =
one / (
one + remin_r);
1132 rden(i,j,k) *= remin_r_consume;
1133 const Real N_Flux_RemineR =
rden(i,j,k) * remin_r;
1134 nh4(i,j,k) += N_Flux_RemineR;
1136 po4(i,j,k) += parms.R_P2N * N_Flux_RemineR;
1138 oxyg(i,j,k) -= N_Flux_RemineR * rOxNH4;
1139 if (use_talk_nonconserv) {
1140 talk(i,j,k) += N_Flux_RemineR;
1145 const Real remin_s = dtdays * parms.SDeRRN;
1146 const Real remin_l = dtdays * parms.LDeRRN;
1147 const Real remin_s_consume =
one / (
one + remin_s);
1148 const Real remin_l_consume =
one / (
one + remin_l);
1149 const Real remin_r = dtdays * parms.RDeRRN;
1150 const Real remin_r_consume =
one / (
one + remin_r);
1151 for (
int k = 0; k <= N; ++k) {
1152 sden(i,j,k) *= remin_s_consume;
1153 lden(i,j,k) *= remin_l_consume;
1154 const Real N_Flux_RemineS =
sden(i,j,k) * remin_s;
1155 const Real N_Flux_RemineL =
lden(i,j,k) * remin_l;
1156 nh4(i,j,k) += N_Flux_RemineS + N_Flux_RemineL;
1158 po4(i,j,k) += parms.R_P2N * (N_Flux_RemineS + N_Flux_RemineL);
1160 if (use_talk_nonconserv) {
1161 talk(i,j,k) += N_Flux_RemineS + N_Flux_RemineL;
1163 if (use_river_don) {
1164 rden(i,j,k) *= remin_r_consume;
1165 const Real N_Flux_RemineR =
rden(i,j,k) * remin_r;
1166 nh4(i,j,k) += N_Flux_RemineR;
1168 po4(i,j,k) += parms.R_P2N * N_Flux_RemineR;
1170 if (use_talk_nonconserv) {
1171 talk(i,j,k) += N_Flux_RemineR;
1177 tag_state(
"G05_REMINN", iter + 1);
1183 const Real
cff1 =
rho0 * Real(550.0);
1184 const Real
cff2 = dtdays * o2_rate * Real(24.0) / Real(100.0);
1190 u10squ = uwind(i,j,0) * uwind(i,j,0) + vwind(i,j,0) * vwind(i,j,0);
1193 std::sqrt((Real(0.5) * (sustr(i,j,0) + sustr(i+1,j,0))) *
1194 (Real(0.5) * (sustr(i,j,0) + sustr(i+1,j,0))) +
1195 (Real(0.5) * (svstr(i,j,0) + svstr(i,j+1,0))) *
1196 (Real(0.5) * (svstr(i,j,0) + svstr(i,j+1,0))));
1198 const Real SchmidtN_Ox = A_O2 - temp(i,j,k) *
1199 (B_O2 - temp(i,j,k) *
1200 (C_O2 - temp(i,j,k) *
1201 (D_O2 - temp(i,j,k) * E_O2)));
1202 const Real cff3 =
cff2 * u10squ * std::sqrt(Real(660.0) / SchmidtN_Ox);
1206 const Real TS = std::log((Real(298.15) - temp(i,j,k)) /
1207 (Real(273.15) + temp(i,j,k)));
1208 const Real AA = OA0 + TS * (OA1 + TS * (OA2 + TS * (OA3 + TS * (OA4 + TS * OA5)))) +
1209 salt(i,j,k) * (OB0 + TS * (OB1 + TS * (OB2 + TS * OB3))) +
1210 OC0 * salt(i,j,k) * salt(i,j,k);
1213 const Real O2satu = l2mol * std::exp(AA);
1216 const Real O2_Flux = cff3 * (O2satu -
oxyg(i,j,k));
1217 oxyg(i,j,k) += O2_Flux * inv_hz(i,j,k);
1219 tag_state(
"G06_O2FLX ", iter + 1);
1225 const Real remin_sc = dtdays * parms.SDeRRC;
1226 const Real remin_sc_consume =
one / (
one + remin_sc);
1227 const Real remin_lc = dtdays * parms.LDeRRC;
1228 const Real remin_lc_consume =
one / (
one + remin_lc);
1229 const Real remin_rc = dtdays * parms.RDeRRC;
1230 const Real remin_rc_consume =
one / (
one + remin_rc);
1231 for (
int k = 0; k <= N; ++k) {
1232 sdec(i,j,k) *= remin_sc_consume;
1233 ldec(i,j,k) *= remin_lc_consume;
1234 const Real C_Flux_RemineS =
sdec(i,j,k) * remin_sc;
1235 const Real C_Flux_RemineL =
ldec(i,j,k) * remin_lc;
1236 tic(i,j,k) += C_Flux_RemineS + C_Flux_RemineL;
1237 if (use_river_don_c) {
1238 rdec(i,j,k) *= remin_rc_consume;
1239 tic(i,j,k) +=
rdec(i,j,k) * remin_rc;
1243 if (!use_talk_nonconserv) {
1249 for (
int k = 0; k <= N; ++k) {
1250 talk(i,j,k) = Real(587.05) + Real(50.56) * salt(i,j,k);
1254 tag_state(
"G07_REMINC", iter + 1);
1261 const Real pCO2 = fennel_pco2_water(temp(i,j,k), salt(i,j,k),
1265 const Real
cff1 =
rho0 * Real(550.0);
1266 const Real
cff2 = dtdays * co2_rate * Real(24.0) / Real(100.0);
1271 u10squ = uwind(i,j,0) * uwind(i,j,0) + vwind(i,j,0) * vwind(i,j,0);
1274 std::sqrt((Real(0.5) * (sustr(i,j,0) + sustr(i+1,j,0))) *
1275 (Real(0.5) * (sustr(i,j,0) + sustr(i+1,j,0))) +
1276 (Real(0.5) * (svstr(i,j,0) + svstr(i,j+1,0))) *
1277 (Real(0.5) * (svstr(i,j,0) + svstr(i,j+1,0))));
1279 const Real SchmidtN = A_CO2 - temp(i,j,k) *
1280 (B_CO2 - temp(i,j,k) *
1281 (C_CO2 - temp(i,j,k) *
1282 (D_CO2 - temp(i,j,k) * E_CO2)));
1283 const Real cff3 =
cff2 * u10squ * std::sqrt(Real(660.0) / SchmidtN);
1287 const Real TempK = Real(0.01) * (temp(i,j,k) + Real(273.15));
1288 const Real CO2_sol = std::exp(A1 +
1290 A3 * std::log(TempK) +
1291 salt(i,j,k) * (B1 + TempK * (B2 + B3 * TempK)));
1294 const Real CO2_Flux = cff3 * CO2_sol * (pco2air - pCO2);
1295 tic(i,j,k) += CO2_Flux * inv_hz(i,j,k);
1297 tag_state(
"G08_CO2FLX", iter + 1);
1306 const int nsink = use_carbon ? 6 : 4;
1307 for (
int isink = 0; isink < nsink; ++isink) {
1308 Array4<Real> bio =
phyt;
1309 Real wbio = parms.wPhy;
1310 int sediment_type = 1;
1311 const bool phyt_sink = (isink == 0);
1316 }
else if (isink == 2) {
1319 }
else if (isink == 3) {
1322 }
else if (isink == 4) {
1326 }
else if (isink == 5) {
1334 for (
int k = 0; k <= N; ++k) {
1335 qc(i,j,k) = bio(i,j,k);
1336 bR(i,j,k) = qc(i,j,k);
1337 bL(i,j,k) = qc(i,j,k);
1341 for (
int k = 0; k <= N + 1; ++k) {
1347 for (
int iface = 1; iface <= N; ++iface) {
1348 FC(i,j,iface) = (qc(i,j,iface) - qc(i,j,iface-1)) * inv_hz2(i,j,iface-1);
1350 for (
int k = 1; k < N; ++k) {
1351 Real dltR = Hz(i,j,k) * FC(i,j,k+1);
1352 Real dltL = Hz(i,j,k) * FC(i,j,k);
1353 const Real cff = Hz(i,j,k-1) +
two * Hz(i,j,k) + Hz(i,j,k+1);
1354 const Real cffR = cff * FC(i,j,k+1);
1355 const Real cffL = cff * FC(i,j,k);
1359 if ((dltR * dltL) <=
zero) {
1362 }
else if (std::abs(dltR) > std::abs(cffL)) {
1364 }
else if (std::abs(dltL) > std::abs(cffR)) {
1371 const Real curv = (dltR - dltL) * inv_hz3(i,j,k);
1372 dltR -= curv * Hz(i,j,k+1);
1373 dltL += curv * Hz(i,j,k-1);
1374 bR(i,j,k) = qc(i,j,k) + dltR;
1375 bL(i,j,k) = qc(i,j,k) - dltL;
1376 WR(i,j,k) = (
two * dltR - dltL) * (
two * dltR - dltL);
1377 WL(i,j,k) = (dltR -
two * dltL) * (dltR -
two * dltL);
1381 for (
int k = 1; k < N - 1; ++k) {
1382 const Real dltL = amrex::max(cff_weno, WL(i,j,k));
1383 const Real dltR = amrex::max(cff_weno, WR(i,j,k+1));
1384 bR(i,j,k) = (dltR * bR(i,j,k) + dltL * bL(i,j,k+1)) / (dltR + dltL);
1385 bL(i,j,k+1) = bR(i,j,k);
1387 FC(i,j,N + 1) =
zero;
1388 bR(i,j,N) = qc(i,j,N);
1389 bL(i,j,N) = qc(i,j,N);
1390 bR(i,j,N - 1) = qc(i,j,N);
1391 bL(i,j,1) = qc(i,j,0);
1392 bR(i,j,0) = qc(i,j,0);
1393 bL(i,j,0) = qc(i,j,0);
1398 for (
int k = 0; k <= N; ++k) {
1399 Real dltR = bR(i,j,k) - qc(i,j,k);
1400 Real dltL = qc(i,j,k) - bL(i,j,k);
1401 const Real cffR =
two * dltR;
1402 const Real cffL =
two * dltL;
1403 if ((dltR * dltL) <
zero) {
1406 }
else if (std::abs(dltR) > std::abs(cffL)) {
1408 }
else if (std::abs(dltL) > std::abs(cffR)) {
1411 bR(i,j,k) = qc(i,j,k) + dltR;
1412 bL(i,j,k) = qc(i,j,k) - dltL;
1422 const Real sink_distance = dtdays * std::abs(wbio);
1423 for (
int k = 0; k <= N; ++k) {
1425 WL(i,j,k) = z_w(i,j,k) + sink_distance;
1426 WR(i,j,k) = Hz(i,j,k) * qc(i,j,k);
1428 FC(i,j,N + 1) =
zero;
1429 for (
int k = 0; k <= N; ++k) {
1432 for (
int ks = k; ks < N; ++ks) {
1433 if (WL(i,j,k) > z_w(i,j,ks+1)) {
1440 const Real cu = amrex::min(
one, (WL(i,j,k) - z_w(i,j,ksource)) *
1441 inv_hz(i,j,ksource));
1442 flux += Hz(i,j,ksource) * cu *
1443 (bL(i,j,ksource) + cu * (Real(0.5) * (bR(i,j,ksource) - bL(i,j,ksource)) -
1444 (Real(1.5) - cu) * (bR(i,j,ksource) + bL(i,j,ksource) -
1445 two * qc(i,j,ksource))));
1448 for (
int k = 0; k <= N; ++k) {
1449 bio(i,j,k) = qc(i,j,k) +
1450 (FC(i,j,k+1) - FC(i,j,k)) * inv_hz(i,j,k);
1459 if (parms.bio_sediment && sediment_type != 0) {
1460 const Real
cff1 = FC(i,j,0) * inv_hz(i,j,0);
1461 if (sediment_type == 1) {
1462 if (use_denitrification) {
1463 nh4(i,j,0) +=
cff1 * denitrification_NH4_fraction;
1472 if (use_talk_nonconserv) {
1477 po4(i,j,0) +=
cff1 * parms.R_P2N;
1479 if (use_carbon && phyt_sink) {
1480 tic(i,j,0) +=
cff1 * parms.PhyCN;
1482 }
else if (use_carbon) {
1488 tag_state(
"G09_SINK ", iter + 1);
1498 tag_state(
"G10_POST ", parms.BioIter);
1501 for (
int k = 0; k <= N; ++k) {
1502 tic(i,j,k) = amrex::min(
tic(i,j,k), Real(3000.0));
1503 tic(i,j,k) = amrex::max(
tic(i,j,k), Real(400.0));
1517 const Real rmask = mskr(i,j,0);
1518 for (
int k = 0; k <= N; ++k) {
1519 const Real old_no3 = amrex::max(
zero, state_old(i,j,k,bio_comp.no3));
1520 const Real old_nh4 = amrex::max(
zero, state_old(i,j,k,bio_comp.nh4));
1521 Real old_po4 =
zero;
1523 old_po4 = amrex::max(
zero, state_old(i,j,k,bio_comp.po4));
1525 const Real old_chlo = amrex::max(
zero, state_old(i,j,k,bio_comp.chlo));
1526 const Real old_phyt = amrex::max(
zero, state_old(i,j,k,bio_comp.phyt));
1527 const Real old_zoop = amrex::max(
zero, state_old(i,j,k,bio_comp.zoop));
1528 const Real old_lden = amrex::max(
zero, state_old(i,j,k,bio_comp.lden));
1529 const Real old_sden = amrex::max(
zero, state_old(i,j,k,bio_comp.sden));
1530 Real old_rden =
zero;
1531 if (use_river_don) {
1532 old_rden = amrex::max(
zero, state_old(i,j,k,bio_comp.rden));
1534 Real old_rdec =
zero;
1535 if (use_river_don_c) {
1536 old_rdec = amrex::max(
zero, state_old(i,j,k,bio_comp.rdec));
1538 Real old_ldec =
zero;
1539 Real old_sdec =
zero;
1540 Real old_tic =
zero;
1541 Real old_talk =
zero;
1543 old_ldec = amrex::max(
zero, state_old(i,j,k,bio_comp.ldec));
1544 old_sdec = amrex::max(
zero, state_old(i,j,k,bio_comp.sdec));
1545 old_tic = amrex::max(
zero, state_old(i,j,k,bio_comp.tic));
1546 old_tic = amrex::min(old_tic, Real(3000.0));
1547 old_tic = amrex::max(old_tic, Real(400.0));
1548 old_talk = amrex::max(
zero, state_old(i,j,k,bio_comp.talk));
1550 Real old_oxyg =
zero;
1552 old_oxyg = amrex::max(
zero, state_old(i,j,k,bio_comp.oxyg));
1554 Real old_odu =
zero;
1556 old_odu = amrex::max(
zero, state_old(i,j,k,bio_comp.odu));
1559 state_new(i,j,k,bio_comp.no3) += (
no3(i,j,k) - old_no3) * rmask * Hz(i,j,k);
1560 state_new(i,j,k,bio_comp.nh4) += (
nh4(i,j,k) - old_nh4) * rmask * Hz(i,j,k);
1562 state_new(i,j,k,bio_comp.po4) += (
po4(i,j,k) - old_po4) * rmask * Hz(i,j,k);
1564 state_new(i,j,k,bio_comp.chlo) += (
chlo(i,j,k) - old_chlo) * rmask * Hz(i,j,k);
1565 state_new(i,j,k,bio_comp.phyt) += (
phyt(i,j,k) - old_phyt) * rmask * Hz(i,j,k);
1566 state_new(i,j,k,bio_comp.zoop) += (
zoop(i,j,k) - old_zoop) * rmask * Hz(i,j,k);
1567 state_new(i,j,k,bio_comp.lden) += (
lden(i,j,k) - old_lden) * rmask * Hz(i,j,k);
1568 state_new(i,j,k,bio_comp.sden) += (
sden(i,j,k) - old_sden) * rmask * Hz(i,j,k);
1569 if (use_river_don) {
1570 state_new(i,j,k,bio_comp.rden) += (
rden(i,j,k) - old_rden) * rmask * Hz(i,j,k);
1573 state_new(i,j,k,bio_comp.ldec) += (
ldec(i,j,k) - old_ldec) * rmask * Hz(i,j,k);
1574 state_new(i,j,k,bio_comp.sdec) += (
sdec(i,j,k) - old_sdec) * rmask * Hz(i,j,k);
1575 state_new(i,j,k,bio_comp.tic) += (
tic(i,j,k) - old_tic) * rmask * Hz(i,j,k);
1576 state_new(i,j,k,bio_comp.talk) += (
talk(i,j,k) - old_talk) * rmask * Hz(i,j,k);
1577 if (use_river_don) {
1578 state_new(i,j,k,bio_comp.rdec) += (
rdec(i,j,k) - old_rdec) * rmask * Hz(i,j,k);
1582 state_new(i,j,k,bio_comp.oxyg) += (
oxyg(i,j,k) - old_oxyg) * rmask * Hz(i,j,k);
1585 state_new(i,j,k,bio_comp.odu) += (
odu(i,j,k) - old_odu) * rmask * Hz(i,j,k);
1589#ifdef REMORA_USE_BIOLOGY_DIAG
1594 if (dbg_level > 0 &&
1595 (dbg_level == 2 || (i == dbg_i && j == dbg_j))) {
1596 const int it = parms.BioIter;
1597 for (
int k = 0; k <= N; ++k) {
1598 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"NO3 ",
1599 state_new(i,j,k,bio_comp.no3));
1600 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"NH4 ",
1601 state_new(i,j,k,bio_comp.nh4));
1602 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"CHLO",
1603 state_new(i,j,k,bio_comp.chlo));
1604 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"PHYT",
1605 state_new(i,j,k,bio_comp.phyt));
1606 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"ZOOP",
1607 state_new(i,j,k,bio_comp.zoop));
1608 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"LDEN",
1609 state_new(i,j,k,bio_comp.lden));
1610 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"SDEN",
1611 state_new(i,j,k,bio_comp.sden));
1612 if (use_river_don) {
1613 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"RDEN",
1614 state_new(i,j,k,bio_comp.rden));
1617 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"PO4 ",
1618 state_new(i,j,k,bio_comp.po4));
1621 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"LDEC",
1622 state_new(i,j,k,bio_comp.ldec));
1623 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"SDEC",
1624 state_new(i,j,k,bio_comp.sdec));
1625 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"TIC ",
1626 state_new(i,j,k,bio_comp.tic));
1627 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"TALK",
1628 state_new(i,j,k,bio_comp.talk));
1629 if (use_river_don) {
1630 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"RDEC",
1631 state_new(i,j,k,bio_comp.rdec));
1635 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"OXYG",
1636 state_new(i,j,k,bio_comp.oxyg));
1639 remora_fennel_tag(
"G11_UPDATE", it, i, j, k,
"ODU ",
1640 state_new(i,j,k,bio_comp.odu));