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