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 { m_current_lev = a_lev; }
180 
181  /*! \brief Get the diagnostics interval */
182  int getDiagnosticsInterval () const override { return m_diagnostics_iter; }
183 
184  /*! \brief Ensure m_mic_fab_vars[lev] is allocated for the given level */
185  void EnsureMicFabVars (const int a_lev, const amrex::MultiFab& a_cons_vars);
186 
187  /*! \brief Build a coarse-cell mask: 1 where exposed, 0 where covered by a finer level */
188  amrex::iMultiFab buildFineMask (const int a_lev) const;
189 
190  /*! \brief Initialize m_mic_fab_vars for a non-zero AMR level */
191  void InitLevel (const int a_lev, const amrex::MultiFab& a_cons_vars) override;
192 
193  /*! \brief Advance for one timestep
194  * \param[in] dt Timestep
195  * \param[in] iteration Current iteration number
196  * \param[in] time Current simulation time
197  * \param[in,out] cons_vars Array of conserved variables
198  * \param[in] mf_array Array of additional multifabs
199  * \param[in] bc_arr Array of boundary conditions
200  */
201  virtual void Advance (const amrex::Real& dt,
202  const int& iteration,
203  const amrex::Real& time,
204  amrex::Vector<amrex::Vector<amrex::MultiFab>>& cons_vars,
205  const amrex::Vector<MFPtr>& mf_array,
206  const BCTypeArr& bc_arr) override;
207 
209 
210  /*! \brief Update microphysics variables
211  * \param[in] a_cons_vars Conservative variables multifab
212  */
213  virtual void Update_Micro_Vars (amrex::MultiFab& a_cons_vars) override;
214 
215  /*! \brief Update state variables from microphysics variables
216  * \param[in,out] a_cons_vars Conservative variables multifab to update
217  * \param[in] a_z_phys_nd Terrain heights (nodal)
218  */
219  virtual void Update_State_Vars (amrex::MultiFab& a_cons_vars,
220  const amrex::MultiFab& a_z_phys_nd) override;
221 
222  /*! \brief Average down moisture multifabs from finest_level down to 0 */
223  virtual void AverageDownMicroVars (const int finest_level) override;
224 
225  /*! \brief Copy moisture model vars from state to member multifabs
226  * \param[in] a_state State multifab to copy from
227  */
228  virtual void Copy_State_to_Micro (const amrex::MultiFab& a_state) override;
229 
230  /*! \brief Copy moisture model vars to state from member multifabs
231  * \param[out] a_state State multifab to copy to
232  */
233  virtual void Copy_Micro_to_State (amrex::MultiFab& a_state) override;
234 
235  /*! \brief returns the moisture variable asked for */
236  inline virtual amrex::MultiFab* Qmoist_Ptr (const int& a_idx) override
237  {
238  AMREX_ALWAYS_ASSERT( a_idx < m_qmoist_size );
239  const int lev = m_current_lev;
240  if (lev < 0 || lev >= static_cast<int>(m_mic_fab_vars.size()) ||
241  m_mic_var_map[a_idx] < 0 || m_mic_var_map[a_idx] >= static_cast<int>(m_mic_fab_vars[lev].size())) {
242  return nullptr;
243  }
244  return m_mic_fab_vars[lev][m_mic_var_map[a_idx]].get();
245  }
246 
247  /*! \brief returns number of variables in this moisture model */
248  inline virtual int Qmoist_Size () override
249  {
250  return m_qmoist_size;
251  }
252 
253  /*! \brief returns the surface rain accumulation (mm, i.e. kg/m^2 of liquid water) */
255  Get_Surface_Precip_Accumulation_Ptrs (const int& a_lev) const override
256  {
258  if (a_lev >= 0 && a_lev < static_cast<int>(m_mic_fab_vars.size())) {
259  sources.rain = { m_mic_fab_vars[a_lev][MicVar_SD::rain_accum].get(),
260  amrex::Real(1.0) };
261  }
262  return sources;
263  }
264 
265  /*! \brief returns number of moist conserved variables */
266  inline virtual int Qstate_Moist_Size () override
267  {
268  return m_qstate_moist_size;
269  }
270 
271  /*! \brief returns number of moist conserved variables that are number concentrations */
272  inline virtual int Qstate_Moist_NumConc_Size () override
273  {
274  return m_qstate_moist_numconc_size;
275  }
276 
277  /*! \brief returns number of non-water species conserved variables */
278  inline virtual int Qstate_NonMoist_Size () override
279  {
280  AMREX_ALWAYS_ASSERT(m_qstate_nonmoist_size >= 0);
281  return m_qstate_nonmoist_size;
282  }
283 
284  /*! \brief returns pointer to super-droplets particle container */
285  inline virtual ERFPC* getParticleContainer() override
286  {
287  return m_super_droplets;
288  }
289 
290  inline virtual const std::string& getName() const override
291  {
292  return m_name;
293  }
294 
295  /*! \brief compute cloud/rain mixing ratios */
296  virtual void computeQcQrWater (const amrex::MultiFab& a_z_phys_nd);
297 
298  /*! \brief compute ice/graupel/snow mixing ratios */
299  virtual void computeQiQgQsWater (const amrex::MultiFab& a_z_phys_nd);
300 
301  /*! \brief compute condensate for all non-water species */
302  virtual void computeQcSpecies (const amrex::MultiFab& a_z_phys_nd)
303  {
304  for (int is = m_istart_sp; is < m_num_species; is++) { computeQcSpecies(is, a_z_phys_nd); }
305  }
306 
307  /*! \brief compute condensate mixing ratio for a non-water species */
308  virtual void computeQcSpecies (const int a_i, const amrex::MultiFab& a_z_phys_nd);
309 
310  /*! \brief compute condensate mixing ratio for a species */
311  virtual void computeQc (const int a_i, const amrex::MultiFab& a_z_phys_nd)
312  {
313  if (a_i == m_idx_w) { computeQcQrWater(a_z_phys_nd); }
314  else if (a_i == m_idx_i) { computeQiQgQsWater(a_z_phys_nd); }
315  else { computeQcSpecies(a_i, a_z_phys_nd); }
316  }
317 
318  /*! \brief compute total water mixing ratio */
319  virtual void computeQtWater ();
320 
321  /*! \brief compute qt (total) for all non-water species */
322  virtual void computeQtSpecies ()
323  {
324  for (int is = m_istart_sp; is < m_num_species; is++) { computeQtSpecies(is); }
325  }
326 
327  /*! \brief compute qt (total) for a non-water species */
328  virtual void computeQtSpecies (const int a_i);
329 
330  /*! \brief Compute rain accumulation */
331  virtual void rainAccumulation (const amrex::MultiFab& a_z_phys_nd);
332 
333  /*! \brief Compute rain accumulation */
334  virtual void snowAccumulation (const amrex::MultiFab& a_z_phys_nd);
335 
336  /*! \brief Compute non-water species accumulation */
337  virtual void speciesAccumulation (const amrex::MultiFab& a_z_phys_nd);
338 
339  /*! \brief Compute aerosol accumulation */
340  virtual void aerosolAccumulation (const amrex::MultiFab& a_z_phys_nd);
341 
342  /*! \brief Convert a multifab containing density of something to its mixing ratio */
343  void densityToRatio ( amrex::MultiFab&, const int a_comp = 0 );
344  /*! \brief Convert a multifab containing the mixing ratio of something to its density */
345  void ratioToDensity ( amrex::MultiFab&, const int a_comp = 0 );
346 
347  /*! \brief Compute phase changes
348  * \param[in] a_dt Timestep for phase change calculation
349  * \param[in] a_z Array of terrain heights
350  * \param[in] a_lev AMR level
351  */
352  virtual void phaseChange ( const amrex::Real& a_dt,
353  const amrex::Vector<MFPtr>& a_z,
354  const int a_lev);
355 
356  /*! \brief Evaporation/condensation for water */
357  virtual void phaseChange_LV_w (const amrex::Real&, const amrex::Vector<MFPtr>&, const int,
358  const amrex::iMultiFab&);
359 
360  /*! \brief Evaporation/condensation for other species */
361  virtual void phaseChange_LV_s (const int, const amrex::Real&, const amrex::Vector<MFPtr>&, const int,
362  const amrex::iMultiFab&);
363 
364  /*! \brief Freezing/melting for water */
365  virtual void phaseChange_SL_w (const amrex::Real&, const amrex::Vector<MFPtr>&, const int,
366  const amrex::iMultiFab&);
367 
368  /*! \brief Deposition/sublimation for ice */
369  virtual void phaseChange_SV_i (const amrex::Real&, const amrex::Vector<MFPtr>&, const int,
370  const amrex::iMultiFab&);
371 
372  virtual void GetPlotVarNames (amrex::Vector<std::string>& a_names) const override
373  {
374  for (int v = m_istart_sp; v < m_num_species; v++) {
375  a_names.push_back("qv_"+amrex::getEnumNameString(m_species[v]));
376  a_names.push_back("qc_"+amrex::getEnumNameString(m_species[v]));
377  a_names.push_back("qt_"+amrex::getEnumNameString(m_species[v]));
378  a_names.push_back("sat_ratio_"+amrex::getEnumNameString(m_species[v]));
379  a_names.push_back("accum_"+amrex::getEnumNameString(m_species[v]));
380  }
381  for (int v = 0; v < m_num_aerosols; v++) {
382  a_names.push_back("accum_"+amrex::getEnumNameString(m_aerosols[v]));
383  }
384  }
385 
386  virtual void GetPlotVar (const std::string& /*a_name*/,
387  amrex::MultiFab& /*a_mf*/) const override
388  {
389  amrex::Abort("SuperDropletsMoist::GetPlotVar() requires a level argument");
390  }
391 
392  virtual void GetPlotVar (const std::string& a_name,
393  amrex::MultiFab& a_mf,
394  const int a_lev) const override
395  {
396  a_mf.setVal(0.0);
397  AMREX_ASSERT(a_mf.nComp() >= 1);
398 
399  const int lev = a_lev;
400  if (lev < 0 || lev >= static_cast<int>(m_mic_fab_vars.size()) ||
401  m_mic_fab_vars[lev].empty()) {
402  return;
403  }
404 
405  const auto& lev_vec = m_mic_fab_vars[lev];
406 
407  // Helper to copy MultiFab if name matches
408  auto try_copy = [&](const std::string& prefix, int idx) -> bool {
409  if (a_name == prefix) {
410  if (idx >= 0 && idx < static_cast<int>(lev_vec.size()) && lev_vec[idx] &&
411  lev_vec[idx]->boxArray() == a_mf.boxArray() &&
412  lev_vec[idx]->DistributionMap() == a_mf.DistributionMap()) {
413  amrex::MultiFab::Copy(a_mf, *lev_vec[idx],
414  0, 0, 1, amrex::IntVect::TheZeroVector());
415  }
416  return true;
417  }
418  return false;
419  };
420 
421  // Species variables
422  for (int v = m_istart_sp; v < m_num_species; v++) {
423  std::string sp_name = amrex::getEnumNameString(m_species[v]);
424  if (try_copy("qv_" + sp_name, s_qv_idx(v, m_istart_sp)) ||
425  try_copy("qc_" + sp_name, s_qc_idx(v, m_istart_sp)) ||
426  try_copy("qt_" + sp_name, s_qt_idx(v, m_istart_sp)) ||
427  try_copy("sat_ratio_" + sp_name, s_sr_idx(v, m_istart_sp)) ||
428  try_copy("accum_" + sp_name, s_accum_idx(v, m_istart_sp))) {
429  return;
430  }
431  }
432 
433  // Aerosol variables
434  for (int v = 0; v < m_num_aerosols; v++) {
435  std::string ae_name = amrex::getEnumNameString(m_aerosols[v]);
436  if (try_copy("accum_" + ae_name, a_accum_idx(m_num_nonmoist_sp, v))) { return; }
437  }
438 
439  amrex::Abort("SuperDropletsMoist::GetPlotVar() called with invalid name");
440  }
441 
442  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
443  int q_qv_idx (const int a_i, /*!< species index */
444  const int a_is /*!< index of first non-water/ice species */ )
445  {
446  AMREX_ALWAYS_ASSERT(a_i >= a_is);
447  return RhoQ1_comp + m_qstate_moist_size + 2*(a_i-a_is) + 0;
448  }
449 
450  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
451  int q_qc_idx (const int a_i, /*!< species index */
452  const int a_is /*!< index of first non-water/ice species */ )
453  {
454  AMREX_ALWAYS_ASSERT(a_i >= a_is);
455  return RhoQ1_comp + m_qstate_moist_size + 2*(a_i-a_is) + 1;
456  }
457 
458  protected:
459 
460  bool m_flag_phase_change; /*!< Enable/disable phase changes */
461  bool m_flag_advection; /*!< Enable/disable advection */
462  bool m_flag_coalescence; /*!< Enable/disable coalescence */
463 
464  amrex::Real m_Cp; /*!< specific heat at constant pressure for dry air */
465  amrex::Real m_r_rain; /*!< minimum radius to be considered rain */
466  amrex::Real m_rime_ratio; /*!< rime mass ratio to be considered graupel */
467 
468  /*! let initial superdroplets "relax" to a physically-appropriate size? */
469  bool m_init_phase_change;
470  /*! time (in seconds) of initial relaxation */
471  amrex::Real m_init_phase_change_time;
472 
473  int m_diagnostics_iter; /*!< number of iterations between computing diagnostics */
474 
475  /*! initialization type */
476  SDMoistInit m_init_type;
477 
478  /*! name of model and its particle container */
479  std::string m_name;
480  /*! Geometry object */
481  amrex::Geometry m_geom;
482  /*! number of microphysics variables */
483  int m_qmoist_size;
484  /*! number of water-related state variables for this moisture model */
485  int m_qstate_moist_size;
486 
487  /*! number of water-related state variables that are number concentrations */
488  int m_qstate_moist_numconc_size = 0;
489 
490  /*! number of non-water-related state variables for this moisture model */
491  int m_qstate_nonmoist_size;
492 
493  amrex::Real m_dt; /*!< timestep */
494  amrex::Vector<int> m_mic_var_map; /*!< moisture model variables map */
495 
496  /*! moisture model variables - per level for AMR support */
497  amrex::Vector<amrex::Vector<FabPtr>> m_mic_fab_vars;
498 
499  /*! current AMR level being processed */
500  mutable int m_current_lev = 0;
501 
502  /*! names of vapour/condensate species */
503  std::vector<Species::Name> m_species;
504  int m_num_species;
505 
506  /*! names of aerosols */
507  std::vector<Species::Name> m_aerosols;
508  int m_num_aerosols;
509 
510  /*! number of substeps for phase change */
511  int m_num_substeps_phase_change;
512 
513  /*! kinematic mode? */
514  bool m_kinematic_mode;
515 
516  /*! Dimensionality of simulation*/
517  SDMSimulationDim m_dimensionality;
518 
519  /*! recycle particles */
520  bool m_recycle_particles;
521 
522  /*! species index of water */
523  int m_idx_w;
524 
525  /*! species index of ice */
526  int m_idx_i;
527 
528  /*! starting index of non-moisture species */
529  int m_istart_sp;
530 
531  /*! number of non-moisture species */
532  int m_num_nonmoist_sp;
533 
534  /*! include cold processes? */
535  bool m_with_ice;
536 
537  /*! particle container for super-droplets
538  * Owned by ERF::particleData which deletes it during teardown;
539  * raw pointer here to avoid double-free. */
540  SuperDropletPC* m_super_droplets;
541 
542  /*! \brief read inputs */
543  virtual void readInputs();
544 
545  private:
546 
547 };
548 
549 #endif
550 #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: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:36
@ NumVars
Definition: ERF_NOAHMP_Fields.H:109
@ theta
Definition: ERF_SLM.H:20
@ rho
Definition: ERF_Kessler.H:24
@ rain_accum
Definition: ERF_Kessler.H:35
@ graup_accum
Definition: ERF_Morrison.H:53
@ snow_accum
Definition: ERF_Morrison.H:52
Definition: ERF_DataStruct.H:634
Definition: ERF_SurfacePrecipitation.H:34
SurfacePrecipAccumulationSource rain
Definition: ERF_SurfacePrecipitation.H:36