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