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>
41 amrex::Real min_value;
42 amrex::Real max_value;
43 amrex::Long wet_cells;
53 using namespace amrex;
54 constexpr Real
lo_sentinel = std::numeric_limits<Real>::max();
55 constexpr Real
hi_sentinel = -std::numeric_limits<Real>::max();
61 Box
bx =
mfi.validbox();
64 const auto m =
mask.const_array(
mfi);
67 const bool wet =
m(
i,
j,
k) > Real(0.5);
70 wet ? Long(1) : Long(0) };
75 ParallelDescriptor::ReduceRealMin(
e.min_value);
76 ParallelDescriptor::ReduceRealMax(
e.max_value);
77 ParallelDescriptor::ReduceLongSum(
e.wet_cells);
87 amrex::Long nan_count;
88 amrex::IntVect example;
89 amrex::Real example_value;
96 using namespace amrex;
97 const Box domain =
mf.boxArray().minimalBox();
98 const Long
nx = domain.length(0);
99 constexpr Long
no_cell = std::numeric_limits<Long>::max();
105 const auto f =
mf.const_array(
mfi);
106 const auto m =
mask.const_array(
mfi);
110 const Real v =
f(
i,
j,
k);
111 const bool wet =
m(
i,
j,
k) > Real(0.5);
113 const bool nan =
wet && (v != v);
119 WetOutOfRange
out{
get<0>(
r),
get<1>(
r), IntVect(0), std::numeric_limits<Real>::max()};
121 ParallelDescriptor::ReduceLongSum(
out.count);
122 ParallelDescriptor::ReduceLongSum(
out.nan_count);
123 ParallelDescriptor::ReduceLongMin(
first);
124 if (
out.count == 0) {
return out; }
126 out.example = IntVect(domain.smallEnd(0) +
static_cast<int>(
first %
nx),
127 domain.smallEnd(1) +
static_cast<int>(
first /
nx),
130 if (!
here.empty()) {
out.example_value =
here[0]; }
131 ParallelDescriptor::ReduceRealMin(
out.example_value);
151 const amrex::MultiFab&
dst,
155 using namespace amrex;
158 const int nboxes =
static_cast<int>(
dst.boxArray().size());
159 constexpr int int_big = std::numeric_limits<int>::max();
165 const int b =
mfi.index();
166 const Box
bx =
mfi.validbox();
180 if (
si < 0 ||
sj < 0) {
continue; }
188 lo[2*
b ] = amrex::get<0>(
hv);
lo[2*
b+1] = amrex::get<1>(
hv);
189 hi[2*
b ] = amrex::get<2>(
hv);
hi[2*
b+1] = amrex::get<3>(
hv);
192 ParallelDescriptor::ReduceIntMin(
lo.dataPtr(),
static_cast<int>(
lo.size()));
193 ParallelDescriptor::ReduceIntMax(
hi.dataPtr(),
static_cast<int>(
hi.size()));
215 return BoxArray(std::move(
bl));
234 amrex::MultiFab&
dst,
238 const amrex::MultiFab*
dst_mask =
nullptr,
242 using namespace amrex;
247 dst.DistributionMap(),
src.nComp(), 0);
255 Box
bx =
mfi.tilebox();
402 amrex::DistributionMapping&
dm)
const
406 "REMORA::GetAtmosToOceanRhoLayout requires post-InitData rho-point forcing storage.");
413 amrex::DistributionMapping&
dm)
const
417 "REMORA::GetAtmosToOceanUFaceLayout requires post-InitData u-face forcing storage.");
424 amrex::DistributionMapping&
dm)
const
428 "REMORA::GetAtmosToOceanVFaceLayout requires post-InitData v-face forcing storage.");
435 const amrex::MultiFab*&
y_psi)
const
449 const amrex::MultiFab*&
lat_psi)
const
463 const amrex::MultiFab*&
msku,
464 const amrex::MultiFab*&
mskv)
const
493 for (
auto&
b :
bl2d) {
b.setRange(2, 0); }
517 constexpr Real
t_lo = Real(273.15 - 2.5);
518 constexpr Real
t_hi = Real(273.15 + 40.0);
522 amrex::Print() <<
"REMORA surface temperature over " <<
e.wet_cells
523 <<
" wet cells: min/max = " <<
e.min_value <<
" / "
524 <<
e.max_value <<
" K\n";
533 amrex::Print() <<
"WARNING: REMORA surface temperature outside [" <<
t_lo <<
", "
534 <<
t_hi <<
"] K on " <<
bad.count <<
" of " <<
e.wet_cells
535 <<
" wet cells (" <<
bad.nan_count <<
" NaN; min/max " <<
e.min_value
536 <<
" / " <<
e.max_value <<
" K; e.g. REMORA (" <<
bad.example[0]
537 <<
"," <<
bad.example[1] <<
") = " <<
bad.example_value
538 <<
" K). Repeated only if it gets worse.\n";
551 dst.ParallelCopy(
tmp, 0, 0, 1);
586 vec_Pair[0]->mult(Real(0.01), 0, 1);
605 vec_Tair[0]->plus(Real(-273.15), 0, 1);
790 struct Row {
const char* name;
const MultiFab*
mf;
int comp;
const MultiFab*
mask; };
801 amrex::Print() <<
"REMORA ApplyAtmosphericFluxes validation (wet cells only; srflx W/m2, "
802 <<
"others kinematic):\n";
803 for (
const auto&
r :
rows) {
805 if (
e.wet_cells == 0) {
806 amrex::Print() <<
" " <<
r.name <<
": no wet cells\n";
808 amrex::Print() <<
" " <<
r.name <<
": min=" <<
e.min_value
809 <<
" max=" <<
e.max_value <<
"\n";
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
Whether max_step was set in the inputs; the default above is not a distinguishable sentinel.
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