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