ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
CloudChamberBudget Class Reference

#include <ERF_CloudChamberBudget.H>

Collaboration diagram for CloudChamberBudget:

Public Types

enum  Scalar : int { RhoTheta = 0 , RhoQv = 1 , RhoQc = 2 , NumScalars = 3 }
 

Public Member Functions

 CloudChamberBudget (int interval)
 
bool enabled () const noexcept
 
bool due (int step) const noexcept
 
void set_initial_state (const amrex::MultiFab &cons, const amrex::Geometry &geom, int step=0, double time=0.0)
 
void capture_stage (int scalar, int nrk, amrex::Real dt, const amrex::MultiFab &xflux, const amrex::MultiFab &yflux, const amrex::MultiFab &zflux, const amrex::Geometry &geom, int flux_comp=0)
 
std::array< amrex::Real, NumScalarsstate_integrals (const amrex::MultiFab &cons, const amrex::Geometry &geom) const
 
void record_internal_source (const std::array< amrex::Real, NumScalars > &before, const std::array< amrex::Real, NumScalars > &after)
 
void report (int step, double time, const amrex::MultiFab &cons, const amrex::Geometry &geom, bool cloudy)
 

Static Public Attributes

static constexpr int NumFaces = 2 * AMREX_SPACEDIM
 

Private Attributes

int m_interval = 0
 
int m_interval_start_step = 0
 
double m_interval_start_time = 0.0
 
bool m_have_initial = false
 
std::array< bool, NumScalarsm_have_stage0 {}
 
std::array< amrex::Real, NumScalarsm_initial_state {}
 
std::array< amrex::Real, NumScalarsm_internal_source {}
 
std::array< std::array< amrex::Real, NumFaces >, NumScalarsm_stage0 {}
 
std::array< std::array< amrex::Real, NumFaces >, NumScalarsm_cumulative {}
 

Detailed Description

Low-overhead Stage 1 conserved-scalar budget accumulator.

Fluxes are positive in the positive coordinate direction. The reported boundary balance is therefore low-minus-high for each coordinate pair. Local face sums are held until a configured report interval, then one packed MPI reduction produces the six-face values. For the anelastic RK2 path, nrk=0 is retained and nrk=1 applies the trapezoidal stage weight; this avoids counting both RHS evaluations as two physical timesteps.

Member Enumeration Documentation

◆ Scalar

Enumerator
RhoTheta 
RhoQv 
RhoQc 
NumScalars 
30 : int { RhoTheta = 0, RhoQv = 1, RhoQc = 2, NumScalars = 3 };
@ RhoTheta
Definition: ERF_CloudChamberBudget.H:30
@ RhoQv
Definition: ERF_CloudChamberBudget.H:30
@ NumScalars
Definition: ERF_CloudChamberBudget.H:30
@ RhoQc
Definition: ERF_CloudChamberBudget.H:30

Constructor & Destructor Documentation

◆ CloudChamberBudget()

CloudChamberBudget::CloudChamberBudget ( int  interval)
inlineexplicit
33 : m_interval(interval) {}
int m_interval
Definition: ERF_CloudChamberBudget.H:218

Member Function Documentation

◆ capture_stage()

void CloudChamberBudget::capture_stage ( int  scalar,
int  nrk,
amrex::Real  dt,
const amrex::MultiFab &  xflux,
const amrex::MultiFab &  yflux,
const amrex::MultiFab &  zflux,
const amrex::Geometry &  geom,
int  flux_comp = 0 
)
inline
62  {
63  if (!enabled() || scalar < 0 || scalar >= NumScalars) { return; }
64  std::array<amrex::Real, NumFaces> current{};
65  for (int d = 0; d < AMREX_SPACEDIM; ++d) {
66  amrex::Box low = geom.Domain();
67  amrex::Box high = low;
68  low.surroundingNodes(d);
69  high.surroundingNodes(d);
70  low.setSmall(d, geom.Domain().smallEnd(d));
71  low.setBig(d, geom.Domain().smallEnd(d));
72  high.setSmall(d, geom.Domain().bigEnd(d)+1);
73  high.setBig(d, geom.Domain().bigEnd(d)+1);
74  const amrex::MultiFab* flux = (d == 0) ? &xflux : ((d == 1) ? &yflux : &zflux);
75  const amrex::Real area = (d == 0) ? geom.CellSize(1)*geom.CellSize(2) :
76  ((d == 1) ? geom.CellSize(0)*geom.CellSize(2) :
77  geom.CellSize(0)*geom.CellSize(1));
78  current[2*d] = flux->sum(low, flux_comp, true) * area * dt;
79  current[2*d+1] = flux->sum(high, flux_comp, true) * area * dt;
80  }
81 
82  if (nrk == 0) {
83  m_stage0[scalar] = current;
84  m_have_stage0[scalar] = true;
85  } else if (nrk == 1 && m_have_stage0[scalar]) {
86  for (int face = 0; face < NumFaces; ++face) {
87  m_cumulative[scalar][face] +=
88  amrex::Real(0.5) * (m_stage0[scalar][face] + current[face]);
89  }
90  m_have_stage0[scalar] = false;
91  }
92  }
amrex::Real Real
Definition: ERF_ShocInterface.H:19
bool enabled() const noexcept
Definition: ERF_CloudChamberBudget.H:35
std::array< std::array< amrex::Real, NumFaces >, NumScalars > m_stage0
Definition: ERF_CloudChamberBudget.H:225
std::array< bool, NumScalars > m_have_stage0
Definition: ERF_CloudChamberBudget.H:222
static constexpr int NumFaces
Definition: ERF_CloudChamberBudget.H:31
std::array< std::array< amrex::Real, NumFaces >, NumScalars > m_cumulative
Definition: ERF_CloudChamberBudget.H:226

Referenced by erf_slow_rhs_post(), and erf_slow_rhs_pre().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ due()

bool CloudChamberBudget::due ( int  step) const
inlinenoexcept
36  {
37  return enabled() && step > 0 && (step % m_interval == 0);
38  }

Referenced by report().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ enabled()

bool CloudChamberBudget::enabled ( ) const
inlinenoexcept
35 { return m_interval > 0; }

Referenced by capture_stage(), and due().

Here is the caller graph for this function:

◆ record_internal_source()

void CloudChamberBudget::record_internal_source ( const std::array< amrex::Real, NumScalars > &  before,
const std::array< amrex::Real, NumScalars > &  after 
)
inline
108  {
109  for (int s = 0; s < NumScalars; ++s) {
110  m_internal_source[s] += after[s] - before[s];
111  }
112  }
std::array< amrex::Real, NumScalars > m_internal_source
Definition: ERF_CloudChamberBudget.H:224

◆ report()

void CloudChamberBudget::report ( int  step,
double  time,
const amrex::MultiFab &  cons,
const amrex::Geometry &  geom,
bool  cloudy 
)
inline
116  {
117  if (!due(step) || !m_have_initial) { return; }
118  const auto current = state_integrals(cons, geom);
119  std::array<amrex::Real, NumScalars*NumFaces + NumScalars*3> packed{};
120  int index = 0;
121  for (int s = 0; s < NumScalars; ++s) {
122  for (int f = 0; f < NumFaces; ++f) { packed[index++] = m_cumulative[s][f]; }
123  }
124  for (int s = 0; s < NumScalars; ++s) { packed[index++] = m_initial_state[s]; }
125  for (int s = 0; s < NumScalars; ++s) { packed[index++] = current[s]; }
126  for (int s = 0; s < NumScalars; ++s) { packed[index++] = m_internal_source[s]; }
127  amrex::ParallelDescriptor::ReduceRealSum(packed.data(), static_cast<int>(packed.size()));
128 
129  std::array<std::array<amrex::Real, NumFaces>, NumScalars> global_faces{};
130  index = 0;
131  for (int s = 0; s < NumScalars; ++s) {
132  for (int f = 0; f < NumFaces; ++f) { global_faces[s][f] = packed[index++]; }
133  }
134  std::array<amrex::Real, NumScalars> initial{};
135  std::array<amrex::Real, NumScalars> global_current{};
136  index = NumScalars*NumFaces;
137  for (int s = 0; s < NumScalars; ++s) { initial[s] = packed[index++]; }
138  for (int s = 0; s < NumScalars; ++s) { global_current[s] = packed[index++]; }
139  std::array<amrex::Real, NumScalars> global_internal{};
140  for (int s = 0; s < NumScalars; ++s) { global_internal[s] = packed[index++]; }
141 
142  if (amrex::ParallelDescriptor::IOProcessor()) {
143  std::ofstream out("cloud_chamber_budget.dat", std::ios::app);
144  if (out.tellp() == std::streampos(0)) {
145  out << "# start_step start_time end_step end_time scalar units "
146  "xlo xhi ylo yhi zlo zhi net_boundary volume_change "
147  "internal_source residual tolerance status\n";
148  }
149  out << std::setprecision(17);
150  const char* names[NumScalars] = {"rhoTheta", "water_vapor", "cloud_water"};
151  const char* units[NumScalars] = {"conserved_scalar", "mixing_ratio_density", "mixing_ratio_density"};
152  for (int s = 0; s < NumScalars; ++s) {
153  std::array<amrex::Real, NumFaces> faces = global_faces[s];
154  amrex::Real net = faces[0] - faces[1] + faces[2] - faces[3] + faces[4] - faces[5];
155  const amrex::Real change = global_current[s] - initial[s];
156  const amrex::Real internal = global_internal[s];
157  const amrex::Real residual = change - net - internal;
158  const amrex::Real scale = std::max({amrex::Real(1.0),
159  std::abs(initial[s]), std::abs(global_current[s]),
160  std::abs(net), std::abs(internal)});
161  const amrex::Real effective_operations =
162  static_cast<amrex::Real>(geom.Domain().numPts()) +
163  static_cast<amrex::Real>(NumFaces);
164  amrex::Real boundary_scale = amrex::Real(0.0);
165  for (const auto value : faces) { boundary_scale += std::abs(value); }
166  const amrex::Real tolerance = amrex::Real(128.0) *
168  (effective_operations * scale + boundary_scale + std::abs(internal));
169  const bool status = std::abs(residual) <= tolerance;
170  const char* status_text = status ? "PASS" :
171  (cloudy && s == RhoTheta ? "UNSUPPORTED_SOURCE" : "FAIL");
173  << step << ' ' << time << ' ' << names[s] << ' ' << units[s];
174  for (const auto value : faces) { out << ' ' << value; }
175  out << ' ' << net << ' ' << change << ' ' << internal << ' '
176  << residual << ' ' << tolerance << ' ' << status_text << '\n';
177  }
178  std::array<amrex::Real, NumFaces> total_faces{};
179  for (int f = 0; f < NumFaces; ++f) {
180  total_faces[f] = global_faces[RhoQv][f] + global_faces[RhoQc][f];
181  }
182  const amrex::Real total_net = total_faces[0] - total_faces[1] +
183  total_faces[2] - total_faces[3] + total_faces[4] - total_faces[5];
184  const amrex::Real total_change = global_current[RhoQv] + global_current[RhoQc] -
185  initial[RhoQv] - initial[RhoQc];
186  const amrex::Real total_internal = global_internal[RhoQv] + global_internal[RhoQc];
187  const amrex::Real total_residual = total_change - total_net - total_internal;
188  const amrex::Real total_scale = std::max({amrex::Real(1.0), std::abs(total_change),
189  std::abs(total_net), std::abs(total_internal)});
190  amrex::Real total_boundary_scale = amrex::Real(0.0);
191  for (const auto value : total_faces) { total_boundary_scale += std::abs(value); }
192  const amrex::Real total_tolerance = amrex::Real(128.0) *
194  (static_cast<amrex::Real>(geom.Domain().numPts() + NumFaces) * total_scale +
195  total_boundary_scale + std::abs(total_internal));
196  const bool total_status = std::abs(total_residual) <= total_tolerance;
198  << step << ' ' << time << " total_nonprecipitating_water mixing_ratio_density";
199  for (const auto value : total_faces) { out << ' ' << value; }
200  out << ' ' << total_net << ' ' << total_change << ' ' << total_internal << ' '
201  << total_residual << ' ' << total_tolerance << ' '
202  << (total_status ? "PASS" : "FAIL") << '\n';
203  }
204  // The next report is an interval-local balance beginning at the
205  // state just reported. Keep this reference rank-local: assigning the
206  // MPI-global value here would make every rank contribute the same
207  // global reference at the next reduction.
208  m_initial_state = current;
209  m_cumulative = {};
210  m_internal_source = {};
211  m_stage0 = {};
212  m_have_stage0 = {};
213  m_interval_start_step = step;
214  m_interval_start_time = time;
215  }
struct @28 out
Real value
Definition: ERF_HurricaneDiagnostics.cpp:30
std::string units
Definition: ERF_Plotfile2DCatalog.cpp:103
std::array< amrex::Real, NumScalars > m_initial_state
Definition: ERF_CloudChamberBudget.H:223
double m_interval_start_time
Definition: ERF_CloudChamberBudget.H:220
std::array< amrex::Real, NumScalars > state_integrals(const amrex::MultiFab &cons, const amrex::Geometry &geom) const
Definition: ERF_CloudChamberBudget.H:95
bool m_have_initial
Definition: ERF_CloudChamberBudget.H:221
int m_interval_start_step
Definition: ERF_CloudChamberBudget.H:219
bool due(int step) const noexcept
Definition: ERF_CloudChamberBudget.H:36
@ cons
Definition: ERF_IndexDefines.H:176
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
Here is the call graph for this function:

◆ set_initial_state()

void CloudChamberBudget::set_initial_state ( const amrex::MultiFab &  cons,
const amrex::Geometry &  geom,
int  step = 0,
double  time = 0.0 
)
inline
44  {
45  if (m_have_initial) { return; }
46  const amrex::Real volume = geom.CellSize(0) * geom.CellSize(1) * geom.CellSize(2);
47  for (int s = 0; s < NumScalars; ++s) {
48  const int comp = (s == RhoTheta) ? RhoTheta_comp : RhoQ1_comp + (s-1);
49  m_initial_state[s] = (comp < cons.nComp()) ? cons.sum(comp, true) * volume : amrex::Real(0.0);
50  }
51  m_interval_start_step = step;
52  m_interval_start_time = time;
53  m_have_initial = true;
54  }
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42

◆ state_integrals()

std::array<amrex::Real, NumScalars> CloudChamberBudget::state_integrals ( const amrex::MultiFab &  cons,
const amrex::Geometry &  geom 
) const
inline
97  {
98  const amrex::Real volume = geom.CellSize(0) * geom.CellSize(1) * geom.CellSize(2);
99  std::array<amrex::Real, NumScalars> result{};
100  result[RhoTheta] = cons.sum(RhoTheta_comp, true) * volume;
101  result[RhoQv] = (RhoQ1_comp < cons.nComp()) ? cons.sum(RhoQ1_comp, true) * volume : amrex::Real(0.0);
102  result[RhoQc] = (RhoQ2_comp < cons.nComp()) ? cons.sum(RhoQ2_comp, true) * volume : amrex::Real(0.0);
103  return result;
104  }
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43

Referenced by report().

Here is the caller graph for this function:

Member Data Documentation

◆ m_cumulative

std::array<std::array<amrex::Real, NumFaces>, NumScalars> CloudChamberBudget::m_cumulative {}
private

Referenced by capture_stage(), and report().

◆ m_have_initial

bool CloudChamberBudget::m_have_initial = false
private

Referenced by report(), and set_initial_state().

◆ m_have_stage0

std::array<bool, NumScalars> CloudChamberBudget::m_have_stage0 {}
private

Referenced by capture_stage(), and report().

◆ m_initial_state

std::array<amrex::Real, NumScalars> CloudChamberBudget::m_initial_state {}
private

Referenced by report(), and set_initial_state().

◆ m_internal_source

std::array<amrex::Real, NumScalars> CloudChamberBudget::m_internal_source {}
private

Referenced by record_internal_source(), and report().

◆ m_interval

int CloudChamberBudget::m_interval = 0
private

Referenced by due(), and enabled().

◆ m_interval_start_step

int CloudChamberBudget::m_interval_start_step = 0
private

Referenced by report(), and set_initial_state().

◆ m_interval_start_time

double CloudChamberBudget::m_interval_start_time = 0.0
private

Referenced by report(), and set_initial_state().

◆ m_stage0

std::array<std::array<amrex::Real, NumFaces>, NumScalars> CloudChamberBudget::m_stage0 {}
private

Referenced by capture_stage(), and report().

◆ NumFaces

constexpr int CloudChamberBudget::NumFaces = 2 * AMREX_SPACEDIM
staticconstexpr

Referenced by capture_stage(), and report().


The documentation for this class was generated from the following file: