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