ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SpectralGrid.H
Go to the documentation of this file.
1 #ifndef ERF_SPECTRAL_GRID_H_
2 #define ERF_SPECTRAL_GRID_H_
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_GpuQualifiers.H>
6 #include <AMReX_Math.H>
7 
8 #include <cmath>
9 #include <limits>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 namespace erf_sbm {
15 
16 // Coordinate mathematics is phase-neutral. Population metadata carries the
17 // material/phase semantic (liquid, ice, aerosol, ...).
18 enum class CoordinateKind { Mass, Radius };
19 enum class MomentMode { OneMoment, TwoMoment };
20 
23  std::string coordinate_units{"kg"};
24  std::vector<amrex::Real> edges;
25  std::vector<amrex::Real> pivots;
26 };
27 
29  bool valid{false};
30  std::string message;
31 };
32 
33 /** Endpoint-number coordinates and tolerances for one 2M bin. */
35  amrex::Real L{0.0};
36  amrex::Real H{0.0};
39  bool normalized_roundoff{false};
40 };
41 
42 /**
43  * Allocation-free canonical forward transform used by host and device code.
44  * Returns false instead of throwing when the state is invalid or materially
45  * unrealizable. The throwing host API below delegates to this function.
46  */
47 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
49  const amrex::Real lower, const amrex::Real upper,
50  EndpointTransform& result) noexcept
51 {
52  if (!amrex::Math::isfinite(C) || !amrex::Math::isfinite(M) || !amrex::Math::isfinite(lower) ||
53  !amrex::Math::isfinite(upper) || lower < amrex::Real(0.0) ||
54  !(lower < upper) || C < amrex::Real(0.0)) {
55  return false;
56  }
57  const amrex::Real scale = std::abs(M) + std::abs(lower * C) + std::abs(upper * C);
58  const amrex::Real moment_tolerance = amrex::Real(128.0) *
60  const amrex::Real low_numerator = std::fma(upper, C, -M);
61  const amrex::Real high_numerator = std::fma(-lower, C, M);
62  if (!amrex::Math::isfinite(scale) || !amrex::Math::isfinite(moment_tolerance) ||
63  !amrex::Math::isfinite(low_numerator) || !amrex::Math::isfinite(high_numerator) ||
64  low_numerator < -moment_tolerance || high_numerator < -moment_tolerance) {
65  return false;
66  }
67  if (C == amrex::Real(0.0)) {
68  if (std::abs(M) > moment_tolerance) return false;
69  result = {amrex::Real(0.0), amrex::Real(0.0), moment_tolerance,
70  moment_tolerance / (upper - lower), M != amrex::Real(0.0)};
71  return amrex::Math::isfinite(result.endpoint_tolerance);
72  }
73  const amrex::Real denominator = upper - lower;
74  amrex::Real L = low_numerator / denominator;
75  amrex::Real H = high_numerator / denominator;
76  const amrex::Real endpoint_tolerance = moment_tolerance / denominator;
77  if (!amrex::Math::isfinite(L) || !amrex::Math::isfinite(H) || !amrex::Math::isfinite(endpoint_tolerance)) {
78  return false;
79  }
80  const bool normalized = L < amrex::Real(0.0) || H < amrex::Real(0.0);
81  if (L < amrex::Real(0.0)) L = amrex::Real(0.0);
82  if (H < amrex::Real(0.0)) H = amrex::Real(0.0);
83  result = {L, H, moment_tolerance, endpoint_tolerance, normalized};
84  return true;
85 }
86 
87 /** Allocation-free canonical inverse transform for host and device callers. */
88 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
90  const amrex::Real lower, const amrex::Real upper,
91  amrex::Real& C, amrex::Real& M) noexcept
92 {
93  if (!amrex::Math::isfinite(L) || !amrex::Math::isfinite(H) || !amrex::Math::isfinite(lower) ||
94  !amrex::Math::isfinite(upper) || L < amrex::Real(0.0) || H < amrex::Real(0.0) ||
95  lower < amrex::Real(0.0) || !(lower < upper)) {
96  return false;
97  }
98  const amrex::Real count = L + H;
99  const amrex::Real mass = std::fma(lower, L, upper * H);
100  if (!amrex::Math::isfinite(count) || !amrex::Math::isfinite(mass) ||
101  count < amrex::Real(0.0) || mass < amrex::Real(0.0)) {
102  return false;
103  }
104  C = count;
105  M = mass;
106  return true;
107 }
108 
109 /** Runtime-sized, immutable-after-construction spectral grid. */
111 public:
112  static GridValidation validate (const SpectralGridSpec& spec);
113 
114  explicit SpectralGrid (SpectralGridSpec spec);
115 
116  [[nodiscard]] CoordinateKind coordinate_kind () const noexcept { return m_spec.coordinate_kind; }
117  [[nodiscard]] const std::string& coordinate_units () const noexcept { return m_spec.coordinate_units; }
118  [[nodiscard]] const std::vector<amrex::Real>& edges () const noexcept { return m_spec.edges; }
119  [[nodiscard]] const std::vector<amrex::Real>& pivots () const noexcept { return m_spec.pivots; }
120  [[nodiscard]] int nbins () const noexcept { return static_cast<int>(m_spec.edges.size()) - 1; }
121 
122  [[nodiscard]] amrex::Real pivot (const int bin) const { return m_spec.pivots.at(static_cast<std::size_t>(bin)); }
123  [[nodiscard]] std::string identity () const;
124 
125  // For a two-moment endpoint representation, L/H are number-equivalent
126  // endpoint masses and C/M are count and first-moment densities.
127  [[nodiscard]] static bool two_moment_realizable (amrex::Real C, amrex::Real M,
128  amrex::Real lower, amrex::Real upper) noexcept;
129  [[nodiscard]] static EndpointTransform
131  amrex::Real lower, amrex::Real upper);
132  [[nodiscard]] static std::pair<amrex::Real, amrex::Real>
134  amrex::Real lower, amrex::Real upper);
135 
136 private:
138 };
139 
140 } // namespace erf_sbm
141 
142 #endif
Real H
Definition: ERF_InitCustomPert_MovingTerrain.H:7
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_SpectralGrid.H:110
std::string identity() const
Definition: ERF_SpectralGrid.cpp:48
int nbins() const noexcept
Definition: ERF_SpectralGrid.H:120
const std::vector< amrex::Real > & pivots() const noexcept
Definition: ERF_SpectralGrid.H:119
amrex::Real pivot(const int bin) const
Definition: ERF_SpectralGrid.H:122
static bool two_moment_realizable(amrex::Real C, amrex::Real M, amrex::Real lower, amrex::Real upper) noexcept
Definition: ERF_SpectralGrid.cpp:59
SpectralGrid(SpectralGridSpec spec)
Definition: ERF_SpectralGrid.cpp:42
static std::pair< amrex::Real, amrex::Real > endpoints_to_two_moment(amrex::Real L, amrex::Real H, amrex::Real lower, amrex::Real upper)
Definition: ERF_SpectralGrid.cpp:78
CoordinateKind coordinate_kind() const noexcept
Definition: ERF_SpectralGrid.H:116
SpectralGridSpec m_spec
Definition: ERF_SpectralGrid.H:137
static EndpointTransform two_moment_to_endpoints(amrex::Real C, amrex::Real M, amrex::Real lower, amrex::Real upper)
Definition: ERF_SpectralGrid.cpp:67
static GridValidation validate(const SpectralGridSpec &spec)
Definition: ERF_SpectralGrid.cpp:13
const std::string & coordinate_units() const noexcept
Definition: ERF_SpectralGrid.H:117
const std::vector< amrex::Real > & edges() const noexcept
Definition: ERF_SpectralGrid.H:118
Definition: ERF.H:108
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool try_endpoints_to_two_moment(const amrex::Real L, const amrex::Real H, const amrex::Real lower, const amrex::Real upper, amrex::Real &C, amrex::Real &M) noexcept
Definition: ERF_SpectralGrid.H:89
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool try_two_moment_to_endpoints(const amrex::Real C, const amrex::Real M, const amrex::Real lower, const amrex::Real upper, EndpointTransform &result) noexcept
Definition: ERF_SpectralGrid.H:48
MomentMode
Definition: ERF_SpectralGrid.H:19
CoordinateKind
Definition: ERF_SpectralGrid.H:18
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
Definition: ERF_SpectralGrid.H:34
amrex::Real L
Definition: ERF_SpectralGrid.H:35
amrex::Real endpoint_tolerance
Definition: ERF_SpectralGrid.H:38
amrex::Real H
Definition: ERF_SpectralGrid.H:36
bool normalized_roundoff
Definition: ERF_SpectralGrid.H:39
amrex::Real moment_tolerance
Definition: ERF_SpectralGrid.H:37
Definition: ERF_SpectralGrid.H:28
bool valid
Definition: ERF_SpectralGrid.H:29
std::string message
Definition: ERF_SpectralGrid.H:30
Definition: ERF_SpectralGrid.H:21
std::string coordinate_units
Definition: ERF_SpectralGrid.H:23
std::vector< amrex::Real > pivots
Definition: ERF_SpectralGrid.H:25
std::vector< amrex::Real > edges
Definition: ERF_SpectralGrid.H:24
CoordinateKind coordinate_kind
Definition: ERF_SpectralGrid.H:22