12 #ifndef CD_ParticleOpsImplem_H
13 #define CD_ParticleOpsImplem_H
23 #include <CD_NamespaceHeader.H>
27 const RealVect& a_probLo,
28 const Real& a_dx) noexcept
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)));
37 const RealVect& a_probLo,
38 const RealVect& a_dx) noexcept
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])));
45 template <
typename P, const Real& (P::*weight)() const>
49 CH_TIME(
"ParticleOps::getPhysicalParticlesPerCell");
51 const RealVect probLo = a_src.getProbLo();
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];
58 const int nbox = dit.size();
60 #pragma omp parallel for schedule(runtime)
61 for (
int mybox = 0; mybox < nbox; mybox++) {
62 const DataIndex& din = dit[mybox];
64 const List<P>& particles = a_src[lvl][din].listItems();
66 FArrayBox& ppc = (*a_ppc[lvl])[din].getFArrayBox();
69 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
71 const RealVect x = p.position();
72 const Real w = (p.*weight)();
85 CH_TIME(
"ParticleOps::getComputationalParticlesPerCell");
87 const RealVect probLo = a_src.getProbLo();
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];
94 const int nbox = dit.size();
96 #pragma omp parallel for schedule(runtime)
97 for (
int mybox = 0; mybox < nbox; mybox++) {
98 const DataIndex& din = dit[mybox];
100 const List<P>& particles = a_src[lvl][din].listItems();
102 FArrayBox& ppc = (*a_ppc[lvl])[din].getFArrayBox();
105 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
107 const RealVect x = p.position();
118 const RealVect& a_probLo,
119 const RealVect& a_dx) noexcept
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])));
128 const RealVect& a_newPos,
129 const RealVect& a_probLo,
130 const RealVect& a_probHi,
139 bool crossedDomainBoundary =
false;
141 const RealVect path = a_newPos - a_oldPos;
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;
147 const RealVect n0 = sign(side) *
150 const Real normPath = PolyGeom::dot(n0, path);
153 if (normPath > 0.0) {
158 const Real s = PolyGeom::dot(wallPoint - a_oldPos, n0) / normPath;
159 if (s >= 0.0 && s <= 1.0) {
160 crossedDomainBoundary =
true;
169 return crossedDomainBoundary;
174 const RealVect& a_oldPos,
175 const RealVect& a_newPos,
176 const Real& a_bisectStep,
185 bool crossedEB =
false;
187 const Real pathLen = (a_newPos - a_oldPos).vectorLength();
188 const int nsteps = ceil(pathLen / a_bisectStep);
189 const RealVect dxStep = (a_newPos - a_oldPos) / nsteps;
192 RealVect curPos = a_oldPos;
193 for (
int istep = 0; istep < nsteps; istep++) {
194 const Real fa = a_impFunc->value(curPos);
195 const Real fb = a_impFunc->value(curPos +
198 if (fa * fb <= 0.0) {
203 a_s = (intersectionPos - a_oldPos).vectorLength() / pathLen;
218 const RealVect& a_oldPos,
219 const RealVect& a_newPos,
220 const Real& a_tolerance,
229 auto dist = [&](
const RealVect& x) -> Real {
230 return std::abs(a_impFunc->value(x));
233 const Real D = (a_newPos - a_oldPos).vectorLength();
234 const Real D0 = dist(a_oldPos);
239 const RealVect t = (a_newPos - a_oldPos) / D;
244 RealVect xa = a_oldPos;
250 if (d < a_tolerance) {
251 a_s = (xa - a_oldPos).vectorLength() / D;
266 template <
typename P>
270 CH_TIME(
"ParticleOps::copy(ParticleContainer<P> x2)");
272 CH_assert(a_dst.getRealm() == a_src.getRealm());
274 for (
int lvl = 0; lvl <= a_dst.getFinestLevel(); lvl++) {
275 const DisjointBoxLayout& dbl = a_dst.getGrids()[lvl];
276 const DataIterator& dit = dbl.dataIterator();
278 const int nbox = dit.size();
280 #pragma omp parallel for schedule(runtime)
281 for (
int mybox = 0; mybox < nbox; mybox++) {
282 const DataIndex& din = dit[mybox];
284 a_dst[lvl][din].listItems() = a_src[lvl][din].listItems();
289 template <
typename P>
293 CH_TIME(
"ParticleOps::copyDestructive(ParticleContainer<P> x2)");
295 CH_assert(a_dst.getRealm() == a_src.getRealm());
297 for (
int lvl = 0; lvl <= a_dst.getFinestLevel(); lvl++) {
298 const DisjointBoxLayout& dbl = a_dst.getGrids()[lvl];
299 const DataIterator& dit = dbl.dataIterator();
301 const int nbox = dit.size();
303 #pragma omp parallel for schedule(runtime)
304 for (
int mybox = 0; mybox < nbox; mybox++) {
305 const DataIndex& din = dit[mybox];
307 a_dst[lvl][din].listItems() = a_src[lvl][din].listItems();
309 a_src[lvl][din].listItems().clear();
314 template <
typename P, const Real& (P::*scalarQuantity)() const>
318 CH_TIME(
"ParticleOps::sum(ParticleContainer<P>)");
320 Real particleSum = 0.0;
322 for (
int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
323 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
324 const DataIterator& dit = dbl.dataIterator();
326 const int nbox = dit.size();
328 #pragma omp parallel for schedule(runtime) reduction(+ : particleSum)
329 for (
int mybox = 0; mybox < nbox; mybox++) {
330 const DataIndex& din = dit[mybox];
332 const List<P>& particles = a_particles[lvl][din].listItems();
334 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
335 particleSum += (lit().*scalarQuantity)();
343 template <
typename P, Real (P::*scalarQuantity)()>
347 CH_TIME(
"ParticleOps::sum(ParticleContainer<P>)");
349 Real particleSum = 0.0;
351 for (
int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
352 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
353 const DataIterator& dit = dbl.dataIterator();
355 const int nbox = dit.size();
357 #pragma omp parallel for schedule(runtime) reduction(+ : particleSum)
358 for (
int mybox = 0; mybox < nbox; mybox++) {
359 const DataIndex& din = dit[mybox];
361 const List<P>& particles = a_particles[lvl][din].listItems();
363 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
364 particleSum += (lit().*scalarQuantity)();
372 template <
typename P>
375 const std::function<
bool(
const P&)>& a_removeCriterion) noexcept
377 CH_TIME(
"ParticleOps::removeParticles(ParticleContainer<P>, std::function<bool(const P&)>)");
380 const DisjointBoxLayout& dbl = a_particles.
getGrids()[lvl];
381 const DataIterator& dit = dbl.dataIterator();
383 const int nbox = dit.size();
385 #pragma omp parallel for schedule(runtime)
386 for (
int mybox = 0; mybox < nbox; mybox++) {
387 const DataIndex& din = dit[mybox];
389 List<P>& particles = a_particles[lvl][din].listItems();
391 for (ListIterator<P> lit(particles); lit.ok();) {
392 if (a_removeCriterion(lit())) {
393 particles.remove(lit);
403 template <
typename P>
407 const std::function<
bool(
const P&)>& a_transferCrit) noexcept
409 CH_TIME(
"ParticleOps::transferParticles(ParticleContainer<P>, ParticleContainer<P>& std::function<bool(const P&)>)");
414 for (
int lvl = 0; lvl <= a_srcParticles.
getFinestLevel(); lvl++) {
415 const DisjointBoxLayout& dbl = a_srcParticles.
getGrids()[lvl];
416 const DataIterator& dit = dbl.dataIterator();
418 const int nbox = dit.size();
420 #pragma omp parallel for schedule(runtime)
421 for (
int mybox = 0; mybox < nbox; mybox++) {
422 const DataIndex& din = dit[mybox];
424 List<P>& dstParticles = a_dstParticles[lvl][din].listItems();
425 List<P>& srcParticles = a_srcParticles[lvl][din].listItems();
427 for (ListIterator<P> lit(srcParticles); lit.ok();) {
428 if (a_transferCrit(lit())) {
429 dstParticles.transfer(lit);
439 template <
typename P>
443 CH_TIME(
"ParticleOps::setData(ParticleContainer<P>, std::function<void(P&)>)");
446 const DisjointBoxLayout& dbl = a_particles.
getGrids()[lvl];
447 const DataIterator& dit = dbl.dataIterator();
449 const int nbox = dit.size();
451 #pragma omp parallel for schedule(runtime)
452 for (
int mybox = 0; mybox < nbox; mybox++) {
453 const DataIndex& din = dit[mybox];
455 List<P>& particles = a_particles[lvl][din].listItems();
457 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
464 template <
typename P, Real& (P::*particleScalarField)()>
468 CH_TIME(
"ParticleOps::setValue(ParticleContainer<P>, Real");
471 const DisjointBoxLayout& dbl = a_particles.
getGrids()[lvl];
472 const DataIterator& dit = dbl.dataIterator();
474 const int nbox = dit.size();
476 #pragma omp parallel for schedule(runtime)
477 for (
int mybox = 0; mybox < nbox; mybox++) {
478 const DataIndex& din = dit[mybox];
480 List<P>& particles = a_particles[lvl][din].listItems();
482 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
485 (p.*particleScalarField)() = a_value;
491 template <
typename P, RealVect& (P::*particleVectorField)()>
495 CH_TIME(
"ParticleOps::setValue(ParticleContainer<P>, RealVect");
498 const DisjointBoxLayout& dbl = a_particles.
getGrids()[lvl];
499 const DataIterator& dit = dbl.dataIterator();
501 const int nbox = dit.size();
503 #pragma omp parallel for schedule(runtime)
504 for (
int mybox = 0; mybox < nbox; mybox++) {
505 const DataIndex& din = dit[mybox];
507 List<P>& particles = a_particles[lvl][din].listItems();
509 for (ListIterator<P> lit(particles); lit.ok(); ++lit) {
512 (p.*particleVectorField)() = a_value;
519 template <
typename P>
521 ParticleOps::scatterParticles(
522 std::map<std::pair<unsigned int, unsigned int>, List<P>>& a_receivedParticles,
523 std::vector<std::map<std::pair<unsigned int, unsigned int>, List<P>>>& a_sentParticles) noexcept
525 CH_TIME(
"ParticleOps::scatterParticles");
527 const int numRanks = numProc();
531 CH_assert(a_sentParticles.size() == numProc());
533 const size_t linearSize = P().size();
535 std::vector<unsigned int> sendSizes(numProc(), 0);
536 std::vector<unsigned int> recvSizes(numProc(), 0);
539 for (
int irank = 0; irank < numRanks; irank++) {
540 sendSizes[irank] = 0;
543 const std::map<std::pair<unsigned int, unsigned int>, List<P>>& particlesToRank = a_sentParticles[irank];
546 for (
const auto& m : particlesToRank) {
547 sendSizes[irank] += m.second.length();
549 sendSizes[irank] *= linearSize;
552 sendSizes[irank] += particlesToRank.size() * (2 *
sizeof(
unsigned int) +
sizeof(
size_t));
555 mpiErr = MPI_Alltoall(&sendSizes[0], 1, MPI_UNSIGNED, &recvSizes[0], 1, MPI_UNSIGNED, Chombo_MPI::comm);
556 if (mpiErr != MPI_SUCCESS) {
557 MayDay::Error(
"ParticleOps::scatterParticles - MPI communication error in MPI_AlltoAll");
561 if (recvSizes[procID()] != 0) {
562 MayDay::Error(
"ParticleOps::scatterParticles - 'recvSizes[procID()] != 0' failed");
565 std::vector<MPI_Request> recvReq(numRanks - 1);
566 std::vector<char*> recvBuf(numRanks,
nullptr);
568 std::vector<MPI_Request> sendReq(numRanks - 1);
569 std::vector<char*> sendBuf(numRanks,
nullptr);
571 int recvReqCount = 0;
572 int sendReqCount = 0;
574 for (
int irank = 0; irank < numRanks; irank++) {
575 if (recvSizes[irank] > 0) {
576 recvBuf[irank] =
new char[recvSizes[irank]];
578 MPI_Irecv(recvBuf[irank], recvSizes[irank], MPI_CHAR, irank, 1, Chombo_MPI::comm, &recvReq[recvReqCount]);
585 for (
int irank = 0; irank < numRanks; irank++) {
586 if (sendSizes[irank] > 0) {
587 sendBuf[irank] =
new char[sendSizes[irank]];
589 char* data = sendBuf[irank];
591 const std::map<std::pair<unsigned int, unsigned int>, List<P>>& particles = a_sentParticles[irank];
594 for (
const auto& cur : particles) {
597 *((
unsigned int*)data) = cur.first.first;
598 data +=
sizeof(
unsigned int);
599 *((
unsigned int*)data) = cur.first.second;
600 data +=
sizeof(
unsigned int);
603 *((
size_t*)data) = cur.second.length();
604 data +=
sizeof(size_t);
607 for (ListIterator<P> lit(cur.second); lit.ok(); ++lit) {
610 p.linearOut((
void*)data);
616 MPI_Isend(sendBuf[irank], sendSizes[irank], MPI_CHAR, irank, 1, Chombo_MPI::comm, &sendReq[sendReqCount]);
622 std::vector<MPI_Status> recvStatus(numRanks - 1);
623 std::vector<MPI_Status> sendStatus(numRanks - 1);
625 if (sendReqCount > 0) {
626 mpiErr = MPI_Waitall(sendReqCount, &sendReq[0], &sendStatus[0]);
628 if (mpiErr != MPI_SUCCESS) {
629 MayDay::Error(
"ParticleOps::scatterParticles: send communication failed");
633 if (recvReqCount > 0) {
634 mpiErr = MPI_Waitall(recvReqCount, &recvReq[0], &recvStatus[0]);
636 if (mpiErr != MPI_SUCCESS) {
637 MayDay::Error(
"ParticleOps::scatterParticles: receive communication failed");
642 for (
int irank = 0; irank < numRanks; irank++) {
645 if (recvSizes[irank] > 0) {
647 char* data = recvBuf[irank];
651 while (in < recvSizes[irank]) {
654 unsigned int lvl = *((
unsigned int*)data);
655 data +=
sizeof(
unsigned int);
657 unsigned int idx = *((
unsigned int*)data);
658 data +=
sizeof(
unsigned int);
661 size_t numParticles = *((
size_t*)data);
662 data +=
sizeof(size_t);
664 for (
size_t ipart = 0; ipart < numParticles; ipart++) {
665 p.linearIn((
void*)data);
668 a_receivedParticles[std::pair<unsigned int, unsigned int>(lvl, idx)].add(p);
671 in += 2 *
sizeof(
unsigned int) +
sizeof(
size_t) + numParticles * linearSize;
677 for (
int irank = 0; irank < numRanks; irank++) {
678 a_sentParticles[irank].clear();
680 if (sendSizes[irank] > 0) {
681 delete[] sendBuf[irank];
683 if (recvSizes[irank] > 0) {
684 delete[] recvBuf[irank];
690 #include <CD_NamespaceFooter.H>
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.
Templated class for holding particles on an AMR hierarchy with particle remapping.
Definition: CD_ParticleContainer.H:50
const Vector< DisjointBoxLayout > & getGrids() const
Get the AMR grids.
Definition: CD_ParticleContainerImplem.H:249
int getFinestLevel() const
Get finest AMR level.
Definition: CD_ParticleContainerImplem.H:231
const std::string getRealm() const
Get the realm where this ParticleContainer lives.
Definition: CD_ParticleContainerImplem.H:240
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
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 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