chombo-discharge
Loading...
Searching...
No Matches
CD_ParticleOpsImplem.H
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021-2026 SINTEF Energy Research
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
13#ifndef CD_PARTICLEOPSIMPLEM_H
14#define CD_PARTICLEOPSIMPLEM_H
15
16// Std includes
17#include <cstdint>
18
19// Chombo includes
20#include <CH_Timer.H>
21#include <PolyGeom.H>
22
23// Our includes
24#include <CD_ParticleOps.H>
25#include <CD_ParallelOps.H>
26#include <CD_PolyUtils.H>
27#include <CD_Random.H>
28#include <CD_NamespaceHeader.H>
29
30inline IntVect
32 const RealVect& a_probLo,
33 const Real& a_dx) noexcept
34{
35 return IntVect(D_DECL(std::floor((a_particlePosition[0] - a_probLo[0]) / a_dx),
36 std::floor((a_particlePosition[1] - a_probLo[1]) / a_dx),
37 std::floor((a_particlePosition[2] - a_probLo[2]) / a_dx)));
38}
39
40inline IntVect
42 const RealVect& a_probLo,
43 const RealVect& a_dx) noexcept
44{
45 return IntVect(D_DECL(std::floor((a_particlePosition[0] - a_probLo[0]) / a_dx[0]),
46 std::floor((a_particlePosition[1] - a_probLo[1]) / a_dx[1]),
47 std::floor((a_particlePosition[2] - a_probLo[2]) / a_dx[2])));
48}
49
50template <typename P, const Real& (P::*weight)() const>
51inline void
53{
54 CH_TIME("ParticleOps::getPhysicalParticlesPerCell");
55
56 const RealVect probLo = a_src.getProbLo();
57
58 for (int lvl = 0; lvl <= a_src.getFinestLevel(); lvl++) {
59 const DisjointBoxLayout& dbl = a_src.getGrids()[lvl];
60 const DataIterator& dit = dbl.dataIterator();
61 const RealVect dx = a_src.getDx()[lvl];
62
63 const int nbox = dit.size();
64
65#pragma omp parallel for schedule(runtime)
66 for (int mybox = 0; mybox < nbox; mybox++) {
67 const DataIndex& din = dit[mybox];
68
69 const List<P>& particles = a_src[lvl][din].listItems();
70
72 ppc.setVal(0.0);
73
74 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
75 const P& p = lit();
76 const RealVect x = p.position();
77 const Real w = (p.*weight)();
79
80 ppc(iv, 0) += w;
81 }
82 }
83 }
84}
85
86template <typename P>
87inline void
89{
90 CH_TIME("ParticleOps::getComputationalParticlesPerCell");
91
92 const RealVect probLo = a_src.getProbLo();
93
94 for (int lvl = 0; lvl <= a_src.getFinestLevel(); lvl++) {
95 const DisjointBoxLayout& dbl = a_src.getGrids()[lvl];
96 const DataIterator& dit = dbl.dataIterator();
97 const RealVect dx = a_src.getDx()[lvl];
98
99 const int nbox = dit.size();
100
101#pragma omp parallel for schedule(runtime)
102 for (int mybox = 0; mybox < nbox; mybox++) {
103 const DataIndex& din = dit[mybox];
104
105 const List<P>& particles = a_src[lvl][din].listItems();
106
108 ppc.setVal(0.0);
109
110 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
111 const P& p = lit();
112 const RealVect x = p.position();
114
115 ppc(iv, 0) += 1.0;
116 }
117 }
118 }
119}
120
121inline IntVect
123 const RealVect& a_probLo,
124 const RealVect& a_dx) noexcept
125{
126 return IntVect(D_DECL(std::floor((a_particlePosition[0] - a_probLo[0]) / a_dx[0]),
127 std::floor((a_particlePosition[1] - a_probLo[1]) / a_dx[1]),
128 std::floor((a_particlePosition[2] - a_probLo[2]) / a_dx[2])));
129}
130
131inline bool
133 const RealVect& a_newPos,
134 const RealVect& a_probLo,
135 const RealVect& a_probHi,
136 Real& a_s)
137{
138
139 // TLDR: This code does a boundary intersection test and returns where on the interval [oldPos, newPos] the intersection
140 // happened. We do this by checking if the particle moves towards a particular domain side and ends up outside of it.
141
142 a_s = std::numeric_limits<Real>::max();
143
144 bool crossedDomainBoundary = false;
145
146 const RealVect path = a_newPos - a_oldPos;
147
148 for (int dir = 0; dir < SpaceDim; dir++) {
149 for (SideIterator sit; sit.ok(); ++sit) {
150 const Side::LoHiSide side = sit();
151 const RealVect wallPoint = (side == Side::Lo) ? a_probLo : a_probHi; // A point on the domain side
152 const RealVect n0 = sign(side) *
153 RealVect(
154 BASISV(dir)); // Normal vector pointing OUT of the domain on side sit and direction dir.
155 const Real normPath = PolyGeom::dot(n0, path); // Component of the path that is normal to the domain edge/face.
156
157 // If normPath > 0 then the particle trajectory points towards the domain edge/face and we can have an intersection.
158 if (normPath > 0.0) {
159
160 // s determines the intersection point between the particle path and the plane corresponding to the domain edge/face. Note that
161 // we consider the edge/face to be an infinite plane and we just compute the intersection point between each edge/face and select the
162 // closest intersection point.
164 if (s >= 0.0 && s <= 1.0) {
166 if (s < a_s) {
167 a_s = s;
168 }
169 }
170 }
171 }
172 }
173
175}
176
177inline bool
179 const RealVect& a_oldPos,
180 const RealVect& a_newPos,
181 const Real& a_bisectStep,
182 Real& a_s)
183{
184
185 // TLDR: We compute the intersection point using a bisection algorithm. We divide the full path into intervals and check if an interval
186 // has a root. If it does, we compute it using Brent's algorithm.
187
188 a_s = std::numeric_limits<Real>::max();
189
190 bool crossedEB = false;
191
192 const Real pathLen = (a_newPos - a_oldPos).vectorLength(); // Total path len
193 const int nsteps = ceil(pathLen / a_bisectStep); // Number of bisection intervals
194 const RealVect dxStep = (a_newPos - a_oldPos) / nsteps; // Physical length of each bisection interval
195
196 // Check each interval
198 for (int istep = 0; istep < nsteps; istep++) {
199 const Real fa = a_impFunc->value(curPos); // Value of the implicit function at the start of the bisection interval
200 const Real fb = a_impFunc->value(curPos +
201 dxStep); // Value of the implicit function at the end of the bisection interval
202
203 if (fa * fb <= 0.0) {
204
205 // If this triggered we happen to know that f(pos+dxStep) > 0.0 and f(pos) < 0.0 and so we must have a root on the interval. We now compute the precise location
206 // where the particle crossed the EB. For that we use a Brent root finder on the interval [pos, pos+dxStep]. This is a 1D problem.
208 a_s = (intersectionPos - a_oldPos).vectorLength() / pathLen;
209 crossedEB = true;
210
211 break;
212 }
213 else { // Move to next interval
214 curPos += dxStep;
215 }
216 }
217
218 return crossedEB;
219}
220
221inline bool
223 const RealVect& a_oldPos,
224 const RealVect& a_newPos,
225 const Real& a_tolerance,
226 Real& a_s)
227{
228
229 a_s = std::numeric_limits<Real>::max();
230
231 bool ret = false;
232
233 // Absolute distance to EB.
234 auto dist = [&](const RealVect& x) -> Real {
235 return std::abs(a_impFunc->value(x));
236 };
237
238 const Real D = (a_newPos - a_oldPos).vectorLength(); // Total particle path length
239 const Real D0 = dist(a_oldPos); // Distance to EB from starting position
240
241 // If the distance to the EB from the starting position is smaller than the total path length, we need to check for intersections.
242 if (D > D0) {
243
244 const RealVect t = (a_newPos - a_oldPos) / D; // Particle trajectory.
245
246 // Move a_oldPos along +t. If we end up too close to the boundary the particle has intersected the BC. Note that this does NOT check for whether or not
247 // the particle moves tangential to the EB surface. The length of each step is the distance to the EB, so if the particle is close to the EB but moves
248 // tangentially to it, this routine will be EXTREMELY slow.
250 Real r = D;
251 Real d = dist(xa);
252
253 while (d < r) {
254
255 if (d < a_tolerance) { // We collided.
256 a_s = (xa - a_oldPos).vectorLength() / D;
257 ret = true;
258 break;
259 }
260 else { // We did not collide.
261 xa += t * d;
262 r -= d;
263 d = dist(xa);
264 }
265 }
266 }
267
268 return ret;
269}
270
271template <typename P>
272inline void
274{
275 CH_TIME("ParticleOps::copy(ParticleContainer<P> x2)");
276
277 CH_assert(a_dst.getRealm() == a_src.getRealm());
278
279 for (int lvl = 0; lvl <= a_dst.getFinestLevel(); lvl++) {
280 const DisjointBoxLayout& dbl = a_dst.getGrids()[lvl];
281 const DataIterator& dit = dbl.dataIterator();
282
283 const int nbox = dit.size();
284
285#pragma omp parallel for schedule(runtime)
286 for (int mybox = 0; mybox < nbox; mybox++) {
287 const DataIndex& din = dit[mybox];
288
289 a_dst[lvl][din].listItems() = a_src[lvl][din].listItems();
290 }
291 }
292}
293
294template <typename P>
295inline void
297{
298 CH_TIME("ParticleOps::copyDestructive(ParticleContainer<P> x2)");
299
300 CH_assert(a_dst.getRealm() == a_src.getRealm());
301
302 for (int lvl = 0; lvl <= a_dst.getFinestLevel(); lvl++) {
303 const DisjointBoxLayout& dbl = a_dst.getGrids()[lvl];
304 const DataIterator& dit = dbl.dataIterator();
305
306 const int nbox = dit.size();
307
308#pragma omp parallel for schedule(runtime)
309 for (int mybox = 0; mybox < nbox; mybox++) {
310 const DataIndex& din = dit[mybox];
311
312 a_dst[lvl][din].listItems() = a_src[lvl][din].listItems();
313
314 a_src[lvl][din].listItems().clear();
315 }
316 }
317}
318
319template <typename P, const Real& (P::*scalarQuantity)() const>
320inline Real
322{
323 CH_TIME("ParticleOps::sum(ParticleContainer<P>)");
324
325 Real particleSum = 0.0;
326
327 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
328 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
329 const DataIterator& dit = dbl.dataIterator();
330
331 const int nbox = dit.size();
332
333#pragma omp parallel for schedule(runtime) reduction(+ : particleSum)
334 for (int mybox = 0; mybox < nbox; mybox++) {
335 const DataIndex& din = dit[mybox];
336
337 const List<P>& particles = a_particles[lvl][din].listItems();
338
339 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
341 }
342 }
343 }
344
346}
347
348template <typename P, Real (P::*scalarQuantity)()>
349inline Real
351{
352 CH_TIME("ParticleOps::sum(ParticleContainer<P>)");
353
354 Real particleSum = 0.0;
355
356 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
357 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
358 const DataIterator& dit = dbl.dataIterator();
359
360 const int nbox = dit.size();
361
362#pragma omp parallel for schedule(runtime) reduction(+ : particleSum)
363 for (int mybox = 0; mybox < nbox; mybox++) {
364 const DataIndex& din = dit[mybox];
365
366 const List<P>& particles = a_particles[lvl][din].listItems();
367
368 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
370 }
371 }
372 }
373
375}
376
377template <typename P>
378inline void
380 const std::function<bool(const P&)>& a_removeCriterion) noexcept
381{
382 CH_TIME("ParticleOps::removeParticles(ParticleContainer<P>, std::function<bool(const P&)>)");
383
384 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
385 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
386 const DataIterator& dit = dbl.dataIterator();
387
388 const int nbox = dit.size();
389
390#pragma omp parallel for schedule(runtime)
391 for (int mybox = 0; mybox < nbox; mybox++) {
392 const DataIndex& din = dit[mybox];
393
394 List<P>& particles = a_particles[lvl][din].listItems();
395
396 for (ListIterator<P> lit(particles); lit.ok();) {
397 if (a_removeCriterion(lit())) {
398 particles.remove(lit);
399 }
400 else {
401 ++lit;
402 }
403 }
404 }
405 }
406}
407
408template <typename P>
409inline void
412 const std::function<bool(const P&)>& a_transferCrit) noexcept
413{
414 CH_TIME("ParticleOps::transferParticles(ParticleContainer<P>, ParticleContainer<P>& std::function<bool(const P&)>)");
415
416 CH_assert(a_dstParticles.getRealm() == a_srcParticles.getRealm());
417 CH_assert(a_dstParticles.getFinestLevel() == a_srcParticles.getFinestLevel());
418
419 for (int lvl = 0; lvl <= a_srcParticles.getFinestLevel(); lvl++) {
420 const DisjointBoxLayout& dbl = a_srcParticles.getGrids()[lvl];
421 const DataIterator& dit = dbl.dataIterator();
422
423 const int nbox = dit.size();
424
425#pragma omp parallel for schedule(runtime)
426 for (int mybox = 0; mybox < nbox; mybox++) {
427 const DataIndex& din = dit[mybox];
428
429 List<P>& dstParticles = a_dstParticles[lvl][din].listItems();
430 List<P>& srcParticles = a_srcParticles[lvl][din].listItems();
431
432 for (ListIterator<P> lit(srcParticles); lit.ok();) {
433 if (a_transferCrit(lit())) {
434 dstParticles.transfer(lit);
435 }
436 else {
437 ++lit;
438 }
439 }
440 }
441 }
442}
443
444template <typename P>
445inline void
447{
448 CH_TIME("ParticleOps::setData(ParticleContainer<P>, std::function<void(P&)>)");
449
450 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
451 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
452 const DataIterator& dit = dbl.dataIterator();
453
454 const int nbox = dit.size();
455
456#pragma omp parallel for schedule(runtime)
457 for (int mybox = 0; mybox < nbox; mybox++) {
458 const DataIndex& din = dit[mybox];
459
460 List<P>& particles = a_particles[lvl][din].listItems();
461
462 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
463 a_functor(lit());
464 }
465 }
466 }
467}
468
469template <typename P, Real& (P::*particleScalarField)()>
470inline void
472{
473 CH_TIME("ParticleOps::setValue(ParticleContainer<P>, Real");
474
475 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
476 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
477 const DataIterator& dit = dbl.dataIterator();
478
479 const int nbox = dit.size();
480
481#pragma omp parallel for schedule(runtime)
482 for (int mybox = 0; mybox < nbox; mybox++) {
483 const DataIndex& din = dit[mybox];
484
485 List<P>& particles = a_particles[lvl][din].listItems();
486
487 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
488 P& p = lit();
489
491 }
492 }
493 }
494}
495
496template <typename P, RealVect& (P::*particleVectorField)()>
497inline void
499{
500 CH_TIME("ParticleOps::setValue(ParticleContainer<P>, RealVect");
501
502 for (int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
503 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
504 const DataIterator& dit = dbl.dataIterator();
505
506 const int nbox = dit.size();
507
508#pragma omp parallel for schedule(runtime)
509 for (int mybox = 0; mybox < nbox; mybox++) {
510 const DataIndex& din = dit[mybox];
511
512 List<P>& particles = a_particles[lvl][din].listItems();
513
514 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
515 P& p = lit();
516
518 }
519 }
520 }
521}
522
523#ifdef CH_MPI
524template <typename P>
525inline void
526ParticleOps::scatterParticles(ParticleMap<List<P>>& a_receivedParticles,
528{
529 CH_TIME("ParticleOps::scatterParticles");
530
531 const int numRanks = numProc();
532
533 int mpiErr;
534
535 CH_assert(a_sentParticles.size() == numProc());
536
537 const size_t linearSize = P().size();
538
541
542 // Figure out the size sent from this rank to other ranks.
543 for (int irank = 0; irank < numRanks; irank++) {
544 sendSizes[irank] = 0;
545
546 // Figure out the message size sent from this rank.
548
549 // Size of particles along.
550 for (const auto& m : particlesToRank) {
551 sendSizes[irank] += (uint64_t)m.second.length();
552 }
554
555 // Send size = #particles * linearSize + level index (uint32_t) + grid index(uint32_t) + list length (size_t)
556 sendSizes[irank] += particlesToRank.size() * (2 * sizeof(uint32_t) + sizeof(size_t));
557 }
558
559 // Collectively exchange send & receive sizes
561 if (mpiErr != MPI_SUCCESS) {
562 MayDay::Error("ParticleOps::scatterParticles - MPI communication error in MPI_AlltoAll(1)");
563 }
564
565 // Sanity check
566 if (recvSizes[procID()] != 0) {
567 MayDay::Error("ParticleOps::scatterParticles - 'recvSizes[procID()] != 0' failed");
568 }
569
570 // Lambda for computing message displacements
573
574 for (size_t i = 1; i < counts.size(); i++) {
575 displacements[i] = displacements[i - 1] + counts[i - 1];
576 }
577
578 return displacements;
579 };
580
583
584 const uint64_t totalSend = sendDisplacements.back() + sendSizes.back();
585 const uint64_t totalRecv = recvDisplacements.back() + recvSizes.back();
586
589
590 // Pack data sent from this rank into buffers
591 for (int irank = 0; irank < numRanks; irank++) {
592 if (sendSizes[irank] == 0) {
593 continue;
594 }
595
596 char* data = sendBuffer.data() + sendDisplacements[irank];
597
598 // Linearize each entry in the map onto the send buffer. We encode this by (level, index, list length, List<P>)
599 for (const auto& cur : a_sentParticles[irank]) {
600
601 // and grid index
602 *((uint32_t*)data) = cur.first.first;
603 data += sizeof(uint32_t);
604 *((uint32_t*)data) = cur.first.second;
605 data += sizeof(uint32_t);
606
607 // List length aka number of particles
608 *((size_t*)data) = cur.second.length();
609 data += sizeof(size_t);
610
611 // Linearize the particle list
612 for (ListIterator<P> lit(cur.second); lit.ok(); ++lit) {
613 const P& p = lit();
614
615 p.linearOut((void*)data);
616 data += linearSize;
617 }
618 }
619 }
620
621 // MPI requires stuff as int -- make sure that we can convert properly
623 std::vector<int> v(v64.size());
624
625 for (size_t i = 0; i < v64.size(); ++i) {
626 CH_assert(v64[i] <= static_cast<uint64_t>(std::numeric_limits<int>::max()));
627
628 v[i] = static_cast<int>(v64[i]);
629 }
630
631 return v;
632 };
633
638
640 sendCounts.data(),
641 sendDispl.data(),
642 MPI_CHAR,
643 recvBuffer.data(),
644 recvCounts.data(),
645 recvDispl.data(),
646 MPI_CHAR,
648
649 if (mpiErr != MPI_SUCCESS) {
650 MayDay::Error("ParticleOps::scatterParticles - MPI communication error in MPI_AlltoAll(2)");
651 }
652
653 // Clear the send buffers.
654 for (int irank = 0; irank < numRanks; irank++) {
655 a_sentParticles[irank].clear();
656 }
657
658 // Unpack data
659 for (int irank = 0; irank < numRanks; irank++) {
660 if (recvSizes[irank] == 0) {
661 continue;
662 }
663 else {
664 char* data = recvBuffer.data() + recvDisplacements[irank];
665
666 uint64_t in = 0;
667
668 while (in < recvSizes[irank]) {
669
670 // Level and grid index
671 uint32_t lvl = *((uint32_t*)data);
672 data += sizeof(uint32_t);
673
674 uint32_t idx = *((uint32_t*)data);
675 data += sizeof(uint32_t);
676
677 // List length aka number of particles
678 size_t numParticles = *((size_t*)data);
679 data += sizeof(size_t);
680
681 for (size_t ipart = 0; ipart < numParticles; ipart++) {
682 P p;
683
684 p.linearIn(static_cast<void*>(data));
685 data += linearSize;
686
688 }
689
690 in += 2 * sizeof(uint32_t) + sizeof(size_t) + numParticles * linearSize;
691 }
692 }
693 }
694}
695#endif
696
697#include <CD_NamespaceFooter.H>
698
699#endif
Agglomeration of basic MPI reductions.
std::unordered_map< std::pair< uint32_t, uint32_t >, T, PairHash > ParticleMap
Underlying particle map when gathering/scattering particles.
Definition CD_ParticleMap.H:75
Declaration of a static class containing some common useful particle routines that would otherwise be...
Agglomeration of some useful algebraic/polynomial routines.
File containing some useful static methods related to random number generation.
static void copy(ParticleContainer< P > &a_dst, const ParticleContainer< P > &a_src) noexcept
Copy all the particles from the a_src to a_dst.
Definition CD_ParticleOpsImplem.H:273
static Real sum(const ParticleContainer< P > &a_particles) noexcept
Perform a sum of some particle quantity.
Definition CD_ParticleOpsImplem.H:321
static void getComputationalParticlesPerCell(EBAMRCellData &a_ppc, const ParticleContainer< P > &a_src) noexcept
Get the number of computational particles per cell.
Definition CD_ParticleOpsImplem.H:88
static void transferParticles(ParticleContainer< P > &a_dstParticles, ParticleContainer< P > &a_srcParticles, const std::function< bool(const P &)> &a_transferCrit) noexcept
Transfer particles if they fulfill a certain removal criterion. Takes particles from a_srcParticles a...
Definition CD_ParticleOpsImplem.H:410
static bool ebIntersectionRaycast(const RefCountedPtr< BaseIF > &a_impFunc, const RealVect &a_oldPos, const RealVect &a_newPos, const Real &a_tolerance, Real &a_s)
Compute the intersection point between a particle path and an implicit function using a ray-casting a...
Definition CD_ParticleOpsImplem.H:222
static bool ebIntersectionBisect(const RefCountedPtr< BaseIF > &a_impFunc, const RealVect &a_oldPos, const RealVect &a_newPos, const Real &a_bisectStep, Real &a_s)
Compute the intersection point between a particle path and an implicit function using a bisection alg...
Definition CD_ParticleOpsImplem.H:178
static void setValue(ParticleContainer< P > &a_particles, const Real a_value) noexcept
Set value function. Lets the user set scalar particle quantity. Use with e.g. setValue<P,...
Definition CD_ParticleOpsImplem.H:471
static void removeParticles(ParticleContainer< P > &a_particles, const std::function< bool(const P &)> &a_removeCriterion) noexcept
Remove particles if they fulfill certain removal criterion.
Definition CD_ParticleOpsImplem.H:379
static void getPhysicalParticlesPerCell(EBAMRCellData &a_ppc, const ParticleContainer< P > &a_src) noexcept
Get the number of physical particles per cell.
Definition CD_ParticleOpsImplem.H:52
static void copyDestructive(ParticleContainer< P > &a_dst, ParticleContainer< P > &a_src) noexcept
Copy all the particles from the a_src to a_dst. This destroys the source particles.
Definition CD_ParticleOpsImplem.H:296
static IntVect getParticleGridCell(const RealVect &a_particlePosition, const RealVect &a_probLo, const RealVect &a_dx) noexcept
Get the grid cell where the particle lives.
Definition CD_ParticleOpsImplem.H:122
static IntVect getParticleCellIndex(const RealVect &a_particlePosition, const RealVect &a_probLo, const Real &a_dx) noexcept
Get the cell index corresponding to the particle position.
Definition CD_ParticleOpsImplem.H:31
static void setData(ParticleContainer< P > &a_particles, const std::function< void(P &)> &a_functor) noexcept
Set value function. Lets the user set particle parameters.
Definition CD_ParticleOpsImplem.H:446
static bool domainIntersection(const RealVect &a_oldPos, const RealVect &a_newPos, const RealVect &a_probLo, const RealVect &a_probHi, Real &a_s)
Compute the intersection point between a particle path and a domain side.
Definition CD_ParticleOpsImplem.H:132
Base class for a tracer particle solver. This solver can advance particles in a pre-defined velocity ...
Definition CD_TracerParticleSolver.H:38
TracerParticleSolver()
Default constructor.
Definition CD_TracerParticleSolverImplem.H:26
Real sum(const Real &a_value) noexcept
Compute the sum across all MPI ranks.
Definition CD_ParallelOpsImplem.H:354
RealVect brentRootFinder(const RefCountedPtr< BaseIF > &a_impFunc, const RealVect &a_point1, const RealVect &a_point2)
Compute the root of a function between two points. This is a 1D problem along the line.
Definition CD_PolyUtils.cpp:25