ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SuperDropletsMoist.H
Go to the documentation of this file.
1 #ifndef SUPERDROPLETSMOIST_H
2 #define SUPERDROPLETSMOIST_H
3 
4 #ifdef ERF_USE_PARTICLES
5 
6 #include <limits>
7 #include <string>
8 #include <AMReX_Enum.H>
9 #include <AMReX_Geometry.H>
10 #include <AMReX_iMultiFab.H>
11 #include <AMReX_MultiFabUtil.H>
13 #include "ERF_SuperDropletPC.H"
14 
15 namespace MicVar_SD {
16  enum {
17  rho = 0, /*!< Density */
18  theta, /*!< Potential temperature */
19  temperature, /*!< Temperature */
20  pressure, /*!< Pressure */
21  q_t, /*!< Total (vapour + cloud) */
22  q_v, /*!< Water vapour */
23  q_c, /*!< Cloud condensate */
24  dqcdt, /*!< Condensation rate */
25  q_r, /*!< Rain */
26  rh, /*!< relative humidity */
27  rain_accum, /*!< rain accumulation (mm) */
28  NumVars
29  };
30 }
31 
32 namespace MicVar_SD_Species {
33  enum {
34  q_t = 0, /*!< Total density ratio */
35  q_v, /*!< Vapour density ratio */
36  q_c, /*!< Condensate density ratio */
37  sr, /*!< Saturation ratio */
38  accum, /*!< Ground accumulation */
39  NumVars
40  };
41 }
42 
43 namespace MicVar_SD_Aerosols {
44  enum {
45  accum = 0, /*!< Ground accumulation */
46  NumVars
47  };
48 }
49 
50 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
51 static int s_qt_idx (const int a_i /*!< species index */ )
52 {
53  AMREX_ALWAYS_ASSERT(a_i > 0);
54  return MicVar_SD::NumVars
57 }
58 
59 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
60 static int s_qv_idx (const int a_i /*!< species index */ )
61 {
62  AMREX_ALWAYS_ASSERT(a_i > 0);
63  return MicVar_SD::NumVars
65  + MicVar_SD_Species::q_v;
66 }
67 
68 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
69 static int s_qc_idx (const int a_i /*!< species index */ )
70 {
71  AMREX_ALWAYS_ASSERT(a_i > 0);
72  return MicVar_SD::NumVars
74  + MicVar_SD_Species::q_c;
75 }
76 
77 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
78 static int s_sr_idx (const int a_i /*!< species index */ )
79 {
80  AMREX_ALWAYS_ASSERT(a_i > 0);
81  return MicVar_SD::NumVars
83  + MicVar_SD_Species::sr;
84 }
85 
86 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
87 static int s_accum_idx (const int a_i /*!< species index */ )
88 {
89  AMREX_ALWAYS_ASSERT(a_i > 0);
90  return MicVar_SD::NumVars
92  + MicVar_SD_Species::accum;
93 }
94 
95 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
96 static int a_accum_idx (const int a_ns, /*!< number of species */
97  const int a_i /*!< aerosol index */ )
98 {
99  AMREX_ALWAYS_ASSERT(a_i >= 0);
100  return MicVar_SD::NumVars
101  + (a_ns-1)*MicVar_SD_Species::NumVars
103  + MicVar_SD_Aerosols::accum;
104 }
105 
106 /*! \brief List of super-droplet moisture model initializations */
107 AMREX_ENUM(SDMoistInit,
108  uniform,
109  condensate_density
110 );
111 
112 AMREX_ENUM(SDMSimulationDim,
113  one_d_z, two_d_xz, two_d_yz, three_d
114 );
115 
116 class SuperDropletsMoist : public NullMoistLagrangian {
117 
118  using FabPtr = std::shared_ptr<amrex::MultiFab>;
119  using MFPtr = std::unique_ptr<amrex::MultiFab>;
120  using BCTypeArr = amrex::GpuArray<ERF_BC, AMREX_SPACEDIM*2>;
121 
122  public:
123 
124  /*! \brief Constructor */
125  SuperDropletsMoist()
126  {
127  m_qmoist_size = 7;
128  m_qstate_moist_size = 3; // qv, qc, qr
129  m_qstate_nonmoist_size = -1; // sentinel; readInputs() sets the actual count before construction returns
130  m_name = "super_droplets_moisture";
131  m_idx_w = -1;
132  m_num_species = 0;
133  m_num_aerosols = 0;
134  readInputs();
135  }
136 
137  /*! \brief Destructor */
138  virtual ~SuperDropletsMoist() = default;
139 
140  /*! \brief Define super-droplet moisture model parameters */
141  virtual void Define (SolverChoice&) override;
142 
143  /*! \brief Initialize super-droplet moisture model data structures */
144  virtual void Init ( const amrex::MultiFab&,
145  const amrex::BoxArray&,
146  const amrex::Geometry&,
147  const amrex::Real&,
148  MFPtr&,
149  MFPtr& ) override;
150 
151  /*! \brief Initialize particles at AMR level */
152  virtual void InitParticles ( const int, MFPtr& ) override;
153 
154  /*! \brief Restart particles */
155  virtual void RestartParticles ( amrex::ParGDBBase*, const std::string& ) override;
156 
157  /*! \brief finish initializations */
158  virtual void FinishInit(const int&,
159  amrex::MultiFab&,
160  const amrex::Vector<MFPtr>&) override;
161 
162  void Advance ( const amrex::Real&, const SolverChoice& ) override
163  {
164  amrex::Abort("Do not use this advance() for Lagrangian microphysics.");
165  }
166 
167  /*! \brief Set the current AMR level being processed */
168  void SetCurrentLevel (const int& a_lev) override { m_current_lev = a_lev; }
169 
170  /*! \brief Get the diagnostics interval */
171  int getDiagnosticsInterval () const override { return m_diagnostics_iter; }
172 
173  /*! \brief Ensure m_mic_fab_vars[lev] is allocated for the given level */
174  void EnsureMicFabVars (const int a_lev, const amrex::MultiFab& a_cons_vars);
175 
176  /*! \brief Build a coarse-cell mask: 1 where exposed, 0 where covered by a finer level */
177  amrex::iMultiFab buildFineMask (const int a_lev) const;
178 
179  /*! \brief Initialize m_mic_fab_vars for a non-zero AMR level */
180  void InitLevel (const int a_lev, const amrex::MultiFab& a_cons_vars) override;
181 
182  /*! \brief Advance for one timestep
183  * \param[in] dt Timestep
184  * \param[in] iteration Current iteration number
185  * \param[in] time Current simulation time
186  * \param[in,out] cons_vars Array of conserved variables
187  * \param[in] mf_array Array of additional multifabs
188  * \param[in] bc_arr Array of boundary conditions
189  */
190  virtual void Advance (const amrex::Real& dt,
191  const int& iteration,
192  const amrex::Real& time,
193  amrex::Vector<amrex::Vector<amrex::MultiFab>>& cons_vars,
194  const amrex::Vector<MFPtr>& mf_array,
195  const BCTypeArr& bc_arr) override;
196 
198 
199  /*! \brief Update microphysics variables
200  * \param[in] a_cons_vars Conservative variables multifab
201  */
202  virtual void Update_Micro_Vars (amrex::MultiFab& a_cons_vars) override;
203 
204  /*! \brief Update state variables from microphysics variables
205  * \param[in,out] a_cons_vars Conservative variables multifab to update
206  * \param[in] a_z_phys_nd Terrain heights (nodal)
207  */
208  virtual void Update_State_Vars (amrex::MultiFab& a_cons_vars,
209  const amrex::MultiFab& a_z_phys_nd) override;
210 
211  /*! \brief Average down moisture multifabs from finest_level down to 0 */
212  virtual void AverageDownMicroVars (const int finest_level) override;
213 
214  /*! \brief Copy moisture model vars from state to member multifabs
215  * \param[in] a_state State multifab to copy from
216  */
217  virtual void Copy_State_to_Micro (const amrex::MultiFab& a_state) override;
218 
219  /*! \brief Copy moisture model vars to state from member multifabs
220  * \param[out] a_state State multifab to copy to
221  */
222  virtual void Copy_Micro_to_State (amrex::MultiFab& a_state) override;
223 
224  /*! \brief returns the moisture variable asked for */
225  inline virtual amrex::MultiFab* Qmoist_Ptr (const int& a_idx) override
226  {
227  AMREX_ALWAYS_ASSERT( a_idx < m_qmoist_size );
228  const int lev = m_current_lev;
229  if (lev < 0 || lev >= static_cast<int>(m_mic_fab_vars.size()) ||
230  m_mic_var_map[a_idx] < 0 || m_mic_var_map[a_idx] >= static_cast<int>(m_mic_fab_vars[lev].size())) {
231  return nullptr;
232  }
233  return m_mic_fab_vars[lev][m_mic_var_map[a_idx]].get();
234  }
235 
236  /*! \brief returns number of variables in this moisture model */
237  inline virtual int Qmoist_Size () override
238  {
239  return m_qmoist_size;
240  }
241 
242  /*! \brief returns the surface rain accumulation (mm, i.e. kg/m^2 of liquid water) */
244  Get_Surface_Precip_Accumulation_Ptrs (const int& a_lev) const override
245  {
247  if (a_lev >= 0 && a_lev < static_cast<int>(m_mic_fab_vars.size())) {
248  sources.rain = { m_mic_fab_vars[a_lev][MicVar_SD::rain_accum].get(),
249  amrex::Real(1.0) };
250  }
251  return sources;
252  }
253 
254  /*! \brief returns number of moist conserved variables */
255  inline virtual int Qstate_Moist_Size () override
256  {
257  return m_qstate_moist_size;
258  }
259 
260  /*! \brief returns number of moist conserved variables that are number concentrations */
261  inline virtual int Qstate_Moist_NumConc_Size () override
262  {
263  return m_qstate_moist_numconc_size;
264  }
265 
266  /*! \brief returns number of non-water species conserved variables */
267  inline virtual int Qstate_NonMoist_Size () override
268  {
269  AMREX_ALWAYS_ASSERT(m_qstate_nonmoist_size >= 0);
270  return m_qstate_nonmoist_size;
271  }
272 
273  /*! \brief returns pointer to super-droplets particle container */
274  inline virtual ERFPC* getParticleContainer() override
275  {
276  return m_super_droplets;
277  }
278 
279  inline virtual const std::string& getName() const override
280  {
281  return m_name;
282  }
283 
284  /*! \brief compute cloud/rain mixing ratio */
285  virtual void computeQcQrWater (const amrex::MultiFab& a_z_phys_nd);
286 
287  /*! \brief compute condensate for all non-water species */
288  virtual void computeQcSpecies (const amrex::MultiFab& a_z_phys_nd)
289  {
290  for (int is = 1; is < m_num_species; is++) { computeQcSpecies(is, a_z_phys_nd); }
291  }
292 
293  /*! \brief compute condensate mixing ratio for a non-water species */
294  virtual void computeQcSpecies (const int a_i, const amrex::MultiFab& a_z_phys_nd);
295 
296  /*! \brief compute condensate mixing ratio for a species */
297  virtual void computeQc (const int a_i, const amrex::MultiFab& a_z_phys_nd)
298  {
299  if (a_i == m_idx_w) { computeQcQrWater(a_z_phys_nd); }
300  else { computeQcSpecies(a_i, a_z_phys_nd); }
301  }
302 
303  /*! \brief compute total water mixing ratio */
304  virtual void computeQtWater ();
305 
306  /*! \brief compute qt (total) for all non-water species */
307  virtual void computeQtSpecies ()
308  {
309  for (int is = 1; is < m_num_species; is++) { computeQtSpecies(is); }
310  }
311 
312  /*! \brief compute qt (total) for a non-water species */
313  virtual void computeQtSpecies (const int a_i);
314 
315  /*! \brief compute qt (total) for a species */
316  virtual void computeQt (const int a_i)
317  {
318  if (a_i == m_idx_w) { computeQtWater(); }
319  else { computeQtSpecies(a_i); }
320  }
321 
322  /*! \brief Compute rain accumulation */
323  virtual void rainAccumulation (const amrex::MultiFab& a_z_phys_nd);
324 
325  /*! \brief Compute non-water species accumulation */
326  virtual void speciesAccumulation (const amrex::MultiFab& a_z_phys_nd);
327 
328  /*! \brief Compute aerosol accumulation */
329  virtual void aerosolAccumulation (const amrex::MultiFab& a_z_phys_nd);
330 
331  /*! \brief Convert a multifab containing density of something to its mixing ratio */
332  void densityToRatio ( amrex::MultiFab&, const int a_comp = 0 );
333  /*! \brief Convert a multifab containing the mixing ratio of something to its density */
334  void ratioToDensity ( amrex::MultiFab&, const int a_comp = 0 );
335 
336  /*! \brief Compute phase changes (vapour <--> cloud water)
337  * \param[in] a_dt Timestep for phase change calculation
338  * \param[in] a_z Array of terrain heights
339  * \param[in] a_lev AMR level
340  */
341  virtual void phaseChange ( const amrex::Real& a_dt,
342  const amrex::Vector<MFPtr>& a_z,
343  const int a_lev);
344 
345  virtual void GetPlotVarNames (amrex::Vector<std::string>& a_names) const override
346  {
347  for (int v = 1; v < m_num_species; v++) {
348  a_names.push_back("qv_"+amrex::getEnumNameString(m_species[v]));
349  a_names.push_back("qc_"+amrex::getEnumNameString(m_species[v]));
350  a_names.push_back("qt_"+amrex::getEnumNameString(m_species[v]));
351  a_names.push_back("sat_ratio_"+amrex::getEnumNameString(m_species[v]));
352  a_names.push_back("accum_"+amrex::getEnumNameString(m_species[v]));
353  }
354  for (int v = 0; v < m_num_aerosols; v++) {
355  a_names.push_back("accum_"+amrex::getEnumNameString(m_aerosols[v]));
356  }
357  }
358 
359  virtual void GetPlotVar (const std::string& /*a_name*/,
360  amrex::MultiFab& /*a_mf*/) const override
361  {
362  amrex::Abort("SuperDropletsMoist::GetPlotVar() requires a level argument");
363  }
364 
365  virtual void GetPlotVar (const std::string& a_name,
366  amrex::MultiFab& a_mf,
367  const int a_lev) const override
368  {
369  a_mf.setVal(0.0);
370  AMREX_ASSERT(a_mf.nComp() >= 1);
371 
372  const int lev = a_lev;
373  if (lev < 0 || lev >= static_cast<int>(m_mic_fab_vars.size()) ||
374  m_mic_fab_vars[lev].empty()) {
375  return;
376  }
377 
378  const auto& lev_vec = m_mic_fab_vars[lev];
379 
380  // Helper to copy MultiFab if name matches
381  auto try_copy = [&](const std::string& prefix, int idx) -> bool {
382  if (a_name == prefix) {
383  if (idx >= 0 && idx < static_cast<int>(lev_vec.size()) && lev_vec[idx] &&
384  lev_vec[idx]->boxArray() == a_mf.boxArray() &&
385  lev_vec[idx]->DistributionMap() == a_mf.DistributionMap()) {
386  amrex::MultiFab::Copy(a_mf, *lev_vec[idx],
387  0, 0, 1, amrex::IntVect::TheZeroVector());
388  }
389  return true;
390  }
391  return false;
392  };
393 
394  // Species variables
395  for (int v = 1; v < m_num_species; v++) {
396  std::string sp_name = amrex::getEnumNameString(m_species[v]);
397  if (try_copy("qv_" + sp_name, s_qv_idx(v)) ||
398  try_copy("qc_" + sp_name, s_qc_idx(v)) ||
399  try_copy("qt_" + sp_name, s_qt_idx(v)) ||
400  try_copy("sat_ratio_" + sp_name, s_sr_idx(v)) ||
401  try_copy("accum_" + sp_name, s_accum_idx(v))) {
402  return;
403  }
404  }
405 
406  // Aerosol variables
407  for (int v = 0; v < m_num_aerosols; v++) {
408  std::string ae_name = amrex::getEnumNameString(m_aerosols[v]);
409  if (try_copy("accum_" + ae_name, a_accum_idx(m_num_species, v))) { return; }
410  }
411 
412  amrex::Abort("SuperDropletsMoist::GetPlotVar() called with invalid name");
413  }
414 
415  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
416  int q_qv_idx (const int a_i /*!< species index */ )
417  {
418  AMREX_ALWAYS_ASSERT(a_i > 0);
419  return RhoQ1_comp + m_qstate_moist_size + 2*(a_i-1) + 0;
420  }
421 
422  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
423  int q_qc_idx (const int a_i /*!< species index */ )
424  {
425  AMREX_ALWAYS_ASSERT(a_i > 0);
426  return RhoQ1_comp + m_qstate_moist_size + 2*(a_i-1) + 1;
427  }
428 
429  protected:
430 
431  bool m_flag_phase_change; /*!< Enable/disable phase change */
432  bool m_flag_advection; /*!< Enable/disable advection */
433  bool m_flag_coalescence; /*!< Enable/disable coalescence */
434 
435  amrex::Real m_Cp; /*!< specific heat at constant pressure for dry air */
436 
437  amrex::Real m_r_rain; /*!< minimum radius to be considered rain */
438 
439  /*! let initial superdroplets "relax" to a physically-appropriate size? */
440  bool m_init_phase_change;
441  /*! time (in seconds) of initial relaxation */
442  amrex::Real m_init_phase_change_time;
443 
444  int m_diagnostics_iter; /*!< number of iterations between computing diagnostics */
445 
446  /*! initialization type */
447  SDMoistInit m_init_type;
448 
449  /*! name of model and its particle container */
450  std::string m_name;
451  /*! Geometry object */
452  amrex::Geometry m_geom;
453  /*! number of microphysics variables */
454  int m_qmoist_size;
455  /*! number of water-related state variables for this moisture model */
456  int m_qstate_moist_size;
457 
458  /*! number of water-related state variables that are number concentrations */
459  int m_qstate_moist_numconc_size = 0;
460 
461  /*! number of non-water-related state variables for this moisture model */
462  int m_qstate_nonmoist_size;
463 
464  amrex::Real m_dt; /*!< timestep */
465  amrex::Vector<int> m_mic_var_map; /*!< moisture model variables map */
466 
467  /*! moisture model variables - per level for AMR support */
468  amrex::Vector<amrex::Vector<FabPtr>> m_mic_fab_vars;
469 
470  /*! current AMR level being processed */
471  mutable int m_current_lev = 0;
472 
473  /*! names of vapour/condensate species */
474  std::vector<Species::Name> m_species;
475  int m_num_species;
476 
477  /*! names of aerosols */
478  std::vector<Species::Name> m_aerosols;
479  int m_num_aerosols;
480 
481  /*! number of substeps for phase change */
482  int m_num_substeps_phase_change;
483 
484  /*! kinematic mode? */
485  bool m_kinematic_mode;
486 
487  /*! Dimensionality of simulation*/
488  SDMSimulationDim m_dimensionality;
489 
490  /*! recycle particles */
491  bool m_recycle_particles;
492 
493  /*! species index of water */
494  int m_idx_w;
495 
496  /*! particle container for super-droplets
497  * Owned by ERF::particleData which deletes it during teardown;
498  * raw pointer here to avoid double-free. */
499  SuperDropletPC* m_super_droplets;
500 
501  /*! \brief read inputs */
502  virtual void readInputs();
503 
504  private:
505 
506 };
507 
508 #endif
509 #endif
AMREX_ENUM(InitType, None, Input_Sounding, NCFile, WRFInput, Metgrid, Uniform, ConstantDensity, ConstantDensityLinearTheta, Isentropic, MoistBaseState, HindCast)
Initial-condition source used to populate the ERF state.
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
rho
Definition: ERF_InitCustomPert_Bubble.H:107
int m_num_species
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:28
std::vector< std::string > m_species
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:27
Real q_t
Definition: ERF_InitCustomPert_SquallLine.H:24
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:365
Contains the Lagrangian moisture model base class.
amrex::Real Real
Definition: ERF_ShocInterface.H:19
virtual void Update_Micro_Vars(amrex::MultiFab &)
Definition: ERF_NullMoist.H:35
@ NumVars
Definition: ERF_NOAHMP_Fields.H:109
@ theta
Definition: ERF_SLM.H:20
@ rain_accum
Definition: ERF_Kessler.H:35
Definition: ERF_DataStruct.H:241
Definition: ERF_SurfacePrecipitation.H:21
SurfacePrecipAccumulationSource rain
Definition: ERF_SurfacePrecipitation.H:23