REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_Coupling.cpp
Go to the documentation of this file.
1#include <REMORA.H>
2
3#include <AMReX_Box.H>
4#include <AMReX_MFIter.H>
5#include <AMReX_Print.H>
6
7using namespace amrex;
8
9/*
10 Coupling reference context (implementation-side):
11
12 1) Legacy state-passing contract:
13 Warner et al. (2010), COAWST, Fig. 5 / Block B.
14 REMORA receives atmospheric states and computes surface fluxes internally
15 (bulk-physics/COARE-style path).
16
17 2) Future direct flux-passing roadmap:
18 COAWST's ATM2OCN_FLUXES pathway (documented in COAWST manuals/workshops
19 and exercised in Zambon et al., 2014) motivates direct flux exchange
20 (tau_x, tau_y, heat/moisture) instead of state-only exchange.
21 COAWST code anchors:
22 - Master/mct_roms_wrf.h
23 - ROMS/Nonlinear/atm2ocn_flux.F
24 - ROMS/Nonlinear/bulk_flux.F
25*/
26
27namespace {
28constexpr int SSTIndex = 0;
29}
30
31amrex::Real
32REMORA::EvolveOneStep (amrex::Real /*time*/, amrex::Real /*dt_request*/)
33{
34 Real cur_time = t_new[0];
35 const int step = istep[0];
36
37 if (cur_time >= stop_time) {
38 return Real(0.0);
39 }
40
41 ComputeDt();
42
43 int lev = 0;
44 int iteration = 1;
45 if (max_level == 0) {
46 timeStep(lev, cur_time, iteration);
47 } else {
48 timeStepML(cur_time, iteration);
49 }
50
51 cur_time += dt[0];
52
53 if ( (plot_int > 0 && (step+1 - last_plot_file_step) == plot_int ) ||
54 (plot_int_time > 0 && (cur_time >= (last_plot_file_time + plot_int_time))) )
55 {
56 last_plot_file_step = step+1;
57 last_plot_file_time = cur_time;
58 WritePlotFile(step+1);
60 }
61
62 if ((check_int > 0 && (step+1 - last_check_file_step) == check_int)
63 || (check_int_time > 0 && cur_time >= (last_check_file_time + check_int_time))) {
64 last_check_file_step = step+1;
65 last_check_file_time = cur_time;
67 }
68
69 post_timestep(step, cur_time, dt[0]);
70
71 return dt[0];
72}
73
74/*
75 * \brief Extracts SST from the 3D conservative state for the atmospheric driver.
76 *
77 * Reads Temp_comp at the top water-column cell (k_sfc), converts from
78 * Celsius to Kelvin, and copies the result into state[SSTIndex].
79 *
80 * @param[in,out] state OCN2ATM slab buffer sized by the driver (one MultiFab
81 * per ocean-to-atmosphere export layer). state[SSTIndex]
82 * (index 0) is overwritten with sea-surface temperature
83 * (SST) sampled from the Temp_comp tracer at the uppermost
84 * sigma level (k = Nz) and converted from degrees Celsius
85 * to Kelvin for the atmospheric driver. An empty vector or
86 * null state[0] is treated as a no-op.
87 * @param[in ] time Current ocean model time (unused; retained for driver
88 * interface conformance).
89 */
90void
91REMORA::PackSurfaceState (Vector<MultiFab*>& state, Real /*time*/)
92{
93 if (state.empty() || state[SSTIndex] == nullptr) { return; }
94 const int lev = 0;
95
96 // REMORA stores temperature in Celsius. Surface is at k=N (top of water column).
97 const int k_sfc = cons_new[lev]->boxArray().minimalBox().bigEnd(2);
98
99 // Build a temp MultiFab on REMORA's ba2d (k=0) derived from cons_new's BoxArray.
100 // Same DistributionMap ensures each box is local; we fill at k=0 from cons at k=k_sfc.
101 BoxList bl2d = cons_new[lev]->boxArray().boxList();
102 for (auto& b : bl2d) { b.setRange(2, 0); }
103 BoxArray ba2d(std::move(bl2d));
104 MultiFab tmp(ba2d, cons_new[lev]->DistributionMap(), 1, 0);
105
106 for (MFIter mfi(*cons_new[lev]); mfi.isValid(); ++mfi) {
107 auto const& c = cons_new[lev]->const_array(mfi);
108 auto t = tmp.array(mfi);
109 Box bx = makeSlab(mfi.validbox(), 2, k_sfc);
110 ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int) {
111 // Write to k=0 in tmp (ba2d range); convert Celsius → Kelvin.
112 t(i, j, 0) = c(i, j, k_sfc, Temp_comp) + 273.15_rt;
113 });
114 }
115 state[SSTIndex]->ParallelCopy(tmp, 0, 0, 1);
116}
117
118/*
119 * \brief Receives atmospheric states from the driver and applies unit conversions.
120 *
121 * Fills REMORA's internal forcing MultiFabs from states and records which
122 * lanes were successfully updated in driver_atmos_state_from_driver.
123 * Unit conversions applied: Pair Pa to mb; Tair K to Celsius.
124 *
125 * @param[in] states ATM2OCN forcing slab buffer from the driver (Warner et al.
126 * 2010, Block B state-passing contract), indexed by AtmosState.
127 * Expected units per lane:
128 * Uwind/Vwind: 10-m winds [m/s];
129 * Pair: mean sea-level pressure [Pa, converted to mb];
130 * Qair: near-surface specific humidity [kg/kg];
131 * Tair: 2-m air temperature [K, converted to degC];
132 * Cloud: cloud fraction [0-1];
133 * Rain: precipitation rate [kg/m^2/s];
134 * SWrad/LWrad: downwelling shortwave/longwave radiation [W/m^2].
135 * Missing lanes (null pointer or index out of range) are skipped;
136 * driver_atmos_state_from_driver tracks populated lanes for the
137 * bulk-flux parameterization fallback logic.
138 * @param[in] time Current ocean model time (unused; retained for driver
139 * interface conformance).
140 */
141void
142REMORA::ApplyAtmosphericStates (const Vector<MultiFab*>& states, Real /*time*/)
143{
145 if (finest_level < 0) { return; }
146
147 // Wind (m/s) — no unit conversion
148 if (vec_uwind[0] != nullptr) {
149 if (states.size() > AtmosState::Uwind && states[AtmosState::Uwind] != nullptr) {
150 vec_uwind[0]->ParallelCopy(*states[AtmosState::Uwind], 0, 0, 1);
151 vec_uwind[0]->FillBoundary(geom[0].periodicity());
153 }
154 }
155 if (vec_vwind[0] != nullptr) {
156 if (states.size() > AtmosState::Vwind && states[AtmosState::Vwind] != nullptr) {
157 vec_vwind[0]->ParallelCopy(*states[AtmosState::Vwind], 0, 0, 1);
158 vec_vwind[0]->FillBoundary(geom[0].periodicity());
160 }
161 }
162
163 // Atmospheric pressure: Pa → mb (REMORA bulk flux expects mb)
164 if (vec_Pair[0] != nullptr) {
165 if (states.size() > AtmosState::Pair && states[AtmosState::Pair] != nullptr) {
166 vec_Pair[0]->ParallelCopy(*states[AtmosState::Pair], 0, 0, 1);
167 vec_Pair[0]->mult(0.01_rt, 0, 1);
168 vec_Pair[0]->FillBoundary(geom[0].periodicity());
170 }
171 }
172
173 // Specific humidity (kg/kg) — no conversion
174 if (vec_qair[0] != nullptr) {
175 if (states.size() > AtmosState::Qair && states[AtmosState::Qair] != nullptr) {
176 vec_qair[0]->ParallelCopy(*states[AtmosState::Qair], 0, 0, 1);
177 vec_qair[0]->FillBoundary(geom[0].periodicity());
179 }
180 }
181
182 // Air temperature: K → °C (REMORA stores/uses Celsius internally)
183 if (vec_Tair[0] != nullptr) {
184 if (states.size() > AtmosState::Tair && states[AtmosState::Tair] != nullptr) {
185 vec_Tair[0]->ParallelCopy(*states[AtmosState::Tair], 0, 0, 1);
186 vec_Tair[0]->plus(-273.15_rt, 0, 1);
187 vec_Tair[0]->FillBoundary(geom[0].periodicity());
189 }
190 }
191
192 // Cloud fraction [0-1], rain, SW/LW radiation — no unit conversion
193 if (vec_cloud[0] != nullptr) {
194 if (states.size() > AtmosState::Cloud && states[AtmosState::Cloud] != nullptr) {
195 vec_cloud[0]->ParallelCopy(*states[AtmosState::Cloud], 0, 0, 1);
196 vec_cloud[0]->FillBoundary(geom[0].periodicity());
198 }
199 }
200 if (vec_rain[0] != nullptr) {
201 if (states.size() > AtmosState::Rain && states[AtmosState::Rain] != nullptr) {
202 vec_rain[0]->ParallelCopy(*states[AtmosState::Rain], 0, 0, 1);
203 vec_rain[0]->FillBoundary(geom[0].periodicity());
205 }
206 }
207 if (vec_srflx[0] != nullptr) {
208 if (states.size() > AtmosState::SWrad && states[AtmosState::SWrad] != nullptr) {
209 vec_srflx[0]->ParallelCopy(*states[AtmosState::SWrad], 0, 0, 1);
210 vec_srflx[0]->FillBoundary(geom[0].periodicity());
212 }
213 }
214 if (vec_longwave_down[0] != nullptr) {
215 if (states.size() > AtmosState::LWrad && states[AtmosState::LWrad] != nullptr) {
216 vec_longwave_down[0]->ParallelCopy(*states[AtmosState::LWrad], 0, 0, 1);
217 vec_longwave_down[0]->FillBoundary(geom[0].periodicity());
219 }
220 }
221
222}
#define Temp_comp
void PackSurfaceState(amrex::Vector< amrex::MultiFab * > &state, amrex::Real time)
Extracts SST from the 3D conservative state for the atmospheric driver.
amrex::Real last_plot_file_time
Simulation time when we last output a plotfile.
Definition REMORA.H:1384
amrex::Vector< amrex::MultiFab * > cons_new
multilevel data container for current step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:294
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vwind
Wind in the v direction, defined at rho-points.
Definition REMORA.H:374
int history_count
Counter for which time index we are writing to in the netcdf history file.
Definition REMORA.H:1454
amrex::Real stop_time
Time to stop.
Definition REMORA.H:1399
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rain
precipitation rate [kg/m^2/s]
Definition REMORA.H:403
amrex::Real EvolveOneStep(amrex::Real time, amrex::Real dt_request)
std::array< bool, AtmosState::NumTypes > driver_atmos_state_from_driver
provenance flags for driver-supplied atmospheric forcing lanes
Definition REMORA.H:412
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
Definition REMORA.H:372
amrex::Real check_int_time
Checkpoint output interval in seconds.
Definition REMORA.H:1444
amrex::Real plot_int_time
Plotfile output interval in seconds.
Definition REMORA.H:1438
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Called after every level 0 timestep.
Definition REMORA.cpp:320
int last_check_file_step
Step when we last output a checkpoint file.
Definition REMORA.H:1387
void ComputeDt()
a wrapper for estTimeStep()
int plot_int
Plotfile output interval in iterations.
Definition REMORA.H:1436
amrex::Vector< int > istep
which step?
Definition REMORA.H:1333
void WriteCheckpointFile()
write checkpoint file to disk
amrex::Vector< amrex::Real > t_new
new time at each level
Definition REMORA.H:1337
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.
Definition REMORA.H:387
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_cloud
cloud cover fraction [0-1], defined at rho-points
Definition REMORA.H:407
int check_int
Checkpoint output interval in iterations.
Definition REMORA.H:1442
void WritePlotFile(int istep)
main driver for writing AMReX plotfiles
int last_plot_file_step
Step when we last output a plotfile.
Definition REMORA.H:1382
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_srflx
Shortwave radiation flux [W/m²], defined at rho-points.
Definition REMORA.H:383
amrex::Real last_check_file_time
Simulation time when we last output a checkpoint file.
Definition REMORA.H:1389
amrex::Vector< amrex::Real > dt
time step at each level
Definition REMORA.H:1341
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Pair
Air pressure [mb], defined at rho-points.
Definition REMORA.H:380
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_qair
Specific humidity [kg/kg], defined at rho-points.
Definition REMORA.H:378
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Tair
Air temperature [°C], defined at rho-points.
Definition REMORA.H:376
@ 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]