ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERFPC.H
Go to the documentation of this file.
1 #ifndef ERF_PC_H_
2 #define ERF_PC_H_
3 
4 #ifdef ERF_USE_PARTICLES
5 
6 #include <string>
7 #include <AMReX_Particles.H>
8 #include <AMReX_ParticleUtil.H>
9 #include <ERF_Constants.H>
10 
11 /** Particle cell-binning functor for DenseBins. Maps a particle to its
12  * cell-tile index via amrex::getParticleCell + amrex::getTileIndex. */
13 struct GetParticleBinERF
14 {
15  amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> plo;
16  amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> dxi;
17  amrex::Box domain;
18  amrex::IntVect bin_size;
19  amrex::Box box;
20  template <typename P>
21  AMREX_GPU_HOST_DEVICE
22  unsigned int operator() (const P& p) const noexcept
23  {
24  amrex::Box tbx;
25  auto iv = amrex::getParticleCell(p, plo, dxi, domain);
26  auto tid = amrex::getTileIndex(iv, box, true, bin_size, tbx);
27  return static_cast<unsigned int>(tid);
28  }
29 };
30 
31 /**
32  * @brief Index mapping for integer particle attributes.
33  */
34 struct ERFParticlesIntIdx
35 {
36  enum {
37  ncomps = 0
38  };
39 };
40 
41 /**
42  * @brief Index mapping for real-valued particle attributes.
43  */
44 struct ERFParticlesRealIdx
45 {
46  enum {
47  vx = 0,
48  vy,
49  vz,
50  mass,
51  temperature,
52  ncomps
53  };
54 };
55 
56 namespace ERFParticleInitializations
57 {
58  /* list of particle initializations */
59  const std::string init_box_uniform = "box";
60 }
61 
62 namespace ERFParticleNames
63 {
64  const std::string tracers = "tracer_particles";
65 }
66 
67 /**
68  * @brief Particle container for ERF particles.
69  */
70 /*! \brief Behaviour a derived container selects before ERFPC reads the input file.
71  *
72  * ERFPC::readInputs() runs from the ERFPC constructor, so a derived class cannot
73  * influence it through a virtual -- the base version is the one that runs. These
74  * options are passed down the constructor instead.
75  */
76 struct ERFPCOptions
77 {
78  /*! Read the generic particle-initialization inputs: initial_distribution_type,
79  * particle_box_lo / particle_box_hi, place_randomly_in_cells and
80  * initial_particles_per_cell. A container with its own initialization scheme
81  * (SuperDropletPC) sets this false, so those names stay free for it to define
82  * with its own meaning under the same input prefix. */
83  bool read_particle_init = true;
84 
85  /*! Value of advect_with_gravity before the input file is consulted. Tracers
86  * default to off, super-droplets to on. */
87  bool advect_with_gravity = false;
88 };
89 
90 class ERFPC : public amrex::ParticleContainer< 0, // AoS real attributes
91  0, // AoS integer attributes
92  ERFParticlesRealIdx::ncomps, // SoA real attributes
93  ERFParticlesIntIdx::ncomps, // SoA integer attributes
94  amrex::DefaultAllocator >
95 {
96  public:
97 
98  /*! Constructor */
99  ERFPC ( amrex::ParGDBBase* a_gdb,
100  const std::string& a_name = "particles",
101  const ERFPCOptions& a_opts = ERFPCOptions() )
102  : amrex::ParticleContainer< 0, // AoS real attributes
103  0, // AoS integer attributes
104  ERFParticlesRealIdx::ncomps, // SoA real attributes
105  ERFParticlesIntIdx::ncomps, // SoA integer attributes
106  amrex::DefaultAllocator> (a_gdb)
107  {
108  BL_PROFILE("ERFPCPC::ERFPC()");
109  m_name = a_name;
110  m_opts = a_opts;
111  readInputs();
112  }
113 
114  /*! Constructor */
115  ERFPC ( const amrex::Geometry& a_geom,
116  const amrex::DistributionMapping& a_dmap,
117  const amrex::BoxArray& a_ba,
118  const std::string& a_name = "particles",
119  const ERFPCOptions& a_opts = ERFPCOptions() )
120  : amrex::ParticleContainer< 0, // AoS real attributes
121  0, // AoS integer attributes
122  ERFParticlesRealIdx::ncomps, // SoA real attributes
123  ERFParticlesIntIdx::ncomps, // SoA integer attributes
124  amrex::DefaultAllocator> ( a_geom, a_dmap, a_ba )
125  {
126  BL_PROFILE("ERFPCPC::ERFPC()");
127  m_name = a_name;
128  m_opts = a_opts;
129  readInputs();
130  }
131 
132  /*! Initialize particles in domain */
133  virtual void InitializeParticles (const double time, const std::unique_ptr<amrex::MultiFab>& a_ptr = nullptr);
134 
135  /*! Evolve particles for one time step */
136  virtual void EvolveParticles (int a_lev,
137  double a_dt_lev,
138  amrex::Vector<amrex::Vector<amrex::MultiFab>>& a_flow_vars,
139  const amrex::Vector<std::unique_ptr<amrex::MultiFab>>& a_z_phys_nd );
140 
141  /*! Get real-type particle attribute names */
142  virtual amrex::Vector<std::string> varNames () const
143  {
144  BL_PROFILE("ERFPCPC::varNames()");
145  return {AMREX_D_DECL("xvel","yvel","zvel"),"mass","temperature"};
146  }
147 
148  /*! Get real-type particle attribute names */
149  virtual amrex::Vector<std::string> meshPlotVarNames () const
150  {
151  BL_PROFILE("ERFPCPC::varNames()");
152  return {"mass_density"};
153  }
154 
155  /*! Uses midpoint method to advance particles using flow velocity. */
156  virtual void AdvectWithFlow (amrex::MultiFab* a_umac,
157  int a_lev,
158  double a_dt,
159  const std::unique_ptr<amrex::MultiFab>& a_z_height);
160 
161  /*! Uses midpoint method to advance particles falling under gravity. */
162  virtual void AdvectWithGravity (int a_lev,
163  double a_dt,
164  const std::unique_ptr<amrex::MultiFab>& a_z_height);
165 
166  /*! Interpolates flow temperature to particles */
167  virtual void ComputeTemperature (const amrex::MultiFab& a_ucons,
168  int a_lev,
169  double /*a_dt*/,
170  const std::unique_ptr<amrex::MultiFab>& a_z_height);
171 
172  /*! Compute mass density */
173  virtual void massDensity ( amrex::MultiFab&,
174  const amrex::MultiFab& a_z_phys_nd,
175  const int&, const int& a_comp = 0) const;
176 
177  /*! Compute mesh variable from particles */
178  virtual void computeMeshVar( const std::string& a_var_name,
179  amrex::MultiFab& a_mf,
180  const amrex::MultiFab& a_z_phys_nd,
181  const int a_lev) const
182  {
183  if (a_var_name == "mass_density") {
184  massDensity( a_mf, a_z_phys_nd, a_lev );
185  } else {
186  a_mf.setVal(0.0);
187  }
188  }
189 
190  /*! Specify if particles should advect with flow */
191  inline void setAdvectWithFlow (bool a_flag)
192  {
193  BL_PROFILE("ERFPCPC::setAdvectWithFlow()");
194  m_advect_w_flow = a_flag;
195  }
196  /*! Specify if particles fall under gravity */
197  inline void setAdvectWithGravity (bool a_flag)
198  {
199  BL_PROFILE("ERFPCPC::setAdvectWithGravity()");
200  m_advect_w_gravity = a_flag;
201  }
202 
203  // the following functions should ideally be private or protected, but need to be
204  // public due to CUDA extended lambda capture rules
205 
206  /*! \brief Helper for ParticleToMesh operations on terrain-following grids.
207  *
208  * Generic CIC deposition from particles to a MultiFab. The caller provides
209  * a device lambda `value_func(ptd, i)` that returns the per-particle scalar
210  * to deposit (e.g. mass, number, flux). Implementation in ERFPCParticleToMesh.H.
211  */
212  template<typename ValueFunc>
213  void ERFPCParticleToMesh(amrex::MultiFab& a_mf,
214  const amrex::MultiFab& a_z_phys_nd,
215  int a_lev, int a_comp,
216  ValueFunc&& value_func) const;
217 
218  /*! Default particle initialization */
219  void initializeParticlesUniformDistributionInBox (const std::unique_ptr<amrex::MultiFab>& a_ptr,
220  const amrex::RealBox& particle_box);
221 
222  /*! Replace pos(2) (zeta) with the corresponding physical z, in place,
223  * on every level. Used around plotfile writes so the on-disk
224  * particles are in physical coordinates. */
225  void ConvertZetaToZ (const amrex::Vector<std::unique_ptr<amrex::MultiFab>>& a_z_phys_nd);
226 
227  /*! Inverse of ConvertZetaToZ: replace pos(2) (physical z) with zeta. */
228  void ConvertZToZeta (const amrex::Vector<std::unique_ptr<amrex::MultiFab>>& a_z_phys_nd);
229 
230  /*! Route fine-level particles whose position is outside the level's
231  * BA down to coarser levels, so per-level Redistribute on the fine
232  * level does not assert. */
233  void ExtractAndRouteOORParticles ( int a_lev );
234 
235  /*! Diagnostic: count particles per level and halo (for AMR) */
236  void CountParticlesPerLevelAndHalo ( int a_finest_level );
237 
238  /*! Split coarse-level particles in newly-refined cells after AMR regrid
239  * to restore the per-cell super-droplet count. Handles cascading
240  * refinement across multiple new levels in a single call (see the
241  * SuperDropletPC override for details). Default no-op. */
242  virtual void SplitParticlesForRefinement ( int /*a_finest_level*/ ) {}
243 
244  /*! Split new entrants and merge departees at AMR level boundaries.
245  * Called every Redistribute(z_phys_nd) to maintain uniform per-cell
246  * super-droplet density across levels. Default no-op. */
247  virtual void SplitMergeAtLevelBoundary () {}
248 
249  /*! Regrid-time de-refinement merge. For cells that were in the old
250  * fine BoxArray at level `a_lev` but are no longer in the current
251  * one, reduces the coarse-level super-droplet count from `np_bin`
252  * to `np_bin / merge_factor`. Default no-op. */
253  virtual void MergeParticlesAtDerefinement ( int /*a_lev*/,
254  const amrex::BoxArray& /*a_old_fine_ba*/,
255  const amrex::IntVect& /*a_ref_ratio*/ ) {}
256 
257  protected:
258 
259  bool m_advect_w_flow; /*!< advect with flow velocity */
260  bool m_advect_w_gravity; /*!< advect under gravitational force */
261 
262  amrex::RealBox m_particle_box; /*!< box within which to place particles */
263 
264  std::string m_name;
265 
266  ERFPCOptions m_opts; /*!< selected by the derived container */ /*!< name of this particle species */
267 
268  std::string m_initialization_type; /*!< initial particle distribution type */
269  int m_ppc_init; /*!< initial number of particles per cell */
270 
271  double m_inject_start_time; /*!< particles will only be initialized/injected if time >= m_inject_start_time */
272 
273  bool m_initialized = false; /*!< have the particles been initialized */
274 
275  bool m_stable_redistribute; /*!< use stable redistribute for deterministic simulations */
276 
277  /*! read inputs from file */
278  virtual void readInputs ();
279 
280  private:
281 
282  bool place_randomly_in_cells; /*!< place particles at random positions? */
283 };
284 
285 #endif
286 #endif
@ P
Definition: ERF_IndexDefines.H:204
@ p
Definition: ERF_WSM6.H:191
Definition: ERF_ConsoleIO.cpp:15