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

#include <ERF_AuxiliaryStage.H>

Collaboration diagram for erf_auxiliary::CompletedStepFluxLedger:

Public Member Functions

 CompletedStepFluxLedger ()=default
 
 CompletedStepFluxLedger (const CompletedStepFluxLedger &)=delete
 
CompletedStepFluxLedger & operator= (const CompletedStepFluxLedger &)=delete
 
void define (const amrex::BoxArray &cell_ba, const amrex::DistributionMapping &dm, int ncomp=1)
 
bool accept_stage (HostIntegrator method, int stage, double step_old_time, const AuxiliaryStageRecipe &recipe, const MappedFaceFluxRate &rate, std::string &diagnostic)
 
bool begin_stage (HostIntegrator method, int stage, double step_old_time, const AuxiliaryStageRecipe &recipe, std::string &diagnostic)
 
bool accumulate_stage_component (const MappedFaceFluxRate &rate, int source_component, int ledger_component, std::string &diagnostic)
 
bool finish_stage (std::string &diagnostic)
 
bool is_defined () const noexcept
 
bool step_active () const noexcept
 
bool step_complete () const noexcept
 
int next_stage () const noexcept
 
const IntegratedMappedFaceFlux & integrated_flux () const noexcept
 

Private Member Functions

void latch_stage_failure (const std::string &diagnostic)
 
void discard_step ()
 

Private Attributes

IntegratedMappedFaceFlux m_integral
 
bool m_step_active {false}
 
bool m_step_complete {false}
 
bool m_stage_open {false}
 
HostIntegrator m_method {HostIntegrator::CompressibleRK3}
 
int m_next_stage {0}
 
int m_open_stage {-1}
 
amrex::Real m_open_stage_weight {0.0}
 
double m_step_old_time {0.0}
 
std::vector< unsigned char > m_stage_components_seen
 
std::string m_stage_failure_diagnostic
 

Detailed Description

Completed-step time integral of accepted mapped face rates and stage order.

Constructor & Destructor Documentation

◆ CompletedStepFluxLedger() [1/2]

erf_auxiliary::CompletedStepFluxLedger::CompletedStepFluxLedger ( )
default

◆ CompletedStepFluxLedger() [2/2]

erf_auxiliary::CompletedStepFluxLedger::CompletedStepFluxLedger ( const CompletedStepFluxLedger &  )
delete

Member Function Documentation

◆ accept_stage()

bool erf_auxiliary::CompletedStepFluxLedger::accept_stage ( HostIntegrator  method,
int  stage,
double  step_old_time,
const AuxiliaryStageRecipe &  recipe,
const MappedFaceFluxRate &  rate,
std::string &  diagnostic 
)

MPI-collective completed-stage admission. All participating ranks must enter for the same host stage, including after a local recoverable error; callers must not branch around the call based on rank-local predicates. Asynchronous rank-local Abort or MPI process failure is outside this protection. A rejected in-progress transaction discards its partial accepted transfers everywhere. If every rank instead has a valid completed prior step and no rank has begun the next step, rejection leaves that prior completed transfer intact. Starting a valid new step invalidates the previous completed record. Read a transfer as accepted only while step_complete() is true; this object does not provide a retained snapshot.

303 {
304  diagnostic.clear();
305  bool local_stage_ok = true;
306  if (!is_defined() || !rate.is_defined() || rate.nComp() != m_integral.nComp()) {
307  diagnostic = "completed-step ledger and face-rate layouts are not defined compatibly";
308  latch_stage_failure(diagnostic);
309  local_stage_ok = false;
310  } else if (!SameMappedFaceLayout(m_integral, rate)) {
311  diagnostic = "completed-step ledger and face-rate BoxArray/DistributionMapping do not match";
312  latch_stage_failure(diagnostic);
313  local_stage_ok = false;
314  }
315  if (local_stage_ok) {
316  local_stage_ok = begin_stage(method, stage, step_old_time, recipe, diagnostic);
317  }
318  if (local_stage_ok) {
319  for (int component = 0; component < rate.nComp(); ++component) {
320  if (!accumulate_stage_component(rate, component, component, diagnostic)) {
321  local_stage_ok = false;
322  break;
323  }
324  }
325  }
326  const bool accepted = finish_stage(diagnostic);
327  return local_stage_ok && accepted;
328 }
bool finish_stage(std::string &diagnostic)
Definition: ERF_AuxiliaryStage.cpp:458
bool accumulate_stage_component(const MappedFaceFluxRate &rate, int source_component, int ledger_component, std::string &diagnostic)
Definition: ERF_AuxiliaryStage.cpp:421
bool begin_stage(HostIntegrator method, int stage, double step_old_time, const AuxiliaryStageRecipe &recipe, std::string &diagnostic)
Definition: ERF_AuxiliaryStage.cpp:330
IntegratedMappedFaceFlux m_integral
Definition: ERF_AuxiliaryStage.H:183
bool is_defined() const noexcept
Definition: ERF_AuxiliaryStage.H:171
void latch_stage_failure(const std::string &diagnostic)
Definition: ERF_AuxiliaryStage.cpp:271
int nComp() const noexcept
Definition: ERF_AuxiliaryMappedTransport.H:44
bool SameMappedFaceLayout(const MappedFaceField< LhsTag > &lhs, const MappedFaceField< RhsTag > &rhs)
Definition: ERF_AuxiliaryMappedTransport.H:104
Here is the call graph for this function:

◆ accumulate_stage_component()

bool erf_auxiliary::CompletedStepFluxLedger::accumulate_stage_component ( const MappedFaceFluxRate &  rate,
int  source_component,
int  ledger_component,
std::string &  diagnostic 
)

Add one accepted source component to its global ledger component.

424 {
425  diagnostic.clear();
426  const auto fail = [this, &diagnostic] () {
427  latch_stage_failure(diagnostic);
428  return false;
429  };
431  diagnostic = "spectral component accumulation requires an open host stage";
432  return fail();
433  }
434  if (!rate.is_defined() || !SameMappedFaceLayout(m_integral, rate)) {
435  diagnostic = "completed-step ledger and chunk face-rate layouts do not match";
436  return fail();
437  }
438  if (source_component < 0 || source_component >= rate.nComp() ||
439  ledger_component < 0 || ledger_component >= m_integral.nComp()) {
440  diagnostic = "completed-step chunk component is outside its source or destination";
441  return fail();
442  }
443  auto& seen = m_stage_components_seen[static_cast<std::size_t>(ledger_component)];
444  if (seen != 0) {
445  diagnostic = "completed-step stage contains a duplicate destination component";
446  return fail();
447  }
448 
449  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
450  amrex::MultiFab::Saxpy(m_integral.dir(dir), m_open_stage_weight,
451  rate.dir(dir), source_component,
452  ledger_component, 1, 0);
453  }
454  seen = 1;
455  return true;
456 }
amrex::Real m_open_stage_weight
Definition: ERF_AuxiliaryStage.H:190
bool m_step_active
Definition: ERF_AuxiliaryStage.H:184
int m_open_stage
Definition: ERF_AuxiliaryStage.H:189
std::vector< unsigned char > m_stage_components_seen
Definition: ERF_AuxiliaryStage.H:192
bool m_stage_open
Definition: ERF_AuxiliaryStage.H:186
int m_next_stage
Definition: ERF_AuxiliaryStage.H:188
amrex::MultiFab & dir(const int direction)
Definition: ERF_AuxiliaryMappedTransport.H:46

Referenced by accept_stage().

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

◆ begin_stage()

bool erf_auxiliary::CompletedStepFluxLedger::begin_stage ( HostIntegrator  method,
int  stage,
double  step_old_time,
const AuxiliaryStageRecipe &  recipe,
std::string &  diagnostic 
)

Begin one host stage; chunk accumulation does not advance stage order.

335 {
336  diagnostic.clear();
337  if (!m_stage_failure_diagnostic.empty()) {
338  diagnostic = m_stage_failure_diagnostic;
339  return false;
340  }
341  if (!is_defined()) {
342  diagnostic = "completed-step ledger storage is not defined";
343  latch_stage_failure(diagnostic);
344  return false;
345  }
346  if (method == HostIntegrator::AnelasticMidPoint) {
347  diagnostic = "AnelasticMidPoint completed-step ledger is not qualified by M2";
348  latch_stage_failure(diagnostic);
349  return false;
350  }
351  if (stage < 0 || stage >= stage_count(method)) {
352  diagnostic = "stage index is outside the completed-step ledger sequence";
353  latch_stage_failure(diagnostic);
354  return false;
355  }
356  if (!std::isfinite(step_old_time) ||
357  !finite_nonnegative(recipe.anchor_weight) ||
358  !finite_nonnegative(recipe.input_weight) ||
359  !std::isfinite(recipe.limiter_trial_interval) || recipe.limiter_trial_interval <= 0.0 ||
360  !std::isfinite(recipe.face_rate_time_coefficient) || recipe.face_rate_time_coefficient <= 0.0 ||
361  !finite_nonnegative(recipe.completed_ledger_time)) {
362  diagnostic = "completed-step ledger received an invalid temporal coefficient";
363  latch_stage_failure(diagnostic);
364  return false;
365  }
366  const amrex::Real stage_weight =
367  static_cast<amrex::Real>(recipe.completed_ledger_time);
368  if (!amrex::Math::isfinite(stage_weight) || stage_weight < amrex::Real(0.0)) {
369  diagnostic = "completed-step ledger weight is not representable in amrex::Real";
370  latch_stage_failure(diagnostic);
371  return false;
372  }
373  if (m_stage_open) {
374  diagnostic = "a completed-step ledger stage transaction is already open";
375  latch_stage_failure(diagnostic);
376  return false;
377  }
378 
379  if (stage == 0) {
380  if (m_step_active) {
381  diagnostic = "stage 0 arrived while the previous auxiliary step was unfinished";
382  latch_stage_failure(diagnostic);
383  return false;
384  }
386  m_step_active = true;
387  m_step_complete = false;
388  m_method = method;
389  m_step_old_time = step_old_time;
390  m_next_stage = 0;
391  } else {
392  if (!m_step_active) {
393  diagnostic = "auxiliary stage arrived before stage 0";
394  latch_stage_failure(diagnostic);
395  return false;
396  }
397  if (method != m_method) {
398  diagnostic = "host integrator changed during an auxiliary timestep";
399  latch_stage_failure(diagnostic);
400  return false;
401  }
402  if (step_old_time != m_step_old_time) {
403  diagnostic = "step-old time changed during an auxiliary timestep";
404  latch_stage_failure(diagnostic);
405  return false;
406  }
407  }
408  if (stage != m_next_stage) {
409  diagnostic = "duplicate, skipped, or out-of-order auxiliary stage";
410  latch_stage_failure(diagnostic);
411  return false;
412  }
413 
415  m_stage_open = true;
416  m_open_stage = stage;
417  m_open_stage_weight = stage_weight;
418  return true;
419 }
amrex::Real Real
Definition: ERF_ShocInterface.H:19
std::string m_stage_failure_diagnostic
Definition: ERF_AuxiliaryStage.H:193
HostIntegrator m_method
Definition: ERF_AuxiliaryStage.H:187
bool m_step_complete
Definition: ERF_AuxiliaryStage.H:185
double m_step_old_time
Definition: ERF_AuxiliaryStage.H:191
void setVal(const amrex::Real value)
Definition: ERF_AuxiliaryMappedTransport.H:60
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool finite_nonnegative(const amrex::Real value) noexcept
Definition: ERF_SBMRemapping.H:165
void fill(MultiFab &dst, int temperature_comp, int mixing_ratio_comp, int source_comp, const Sources &sources, Real missing_value)
Definition: ERF_NearSurfaceDiagnostics.cpp:41

Referenced by accept_stage().

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

◆ define()

void erf_auxiliary::CompletedStepFluxLedger::define ( const amrex::BoxArray &  cell_ba,
const amrex::DistributionMapping &  dm,
int  ncomp = 1 
)
257 {
258  m_integral.define(cell_ba, dm, ncomp, 0);
260  m_step_active = false;
261  m_step_complete = false;
262  m_stage_open = false;
263  m_next_stage = 0;
264  m_open_stage = -1;
266  m_step_old_time = 0.0;
267  m_stage_components_seen.assign(static_cast<std::size_t>(ncomp), 0);
269 }
void define(const amrex::BoxArray &cell_ba, const amrex::DistributionMapping &dm, const int ncomp, const int ngrow=0)
Definition: ERF_AuxiliaryMappedTransport.H:28
Here is the call graph for this function:

◆ discard_step()

void erf_auxiliary::CompletedStepFluxLedger::discard_step ( )
private
282 {
283  if (m_integral.is_defined()) {
285  }
286  m_step_active = false;
287  m_step_complete = false;
288  m_stage_open = false;
289  m_next_stage = 0;
290  m_open_stage = -1;
292  m_step_old_time = 0.0;
295 }
bool is_defined() const noexcept
Definition: ERF_AuxiliaryMappedTransport.H:43

Referenced by finish_stage().

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

◆ finish_stage()

bool erf_auxiliary::CompletedStepFluxLedger::finish_stage ( std::string &  diagnostic)

MPI-collective stage admission. Every rank participating in this level's call must enter despite local recoverable errors; callers must not branch around it using rank-local predicates. Incomplete, invalid, mismatched, or nonfinite in-progress stages invalidate the partial record everywhere. If all ranks instead have a completed prior step and no active next step, a rejected idle call preserves that prior record. A valid new stage zero invalidates it. A rank that never enters, asynchronous Abort, or MPI process failure is outside this protection.

459 {
460  diagnostic.clear();
461  if (!m_stage_failure_diagnostic.empty()) {
462  diagnostic = m_stage_failure_diagnostic;
463  }
464  const bool local_stage_valid =
467  m_open_stage >= 0 && m_open_stage < stage_count(m_method);
468  if (!local_stage_valid && diagnostic.empty()) {
469  diagnostic = "completed-step stage finish requires an open host stage";
470  }
471 
472  bool all_components_seen = true;
473  for (std::size_t component = 0; component < m_stage_components_seen.size(); ++component) {
474  if (m_stage_components_seen[component] == 0) {
475  all_components_seen = false;
476  if (diagnostic.empty()) {
477  diagnostic =
478  "completed-step stage omitted destination component " +
479  std::to_string(component);
480  }
481  }
482  }
483 
484  // Reserve disjoint ranges for each logical host integrator. A zero code
485  // means that this rank has no locally valid, complete stage transaction.
486  int local_stage_code = 0;
487  if (local_stage_valid && all_components_seen) {
488  switch (m_method) {
490  local_stage_code = 1 + m_open_stage;
491  break;
493  local_stage_code = 4 + m_open_stage;
494  break;
496  local_stage_code = 7 + m_open_stage;
497  break;
498  }
499  }
500  const bool completes_step = local_stage_code != 0 &&
501  m_next_stage + 1 == stage_count(m_method);
502  bool locally_finite = true;
503  if (completes_step) {
504  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
505  locally_finite =
506  m_integral.dir(dir).is_finite(0, m_integral.nComp(), 0, true) &&
507  locally_finite;
508  }
509  }
510  const int prior_complete_and_idle =
512  int vote[4] = {local_stage_code, -local_stage_code, locally_finite ? 0 : -1,
513  prior_complete_and_idle};
514  amrex::ParallelDescriptor::ReduceIntMin(vote, 4);
515  const bool stage_agreed = vote[0] != 0 && vote[0] == -vote[1];
516  const bool globally_finite = vote[2] == 0;
517  const bool all_prior_complete_and_idle = vote[3] == 1;
518  if (!stage_agreed || !globally_finite) {
519  if (!stage_agreed && diagnostic.empty()) {
520  diagnostic = vote[0] == 0
521  ? "completed-step stage is invalid or incomplete on another MPI rank"
522  : "completed-step stage identity differs across MPI ranks";
523  } else if (stage_agreed && !globally_finite && diagnostic.empty()) {
524  diagnostic = locally_finite
525  ? "completed-step integrated face transfer is nonfinite on another MPI rank"
526  : "completed-step integrated face transfer is nonfinite";
527  }
528  if (all_prior_complete_and_idle) {
529  // Keep the diagnostic for this rejected call, but allow a later
530  // valid stage zero to start a fresh transaction.
532  } else {
533  discard_step();
534  }
535  return false;
536  }
537 
538  m_stage_open = false;
539  m_open_stage = -1;
541  ++m_next_stage;
542  if (completes_step) {
543  m_step_active = false;
544  m_step_complete = true;
545  }
547  return true;
548 }
void discard_step()
Definition: ERF_AuxiliaryStage.cpp:281

Referenced by accept_stage().

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

◆ integrated_flux()

const IntegratedMappedFaceFlux& erf_auxiliary::CompletedStepFluxLedger::integrated_flux ( ) const
inlinenoexcept
175  {
176  return m_integral;
177  }

◆ is_defined()

bool erf_auxiliary::CompletedStepFluxLedger::is_defined ( ) const
inlinenoexcept
171 { return m_integral.is_defined(); }

Referenced by accept_stage(), and begin_stage().

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

◆ latch_stage_failure()

void erf_auxiliary::CompletedStepFluxLedger::latch_stage_failure ( const std::string &  diagnostic)
private
273 {
274  if (m_stage_failure_diagnostic.empty()) {
275  m_stage_failure_diagnostic = diagnostic.empty()
276  ? "completed-step ledger stage operation failed"
277  : diagnostic;
278  }
279 }

Referenced by accept_stage(), accumulate_stage_component(), and begin_stage().

Here is the caller graph for this function:

◆ next_stage()

int erf_auxiliary::CompletedStepFluxLedger::next_stage ( ) const
inlinenoexcept
174 { return m_next_stage; }

◆ operator=()

CompletedStepFluxLedger& erf_auxiliary::CompletedStepFluxLedger::operator= ( const CompletedStepFluxLedger &  )
delete

◆ step_active()

bool erf_auxiliary::CompletedStepFluxLedger::step_active ( ) const
inlinenoexcept
172 { return m_step_active; }

◆ step_complete()

bool erf_auxiliary::CompletedStepFluxLedger::step_complete ( ) const
inlinenoexcept
173 { return m_step_complete; }

Member Data Documentation

◆ m_integral

◆ m_method

HostIntegrator erf_auxiliary::CompletedStepFluxLedger::m_method {HostIntegrator::CompressibleRK3}
private

Referenced by begin_stage(), and finish_stage().

◆ m_next_stage

int erf_auxiliary::CompletedStepFluxLedger::m_next_stage {0}
private

◆ m_open_stage

int erf_auxiliary::CompletedStepFluxLedger::m_open_stage {-1}
private

◆ m_open_stage_weight

amrex::Real erf_auxiliary::CompletedStepFluxLedger::m_open_stage_weight {0.0}
private

◆ m_stage_components_seen

std::vector<unsigned char> erf_auxiliary::CompletedStepFluxLedger::m_stage_components_seen
private

◆ m_stage_failure_diagnostic

std::string erf_auxiliary::CompletedStepFluxLedger::m_stage_failure_diagnostic
private

◆ m_stage_open

bool erf_auxiliary::CompletedStepFluxLedger::m_stage_open {false}
private

◆ m_step_active

bool erf_auxiliary::CompletedStepFluxLedger::m_step_active {false}
private

◆ m_step_complete

bool erf_auxiliary::CompletedStepFluxLedger::m_step_complete {false}
private

◆ m_step_old_time

double erf_auxiliary::CompletedStepFluxLedger::m_step_old_time {0.0}
private

Referenced by begin_stage(), define(), and discard_step().


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