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