3#include <AMReX_BCRec.H>
5#include <AMReX_FillPatchUtil.H>
6#include <AMReX_Geometry.H>
7#include <AMReX_Interpolater.H>
8#include <AMReX_MFIter.H>
9#include <AMReX_MultiFabUtil.H>
10#include <AMReX_iMultiFab.H>
11#include <AMReX_Print.H>
12#include <AMReX_Reduce.H>
54 amrex::Long wet_cells;
55 amrex::Real min_value;
56 amrex::Real max_value;
57 amrex::Long bad_count;
58 amrex::Long nan_count;
59 amrex::IntVect example;
60 amrex::Real example_value;
62 bool has_finite ()
const {
return min_value <= max_value; }
67 amrex::Real
lo_bound = -std::numeric_limits<amrex::Real>::max(),
68 amrex::Real
hi_bound = std::numeric_limits<amrex::Real>::max())
70 using namespace amrex;
71 const Box domain =
mf.boxArray().minimalBox();
72 const Long
nx = domain.length(0);
73 const int k0 = domain.smallEnd(2);
74 constexpr Long
no_cell = std::numeric_limits<Long>::max();
75 constexpr Real
big = std::numeric_limits<Real>::max();
82 Box
bx =
mfi.validbox();
85 const auto m =
mask.const_array(
mfi);
90 const Real v =
f(
i,
j,k);
91 const bool wet =
m(
i,
j,k) > Real(0.5);
93 const bool nan =
wet && (v != v);
96 return {
wet ? Long(1) : Long(0),
97 bad ? Long(1) : Long(0),
98 nan ? Long(1) : Long(0),
108 ParallelDescriptor::ReduceLongSum(counts, 3);
109 ParallelDescriptor::ReduceRealMin(
extrema, 2);
110 ParallelDescriptor::ReduceLongMin(
first);
113 counts[2], IntVect(0),
big};
114 if (
out.bad_count == 0) {
return out; }
117 out.example = IntVect(domain.smallEnd(0) +
static_cast<int>(
first %
nx),
118 domain.smallEnd(1) +
static_cast<int>(
first /
nx),
124 ParallelDescriptor::ReduceRealSum(
out.example_value);
144 const amrex::MultiFab&
dst,
148 using namespace amrex;
151 const int nboxes =
static_cast<int>(
dst.boxArray().size());
152 constexpr int int_big = std::numeric_limits<int>::max();
158 const int b =
mfi.index();
159 const Box
bx =
mfi.validbox();
172 const int sj =
idx(
i,
j, k,
m * 3 + 1);
173 if (
si < 0 ||
sj < 0) {
continue; }
181 lo[2*
b ] = amrex::get<0>(
hv);
lo[2*
b+1] = amrex::get<1>(
hv);
182 hi[2*
b ] = amrex::get<2>(
hv);
hi[2*
b+1] = amrex::get<3>(
hv);
185 ParallelDescriptor::ReduceIntMin(
lo.dataPtr(),
static_cast<int>(
lo.size()));
186 ParallelDescriptor::ReduceIntMax(
hi.dataPtr(),
static_cast<int>(
hi.size()));
208 return BoxArray(std::move(
bl));
227 amrex::MultiFab&
dst,
231 const amrex::MultiFab*
dst_mask =
nullptr,
235 using namespace amrex;
240 dst.DistributionMap(),
src.nComp(), 0);
248 Box
bx =
mfi.tilebox();
395 amrex::DistributionMapping&
dm)
const
399 "REMORA::GetAtmosToOceanRhoLayout requires post-InitData rho-point forcing storage.");
406 amrex::DistributionMapping&
dm)
const
410 "REMORA::GetAtmosToOceanUFaceLayout requires post-InitData u-face forcing storage.");
417 amrex::DistributionMapping&
dm)
const
421 "REMORA::GetAtmosToOceanVFaceLayout requires post-InitData v-face forcing storage.");
428 const amrex::MultiFab*&
y_psi)
const
442 const amrex::MultiFab*&
lat_psi)
const
456 const amrex::MultiFab*&
msku,
457 const amrex::MultiFab*&
mskv)
const
486 for (
auto&
b :
bl2d) {
b.setRange(2, 0); }
513 constexpr Real
t_lo = Real(273.15 - 2.5);
514 constexpr Real
t_hi = Real(273.15 + 40.0);
518 os <<
"REMORA surface temperature over " <<
c.wet_cells
520 if (
c.has_finite()) {
521 os <<
"min/max = " <<
c.min_value <<
" / " <<
c.max_value
524 os <<
"no finite values";
533 if (
c.bad_count > 0 &&
worse) {
541 os <<
"WARNING: REMORA surface temperature outside [" <<
t_lo
542 <<
", " <<
t_hi <<
"] K on " <<
c.bad_count <<
" of "
543 <<
c.wet_cells <<
" wet cells (" <<
c.nan_count <<
" NaN";
544 if (
c.has_finite()) {
545 os <<
"; min/max " <<
c.min_value <<
" / " <<
c.max_value
548 os <<
"; e.g. REMORA (" <<
c.example[0] <<
"," <<
c.example[1]
549 <<
") = " <<
c.example_value
550 <<
" K). Repeated only if it gets worse.\n";
563 dst.ParallelCopy(
tmp, 0, 0, 1);
598 vec_Pair[0]->mult(Real(0.01), 0, 1);
617 vec_Tair[0]->plus(Real(-273.15), 0, 1);
802 struct Row {
const char* name;
const MultiFab*
mf;
int comp;
const MultiFab*
mask; };
813 amrex::Print() <<
"REMORA ApplyAtmosphericFluxes validation (wet cells only; srflx W/m2, "
814 <<
"others kinematic):\n";
815 for (
const auto&
r :
rows) {
818 os <<
" " <<
r.name <<
": ";
819 if (
e.wet_cells == 0) {
820 os <<
"no wet cells";
821 }
else if (!
e.has_finite()) {
822 os <<
"all " <<
e.wet_cells <<
" wet cells NaN";
824 os <<
"min=" <<
e.min_value <<
" max=" <<
e.max_value;
825 if (
e.nan_count > 0) {
os <<
" (" <<
e.nan_count <<
" NaN)"; }
constexpr amrex::Real one
constexpr amrex::Real zero
constexpr amrex::Real rhow
mf_h setVal(geomdata.ProbHi(2))
void ConfigureDriverAtmosToOceanCoupling(bool use_coupling_driver, bool use_two_way_coupling, DriverAtmosForcingMode active_mode)
double stop_time
Time to stop, in seconds on the model clock (not since start_time)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_evap
evaporation rate [kg/m^2/s]
amrex::Long m_warned_surface_temp_nan
bool running_with_coupling_driver
True once REMORA has received forcing through the coupling driver.
void GetLandSeaMasks(const amrex::MultiFab *&mskr, const amrex::MultiFab *&msku, const amrex::MultiFab *&mskv) const
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_lrflx
longwave radiation
amrex::Vector< amrex::MultiFab * > cons_new
multilevel data container for current step's scalar data: temperature, salinity, passive tracer
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)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rain
precipitation rate [kg/m^2/s]
int do_substep
Whether to substep fine levels in time.
amrex::Real m_warned_surface_temp_min
void GetAtmosToOceanPsiLonLat(const amrex::MultiFab *&lon_psi, const amrex::MultiFab *&lat_psi) const
void ApplyAtmosphericFluxes(const amrex::Vector< amrex::MultiFab * > &states, amrex::Real time)
Receives atmospheric flux lanes from the driver and assembles REMORA flux inputs.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_sustr
Surface stress in the u direction.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_yp
y_grid on psi-points (2D)
void GetAtmosToOceanVFaceLayout(amrex::BoxArray &ba, amrex::DistributionMapping &dm) const
void GetAtmosToOceanRhoLayout(amrex::BoxArray &ba, amrex::DistributionMapping &dm) const
void WriteAtIntermediateTime(int step, amrex::Real cur_time)
Write checkpoint and plotfiles at intermediate point of simulation, if needed.
amrex::Real EvolveOneStep(amrex::Real time, amrex::Real dt_request)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_msku
land/sea mask at x-faces (2D)
std::array< bool, AtmosState::NumTypes > driver_atmos_state_from_driver
provenance flags for driver-supplied atmospheric forcing lanes
void GetAtmosToOceanPsiCoordinates(const amrex::MultiFab *&x_psi, const amrex::MultiFab *&y_psi) const
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
DriverAtmosForcingMode driver_atmos_forcing_mode
Active atmosphere-to-ocean forcing contract on the most recent driver apply.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_shflx
sensible heat flux
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Called after every level 0 timestep.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_lhflx
latent heat flux
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_lonp
longitude on psi-points (2D, degrees east); only filled when the grid NetCDF file carries lon_psi
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskv
land/sea mask at y-faces (2D)
void ComputeDt()
a wrapper for estTimeStep()
amrex::Vector< int > istep
which step?
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_svstr
Surface stress in the v direction.
void GetDeckConfiguredAtmosStateLanes(std::array< bool, AtmosState::NumTypes > &deck_configured) const
amrex::Real m_warned_surface_temp_max
amrex::Vector< amrex::Real > t_new
new time at each level, in seconds since start_time
static SolverChoice solverChoice
Container for algorithmic choices.
void ApplyAtmosphericStates(const amrex::Vector< amrex::MultiFab * > &states, amrex::Real time)
Receives atmospheric states from the driver and applies unit conversions.
bool m_reported_atm_flux_validation
Latch so the flux validation block prints once per run unless remora.v >= 1.
void SetLongwaveFromDriver()
bool driver_uses_two_way_coupling
Driver-level direction flag copied in before InitData.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_xp
x_grid on psi-points (2D)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_longwave_down
Downward longwave radiation.
void GetAtmosToOceanUFaceLayout(amrex::BoxArray &ba, amrex::DistributionMapping &dm) const
void SetDriverAtmosToOceanForcingMode(DriverAtmosForcingMode mode)
void timeStep(int lev, amrex::Real time, int iteration)
advance a level by dt, includes a recursive call for finer levels
void timeStepML(amrex::Real time, int iteration)
advance all levels by dt, loops over finer levels
amrex::Real elapsed_time(double time) const noexcept
Elapsed time since start_time of a time on the model clock.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_stflux
Surface tracer flux; input arrays.
static int verbose
Verbosity level of output.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_cloud
cloud cover fraction [0-1], defined at rho-points
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_srflx
Shortwave radiation flux [W/m²], defined at rho-points.
amrex::Vector< amrex::Real > dt
time step at each level
void PackSurfaceState(amrex::Vector< amrex::MultiFab * > &state, amrex::Real time, const amrex::MultiFab *weight_o2a_mf, const amrex::iMultiFab *index_o2a_mf, int max_stencil_size, const amrex::iMultiFab *dst_land_mask=nullptr)
Extracts SST from the 3D conservative state for the atmospheric driver.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Pair
Air pressure [mb], defined at rho-points.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_qair
Specific humidity [kg/kg], defined at rho-points.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Tair
Air temperature [°C], defined at rho-points.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_latp
latitude on psi-points (2D, degrees north); only filled when the grid NetCDF file carries lat_psi
@ LWrad
longwave flux lane
@ LHflux
latent heat flux lane
@ Rain
precipitation rate lane
@ Evap
evaporation rate lane
@ SHflux
sensible heat flux lane
@ TauX
surface zonal stress lane
@ TauY
surface meridional stress lane
@ SWrad
shortwave radiation lane
@ Pair
atmospheric pressure [Pa from driver, mb in REMORA]
@ Vwind
10-m meridional wind [m/s]
@ Qair
specific humidity [kg/kg]
@ SWrad
downward shortwave radiation [W/m^2]
@ LWrad
downward longwave radiation [W/m^2]
@ Uwind
10-m zonal wind [m/s]
@ Rain
precipitation rate [kg/m^2/s]
@ Cloud
cloud fraction [0-1]
@ Tair
air temperature [K from driver, degC in REMORA]
@ Vwind
10-m meridional wind [m/s]
@ Pair
atmospheric pressure [mb]
@ Uwind
10-m zonal wind [m/s]
@ LWrad
longwave radiation [W/m^2]
@ Tair
air temperature [degC]
@ Qair
specific humidity or relative humidity [kg/kg or fraction]
@ Cloud
cloud fraction [0-1]
@ SWrad
downward shortwave radiation [W/m^2]
@ Rain
precipitation rate [kg/m^2/s]
@ data
annual climatology of Laurent et al. (2017)
std::array< bool, BulkFlux::NumTypes > bulk_flux_type_specified
std::array< bool, BulkFlux::NumTypes > bulk_flux_value_specified
std::array< BulkForcingType, BulkFlux::NumTypes > bulk_flux_type