ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_AuxiliaryMappedTransport.H
Go to the documentation of this file.
1 #ifndef ERF_AUXILIARY_MAPPED_TRANSPORT_H_
2 #define ERF_AUXILIARY_MAPPED_TRANSPORT_H_
3 
4 #include <AMReX_Array4.H>
5 #include <AMReX.H>
6 #include <AMReX_GpuQualifiers.H>
7 #include <AMReX_MultiFab.H>
8 
9 #include <array>
10 #include <memory>
11 #include <string>
12 
13 namespace erf_auxiliary {
14 
17 
18 /** A directionally face-centered mapped-coordinate field with a semantic tag. */
19 template <typename Tag>
21 public:
22  MappedFaceField () = default;
23  MappedFaceField (const MappedFaceField&) = delete;
25  MappedFaceField (MappedFaceField&&) noexcept = default;
26  MappedFaceField& operator= (MappedFaceField&&) noexcept = default;
27 
28  void define (const amrex::BoxArray& cell_ba,
29  const amrex::DistributionMapping& dm,
30  const int ncomp,
31  const int ngrow = 0)
32  {
33  AMREX_ALWAYS_ASSERT(ncomp > 0);
34  AMREX_ALWAYS_ASSERT(ngrow >= 0);
35  m_ncomp = ncomp;
36  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
37  m_faces[static_cast<std::size_t>(dir)] = std::make_unique<amrex::MultiFab>(
38  amrex::convert(cell_ba, amrex::IntVect::TheDimensionVector(dir)),
39  dm, ncomp, ngrow);
40  }
41  }
42 
43  [[nodiscard]] bool is_defined () const noexcept { return m_ncomp > 0; }
44  [[nodiscard]] int nComp () const noexcept { return m_ncomp; }
45 
46  amrex::MultiFab& dir (const int direction)
47  {
48  AMREX_ALWAYS_ASSERT(direction >= 0 && direction < AMREX_SPACEDIM);
49  AMREX_ALWAYS_ASSERT(m_faces[static_cast<std::size_t>(direction)] != nullptr);
50  return *m_faces[static_cast<std::size_t>(direction)];
51  }
52 
53  const amrex::MultiFab& dir (const int direction) const
54  {
55  AMREX_ALWAYS_ASSERT(direction >= 0 && direction < AMREX_SPACEDIM);
56  AMREX_ALWAYS_ASSERT(m_faces[static_cast<std::size_t>(direction)] != nullptr);
57  return *m_faces[static_cast<std::size_t>(direction)];
58  }
59 
60  void setVal (const amrex::Real value)
61  {
63  for (auto& face : m_faces) { face->setVal(value); }
64  }
65 
66 private:
67  std::array<std::unique_ptr<amrex::MultiFab>, AMREX_SPACEDIM> m_faces{};
68  int m_ncomp{0};
69 };
70 
73 
74 /** Exact cell-centered BoxArray and DistributionMapping identity. */
75 bool SameCellLayout (const amrex::MultiFab& lhs, const amrex::MultiFab& rhs);
76 
77 /** Check directional face staggering and ownership against a cell layout. */
78 template <typename Tag>
80  const amrex::BoxArray& cell_ba,
81  const amrex::DistributionMapping& dm)
82 {
83  if (!faces.is_defined()) { return false; }
84  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
85  const auto& face = faces.dir(dir);
86  if (face.boxArray() !=
87  amrex::convert(cell_ba, amrex::IntVect::TheDimensionVector(dir)) ||
88  face.DistributionMap() != dm) {
89  return false;
90  }
91  }
92  return true;
93 }
94 
95 template <typename Tag>
97  const amrex::MultiFab& cell)
98 {
99  return MappedFaceLayoutMatchesCellLayout(faces, cell.boxArray(), cell.DistributionMap());
100 }
101 
102 /** Check that two semantically tagged face fields have identical face layouts. */
103 template <typename LhsTag, typename RhsTag>
105  const MappedFaceField<RhsTag>& rhs)
106 {
107  if (!lhs.is_defined() || !rhs.is_defined()) { return false; }
108  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
109  if (lhs.dir(dir).boxArray() != rhs.dir(dir).boxArray() ||
110  lhs.dir(dir).DistributionMap() != rhs.dir(dir).DistributionMap()) {
111  return false;
112  }
113  }
114  return true;
115 }
116 
117 /** Computational-coordinate divergence only: no metric or physical face area. */
118 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real
120  const amrex::Real fx_lo,
121  const amrex::Real fy_hi,
122  const amrex::Real fy_lo,
123  const amrex::Real fz_hi,
124  const amrex::Real fz_lo,
125  const amrex::Real dx_inv,
126  const amrex::Real dy_inv,
127  const amrex::Real dzeta_inv) noexcept
128 {
129  return (fx_hi - fx_lo) * dx_inv +
130  (fy_hi - fy_lo) * dy_inv +
131  (fz_hi - fz_lo) * dzeta_inv;
132 }
133 
134 /** Outgoing donor rate for one cell in mapped coordinates. */
135 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real
137  const amrex::Real fx_lo,
138  const amrex::Real fy_hi,
139  const amrex::Real fy_lo,
140  const amrex::Real fz_hi,
141  const amrex::Real fz_lo,
142  const amrex::Real measure,
143  const amrex::Real density,
144  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx_inv) noexcept
145 {
146  const amrex::Real outward =
147  (amrex::max(fx_hi, amrex::Real(0.0)) +
148  amrex::max(-fx_lo, amrex::Real(0.0))) * dx_inv[0] +
149  (amrex::max(fy_hi, amrex::Real(0.0)) +
150  amrex::max(-fy_lo, amrex::Real(0.0))) * dx_inv[1] +
151  (amrex::max(fz_hi, amrex::Real(0.0)) +
152  amrex::max(-fz_lo, amrex::Real(0.0))) * dx_inv[2];
153  return outward / (measure * density);
154 }
155 
156 /** Build the production mapped dry-air face rates from face momentum and metrics. */
158  MappedFaceFluxRate& rate,
159  const amrex::MultiFab& rho_u,
160  const amrex::MultiFab& rho_v,
161  const amrex::MultiFab& omega,
162  const amrex::MultiFab& ax,
163  const amrex::MultiFab& ay,
164  const amrex::MultiFab& az,
165  const amrex::MultiFab& mf_uy,
166  const amrex::MultiFab& mf_vx,
167  const amrex::MultiFab& mx,
168  const amrex::MultiFab& my,
169  std::string& diagnostic);
170 
171 /** Copy face fields that are already in ERF's native mapped carrier convention. */
173  MappedFaceFluxRate& rate,
174  const amrex::MultiFab& rho_u,
175  const amrex::MultiFab& rho_v,
176  const amrex::MultiFab& rho_w,
177  std::string& diagnostic);
178 
179 /** Reduce the largest mapped donor outgoing rate over a cell-centered domain. */
181  const MappedFaceFluxRate& rate,
182  const amrex::MultiFab& measure,
183  const amrex::MultiFab& conserved,
184  int density_component,
185  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx_inv,
186  amrex::Real& max_rate,
187  std::string& diagnostic);
188 
189 /** Test a fixed interval against the hard mapped donor-positivity bound. */
190 bool FixedDtExceedsMappedDonorLimit (double fixed_dt,
191  amrex::Real max_outgoing_rate,
192  double& hard_limit) noexcept;
193 
194 /** Build omega=detJ/(mx*my), returning false and a diagnostic on invalid cells. */
195 bool BuildMappedCellMeasure (amrex::MultiFab& omega,
196  const amrex::MultiFab& detJ,
197  const amrex::MultiFab& mx,
198  const amrex::MultiFab& my,
199  std::string& diagnostic);
200 
201 /** Check that a selected cell-centered component is finite and strictly positive. */
202 bool ValidatePositiveFiniteComponent (const amrex::MultiFab& field,
203  int component,
204  std::string& diagnostic);
205 
206 /** Check that a selected cell-centered component is finite. */
207 bool ValidateFiniteComponent (const amrex::MultiFab& field,
208  int component,
209  std::string& diagnostic);
210 
211 /**
212  * Apply -D_xi(flux)/omega into one selected output component. The supplied
213  * face values are already in ERF's mapped coordinate convention.
214  */
215 template <typename Tag>
217  const MappedFaceField<Tag>& flux,
218  const int flux_comp,
219  const amrex::MultiFab& omega,
220  const int omega_comp,
221  amrex::MultiFab& tendency,
222  const int tendency_comp,
223  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx_inv)
224 {
226  AMREX_ALWAYS_ASSERT(flux_comp >= 0 && flux_comp < flux.nComp());
227  AMREX_ALWAYS_ASSERT(omega_comp >= 0 && omega_comp < omega.nComp());
228  AMREX_ALWAYS_ASSERT(tendency_comp >= 0 && tendency_comp < tendency.nComp());
231 
232  for (amrex::MFIter mfi(tendency, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) {
233  const amrex::Box bx = mfi.tilebox();
234  const auto fx = flux.dir(0).const_array(mfi);
235  const auto fy = flux.dir(1).const_array(mfi);
236  const auto fz = flux.dir(2).const_array(mfi);
237  const auto measure = omega.const_array(mfi);
238  const auto out = tendency.array(mfi);
239  const auto dx = dx_inv[0];
240  const auto dy = dx_inv[1];
241  const auto dz = dx_inv[2];
242 
243  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
245  fx(i + 1, j, k, flux_comp), fx(i, j, k, flux_comp),
246  fy(i, j + 1, k, flux_comp), fy(i, j, k, flux_comp),
247  fz(i, j, k + 1, flux_comp), fz(i, j, k, flux_comp),
248  dx, dy, dz);
249  out(i, j, k, tendency_comp) = -div / measure(i, j, k, omega_comp);
250  });
251  }
252 }
253 
254 /** Return the max absolute difference between two component-selected face fields. */
256  int lhs_comp,
257  const MappedFaceFluxRate& rhs,
258  int rhs_comp);
259 
260 /** Scale every component and direction of a flux rate into an integrated ledger. */
262  const MappedFaceFluxRate& rate,
263  amrex::Real weight);
264 
265 } // namespace erf_auxiliary
266 
267 #endif
const Real dy
Definition: ERF_InitCustomPert_ABL.H:45
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_AuxiliaryMappedTransport.H:20
const amrex::MultiFab & dir(const int direction) const
Definition: ERF_AuxiliaryMappedTransport.H:53
MappedFaceField(MappedFaceField &&) noexcept=default
std::array< std::unique_ptr< amrex::MultiFab >, AMREX_SPACEDIM > m_faces
Definition: ERF_AuxiliaryMappedTransport.H:67
int nComp() const noexcept
Definition: ERF_AuxiliaryMappedTransport.H:44
amrex::MultiFab & dir(const int direction)
Definition: ERF_AuxiliaryMappedTransport.H:46
MappedFaceField(const MappedFaceField &)=delete
bool is_defined() const noexcept
Definition: ERF_AuxiliaryMappedTransport.H:43
int m_ncomp
Definition: ERF_AuxiliaryMappedTransport.H:68
void define(const amrex::BoxArray &cell_ba, const amrex::DistributionMapping &dm, const int ncomp, const int ngrow=0)
Definition: ERF_AuxiliaryMappedTransport.H:28
MappedFaceField & operator=(const MappedFaceField &)=delete
void setVal(const amrex::Real value)
Definition: ERF_AuxiliaryMappedTransport.H:60
@ omega
Definition: ERF_Morrison.H:55
@ dz
Definition: ERF_AdvanceWDM6.cpp:272
Definition: ERF_ConsoleIO.cpp:17
Definition: ERF_AuxiliaryInertTracer.cpp:15
bool BuildMappedCellMeasure(amrex::MultiFab &omega, const amrex::MultiFab &detJ, const amrex::MultiFab &mx, const amrex::MultiFab &my, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:42
void AccumulateIntegratedFaceFlux(IntegratedMappedFaceFlux &ledger, const MappedFaceFluxRate &rate, const amrex::Real weight)
Definition: ERF_AuxiliaryMappedTransport.cpp:378
bool ComputeMaxMappedOutgoingRate(const MappedFaceFluxRate &rate, const amrex::MultiFab &measure, const amrex::MultiFab &conserved, const int density_component, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx_inv, amrex::Real &max_rate, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:218
void ApplyMappedFluxTendency(const MappedFaceField< Tag > &flux, const int flux_comp, const amrex::MultiFab &omega, const int omega_comp, amrex::MultiFab &tendency, const int tendency_comp, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx_inv)
Definition: ERF_AuxiliaryMappedTransport.H:216
amrex::Real MaxFaceFieldDifference(const MappedFaceFluxRate &lhs, const int lhs_comp, const MappedFaceFluxRate &rhs, const int rhs_comp)
Definition: ERF_AuxiliaryMappedTransport.cpp:349
bool ValidateFiniteComponent(const amrex::MultiFab &field, const int component, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:322
bool CopyNativeMappedDryAirCarrierFluxRate(MappedFaceFluxRate &rate, const amrex::MultiFab &rho_u, const amrex::MultiFab &rho_v, const amrex::MultiFab &rho_w, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:179
MappedFaceField< MappedFaceFluxRateTag > MappedFaceFluxRate
Definition: ERF_AuxiliaryMappedTransport.H:71
bool BuildMappedDryAirCarrierFluxRate(MappedFaceFluxRate &rate, const amrex::MultiFab &rho_u, const amrex::MultiFab &rho_v, const amrex::MultiFab &omega, const amrex::MultiFab &ax, const amrex::MultiFab &ay, const amrex::MultiFab &az, const amrex::MultiFab &mf_uy, const amrex::MultiFab &mf_vx, const amrex::MultiFab &mx, const amrex::MultiFab &my, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:90
bool ValidatePositiveFiniteComponent(const amrex::MultiFab &field, const int component, std::string &diagnostic)
Definition: ERF_AuxiliaryMappedTransport.cpp:294
MappedFaceField< IntegratedMappedFaceFluxTag > IntegratedMappedFaceFlux
Definition: ERF_AuxiliaryMappedTransport.H:72
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real ComputationalMappedDivergence(const amrex::Real fx_hi, const amrex::Real fx_lo, const amrex::Real fy_hi, const amrex::Real fy_lo, const amrex::Real fz_hi, const amrex::Real fz_lo, const amrex::Real dx_inv, const amrex::Real dy_inv, const amrex::Real dzeta_inv) noexcept
Definition: ERF_AuxiliaryMappedTransport.H:119
bool MappedFaceLayoutMatchesCellLayout(const MappedFaceField< Tag > &faces, const amrex::BoxArray &cell_ba, const amrex::DistributionMapping &dm)
Definition: ERF_AuxiliaryMappedTransport.H:79
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real MappedOutgoingDemandRate(const amrex::Real fx_hi, const amrex::Real fx_lo, const amrex::Real fy_hi, const amrex::Real fy_lo, const amrex::Real fz_hi, const amrex::Real fz_lo, const amrex::Real measure, const amrex::Real density, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx_inv) noexcept
Definition: ERF_AuxiliaryMappedTransport.H:136
bool SameCellLayout(const amrex::MultiFab &lhs, const amrex::MultiFab &rhs)
Definition: ERF_AuxiliaryMappedTransport.cpp:36
bool FixedDtExceedsMappedDonorLimit(const double fixed_dt, const amrex::Real max_outgoing_rate, double &hard_limit) noexcept
Definition: ERF_AuxiliaryMappedTransport.cpp:268
bool SameMappedFaceLayout(const MappedFaceField< LhsTag > &lhs, const MappedFaceField< RhsTag > &rhs)
Definition: ERF_AuxiliaryMappedTransport.H:104
Definition: ERF_AuxiliaryMappedTransport.H:16
Definition: ERF_AuxiliaryMappedTransport.H:15