REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_SumIQ.cpp
Go to the documentation of this file.
1#include <iomanip>
2
3#include "REMORA.H"
4#include "AMReX_MultiFab.H"
5
6using namespace amrex;
7/**
8 * @param[in ] time current time
9 */
10void
12{
13 BL_PROFILE("REMORA::sum_integrated_quantities()");
14
15 if (verbose <= 0)
16 return;
17
18 int datwidth = 14;
19 // Six digits is enough to watch a run by eye but not to compare two runs: an averaged-down
20 // bathymetry shifts the volume by ~1e-5 relative. Raise it when the sums are being used as
21 // a diagnostic to assert on rather than to read.
22 int datprecision = 6;
23 amrex::ParmParse pp("remora");
24 pp.queryAdd("sum_precision", datprecision);
25 bool local = true;
26
27 // One sum per cell-centered tracer past salinity: the passive scalars and the
28 // biology tracers. Empty when the run carries neither.
29 const int n_tracers = ncons - Tracer_comp;
30
32 Real kineng_ml = zero;
33 Real volume_ml = zero;
34 Real max_vel_ml = zero;
35
37 Real kineng_sl = zero;
38 Real volume_sl = zero;
39 Real max_vel_sl = zero;
40
41 for (int t = 0; t < n_tracers; ++t) {
43 }
44
45 for (int lev = 0; lev <= finest_level; lev++)
46 {
47 MultiFab kineng_mf(grids[lev], dmap[lev], 1, 0);
48 MultiFab ones_mf(grids[lev], dmap[lev], 1, 0);
49 ones_mf.setVal(one);
50
51#ifdef _OPENMP
52#pragma omp parallel if (Gpu::notInLaunchRegion())
53#endif
54 for (MFIter mfi(*cons_new[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
55 const Box& bx = mfi.tilebox();
57 const Array4<const Real> xvel_u_arr = xvel_new[lev]->const_array(mfi);
58 const Array4<const Real> yvel_v_arr = yvel_new[lev]->const_array(mfi);
59 ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
60 {
61 // This is the same expression for kinetic energy that is used in ROMS
64 });
65 } // mfi
66
67 const int icomp = 0;
68 Real max_vel_local = std::sqrt(two * kineng_mf.max(icomp));
69
70 if (lev==0) {
74 }
75
76 for (int t = 0; t < n_tracers; ++t) {
78 }
82 }
83
84 if (verbose > 0) {
85 // Layout: every tracer's single-level sum, then kineng/volume, then the same
86 // for the multi-level sums. Unpacked below in the same order.
88 sum_vars.reserve(2*n_tracers + 4);
89 for (int t = 0; t < n_tracers; ++t) { sum_vars.push_back(tracer_sl[t]); }
90 sum_vars.push_back(kineng_sl);
91 sum_vars.push_back(volume_sl);
92 for (int t = 0; t < n_tracers; ++t) { sum_vars.push_back(tracer_ml[t]); }
93 sum_vars.push_back(kineng_ml);
94 sum_vars.push_back(volume_ml);
95 const int n_sum_vars = static_cast<int>(sum_vars.size());
96
97 const int n_max_vars = 2;
99#ifdef AMREX_LAZY
100 Lazy::QueueReduction([=]() mutable {
101#endif
102 ParallelDescriptor::ReduceRealSum(
103 sum_vars.data(), n_sum_vars, ParallelDescriptor::IOProcessorNumber());
104 ParallelDescriptor::ReduceRealMax(
105 max_vars, n_max_vars, ParallelDescriptor::IOProcessorNumber());
106
107 if (ParallelDescriptor::IOProcessor()) {
108 int i = 0;
109 for (int t = 0; t < n_tracers; ++t) { tracer_sl[t] = sum_vars[i++]; }
110 kineng_sl = sum_vars[i++];
111 volume_sl = sum_vars[i++];
112 for (int t = 0; t < n_tracers; ++t) { tracer_ml[t] = sum_vars[i++]; }
113 kineng_ml = sum_vars[i++];
114 volume_ml = sum_vars[i++];
115 int j = 0;
116 max_vel_sl = max_vars[j++];
117 max_vel_ml = max_vars[j++];
118
119 // Label field is as wide as the widest tracer name so the columns line up
120 // whether the run carries "tracer" or "phytoplankton"
121 int namewidth = 9;
122 for (int t = 0; t < n_tracers; ++t) {
123 namewidth = std::max(namewidth, static_cast<int>(cons_names[Tracer_comp+t].size()));
124 }
125
126 if (finest_level == 0) {
127 amrex::Print() << '\n';
128 amrex::Print() << std::setw(namewidth) << std::left << "TIME" << std::right
129 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << time << '\n';
130 for (int t = 0; t < n_tracers; ++t) {
131 amrex::Print() << std::setw(namewidth) << std::left << cons_names[Tracer_comp+t] << std::right
132 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << tracer_sl[t] << '\n';
133 }
134 amrex::Print() << std::setw(namewidth) << std::left << "KIN. ENG." << std::right
135 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << kineng_sl << '\n';
136 amrex::Print() << std::setw(namewidth) << std::left << "VOLUME" << std::right
137 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << volume_sl << '\n';
138 amrex::Print() << std::setw(namewidth) << std::left << "MAX. VEL." << std::right
139 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << max_vel_sl << '\n';
140 } else {
141 amrex::Print() << '\n';
142 amrex::Print() << std::setw(namewidth) << std::left << "TIME" << std::right
143 << " = " << std::setw(datwidth) << std::setprecision(datprecision) << time << '\n';
144 for (int t = 0; t < n_tracers; ++t) {
145 amrex::Print() << std::setw(namewidth) << std::left << cons_names[Tracer_comp+t] << std::right
146 << " SL/ML = " << std::setw(datwidth) << std::setprecision(datprecision) << tracer_sl[t] << ' '
147 << std::setw(datwidth) << std::setprecision(datprecision) << tracer_ml[t] << '\n';
148 }
149 amrex::Print() << std::setw(namewidth) << std::left << "KIN. ENG." << std::right
150 << " SL/ML = " << std::setw(datwidth) << std::setprecision(datprecision) << kineng_sl << ' '
151 << std::setw(datwidth) << std::setprecision(datprecision) << kineng_ml << '\n';
152 amrex::Print() << std::setw(namewidth) << std::left << "VOLUME" << std::right
153 << " SL/ML = " << std::setw(datwidth) << std::setprecision(datprecision) << volume_sl << ' '
154 << std::setw(datwidth) << std::setprecision(datprecision) << volume_ml << '\n';
155 amrex::Print() << std::setw(namewidth) << std::left << "MAX. VEL." << std::right
156 << " SL/ML = " << std::setw(datwidth) << std::setprecision(datprecision) << max_vel_sl << ' '
157 << std::setw(datwidth) << std::setprecision(datprecision) << max_vel_ml << '\n';
158 }
159
160 if (NumDataLogs() > 0) {
161 std::ostream& data_log1 = DataLog(0);
162 if (data_log1.good()) {
163 if (time == zero) {
164 data_log1 << std::setw(datwidth) << "time";
165 for (int t = 0; t < n_tracers; ++t) {
166 data_log1 << std::setw(datwidth) << cons_names[Tracer_comp+t];
167 }
168 data_log1 << std::setw(datwidth) << "kineng";
169 data_log1 << std::setw(datwidth) << "volume";
170 data_log1 << std::setw(datwidth) << "max_vel";
171 data_log1 << std::endl;
172 }
173
174 // Write the quantities at this time
175 data_log1 << std::setw(datwidth) << time;
176 for (int t = 0; t < n_tracers; ++t) {
177 data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
178 << tracer_ml[t];
179 }
180 data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
181 << kineng_ml;
182 data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
183 << volume_ml;
184 data_log1 << std::setw(datwidth) << std::setprecision(datprecision)
185 << max_vel_ml;
186 data_log1 << std::endl;
187 }
188 }
189 }
190#ifdef AMREX_LAZY
191 });
192#endif
193 }
194}
195
196/**
197 * @param[in ] lev level to calculate on
198 * @param[in ] mf data to sum over
199 * @param[in ] comp component on which to calculate sum
200 * @param[in ] local whether to do the sum locally
201 * @param[in ] finemask whether to mask fine level
202 */
203Real
204REMORA::volWgtSumMF(int lev, const MultiFab& mf, int comp, bool local, bool finemask)
205{
206 BL_PROFILE("REMORA::volWgtSumMF()");
207
208 Real sum = zero;
209 MultiFab tmp(grids[lev], dmap[lev], 1, 0);
210 MultiFab::Copy(tmp, mf, comp, 0, 1, 0);
211
212 if (lev < finest_level && finemask) {
213 const MultiFab& mask = build_fine_mask(lev+1);
214 MultiFab::Multiply(tmp, mask, 0, 0, 1, 0);
215 }
216
217 MultiFab volume(grids[lev], dmap[lev], 1, 0);
218#ifdef _OPENMP
219#pragma omp parallel if (Gpu::notInLaunchRegion())
220#endif
221 for (MFIter mfi(*cons_new[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi) {
222 const Box& bx = mfi.tilebox();
223 const Array4< Real> vol_arr = volume.array(mfi);
224 const Array4<const Real> Hz = vec_Hz[lev]->const_array(mfi);
225 const Array4<const Real> pm = vec_pm[lev]->const_array(mfi);
226 const Array4<const Real> pn = vec_pn[lev]->const_array(mfi);
227 ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
228 {
229 vol_arr(i,j,k) = Hz(i,j,k) / (pm(i,j,0) * pn(i,j,0));
230 });
231 } // mfi
232
233 sum = MultiFab::Dot(tmp, 0, volume, 0, 1, 0, local);
234
235 if (!local)
236 ParallelDescriptor::ReduceRealSum(sum);
237
238 return sum;
239}
240
241/**
242 * @param[in ] lev level to calculate on
243 */
244MultiFab&
246{
247 // Mask for zeroing covered cells
248 AMREX_ASSERT(level > 0);
249
250 const BoxArray& cba = grids[level-1];
251 const DistributionMapping& cdm = dmap[level-1];
252
253 // TODO -- we should make a vector of these a member of REMORA class
254 fine_mask.define(cba, cdm, 1, 0, MFInfo());
255 fine_mask.setVal(one);
256
257 BoxArray fba = grids[level];
258 iMultiFab ifine_mask = makeFineMask(cba, cdm, fba, ref_ratio[level-1], 1, 0);
259
260 const auto fma = fine_mask.arrays();
261 const auto ifma = ifine_mask.arrays();
262 ParallelFor(fine_mask, [=] AMREX_GPU_DEVICE(int bno, int i, int j, int k) noexcept
263 {
264 fma[bno](i,j,k) = ifma[bno](i,j,k);
265 });
266
267 Gpu::synchronize();
268
269 return fine_mask;
270}
271
272/**
273 * @param[in ] nstep what step we're on
274 * @param[in ] lev level to calculate on
275 * @param[in ] dtlev time step for this level
276 * @param[in ] action_interval number of time steps between actions
277 * @param[in ] action_per time interval between actions
278 */
279bool
281{
282 bool int_test = (action_interval > 0 && nstep % action_interval == 0);
283
284 bool per_test = false;
285 if (action_per > zero) {
286 const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
287 const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
288
289 if (num_per_old != num_per_new) {
290 per_test = true;
291 }
292 }
293
294 return int_test || per_test;
295}
constexpr amrex::Real two
constexpr amrex::Real one
constexpr amrex::Real fourth
constexpr amrex::Real zero
#define Tracer_comp
mf_h setVal(geomdata.ProbHi(2))
int ncons
Number of conserved scalars in the state (temperature + salt + passive scalars + biology tracers)
Definition REMORA.H:1644
amrex::Vector< std::string > cons_names
Names of scalars for plotfile output.
Definition REMORA.H:1709
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm
horizontal scaling factor: 1 / dx (2D)
Definition REMORA.H:568
amrex::MultiFab fine_mask
Mask that zeroes out values on a coarse level underlying grids on the next finest level.
Definition REMORA.H:1834
amrex::Vector< amrex::MultiFab * > cons_new
multilevel data container for current step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:386
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Hz
Width of cells in the vertical (z-) direction (3D, Hz in ROMS)
Definition REMORA.H:412
amrex::Vector< amrex::MultiFab * > yvel_new
multilevel data container for current step's y velocities (v in ROMS)
Definition REMORA.H:390
amrex::MultiFab & build_fine_mask(int lev)
Make mask to zero out covered cells (for mesh refinement)
amrex::Vector< amrex::MultiFab * > xvel_new
multilevel data container for current step's x velocities (u in ROMS)
Definition REMORA.H:388
void sum_integrated_quantities(amrex::Real time)
Integrate conserved quantities for diagnostics.
AMREX_FORCE_INLINE int NumDataLogs() noexcept
Definition REMORA.H:1874
amrex::Real volWgtSumMF(int lev, const amrex::MultiFab &mf, int comp, bool local, bool finemask)
Perform the volume-weighted sum.
bool is_it_time_for_action(int nstep, amrex::Real time, amrex::Real dt, int action_interval, amrex::Real action_per)
Decide if it is time to take an action.
AMREX_FORCE_INLINE std::ostream & DataLog(int i)
Helper function for IO stream.
Definition REMORA.H:1867
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pn
horizontal scaling factor: 1 / dy (2D)
Definition REMORA.H:570
static int verbose
Verbosity level of output.
Definition REMORA.H:1753