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_Print.H>
33constexpr int SSTIndex = 0;
36make_unit_slab_geometry (Box
const& domain)
38 static constexpr Real lo[AMREX_SPACEDIM] = {0.0_rt, 0.0_rt, 0.0_rt};
39 static constexpr Real hi[AMREX_SPACEDIM] = {1.0_rt, 1.0_rt, 1.0_rt};
40 static constexpr int periodicity[AMREX_SPACEDIM] = {0, 0, 0};
42 return Geometry(domain, &rb, CoordSys::cartesian, periodicity);
46make_internal_bcs (
int ncomp)
48 Vector<BCRec> bcs(ncomp);
49 for (
auto& bc : bcs) {
50 for (
int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
51 bc.setLo(dir, BCType::int_dir);
52 bc.setHi(dir, BCType::int_dir);
62 Real cur_time =
t_new[0];
63 const int step =
istep[0];
107 if (state.empty() || state[SSTIndex] ==
nullptr) {
return; }
111 const int k_sfc =
cons_new[lev]->boxArray().minimalBox().bigEnd(2);
115 BoxList bl2d =
cons_new[lev]->boxArray().boxList();
116 for (
auto& b : bl2d) { b.setRange(2, 0); }
117 BoxArray ba2d(std::move(bl2d));
118 MultiFab tmp(ba2d,
cons_new[lev]->DistributionMap(), 1, 0);
120 for (MFIter mfi(*
cons_new[lev]); mfi.isValid(); ++mfi) {
121 auto const& c =
cons_new[lev]->const_array(mfi);
122 auto t = tmp.array(mfi);
123 Box bx = makeSlab(mfi.validbox(), 2, k_sfc);
124 ParallelFor(bx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int) {
126 t(i, j, 0) = c(i, j, k_sfc,
Temp_comp) + 273.15_rt;
130 MultiFab& dst = *state[SSTIndex];
131 const Box src_domain = tmp.boxArray().minimalBox();
132 const Box dst_domain = dst.boxArray().minimalBox();
134 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
135 src_domain.smallEnd(2) == src_domain.bigEnd(2) &&
136 dst_domain.smallEnd(2) == dst_domain.bigEnd(2),
137 "REMORA::PackSurfaceState expects 2D slab source and destination MultiFabs.");
138 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
139 src_domain.smallEnd(0) == dst_domain.smallEnd(0) &&
140 src_domain.smallEnd(1) == dst_domain.smallEnd(1),
141 "REMORA::PackSurfaceState requires aligned atmosphere/ocean slab origins.");
143 const IntVect src_len = src_domain.length();
144 const IntVect dst_len = dst_domain.length();
145 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
146 src_len[2] == 1 && dst_len[2] == 1,
147 "REMORA::PackSurfaceState expects unit-thickness source and destination slabs.");
149 const bool same_xy = (src_len[0] == dst_len[0] && src_len[1] == dst_len[1]);
150 const bool dst_finer =
151 (dst_len[0] >= src_len[0] && dst_len[1] >= src_len[1] &&
152 dst_len[0] % src_len[0] == 0 && dst_len[1] % src_len[1] == 0);
153 const bool dst_coarser =
154 (src_len[0] >= dst_len[0] && src_len[1] >= dst_len[1] &&
155 src_len[0] % dst_len[0] == 0 && src_len[1] % dst_len[1] == 0);
158 dst.ParallelCopy(tmp, 0, 0, 1);
163 const IntVect ratio(dst_len[0] / src_len[0], dst_len[1] / src_len[1], 1);
164 const auto src_geom = make_unit_slab_geometry(src_domain);
165 const auto dst_geom = make_unit_slab_geometry(dst_domain);
166 const auto bcs = make_internal_bcs(1);
167 amrex::InterpFromCoarseLevel(dst, IntVect(0), IntVect(0),
170 ratio, &pc_interp, bcs, 0);
175 const IntVect ratio(src_len[0] / dst_len[0], src_len[1] / dst_len[1], 1);
176 amrex::average_down(tmp, dst, 0, 1, ratio);
180 amrex::Abort(
"REMORA::PackSurfaceState requires matching horizontal extents and integer-ratio atmosphere/ocean slab resolutions.");
210 if (finest_level < 0) {
return; }
216 vec_uwind[0]->FillBoundary(geom[0].periodicity());
223 vec_vwind[0]->FillBoundary(geom[0].periodicity());
233 vec_Pair[0]->FillBoundary(geom[0].periodicity());
242 vec_qair[0]->FillBoundary(geom[0].periodicity());
251 vec_Tair[0]->plus(-273.15_rt, 0, 1);
252 vec_Tair[0]->FillBoundary(geom[0].periodicity());
261 vec_cloud[0]->FillBoundary(geom[0].periodicity());
268 vec_rain[0]->FillBoundary(geom[0].periodicity());
275 vec_srflx[0]->FillBoundary(geom[0].periodicity());
293 if (finest_level < 0) {
return; }
319 for (MFIter mfi(*
vec_stflux[0], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
320 Array4<Real>
const& stflux =
vec_stflux[0]->array(mfi);
321 Array4<Real>
const& sustr =
vec_sustr[0]->array(mfi);
322 Array4<Real>
const& svstr =
vec_svstr[0]->array(mfi);
323 Array4<Real>
const& lrflx =
vec_lrflx[0]->array(mfi);
324 Array4<Real>
const& lhflx =
vec_lhflx[0]->array(mfi);
325 Array4<Real>
const& shflx =
vec_shflx[0]->array(mfi);
326 Array4<const Real>
const& mskr =
vec_mskr[0]->const_array(mfi);
327 Array4<const Real>
const& msku =
vec_msku[0]->const_array(mfi);
328 Array4<const Real>
const& mskv =
vec_mskv[0]->const_array(mfi);
329 Array4<const Real>
const& srflx =
vec_srflx[0]->const_array(mfi);
330 Array4<const Real>
const& rain =
vec_rain[0]->const_array(mfi);
331 Array4<const Real>
const& evap =
vec_evap[0]->const_array(mfi);
338 Box gbx2 = mfi.growntilebox(IntVect(
NGROW,
NGROW,0));
341 Box ubx = mfi.grownnodaltilebox(0, IntVect(
NGROW,
NGROW,0));
344 Box vbx = mfi.grownnodaltilebox(1, IntVect(
NGROW,
NGROW,0));
348 ParallelFor(ubxD, [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) {
350 * (tau_x(i-1,j,0) + tau_x(i,j,0))
354 ParallelFor(vbxD, [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) {
356 * (tau_y(i,j-1,0) + tau_y(i,j,0))
360 ParallelFor(gbx2D, [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) {
362 lrflx(i,j,0) = lwflux(i,j,0) * Hscale2;
363 lhflx(i,j,0) = -lhflux(i,j,0) * Hscale2;
364 shflx(i,j,0) = -shflux(i,j,0) * Hscale2;
366 (srflx(i,j,0) * Hscale2 + lrflx(i,j,0) + lhflx(i,j,0) + shflx(i,j,0))
369 mskr(i,j,0) * (evap(i,j,0) - rain(i,j,0)) /
rhow;
373 vec_sustr[0]->FillBoundary(geom[0].periodicity());
374 vec_svstr[0]->FillBoundary(geom[0].periodicity());
375 vec_srflx[0]->FillBoundary(geom[0].periodicity());
376 vec_lrflx[0]->FillBoundary(geom[0].periodicity());
377 vec_lhflx[0]->FillBoundary(geom[0].periodicity());
378 vec_shflx[0]->FillBoundary(geom[0].periodicity());
379 vec_stflux[0]->FillBoundary(geom[0].periodicity());
380 vec_rain[0]->FillBoundary(geom[0].periodicity());
381 vec_evap[0]->FillBoundary(geom[0].periodicity());
382 vec_stflux[0]->FillBoundary(geom[0].periodicity());
384 if (amrex::ParallelDescriptor::IOProcessor()) {
385 amrex::Print() <<
"REMORA ApplyAtmosphericFluxes validation:\n"
constexpr amrex::Real rhow
void PackSurfaceState(amrex::Vector< amrex::MultiFab * > &state, amrex::Real time)
Extracts SST from the 3D conservative state for the atmospheric driver.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_evap
evaporation rate [kg/m^2/s]
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::Real stop_time
Time to stop.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rain
precipitation rate [kg/m^2/s]
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.
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
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
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_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.
amrex::Vector< amrex::Real > t_new
new time at each level
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.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_longwave_down
Downward longwave radiation.
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::Vector< std::unique_ptr< amrex::MultiFab > > vec_stflux
Surface tracer flux; input arrays.
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
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.
@ 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]