12 #ifndef CD_ParticleManagementImplem_H
13 #define CD_ParticleManagementImplem_H
17 #include <type_traits>
25 #include <CD_NamespaceHeader.H>
29 template <
class P, Real& (P::*weight)(), const RealVect& (P::*position)() const>
31 partitionAndSplitEqualWeightKD(
KDNode<P>& a_node,
const BinaryParticleReconcile<P> a_particleReconcile) noexcept
33 CH_assert(!(a_node.isInteriorNode()));
41 const Real W = a_node.weight();
48 for (
auto& p : particles) {
49 const RealVect& pos = (p.*
position)();
50 for (
int dir = 0; dir < SpaceDim; dir++) {
51 loCorner[dir] =
std::min(pos[dir], loCorner[dir]);
52 hiCorner[dir] =
std::max(pos[dir], hiCorner[dir]);
56 const int splitDir = (hiCorner - loCorner).maxDir(
true);
58 auto sortCrit = [splitDir](
const P& p1,
const P& p2) ->
bool {
62 std::sort(particles.begin(), particles.end(), sortCrit);
68 Real wr = W - (particles[id].*weight)();
70 for (
size_t i = 1; i < particles.size(); i++) {
71 const Real& w = (particles[id].*weight)();
76 wr = W - wl - (particles[id].*weight)();
89 std::move(particles.begin(), particles.begin() +
id, std::back_inserter(pl));
90 std::move(particles.begin() +
id + 1, particles.end(), std::back_inserter(pr));
92 const Real& pw = (p.*weight)();
93 const Real dw = wr - wl;
95 CH_assert(wl + wr + pw == W);
98 if (pw >= splitThresh && pw >= std::abs(dw)) {
103 const long long N = (
long long)ddw;
107 const long long Nr = N / 2;
108 const long long Nl = N - Nr;
110 dwl += (ddw / N) * Nl;
111 dwr += (ddw / N) * Nr;
114 if (dwl > 0.0 && dwr > 0.0) {
120 CH_assert(dwl >= 1.0);
121 CH_assert(dwr >= 1.0);
126 (il.*weight)() = dwl;
127 (ir.*weight)() = dwr;
130 a_particleReconcile(il, ir, p);
132 pl.emplace_back(std::move(il));
133 pr.emplace_back(std::move(ir));
135 else if (dwl > 0.0 && dwr == 0.0) {
140 CH_assert(dwl >= 1.0);
143 (il.*weight)() = dwl;
144 pl.emplace_back(std::move(il));
146 else if (dwl == 0.0 && dwr > 0.0) {
151 CH_assert(dwr >= 1.0);
154 (ir.*weight)() = dwr;
155 pr.emplace_back(std::move(ir));
160 MayDay::Abort(
"ParticleManagement::partitionAndSplitEqualWeightKD - logic bust");
166 pl.emplace_back(std::move(p));
170 pr.emplace_back(std::move(p));
176 CH_assert(wl + wr == W);
177 CH_assert(std::abs(wl - wr) <= 1.0);
182 a_node.getLeft() = std::make_shared<KDNode<P>>(pl);
183 a_node.getRight() = std::make_shared<KDNode<P>>(pr);
185 a_node.getLeft()->weight() = wl;
186 a_node.getRight()->weight() = wr;
194 for (
auto& l : a_node.getLeft()->getParticles()) {
195 CH_assert((l.*weight)() >= 1.0);
200 for (
auto& r : a_node.getRight()->getParticles()) {
201 CH_assert((r.*weight)() >= 1.0);
211 template <
class P, Real& (P::*weight)(), const RealVect& (P::*position)() const>
212 inline std::vector<std::shared_ptr<KDNode<P>>>
214 const int a_maxLeaves,
217 CH_TIME(
"ParticleManagement::recursivePartitionAndSplitEqualWeightKD");
221 for (
auto& p : a_inputParticles) {
225 std::vector<std::shared_ptr<KDNode<P>>> leaves;
227 leaves.emplace_back(std::make_shared<
KDNode<P>>(a_inputParticles));
228 leaves[0]->weight() = W;
230 bool keepGoing =
true;
232 while (keepGoing && leaves.size() < a_maxLeaves) {
235 std::vector<std::shared_ptr<KDNode<P>>> newLeaves;
237 for (
const auto& l : leaves) {
239 ParticleManagement::partitionAndSplitEqualWeightKD<P, weight, position>(*l, a_particleReconcile);
241 newLeaves.emplace_back(l->getLeft());
242 newLeaves.emplace_back(l->getRight());
247 newLeaves.emplace_back(l);
251 if (newLeaves.size() >= a_maxLeaves) {
262 template <
typename P,
typename T,
typename>
264 removePhysicalParticles(List<P>& a_particles,
const T a_numPhysPartToRemove) noexcept
266 CH_TIME(
"ParticleManagement::removePhysicalParticles");
268 constexpr T zero = (T)0;
271 if (a_numPhysPartToRemove < zero) {
272 MayDay::Error(
"ParticleManagement::removePhysicalParticles - 'a_numPhysPartoToRemove < 0'");
275 if (a_particles.length() > 0) {
276 ListIterator<P> lit(a_particles);
282 for (lit.begin(); lit.ok(); ++lit) {
283 minWeight =
std::min(minWeight, (T)lit().weight());
287 for (lit.begin(); lit.ok(); ++lit) {
288 const T diff1 = (T)lit().weight() - minWeight;
289 const T diff2 = a_numPhysPartToRemove - numRemoved;
291 CH_assert(diff1 >= zero);
292 CH_assert(diff2 >= zero);
296 lit().weight() -= 1.0 * r;
301 if (a_numPhysPartToRemove - numRemoved > zero) {
302 const T numCompParticles = (T)a_particles.length();
303 const T uniformWeight = (a_numPhysPartToRemove - numRemoved) / numCompParticles;
304 const T uniformRemainder = (a_numPhysPartToRemove - numRemoved) % numCompParticles;
307 if (uniformWeight > zero) {
308 for (lit.begin(); lit.ok(); ++lit) {
309 lit().weight() -= 1.0 * uniformWeight;
311 numRemoved += uniformWeight;
317 if (uniformRemainder > zero) {
320 for (lit.begin(); lit.ok(); ++lit) {
323 const T w =
std::min((T)lit().weight(), uniformRemainder - W);
325 lit().weight() -= 1.0 * w;
330 if (W == uniformRemainder) {
338 CH_assert(numRemoved == a_numPhysPartToRemove);
340 for (lit.begin(); lit.ok(); ++lit) {
341 CH_assert(lit().weight() >= 0.0);
347 template <
typename P>
349 deleteParticles(List<P>& a_particles,
const Real a_weightThresh) noexcept
351 CH_TIME(
"ParticleManagement::deleteParticles");
353 for (ListIterator<P> lit(a_particles); lit.ok();) {
354 if (lit().weight() < a_weightThresh) {
355 a_particles.remove(lit);
363 template <
typename T,
typename>
364 inline std::vector<T>
365 partitionParticleWeights(
const T a_numPhysicalParticles,
const T a_maxCompParticles) noexcept
367 std::vector<T> ret(0);
369 constexpr T zero = (T)0;
370 constexpr T one = (T)1;
372 if (a_maxCompParticles > zero) {
373 if (a_numPhysicalParticles <= a_maxCompParticles) {
374 ret.resize(a_numPhysicalParticles, one);
377 const T W = a_numPhysicalParticles / a_maxCompParticles;
378 T r = a_numPhysicalParticles % a_maxCompParticles;
381 ret.resize(a_maxCompParticles, W);
383 for (
int i = 0; i < ret.size() && r > zero; i++) {
397 template <
typename T,
typename>
399 partitionParticles(
const T a_numParticles)
402 const T quotient = a_numParticles / numProc();
403 const T remainder = a_numParticles % numProc();
405 Vector<T> particlesPerRank(numProc(), quotient);
407 for (
int i = 0; i < remainder; i++) {
408 particlesPerRank[i]++;
411 return particlesPerRank[procID()];
413 return a_numParticles;
417 template <
typename P,
typename T,
typename>
419 drawRandomParticles(List<P>& a_particles,
const T a_numParticles,
const std::function<RealVect()>& a_distribution)
424 const T numParticles = partitionParticles(a_numParticles);
426 for (T t = 0; t < numParticles; t++) {
428 p.position() = a_distribution();
434 template <
typename P,
typename T,
typename>
436 drawSphereParticles(List<P>& a_particles,
437 const T a_numParticles,
438 const RealVect a_center,
439 const Real a_radius) noexcept
441 CH_TIME(
"ParticleManagement::drawSphereParticles");
445 const T numParticles = partitionParticles(a_numParticles);
447 for (T t = 0; t < numParticles; t++) {
450 RealVect& x = p.position();
454 while (x.vectorLength() > a_radius) {
455 for (
int d = 0; d < SpaceDim; d++) {
466 template <
typename P,
typename T,
typename>
468 drawBoxParticles(List<P>& a_particles,
469 const T a_numParticles,
470 const RealVect a_loCorner,
471 const RealVect a_hiCorner) noexcept
473 CH_TIME(
"ParticleManagement::drawBoxParticles");
475 CH_assert(a_hiCorner >= a_loCorner);
477 auto ranBox = [&]() -> RealVect {
483 drawRandomParticles(a_particles, a_numParticles, ranBox);
486 template <
typename P,
typename T,
typename>
488 drawGaussianParticles(List<P>& a_particles,
489 const T a_numParticles,
490 const RealVect a_center,
491 const Real a_radius) noexcept
493 CH_TIME(
"ParticleManagement::drawGaussianParticles");
495 std::normal_distribution<Real> gauss(0.0, a_radius);
497 auto ranGauss = [&]() -> RealVect {
501 drawRandomParticles(a_particles, a_numParticles, ranGauss);
505 #include <CD_NamespaceFooter.H>
Namespace containing various particle management utilities.
File containing some useful static methods related to random number generation.
Node in a particle-merging KD-tree.
Definition: CD_KDNode.H:33
std::vector< P > ParticleList
List of particles. This is aliased because the KD-tree construction may require both random access an...
Definition: CD_KDNode.H:39
static Real get(T &a_distribution)
For getting a random number from a user-supplied distribution. T must be a distribution for which we ...
Definition: CD_RandomImplem.H:208
static RealVect getDirection()
Get a random direction in space.
Definition: CD_RandomImplem.H:171
static Real getUniformReal11()
Get a uniform real number on the interval [-1,1].
Definition: CD_RandomImplem.H:155
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition: CD_RandomImplem.H:147
RealVect position(const Location::Cell a_location, const VolIndex &a_vof, const EBISBox &a_ebisbox, const Real &a_dx)
Compute the position (ignoring the "origin) of a Vof.
Definition: CD_LocationImplem.H:20
Real max(const Real &a_input) noexcept
Get the maximum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:176
Real min(const Real &a_input) noexcept
Get the minimum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:58
Namespace for various particle management tools.
Definition: CD_ParticleManagement.H:31
std::function< void(P &p1, P &p2, const P &p0)> BinaryParticleReconcile
Declaration of a reconciliation function when splitting particles.
Definition: CD_ParticleManagement.H:50