Canoe
Comprehensive Atmosphere N' Ocean Engine
particulate.cpp
Go to the documentation of this file.
1 
9 // C++ headers
10 #include <cassert>
11 #include <functional> // hash
12 #include <sstream>
13 #include <stdexcept>
14 
15 // Athena++ headers
16 #include "../coordinates/coordinates.hpp"
17 #include "../debugger/debugger.hpp"
18 #include "../globals.hpp"
19 #include "particles.hpp"
20 
21 // Particulate executes after chemistry, which is applied to aggreated
22 // quantities u It synchronized the particles in mp and the aggreated quantities
23 // after chemistry
24 void Particles::Particulate(std::vector<MaterialPoint> &mp,
25  AthenaArray<Real> const &u) {
26  MeshBlock *pmb = pmy_block;
27  pmb->pdebug->Call("Particles::Particulate-" + myname);
28 
29  Coordinates *pco = pmb->pcoord;
30  // particle buffer
31  std::vector<MaterialPoint> mpb;
32 
33  for (int t = 0; t < u.GetDim4(); ++t)
34  for (int k = pmb->ks; k <= pmb->ke; ++k)
35  for (int j = pmb->js; j <= pmb->je; ++j)
36  for (int i = pmb->is; i <= pmb->ie; ++i) {
37  // u1_ stores the total particle density before chemistry
38  // u stores the total particle density after chemistry
39  // if delta_u is positive, new particles are added. Otherwise,
40  // particle densities are adjusted to reflect the change of density
41  Real delta_u = u(t, k, j, i) - u1_(t, k, j, i);
42  // 1. count current number of particles in the cell
43  int nparts = 0;
44  MaterialPoint *pc = pcell_(t, k, j, i);
45  while (pc != nullptr) {
46  pc = pc->next;
47  nparts++;
48  }
49 
50  // 2. if the number of particles (n0) is greater than the maximum
51  // allowed particles per cell (nmax_per_cell_), mark particles for
52  // merging (destroy). Particle densities have been sorted from low to
53  // high. particles to be removed (merged) are marked as inactive (id =
54  // -1) and zero density (rho = 0). nparts reflects the number of
55  // active particles in cell
56  int n0 = nparts;
57  Real drho = 0., sum = 0.;
58  pc = pcell_(t, k, j, i);
59  /* method 1
60  if (pc != nullptr) {
61  while (nparts > nmax_per_cell_ || pc->rho+drho < density_floor_) {
62  if (nparts == 1) break;
63  drho += (pc->rho+drho)/(nparts-1);
64  pc->id = -1;
65  pc->rho = 0;
66  pc = pc->next;
67  nparts--;
68  }
69  }*/
70 
71  // method 2
72  for (int n = 0; n < n0 - nmax_per_cell_; ++n) {
73  sum += pc->rho;
74  pc->id = -1;
75  pc->rho = 0;
76  pc = pc->next;
77  nparts--;
78  }
79  drho = sum / nparts;
80 
81  // Distribute the total density of inactive particles to active
82  // particles.
83  pcell_(t, k, j, i) = pc;
84  while (pc != nullptr) {
85  pc->rho += drho;
86  pc = pc->next;
87  }
88 
89  // 3. add new particles to the empty particle buffer mpb or increase
90  // the density of existing particles
91  if (delta_u > 0.) {
92  // avg stores the mean density to be allocated to particles
93  Real avg = delta_u / seeds_per_cell_;
94  // num sotres the available number of particles to be added to cell
95  int num = std::min(nmax_per_cell_ - nparts, seeds_per_cell_);
96  // add new particles with density avg
97  std::string str = myname + std::to_string(t) +
98  std::to_string(pmb->gid) + std::to_string(i) +
99  std::to_string(j) + std::to_string(k) + 't' +
100  std::to_string(pmb->pmy_mesh->time) + 'n';
101  for (int n = 0; n < num; ++n) {
102  MaterialPoint p;
103  p.id = std::abs((int)std::hash<std::string>{}(
104  str + std::to_string(n))) %
105  (1 << 20);
106  p.type = t;
107  p.time = pmb->pmy_mesh->time;
108  p.x1 = pco->x1f(i) + (1. * rand() / RAND_MAX) * pco->dx1f(i);
109  p.x2 = pco->x2f(j) + (1. * rand() / RAND_MAX) * pco->dx2f(j);
110  p.x3 = pco->x3f(k) + (1. * rand() / RAND_MAX) * pco->dx3f(k);
111  p.v1 = 0.;
112  p.v2 = 0.;
113  p.v3 = 0.;
114  p.rho = avg;
115  mpb.push_back(p);
116  }
117 
118  // add the remaining mass to existing particles
119  pc = pcell_(t, k, j, i);
120  for (int n = 0; n < seeds_per_cell_ - num; ++n) {
121  pc->rho += avg;
122  pc = pc->next;
123  }
124  // 4. removes existing particles
125  } else if (delta_u < 0.) {
126  Real avg = std::abs(delta_u) / nparts;
127  pc = pcell_(t, k, j, i);
128  // std::cout << "c = " << u(t,k,j,i) << " c1 = " << u1_(t,k,j,i) <<
129  // std::endl; std::cout << "[" << pco->x1f(i) << "," <<
130  // pco->x1f(i+1) << "]" << std::endl; std::cout << "delta_u = " <<
131  // delta_u << " nparts = " << nparts << std::endl;
132  for (int n = 0; n < nparts; ++n) {
133  // std::cout << pc->x1 << " " << pc->rho << " ";
134  if (pc->rho > avg) {
135  delta_u += avg;
136  pc->rho -= avg;
137  } else {
138  delta_u += pc->rho;
139  avg = std::abs(delta_u) / (nparts - n - 1);
140  // available_ids_.push_back(pc->id);
141  pc->id = -1;
142  pc->rho = 0;
143  }
144  // std::cout << pc->rho << std::endl;
145  // std::cout << delta_u << " " << avg << std::endl;
146  pc = pc->next;
147  }
148  std::stringstream msg;
149  /*if (std::abs(delta_u) > density_floor_) {
150  msg << "### FATAL ERROR in Particles::Particulate:" << std::endl
151  << "(" << k << "," << j << "," << i << ") = " << nparts <<
152  std::endl
153  << "u = " << u(t,k,j,i) << " u1 = " << u1_(t,k,j,i) <<
154  std::endl
155  << "delta_u = " << delta_u << std::endl
156  << "density_floor_ = " << density_floor_ << std::endl;
157  ATHENA_ERROR(msg);
158  }*/
159  }
160  }
161 
162  // transfer from particle buffer (mpb) to storage (mp);
163  // mp.reserve(mp.size() + mpb.size());
164  // mp.insert(mp.end(), mpb.begin(), mpb.end());
165  for (std::vector<MaterialPoint>::iterator it = mpb.begin(); it != mpb.end();
166  ++it)
167  mp.push_back(*it);
168 
169 #if DEBUG_LEVEL > 2
170  pmb->pdebug->CheckParticleConservation(cnames_, mp);
171 #endif
172 
173  pmb->pdebug->Leave();
174 }
double min(double x1, double x2, double x3)
Definition: core.h:16