chombo-discharge
CD_AmrMeshImplem.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_AmrMeshImplem_H
13 #define CD_AmrMeshImplem_H
14 
15 // Our includes
16 #include <CD_AmrMesh.H>
17 #include <CD_ParticleOps.H>
18 #include <CD_NamespaceHeader.H>
19 
20 template <typename T>
21 void
23  const EBAMRData<T>& a_src,
24  const CopyStrategy& a_toRegion,
25  const CopyStrategy& a_fromRegion) const noexcept
26 {
27  CH_TIME("AmrMesh::copyData(EBAMRData, simple)");
28  if (m_verbosity > 5) {
29  pout() << "AmrMesh::copyData(EBAMRData, simple)" << endl;
30  }
31 
32  const int nComp = a_dst[0]->nComp();
33  const Interval dstComps = Interval(0, nComp - 1);
34  const Interval srcComps = Interval(0, nComp - 1);
35 
36  const std::string toRealm = a_dst.getRealm();
37  const std::string fromRealm = a_src.getRealm();
38 
39  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
40  CH_assert(!(a_dst[lvl].isNull()));
41  CH_assert(!(a_src[lvl].isNull()));
42 
43  this->copyData(*a_dst[lvl], *a_src[lvl], lvl, toRealm, fromRealm, dstComps, srcComps, a_toRegion, a_fromRegion);
44  }
45 }
46 
47 template <typename T>
48 void
50  const EBAMRData<T>& a_src,
51  const Interval& a_dstComps,
52  const Interval& a_srcComps,
53  const CopyStrategy& a_toRegion,
54  const CopyStrategy& a_fromRegion) const noexcept
55 {
56  CH_TIME("AmrMesh::copyData(EBAMRData, full)");
57  if (m_verbosity > 5) {
58  pout() << "AmrMesh::copyData(EBAMRData, full)" << endl;
59  }
60 
61  const std::string toRealm = a_dst.getRealm();
62  const std::string fromRealm = a_src.getRealm();
63 
64  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
65  CH_assert(!(a_dst[lvl].isNull()));
66  CH_assert(!(a_src[lvl].isNull()));
67 
68  this->copyData(*a_dst[lvl], *a_src[lvl], lvl, toRealm, fromRealm, a_dstComps, a_srcComps, a_toRegion, a_fromRegion);
69  }
70 }
71 
72 template <typename T>
73 void
74 AmrMesh::copyData(LevelData<T>& a_dst,
75  const LevelData<T>& a_src,
76  const int a_level,
77  const std::string a_toRealm,
78  const std::string a_fromRealm,
79  const CopyStrategy& a_toRegion,
80  const CopyStrategy& a_fromRegion) const noexcept
81 {
82  CH_TIME("AmrMesh::copyData(LD<T>_full)");
83  if (m_verbosity > 5) {
84  pout() << "AmrMesh::copyData(LD<T>_full)" << endl;
85  }
86 
87  const Interval dstComps = Interval(0, a_dst.nComp() - 1);
88  const Interval srcComps = Interval(0, a_src.nComp() - 1);
89 
90  this->copyData(a_dst, a_src, a_level, a_toRealm, a_fromRealm, dstComps, srcComps, a_toRegion, a_fromRegion);
91 }
92 
93 template <typename T>
94 void
95 AmrMesh::copyData(LevelData<T>& a_dst,
96  const LevelData<T>& a_src,
97  const int a_level,
98  const std::string a_toRealm,
99  const std::string a_fromRealm,
100  const Interval& a_dstComps,
101  const Interval& a_srcComps,
102  const CopyStrategy& a_toRegion,
103  const CopyStrategy& a_fromRegion) const noexcept
104 {
105  CH_TIME("AmrMesh::copyData(LD<T>_full)");
106  if (m_verbosity > 5) {
107  pout() << "AmrMesh::copyData(LD<T>_full)" << endl;
108  }
109 
110  CH_assert(a_dstComps.size() == a_srcComps.size());
111  CH_assert(a_dst.nComp() > a_dstComps.end());
112  CH_assert(a_src.nComp() > a_srcComps.end());
113 
114  if (a_toRealm != a_fromRealm) {
115  const auto id = std::make_pair(a_fromRealm, a_toRealm);
116 
117  if (a_toRegion == CopyStrategy::ValidGhost) {
118  CH_assert(a_dst.ghostVect() == m_numGhostCells * IntVect::Unit);
119  }
120  if (a_fromRegion == CopyStrategy::ValidGhost) {
121  CH_assert(a_src.ghostVect() == m_numGhostCells * IntVect::Unit);
122  }
123 
124  Copier copier;
125 
126  if (a_fromRegion == CopyStrategy::Valid) {
127  if (a_toRegion == CopyStrategy::Valid) {
128  copier = m_validToValidRealmCopiers.at(id)[a_level];
129  }
130  else if (a_toRegion == CopyStrategy::ValidGhost) {
131  copier = m_validToValidGhostRealmCopiers.at(id)[a_level];
132  }
133  else {
134  MayDay::Abort("AmrMesh::copyData - logic bust 1");
135  }
136  }
137  else if (a_fromRegion == CopyStrategy::ValidGhost) {
138  if (a_toRegion == CopyStrategy::Valid) {
139  copier = m_validGhostToValidRealmCopiers.at(id)[a_level];
140  }
141  else if (a_toRegion == CopyStrategy::ValidGhost) {
142  copier = m_validGhostToValidGhostRealmCopiers.at(id)[a_level];
143  }
144  else {
145  MayDay::Abort("AmrMesh::copyData - logic bust 2");
146  }
147  }
148  else {
149  MayDay::Abort("AmrMesh::copyData - logic bust 3");
150  }
151 
152  a_src.copyTo(a_srcComps, a_dst, a_dstComps, copier);
153  }
154  else {
155  a_src.localCopyTo(a_srcComps, a_dst, a_dstComps);
156  }
157 }
158 
159 template <typename T>
160 void
161 AmrMesh::deallocate(Vector<T*>& a_data) const
162 {
163  CH_TIME("AmrMesh::deallocate(Vector<T*>)");
164  if (m_verbosity > 5) {
165  pout() << "AmrMesh::deallocate(Vector<T*>)" << endl;
166  }
167 
168  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
169  delete a_data[lvl];
170  }
171 }
172 
173 template <typename T>
174 void
175 AmrMesh::deallocate(Vector<RefCountedPtr<T>>& a_data) const
176 {
177  CH_TIME("AmrMesh::deallocate(Vector<RefCountedPtr<T>)");
178  if (m_verbosity > 5) {
179  pout() << "AmrMesh::deallocate(Vector<RefCountedPtr<T>)" << endl;
180  }
181 
182  for (int lvl = 0; lvl < a_data.size(); lvl++) {
183  // delete &a_data[lvl];
184  a_data[lvl] = RefCountedPtr<T>(0);
185 #if 0
186  if(!a_data[lvl].isNull()){
187  delete &(*a_data[lvl]);
188  a_data[lvl] = RefCountedPtr<T> (NULL);
189  }
190 
191 #endif
192  }
193 }
194 
195 template <typename T>
196 void
198 {
199  CH_TIME("AmrMesh::deallocate(EBAMRData<T>)");
200  if (m_verbosity > 5) {
201  pout() << "AmrMesh::deallocate(EBAMRData<T>)" << endl;
202  }
203 
204  return this->deallocate(a_data.getData());
205 }
206 
207 template <typename T>
208 void
209 AmrMesh::alias(Vector<T*>& a_alias, const Vector<RefCountedPtr<T>>& a_data) const
210 {
211  CH_TIME("AmrMesh::alias(Vector<T*>, Vector<RefCountedPtr<T>)");
212  if (m_verbosity > 5) {
213  pout() << "AmrMesh::alias(Vector<T*>, Vector<RefCountedPtr<T>)" << endl;
214  }
215 
216  a_alias.resize(a_data.size());
217 
218  for (int lvl = 0; lvl < a_data.size(); lvl++) {
219  a_alias[lvl] = &(*a_data[lvl]);
220  }
221 }
222 
223 template <typename T, typename S>
224 void
225 AmrMesh::alias(Vector<T*>& a_alias, const EBAMRData<S>& a_data) const
226 {
227  CH_TIME("AmrMesh::alias(Vector<T*>, EBAMRData<S>)");
228  if (m_verbosity > 5) {
229  pout() << "AmrMesh::alias(Vector<T*>, EBAMRData<S>" << endl;
230  }
231 
232  return this->alias(a_alias, a_data.getData());
233 }
234 
235 template <typename T>
236 void
237 AmrMesh::allocate(Vector<RefCountedPtr<ParticleData<T>>>& a_particles, const std::string a_realm) const
238 {
239  CH_TIME("AmrMesh::allocate(Vector<RefCountedPtr<ParticleData<T> > >, string)");
240  if (m_verbosity > 5) {
241  pout() << "AmrMesh::allocate(Vector<RefCountedPtr<ParticleData<T> > >, string)" << endl;
242  }
243 
244  if (!this->queryRealm(a_realm)) {
245  const std::string
246  str = "AmrMesh::allocate(Vector<RefCountedPtr<ParticleData<T> > >, string) - could not find Realm '" + a_realm +
247  "'";
248  MayDay::Abort(str.c_str());
249  }
250 
252  MayDay::Abort(
253  "AmrMesh::allocate(Vector<RefCountedPtr<ParticleData<T> > >, string) - only constant box sizes supported for particle methods");
254  }
255 
256  a_particles.resize(1 + m_finestLevel);
257 
258  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
259  const DisjointBoxLayout& dbl = m_realms[a_realm]->getGrids()[lvl];
260  const ProblemDomain& domain = m_realms[a_realm]->getDomains()[lvl];
261 
262  const Real dx = m_dx[lvl];
263 
264  a_particles[lvl] = RefCountedPtr<ParticleData<T>>(
265  new ParticleData<T>(dbl, domain, m_blockingFactor, dx * RealVect::Unit, m_probLo));
266  }
267 }
268 
269 template <typename T>
270 void
271 AmrMesh::allocate(ParticleContainer<T>& a_container, const std::string a_realm) const
272 {
273  CH_TIME("AmrMesh::allocate(ParticleContainer<T>, int, string)");
274  if (m_verbosity > 5) {
275  pout() << "AmrMesh::allocate(ParticleContainer<T>, int, string)" << endl;
276  }
277 
278  if (!this->queryRealm(a_realm)) {
279  const std::string str = "AmrMesh::allocate(ParticleContainer<T>, int, string) - could not find Realm '" + a_realm +
280  "'";
281  MayDay::Abort(str.c_str());
282  }
283 
285  MayDay::Abort(
286  "AmrMesh::allocate(ParticleContainer<T>, int, string) - only constant box sizes are supported for particle methods");
287  }
288 
289  a_container.define(m_realms[a_realm]->getGrids(),
290  m_realms[a_realm]->getDomains(),
291  m_realms[a_realm]->getDx(),
292  m_realms[a_realm]->getRefinementRatios(),
293  m_realms[a_realm]->getValidCells(),
294  m_realms[a_realm]->getLevelTiles(),
295  m_probLo,
298  a_realm);
299 }
300 
301 template <typename T>
302 void
303 AmrMesh::allocatePointer(Vector<RefCountedPtr<T>>& a_data) const
304 {
305  CH_TIME("AmrMesh::allocatePointer(Vector<RefCountedPtr<T> >)");
306  if (m_verbosity > 5) {
307  pout() << "AmrMesh::allocatePointer(Vector<RefCountedPtr<T> >)" << endl;
308  }
309 
310  a_data.resize(1 + m_finestLevel);
311  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
312  a_data[lvl] = RefCountedPtr<T>(new T());
313  }
314 }
315 
316 template <typename T>
317 void
318 AmrMesh::allocatePointer(Vector<RefCountedPtr<T>>& a_data, const int a_finestLevel) const
319 {
320  CH_TIME("AmrMesh::allocatePointer(Vector<RefCountedPtr<T> >, int)");
321  if (m_verbosity > 5) {
322  pout() << "AmrMesh::allocatePointer(Vector<RefCountedPtr<T> >, int)" << endl;
323  }
324 
325  a_data.resize(1 + a_finestLevel);
326 
327  for (int lvl = 0; lvl <= a_finestLevel; lvl++) {
328  a_data[lvl] = RefCountedPtr<T>(new T());
329  }
330 }
331 
332 template <typename T>
333 void
334 AmrMesh::allocatePointer(EBAMRData<T>& a_data, const std::string a_realm) const
335 {
336  CH_TIME("AmrMesh::allocatePointer(EBAMRData<T>, std::string)");
337  if (m_verbosity > 5) {
338  pout() << "AmrMesh::allocatePointer(EBAMRData<T>, std::string)" << endl;
339  }
340 
341  this->allocatePointer(a_data.getData());
342 
343  a_data.setRealm(a_realm);
344 }
345 
346 template <typename T>
347 void
348 AmrMesh::allocatePointer(EBAMRData<T>& a_data, const std::string a_realm, const int a_finestLevel) const
349 {
350  CH_TIME("AmrMesh::allocatePointer(EBAMRData<T>, std::string, int)");
351  if (m_verbosity > 5) {
352  pout() << "AmrMesh::allocatePointer(EBAMRData<T>, std::string, int)" << endl;
353  }
354 
355  this->allocatePointer(a_data.getData(), a_finestLevel);
356 
357  a_data.setRealm(a_realm);
358 }
359 
360 template <class P>
361 void
362 AmrMesh::remapToNewGrids(ParticleContainer<P>& a_particles, const int a_lmin, const int a_newFinestLevel) const noexcept
363 {
364  CH_TIME("AmrMesh::remapToNewGrids");
365  if (m_verbosity > 5) {
366  pout() << "AmrMesh::remapToNewGrids" << endl;
367  }
368 
369  const std::string realm = a_particles.getRealm();
370 
371  a_particles.regrid(this->getGrids(realm),
372  this->getDomains(),
373  this->getDx(),
374  this->getRefinementRatios(),
375  this->getValidCells(realm),
376  this->getLevelTiles(realm),
377  a_lmin,
378  a_newFinestLevel);
379 }
380 
381 template <class P, const Real& (P::*particleScalarField)() const>
382 void
384  const std::string& a_realm,
385  const phase::which_phase& a_phase,
386  const ParticleContainer<P>& a_particles,
387  const DepositionType a_depositionType,
388  const CoarseFineDeposition a_coarseFineDeposition,
389  const bool a_forceIrregNGP)
390 {
391  CH_TIME("AmrMesh::depositParticles");
392  if (m_verbosity > 5) {
393  pout() << "AmrMesh::depositParticles" << endl;
394  }
395 
396  EBAMRParticleMesh& particleMesh = this->getParticleMesh(a_realm, a_phase);
397 
398  particleMesh.deposit<P, particleScalarField>(a_meshData,
399  a_particles,
400  a_depositionType,
401  a_coarseFineDeposition,
402  a_forceIrregNGP);
403 }
404 
405 template <class P, Real (P::*particleScalarField)() const>
406 void
408  const std::string& a_realm,
409  const phase::which_phase& a_phase,
410  const ParticleContainer<P>& a_particles,
411  const DepositionType a_depositionType,
412  const CoarseFineDeposition a_coarseFineDeposition,
413  const bool a_forceIrregNGP)
414 {
415  CH_TIME("AmrMesh::depositParticles");
416  if (m_verbosity > 5) {
417  pout() << "AmrMesh::depositParticles" << endl;
418  }
419 
420  EBAMRParticleMesh& particleMesh = this->getParticleMesh(a_realm, a_phase);
421 
422  particleMesh.deposit<P, particleScalarField>(a_meshData,
423  a_particles,
424  a_depositionType,
425  a_coarseFineDeposition,
426  a_forceIrregNGP);
427 }
428 
429 template <class P, const RealVect& (P::*particleVectorField)() const>
430 void
432  const std::string& a_realm,
433  const phase::which_phase& a_phase,
434  const ParticleContainer<P>& a_particles,
435  const DepositionType a_depositionType,
436  const CoarseFineDeposition a_coarseFineDeposition,
437  const bool a_forceIrregNGP)
438 {
439  CH_TIME("AmrMesh::depositParticles");
440  if (m_verbosity > 5) {
441  pout() << "AmrMesh::depositParticles" << endl;
442  }
443 
444  EBAMRParticleMesh& particleMesh = this->getParticleMesh(a_realm, a_phase);
445 
446  particleMesh.deposit<P, particleVectorField>(a_meshData,
447  a_particles,
448  a_depositionType,
449  a_coarseFineDeposition,
450  a_forceIrregNGP);
451 }
452 
453 template <class P, const Real& (P::*particleScalarField)() const>
454 void
456  const std::string& a_realm,
457  const phase::which_phase& a_phase,
458  const ParticleContainer<P>& a_particles) const noexcept
459 {
460  CH_TIME("AmrMesh::depositParticles(surface)");
461  if (m_verbosity > 5) {
462  pout() << "AmrMesh::depositParticles(surface)" << endl;
463  }
464 
465  CH_assert(a_meshData[0]->nComp() == 1);
466  CH_assert(a_meshData.getRealm() == a_particles.getRealm());
467 
468  EBAMRSurfaceDeposition& surfaceDeposition = this->getSurfaceDeposition(a_realm, a_phase);
469 
470  surfaceDeposition.deposit<P, particleScalarField>(a_meshData, a_particles);
471 }
472 
473 template <class P, Real (P::*particleScalarField)() const>
474 void
476  const std::string& a_realm,
477  const phase::which_phase& a_phase,
478  const ParticleContainer<P>& a_particles) const noexcept
479 {
480  CH_TIME("AmrMesh::depositParticles(surface)");
481  if (m_verbosity > 5) {
482  pout() << "AmrMesh::depositParticles(surface)" << endl;
483  }
484 
485  CH_assert(a_meshData[0]->nComp() == 1);
486  CH_assert(a_meshData.getRealm() == a_particles.getRealm());
487 
488  EBAMRSurfaceDeposition& surfaceDeposition = this->getSurfaceDeposition(a_realm, a_phase);
489 
490  surfaceDeposition.deposit<P, particleScalarField>(a_meshData, a_particles);
491 }
492 
493 template <class P, Real& (P::*particleScalarField)()>
494 void
496  const std::string& a_realm,
497  const phase::which_phase& a_phase,
498  const EBAMRCellData& a_meshScalarField,
499  const DepositionType a_interpType,
500  const bool a_forceIrregNGP) const
501 {
502  CH_TIME("AmrMesh::interpolateParticles(scalar)");
503  if (m_verbosity > 5) {
504  pout() << "AmrMesh::interpolateParticles(scalar)" << endl;
505  }
506 
507  CH_assert(a_realm == a_particles.getRealm());
508  CH_assert(a_realm == a_meshScalarField.getRealm());
509 
510  EBAMRParticleMesh& particleMesh = this->getParticleMesh(a_realm, a_phase);
511 
512  particleMesh.interpolate<P, particleScalarField>(a_particles, a_meshScalarField, a_interpType, a_forceIrregNGP);
513 }
514 
515 template <class P, RealVect& (P::*particleVectorField)()>
516 void
518  const std::string& a_realm,
519  const phase::which_phase& a_phase,
520  const EBAMRCellData& a_meshVectorField,
521  const DepositionType a_interpType,
522  const bool a_forceIrregNGP) const
523 {
524  CH_TIME("AmrMesh::interpolateParticles(vector)");
525  if (m_verbosity > 5) {
526  pout() << "AmrMesh::interpolateParticles(vector)" << endl;
527  }
528 
529  CH_assert(a_realm == a_particles.getRealm());
530  CH_assert(a_realm == a_meshVectorField.getRealm());
531 
532  EBAMRParticleMesh& particleMesh = this->getParticleMesh(a_realm, a_phase);
533 
534  particleMesh.interpolate<P, particleVectorField>(a_particles, a_meshVectorField, a_interpType, a_forceIrregNGP);
535 }
536 
537 template <class P>
538 void
540  const phase::which_phase& a_phase,
541  const Real a_tolerance) const
542 {
543  CH_TIME("AmrMesh::removeCoveredParticlesIF");
544  if (m_verbosity > 5) {
545  pout() << "AmrMesh::removeCoveredParticlesIF" << endl;
546  }
547 
548  CH_assert(!a_particles.isOrganizedByCell());
549 
550  // Figure out the implicit function
551  RefCountedPtr<BaseIF> implicitFunction;
552 
553  switch (a_phase) {
554  case phase::gas: {
555  implicitFunction = m_baseif.at(phase::gas);
556 
557  break;
558  }
559  case phase::solid: {
560  implicitFunction = m_baseif.at(phase::solid);
561 
562  break;
563  }
564  default: {
565  MayDay::Error("AmrMesh::removeCoveredParticlesIF - logic bust");
566  }
567  }
568 
569  // Get the realm where the particles live.
570  const std::string whichRealm = a_particles.getRealm();
571 
572  // Go through all particles and remove them if they are less than dx*a_tolerance away from the EB.
573  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
574  const DisjointBoxLayout& dbl = this->getGrids(whichRealm)[lvl];
575  const DataIterator& dit = dbl.dataIterator();
576  const Real dx = this->getDx()[lvl];
577  const Real tol = a_tolerance * dx;
578 
579  const int nbox = dit.size();
580 #pragma omp parallel for schedule(runtime)
581  for (int mybox = 0; mybox < nbox; mybox++) {
582  const DataIndex& din = dit[mybox];
583 
584  List<P>& particles = a_particles[lvl][din].listItems();
585 
586  // Check if particles are outside the implicit function.
587  for (ListIterator<P> lit(particles); lit.ok();) {
588  const RealVect& pos = lit().position();
589 
590  const Real f = implicitFunction->value(pos);
591 
592  if (f > tol) {
593  particles.remove(lit);
594  }
595  else {
596  lit++;
597  }
598  }
599  }
600  }
601 }
602 
603 template <class P>
604 void
606  const phase::which_phase& a_phase,
607  const Real a_tolerance) const
608 {
609  CH_TIME("AmrMesh::removeCoveredParticlesDiscrete");
610  if (m_verbosity > 5) {
611  pout() << "AmrMesh::removeCoveredParticlesDiscrete" << endl;
612  }
613 
614  CH_assert(!a_particles.isOrganizedByCell());
615 
616  // Get the realm where the particles live.
617  const std::string whichRealm = a_particles.getRealm();
618 
619  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
620  const DisjointBoxLayout& dbl = this->getGrids(whichRealm)[lvl];
621  const DataIterator& dit = dbl.dataIterator();
622  const EBISLayout& ebisl = this->getEBISLayout(whichRealm, a_phase)[lvl];
623  const Real dx = this->getDx()[lvl];
624  const Real tol = a_tolerance * dx;
625 
626  const int nbox = dit.size();
627 #pragma omp parallel for schedule(runtime)
628  for (int mybox = 0; mybox < nbox; mybox++) {
629  const DataIndex& din = dit[mybox];
630  const EBISBox& ebisBox = ebisl[din];
631  const Box region = ebisBox.getRegion();
632 
633  const bool isRegular = ebisBox.isAllRegular();
634  const bool isCovered = ebisBox.isAllCovered();
635  const bool isIrregular = !isRegular && !isCovered;
636 
637  List<P>& particles = a_particles[lvl][din].listItems();
638 
639  if (isCovered) {
640  particles.clear();
641  }
642  else if (isIrregular) {
643  for (ListIterator<P> lit(particles); lit.ok();) {
644  const P& particle = lit();
645  const RealVect& pos = particle.position();
646 
647  // Get the cell where the particle lives.
648  const IntVect iv = ParticleOps::getParticleCellIndex(pos, m_probLo, dx);
649 
650  CH_assert(region.contains(iv));
651 
652  if (ebisBox.isCovered(iv)) {
653  particles.remove(lit);
654  }
655  else if (ebisBox.isIrregular(iv)) {
656 
657  // There could potentially be multiple degrees of freedom -- we check if the particle is inside at least one
658  // of the VoFs in the cell.
659 
660  bool insideAtLeastOneVoF = false;
661 
662  // For each VoF, compute the projection of the particle position onth the EB face. Beacuse the EB normal points outwards, we have a positive
663  // value if the particle lies in the valid region.
664  const std::vector<VolIndex> vofs = ebisBox.getVoFs(iv).stdVector();
665  for (const auto& vof : vofs) {
666  const RealVect ebNormal = ebisBox.normal(vof);
667  const RealVect ebCentroid = m_probLo + Location::position(Location::Cell::Boundary, vof, ebisBox, dx);
668  const Real faceProjection = ebNormal.dotProduct(pos - ebCentroid);
669 
670  if (faceProjection >= -tol) {
671  insideAtLeastOneVoF = true;
672 
673  break;
674  }
675  }
676 
677  if (!insideAtLeastOneVoF) {
678  particles.remove(lit);
679  }
680  else {
681  ++lit;
682  }
683  }
684  else {
685  ++lit;
686  }
687  }
688  }
689  }
690  }
691 }
692 
693 template <class P>
694 void
695 AmrMesh::removeCoveredParticlesVoxels(ParticleContainer<P>& a_particles, const phase::which_phase& a_phase) const
696 {
697  CH_TIME("AmrMesh::removeCoveredParticlesVoxels");
698  if (m_verbosity > 5) {
699  pout() << "AmrMesh::removeCoveredParticlesVoxels" << endl;
700  }
701 
702  CH_assert(!a_particles.isOrganizedByCell());
703 
704  // Get the realm where the particles live.
705  const std::string whichRealm = a_particles.getRealm();
706 
707  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
708  const DisjointBoxLayout& dbl = this->getGrids(whichRealm)[lvl];
709  const DataIterator& dit = dbl.dataIterator();
710  const EBISLayout& ebisl = this->getEBISLayout(whichRealm, a_phase)[lvl];
711  const Real dx = this->getDx()[lvl];
712 
713  const int nbox = dit.size();
714 #pragma omp parallel for schedule(runtime)
715  for (int mybox = 0; mybox < nbox; mybox++) {
716  const DataIndex& din = dit[mybox];
717  const EBISBox& ebisBox = ebisl[din];
718  const Box region = ebisBox.getRegion();
719 
720  const bool isRegular = ebisBox.isAllRegular();
721  const bool isCovered = ebisBox.isAllCovered();
722  const bool isIrregular = !isRegular && !isCovered;
723 
724  List<P>& particles = a_particles[lvl][din].listItems();
725 
726  if (isCovered) {
727  particles.clear();
728  }
729  else if (isIrregular) {
730  for (ListIterator<P> lit(particles); lit.ok();) {
731  const P& particle = lit();
732  const RealVect& pos = particle.position();
733 
734  // Get the cell where the particle lives.
735  const RealVect rv = (pos - m_probLo) / dx;
736  const IntVect iv = IntVect(D_DECL(floor(rv[0]), floor(rv[1]), floor(rv[2])));
737 
738  CH_assert(region.contains(iv));
739 
740  if (ebisBox.isCovered(iv)) {
741  particles.remove(lit);
742  }
743  else {
744  ++lit;
745  }
746  }
747  }
748  }
749  }
750 }
751 
752 template <class P>
753 void
755  ParticleContainer<P>& a_particlesTo,
756  const phase::which_phase& a_phase,
757  const Real a_tolerance) const
758 {
759  CH_TIME("AmrMesh::transferCoveredParticlesIF");
760  if (m_verbosity > 5) {
761  pout() << "AmrMesh::transferCoveredParticlesIF" << endl;
762  }
763 
764  CH_assert(!a_particlesFrom.isOrganizedByCell());
765  CH_assert(!a_particlesTo.isOrganizedByCell());
766 
767  // Figure out the implicit function
768  RefCountedPtr<BaseIF> implicitFunction;
769 
770  switch (a_phase) {
771  case phase::gas: {
772  implicitFunction = m_baseif.at(phase::gas);
773 
774  break;
775  }
776  case phase::solid: {
777  implicitFunction = m_baseif.at(phase::solid);
778 
779  break;
780  }
781  default: {
782  MayDay::Error("AmrMesh::removeCoveredParticlesIF - logic bust");
783 
784  break;
785  }
786  }
787 
788  // Get the realm where the particles live.
789  const std::string realmFrom = a_particlesFrom.getRealm();
790  const std::string realmTo = a_particlesTo.getRealm();
791 
792  CH_assert(realmFrom == realmTo);
793 
794  // Go through all particles and remove them if they are less than dx*a_tolerance away from the EB.
795  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
796  const DisjointBoxLayout& dbl = this->getGrids(realmFrom)[lvl];
797  const DataIterator& dit = dbl.dataIterator();
798  const Real dx = this->getDx()[lvl];
799  const Real tol = a_tolerance * dx;
800 
801  const int nbox = dit.size();
802 #pragma omp parallel for schedule(runtime)
803  for (int mybox = 0; mybox < nbox; mybox++) {
804  const DataIndex& din = dit[mybox];
805 
806  List<P>& particlesFrom = a_particlesFrom[lvl][din].listItems();
807  List<P>& particlesTo = a_particlesTo[lvl][din].listItems();
808 
809  // Check if particles are outside the implicit function.
810  for (ListIterator<P> lit(particlesFrom); lit.ok();) {
811  const RealVect& pos = lit().position();
812 
813  const Real f = implicitFunction->value(pos);
814 
815  if (f > tol) {
816  particlesTo.transfer(lit);
817  }
818  else {
819  ++lit;
820  }
821  }
822  }
823  }
824 }
825 
826 template <class P>
827 void
829  ParticleContainer<P>& a_particlesTo,
830  const phase::which_phase& a_phase,
831  const Real a_tolerance) const
832 {
833  CH_TIME("AmrMesh::transferCoveredParticlesDiscrete");
834  if (m_verbosity > 5) {
835  pout() << "AmrMesh::transferCoveredParticlesDiscrete" << endl;
836  }
837 
838  CH_assert(!a_particlesFrom.isOrganizedByCell());
839  CH_assert(!a_particlesTo.isOrganizedByCell());
840 
841  // Get the realm where the particles live.
842  const std::string realmFrom = a_particlesFrom.getRealm();
843  const std::string realmTo = a_particlesTo.getRealm();
844 
845  CH_assert(realmFrom == realmTo);
846 
847  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
848  const DisjointBoxLayout& dbl = this->getGrids(realmFrom)[lvl];
849  const DataIterator& dit = dbl.dataIterator();
850  const EBISLayout& ebisl = this->getEBISLayout(realmFrom, a_phase)[lvl];
851  const Real dx = this->getDx()[lvl];
852  const Real tol = a_tolerance * dx;
853 
854  const int nbox = dit.size();
855 #pragma omp parallel for schedule(runtime)
856  for (int mybox = 0; mybox < nbox; mybox++) {
857  const DataIndex& din = dit[mybox];
858  const EBISBox& ebisBox = ebisl[din];
859  const Box region = ebisBox.getRegion();
860 
861  const bool isRegular = ebisBox.isAllRegular();
862  const bool isCovered = ebisBox.isAllCovered();
863  const bool isIrregular = !isRegular && !isCovered;
864 
865  List<P>& particlesFrom = a_particlesFrom[lvl][din].listItems();
866  List<P>& particlesTo = a_particlesTo[lvl][din].listItems();
867 
868  if (isCovered) {
869  particlesTo.catenate(particlesFrom);
870  }
871  else if (isIrregular) {
872  for (ListIterator<P> lit(particlesFrom); lit.ok();) {
873  const P& particle = lit();
874  const RealVect& pos = particle.position();
875 
876  // Get the cell where the particle lives.
877  const IntVect iv = ParticleOps::getParticleCellIndex(pos, m_probLo, dx);
878 
879  CH_assert(region.contains(iv));
880 
881  if (ebisBox.isCovered(iv)) {
882  particlesTo.transfer(lit);
883  }
884  else if (ebisBox.isIrregular(iv)) {
885  // There could potentially be multiple degrees of freedom -- we check if the particle is inside at least one of the VoFs in the cell.
886 
887  bool insideAtLeastOneVoF = false;
888 
889  // For each VoF, compute the projection of the particle position onth the EB face. Beacuse the EB normal points outwards, we have a positive
890  // value if the particle lies in the valid region.
891  const std::vector<VolIndex> vofs = ebisBox.getVoFs(iv).stdVector();
892  for (const auto& vof : vofs) {
893  const RealVect ebCentroid = m_probLo + Location::position(Location::Cell::Boundary, vof, ebisBox, dx);
894  const RealVect ebNormal = ebisBox.normal(vof);
895  const Real faceProjection = ebNormal.dotProduct(pos - ebCentroid);
896 
897  if (faceProjection >= -tol) {
898  insideAtLeastOneVoF = true;
899 
900  break;
901  }
902  }
903 
904  if (!insideAtLeastOneVoF) {
905  particlesTo.transfer(lit);
906  }
907  else {
908  ++lit;
909  }
910  }
911  else {
912  ++lit;
913  }
914  }
915  }
916  }
917  }
918 }
919 
920 template <class P>
921 void
923  ParticleContainer<P>& a_particlesTo,
924  const phase::which_phase& a_phase) const
925 {
926  CH_TIME("AmrMesh::transferCoveredParticlesVoxels");
927  if (m_verbosity > 5) {
928  pout() << "AmrMesh::transferCoveredParticlesVoxels" << endl;
929  }
930 
931  CH_assert(!a_particlesFrom.isOrganizedByCell());
932  CH_assert(!a_particlesTo.isOrganizedByCell());
933 
934  // Get the realm where the particles live.
935  const std::string realmFrom = a_particlesFrom.getRealm();
936  const std::string realmTo = a_particlesTo.getRealm();
937 
938  CH_assert(realmFrom == realmTo);
939 
940  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
941  const DisjointBoxLayout& dbl = this->getGrids(realmFrom)[lvl];
942  const DataIterator dit = dbl.dataIterator();
943  const EBISLayout& ebisl = this->getEBISLayout(realmFrom, a_phase)[lvl];
944  const Real dx = this->getDx()[lvl];
945 
946  const int nbox = dit.size();
947 #pragma omp parallel for schedule(runtime)
948  for (int mybox = 0; mybox < nbox; mybox++) {
949  const DataIndex& din = dit[mybox];
950  const EBISBox& ebisBox = ebisl[din];
951  const Box region = ebisBox.getRegion();
952 
953  const bool isRegular = ebisBox.isAllRegular();
954  const bool isCovered = ebisBox.isAllCovered();
955  const bool isIrregular = !isRegular && !isCovered;
956 
957  List<P>& particlesFrom = a_particlesFrom[lvl][din].listItems();
958  List<P>& particlesTo = a_particlesTo[lvl][din].listItems();
959 
960  if (isCovered) {
961  particlesTo.catenate(particlesFrom);
962  }
963  else if (isIrregular) {
964  for (ListIterator<P> lit(particlesFrom); lit.ok();) {
965  const P& particle = lit();
966  const RealVect& pos = particle.position();
967 
968  // Get the cell where the particle lives.
969  const IntVect iv = ParticleOps::getParticleCellIndex(pos, m_probLo, dx);
970 
971  CH_assert(region.contains(iv));
972 
973  if (ebisBox.isCovered(iv)) {
974  particlesTo.transfer(lit);
975  }
976  else {
977  ++lit;
978  }
979  }
980  }
981  }
982  }
983 }
984 
985 template <class P>
986 void
988  ParticleContainer<P>& a_srcParticles,
989  const phase::which_phase a_phase,
990  const std::function<void(P&)> a_transferModifier) const noexcept
991 {
992  CH_TIME("AmrMesh::transferIrregularParticles");
993  if (m_verbosity > 5) {
994  pout() << "AmrMesh::transferIrregularParticles" << endl;
995  }
996 
997  CH_assert(a_dstParticles.getRealm() == a_srcParticles.getRealm());
998 
999  const std::string realm = a_dstParticles.getRealm();
1000 
1001  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
1002  const DisjointBoxLayout& dbl = this->getGrids(realm)[lvl];
1003  const DataIterator& dit = dbl.dataIterator();
1004  const EBISLayout& ebisl = this->getEBISLayout(realm, a_phase)[lvl];
1005  const ProblemDomain& domain = this->getDomains()[lvl];
1006  const RealVect probLo = this->getProbLo();
1007  const Real dx = this->getDx()[lvl];
1008 
1009  const int nbox = dit.size();
1010 #pragma omp parallel for schedule(runtime)
1011  for (int mybox = 0; mybox < nbox; mybox++) {
1012  const DataIndex& din = dit[mybox];
1013 
1014  const Box cellBox = dbl[din];
1015  const EBISBox& ebisbox = ebisl[din];
1016 
1017  List<P>& dstParticles = a_dstParticles[lvl][din].listItems();
1018  List<P>& srcParticles = a_srcParticles[lvl][din].listItems();
1019 
1020  for (ListIterator<P> lit(srcParticles); lit.ok();) {
1021  P& p = lit();
1022 
1023  const IntVect iv = ParticleOps::getParticleCellIndex(p.position(), probLo, dx);
1024 
1025  if (!(cellBox.contains(iv))) {
1026  MayDay::Warning("CD_AmrMeshImplem.H in routine 'transferIrregularParticles' - particle not in box!");
1027 
1028  ++lit;
1029  }
1030 
1031  if (ebisbox.isIrregular(iv)) {
1032  bool insideAnyVoF = false;
1033 
1034  const Vector<VolIndex> allVoFs = ebisbox.getVoFs(iv);
1035 
1036  for (int i = 0; i < allVoFs.size(); i++) {
1037  const VolIndex& vof = allVoFs[i];
1038  const RealVect normal = ebisbox.normal(vof);
1039  const RealVect ebPos = probLo + Location::position(Location::Cell::Boundary, vof, ebisbox, dx);
1040 
1041  // Note: Can have normal = 0!
1042  if ((p.position() - ebPos).dotProduct(normal) >= 0.0) {
1043  insideAnyVoF = true;
1044  }
1045  }
1046 
1047  if (!insideAnyVoF) {
1048  const VolIndex& vof = allVoFs[0];
1049  const RealVect ebPos = probLo + Location::position(Location::Cell::Boundary, vof, ebisbox, dx);
1050 
1051  p.position() = ebPos;
1052 
1053  a_transferModifier(p);
1054 
1055  dstParticles.transfer(lit);
1056  }
1057  else {
1058  ++lit;
1059  }
1060  }
1061  else {
1062  ++lit;
1063  }
1064  }
1065  }
1066  }
1067 }
1068 
1069 template <class P>
1070 void
1072  ParticleContainer<P>& a_ebParticles,
1073  ParticleContainer<P>& a_domainParticles,
1074  const phase::which_phase a_phase,
1075  const Real a_tolerance,
1076  const bool a_deleteParticles,
1077  const std::function<void(P&)> a_nonDeletionModifier) const noexcept
1078 {
1079  CH_TIME("AmrMesh::intersectParticlesRaycastIF");
1080  if (m_verbosity > 5) {
1081  pout() << "AmrMesh::intersectParticlesRaycastIF" << endl;
1082  }
1083 
1084  CH_assert(a_activeParticles.getRealm() == a_ebParticles.getRealm());
1085  CH_assert(a_activeParticles.getRealm() == a_domainParticles.getRealm());
1086 
1087  a_ebParticles.clearParticles();
1088  a_domainParticles.clearParticles();
1089 
1090  const std::string whichRealm = a_activeParticles.getRealm();
1091 
1092  // Figure out the implicit function
1093  RefCountedPtr<BaseIF> implicitFunction;
1094 
1095  switch (a_phase) {
1096  case phase::gas: {
1097  implicitFunction = m_baseif.at(phase::gas);
1098 
1099  break;
1100  }
1101  case phase::solid: {
1102  implicitFunction = m_baseif.at(phase::solid);
1103 
1104  break;
1105  }
1106  default: {
1107  MayDay::Error("AmrMesh::intersectParticlesRaycastIF - logic bust");
1108 
1109  break;
1110  }
1111  }
1112 
1113  // Safety factor to prevent particles falling off the domain if they intersect the high-side of the domain
1114  constexpr Real safety = 1.E-12;
1115 
1116  // Level loop -- go through each AMR level
1117  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
1118 
1119  // Handle to various grid stuff.
1120  const DisjointBoxLayout& dbl = this->getGrids(whichRealm)[lvl];
1121  const DataIterator& dit = dbl.dataIterator();
1122 
1123  const int nbox = dit.size();
1124 #pragma omp parallel for schedule(runtime)
1125  for (int mybox = 0; mybox < nbox; mybox++) {
1126  const DataIndex& din = dit[mybox];
1127 
1128  List<P>& activeParticles = a_activeParticles[lvl][din].listItems();
1129  List<P>& ebParticles = a_ebParticles[lvl][din].listItems();
1130  List<P>& domainParticles = a_domainParticles[lvl][din].listItems();
1131 
1132  for (ListIterator<P> lit(activeParticles); lit.ok();) {
1133  P& particle = lit();
1134 
1135  const RealVect newPos = particle.position();
1136  const RealVect oldPos = particle.oldPosition();
1137  const RealVect path = newPos - oldPos;
1138 
1139  // Cheap initial tests that allow us to skip some intersections tests.
1140  bool checkEB = false;
1141  bool checkDomain = false;
1142 
1143  if (!implicitFunction.isNull()) {
1144  checkEB = true;
1145  }
1146  for (int dir = 0; dir < SpaceDim; dir++) {
1147  const bool outsideLo = newPos[dir] < m_probLo[dir];
1148  const bool outsideHi = newPos[dir] > m_probHi[dir];
1149 
1150  if (outsideLo || outsideHi) {
1151  checkDomain = true;
1152  }
1153  }
1154 
1155  // Do the intersection tests.
1156  if (checkEB || checkDomain) {
1157 
1158  // These are the solution
1159  Real sDomain = std::numeric_limits<Real>::max();
1160  Real sEB = std::numeric_limits<Real>::max();
1161 
1162  bool contactDomain = false;
1163  bool contactEB = false;
1164 
1165  // Check if the particle intersected the domain. If it did, we compute sDomain such that the intersection
1166  // point with the domain is X = X0 + sDomain * (X1-X0) where X1=newPos and X0=oldPos
1167  if (checkDomain) {
1168  contactDomain = ParticleOps::domainIntersection(oldPos, newPos, m_probLo, m_probHi, sDomain);
1169  }
1170 
1171  // Check if the particle intersected the EB. If it did, we compute sEB such that the intersection
1172  // point with the domain is X = X0 + sEB * (X1-X0) where X1=newPos and X0=oldPos
1173  if (checkEB) {
1174  contactEB = ParticleOps::ebIntersectionRaycast(implicitFunction, oldPos, newPos, a_tolerance, sEB);
1175  }
1176 
1177  // Particle bumped into something.
1178  if (contactDomain || contactEB) {
1179  if (sEB <= sDomain) { // Crashed with EB "first".
1180  const RealVect intersectionPos = oldPos + sEB * path;
1181 
1182  // If we delete the original particles we can just transfer the one we have. Otherwise we create
1183  // a new particle.
1184  if (a_deleteParticles) {
1185  particle.position() = intersectionPos;
1186 
1187  ebParticles.transfer(lit);
1188  }
1189  else {
1190  P p = lit();
1191 
1192  p.position() = intersectionPos;
1193 
1194  ebParticles.add(p);
1195 
1196  a_nonDeletionModifier(particle);
1197 
1198  lit++;
1199  }
1200  }
1201  else {
1202  // Crashed with domain "first". Safety factor is to prevent particles falling off the high side of the domain
1203  const Real sSafety = std::max((Real)0.0, sDomain - safety);
1204 
1205  const RealVect intersectionPos = oldPos + sSafety * path;
1206 
1207  if (a_deleteParticles) {
1208  particle.position() = intersectionPos;
1209 
1210  domainParticles.transfer(lit);
1211  }
1212  else {
1213  P p = lit();
1214 
1215  p.position() = intersectionPos;
1216 
1217  domainParticles.add(p);
1218 
1219  a_nonDeletionModifier(particle);
1220 
1221  ++lit;
1222  }
1223  }
1224  }
1225  else {
1226  ++lit;
1227  }
1228  }
1229  else {
1230  ++lit;
1231  }
1232  }
1233  }
1234  }
1235 
1236  // These need to be remapped.
1237  a_ebParticles.remap();
1238  a_domainParticles.remap();
1239 }
1240 
1241 template <class P>
1242 void
1244  ParticleContainer<P>& a_ebParticles,
1245  ParticleContainer<P>& a_domainParticles,
1246  const phase::which_phase a_phase,
1247  const Real a_bisectionStep,
1248  const bool a_deleteParticles,
1249  const std::function<void(P&)> a_nonDeletionModifier) const noexcept
1250 {
1251  CH_TIME("AmrMesh::intersectParticlesBisectIF");
1252  if (m_verbosity > 5) {
1253  pout() << "AmrMesh::intersectParticlesBisectIF" << endl;
1254  }
1255 
1256  CH_assert(a_activeParticles.getRealm() == a_ebParticles.getRealm());
1257  CH_assert(a_activeParticles.getRealm() == a_domainParticles.getRealm());
1258 
1259  // TLDR: This is pretty much a hard-copy of intersectParticlesRaycastIF, with the exception that the EB intersection
1260  // test is replaced by a bisection test.
1261 
1262  a_ebParticles.clearParticles();
1263  a_domainParticles.clearParticles();
1264 
1265  const std::string whichRealm = a_activeParticles.getRealm();
1266 
1267  // Figure out the implicit function
1268  RefCountedPtr<BaseIF> implicitFunction;
1269 
1270  switch (a_phase) {
1271  case phase::gas: {
1272  implicitFunction = m_baseif.at(phase::gas);
1273 
1274  break;
1275  }
1276  case phase::solid: {
1277  implicitFunction = m_baseif.at(phase::solid);
1278 
1279  break;
1280  }
1281  default: {
1282  MayDay::Error("AmrMesh::intersectParticlesBisectIF - logic bust");
1283 
1284  break;
1285  }
1286  }
1287 
1288  // Safety factor to prevent particles falling off the domain if they intersect the high-side of the domain
1289  constexpr Real safety = 1.E-12;
1290 
1291  // Level loop -- go through each AMR level
1292  for (int lvl = 0; lvl <= m_finestLevel; lvl++) {
1293 
1294  // Handle to various grid stuff.
1295  const DisjointBoxLayout& dbl = this->getGrids(whichRealm)[lvl];
1296  const DataIterator& dit = dbl.dataIterator();
1297 
1298  const int nbox = dit.size();
1299 #pragma omp parallel for schedule(runtime)
1300  for (int mybox = 0; mybox < nbox; mybox++) {
1301  const DataIndex& din = dit[mybox];
1302 
1303  List<P>& activeParticles = a_activeParticles[lvl][din].listItems();
1304  List<P>& ebParticles = a_ebParticles[lvl][din].listItems();
1305  List<P>& domainParticles = a_domainParticles[lvl][din].listItems();
1306 
1307  for (ListIterator<P> lit(activeParticles); lit.ok();) {
1308  P& particle = lit();
1309 
1310  const RealVect newPos = particle.position();
1311  const RealVect oldPos = particle.oldPosition();
1312  const RealVect path = newPos - oldPos;
1313 
1314  // Cheap initial tests that allow us to skip some intersections tests.
1315  bool checkEB = false;
1316  bool checkDomain = false;
1317 
1318  if (!implicitFunction.isNull()) {
1319  checkEB = true;
1320  }
1321  for (int dir = 0; dir < SpaceDim; dir++) {
1322  const bool outsideLo = newPos[dir] < m_probLo[dir];
1323  const bool outsideHi = newPos[dir] > m_probHi[dir];
1324 
1325  if (outsideLo || outsideHi) {
1326  checkDomain = true;
1327  }
1328  }
1329 
1330  // Do the intersection tests.
1331  if (checkEB || checkDomain) {
1332 
1333  // These are the solution
1334  Real sDomain = std::numeric_limits<Real>::max();
1335  Real sEB = std::numeric_limits<Real>::max();
1336 
1337  bool contactDomain = false;
1338  bool contactEB = false;
1339 
1340  // Check if the particle intersected the domain. If it did, we compute sDomain such that the intersection
1341  // point with the domain is X = X0 + sDomain * (X1-X0) where X1=newPos and X0=oldPos
1342  if (checkDomain) {
1343  contactDomain = ParticleOps::domainIntersection(oldPos, newPos, m_probLo, m_probHi, sDomain);
1344  }
1345 
1346  // Check if the particle intersected the EB. If it did, we compute sEB such that the intersection
1347  // point with the domain is X = X0 + sEB * (X1-X0) where X1=newPos and X0=oldPos
1348  if (checkEB) {
1349  contactEB = ParticleOps::ebIntersectionBisect(implicitFunction, oldPos, newPos, a_bisectionStep, sEB);
1350  }
1351 
1352  // Particle bumped into something.
1353  if (contactDomain || contactEB) {
1354  if (sEB <= sDomain) {
1355  // Crashed with EB "first".
1356  const RealVect intersectionPos = oldPos + sEB * path;
1357 
1358  if (a_deleteParticles) {
1359  particle.position() = intersectionPos;
1360 
1361  ebParticles.transfer(lit);
1362  }
1363  else {
1364  P p = particle;
1365 
1366  p.position() = intersectionPos;
1367 
1368  ebParticles.add(p);
1369 
1370  ++lit;
1371 
1372  a_nonDeletionModifier(particle);
1373  }
1374  }
1375  else {
1376  // Crashed with domain "first".
1377  const Real sSafety = std::max((Real)0.0, sDomain - safety);
1378 
1379  const RealVect intersectionPos = oldPos + sSafety * path;
1380 
1381  if (a_deleteParticles) {
1382  particle.position() = intersectionPos;
1383 
1384  domainParticles.transfer(lit);
1385  }
1386  else {
1387  P p = particle;
1388 
1389  p.position() = intersectionPos;
1390 
1391  domainParticles.add(p);
1392 
1393  ++lit;
1394 
1395  a_nonDeletionModifier(particle);
1396  }
1397  }
1398  }
1399  else {
1400  ++lit;
1401  }
1402  }
1403  else {
1404  ++lit;
1405  }
1406  }
1407  }
1408  }
1409 
1410  // These need to be remapped.
1411  a_ebParticles.remap();
1412  a_domainParticles.remap();
1413 }
1414 
1415 #include <CD_NamespaceFooter.H>
1416 
1417 #endif
Declaration of core class for handling AMR-related operations (with embedded boundaries)
CoarseFineDeposition
Coarse-fine deposition types (see CD_EBAMRParticleMesh for how these are handled).
Definition: CD_CoarseFineDeposition.H:26
CopyStrategy
Enum for distinguishing how we copy data Valid => valid region ValidGhost => valid+ghost region.
Definition: CD_CopyStrategy.H:23
DepositionType
Deposition types.
Definition: CD_DepositionType.H:23
Declaration of a static class containing some common useful particle routines that would otherwise be...
void removeCoveredParticlesVoxels(ParticleContainer< P > &a_particles, const phase::which_phase &a_phase) const
Function which removes particles from the domain if they fall inside the EB.
Definition: CD_AmrMeshImplem.H:695
void transferCoveredParticlesDiscrete(ParticleContainer< P > &a_particlesFrom, ParticleContainer< P > &a_particlesTo, const phase::which_phase &a_phase, const Real a_tolerance=0.0) const
Function which transferse particles from one particle container to another if they fall inside the EB...
Definition: CD_AmrMeshImplem.H:828
const AMRMask & getValidCells(const std::string a_realm) const
Get a map of all valid cells on a specified realm.
Definition: CD_AmrMesh.cpp:3034
void copyData(EBAMRData< T > &a_dst, const EBAMRData< T > &a_src, const CopyStrategy &a_toRegion=CopyStrategy::Valid, const CopyStrategy &a_fromRegion=CopyStrategy::Valid) const noexcept
Method for copying from a source container to a destination container. User supplies information abou...
Definition: CD_AmrMeshImplem.H:22
void transferCoveredParticlesIF(ParticleContainer< P > &a_particlesFrom, ParticleContainer< P > &a_particlesTo, const phase::which_phase &a_phase, const Real a_tolerance=0.0) const
Function which transferse particles from one particle container to another if they fall inside the EB...
Definition: CD_AmrMeshImplem.H:754
int m_maxBoxSize
Max box size.
Definition: CD_AmrMesh.H:2001
RealVect m_probLo
Domain simulation corner.
Definition: CD_AmrMesh.H:1961
void remapToNewGrids(ParticleContainer< P > &a_particles, const int a_lmin, const int a_newFinestLevel) const noexcept
Regrid particle to new grids.
Definition: CD_AmrMeshImplem.H:362
void transferIrregularParticles(ParticleContainer< P > &a_dstParticles, ParticleContainer< P > &a_srcParticles, const phase::which_phase a_phase, const std::function< void(P &)> a_transferModifier=[](P &) -> void { return;}) const noexcept
Transfer particles that are on the wrong side of the EB to a different container.
Definition: CD_AmrMeshImplem.H:987
bool queryRealm(const std::string a_realm) const
Query if a realm exists.
Definition: CD_AmrMesh.cpp:3306
void removeCoveredParticlesIF(ParticleContainer< P > &a_particles, const phase::which_phase &a_phase, const Real a_tolerance=0.0) const
Function which removes particles from the domain if they fall inside the EB.
Definition: CD_AmrMeshImplem.H:539
void depositParticles(EBAMRCellData &a_meshData, const std::string &a_realm, const phase::which_phase &a_phase, const ParticleContainer< P > &a_particles, const DepositionType a_depositionType, const CoarseFineDeposition a_coarseFineDeposition, const bool a_forceIrregNGP=false)
Deposit scalar particle quantities on the mesh.
Definition: CD_AmrMeshImplem.H:383
int m_verbosity
Verbosity.
Definition: CD_AmrMesh.H:1976
void intersectParticlesRaycastIF(ParticleContainer< P > &a_activeParticles, ParticleContainer< P > &a_ebParticles, ParticleContainer< P > &a_domainParticles, const phase::which_phase a_phase, const Real a_tolerance, const bool a_deleteParticles, const std::function< void(P &)> a_nonDeletionModifier=[](P &) -> void { return;}) const noexcept
Particle intersection algorithm based on ray-casting.
Definition: CD_AmrMeshImplem.H:1071
void removeCoveredParticlesDiscrete(ParticleContainer< P > &a_particles, const phase::which_phase &a_phase, const Real a_tolerance=0.0) const
Function which removes particles from the domain if they fall inside the EB.
Definition: CD_AmrMeshImplem.H:605
Vector< Real > m_dx
Level resolutions.
Definition: CD_AmrMesh.H:2111
const Vector< DisjointBoxLayout > & getGrids(const std::string a_realm) const
Get the grids.
Definition: CD_AmrMesh.cpp:2968
void intersectParticlesBisectIF(ParticleContainer< P > &a_activeParticles, ParticleContainer< P > &a_ebParticles, ParticleContainer< P > &a_domainParticles, const phase::which_phase a_phase, const Real a_bisectionStep, const bool a_deleteParticles, const std::function< void(P &)> a_nonDeletionModifier=[](P &) -> void { return;}) const noexcept
Particle intersection algorithm based on bisection.
Definition: CD_AmrMeshImplem.H:1243
int m_finestLevel
Finest level.
Definition: CD_AmrMesh.H:1981
const Vector< EBISLayout > & getEBISLayout(const std::string a_realm, const phase::which_phase a_phase) const
Get EBISLayouts for a Realm and phase.
Definition: CD_AmrMesh.cpp:2984
std::map< phase::which_phase, RefCountedPtr< BaseIF > > m_baseif
Implicit functions.
Definition: CD_AmrMesh.H:1875
void interpolateParticles(ParticleContainer< P > &a_particles, const std::string &a_realm, const phase::which_phase &a_phase, const EBAMRCellData &a_meshScalarField, const DepositionType a_interpType, const bool a_forceIrregNGP=false) const
Interpolate a scalar field onto the particle position.
Definition: CD_AmrMeshImplem.H:495
const Vector< Real > & getDx() const
Get spatial resolutions.
Definition: CD_AmrMesh.cpp:2913
std::map< std::string, RefCountedPtr< Realm > > m_realms
These are all the Realms.
Definition: CD_AmrMesh.H:1870
int m_blockingFactor
Blocking factor.
Definition: CD_AmrMesh.H:2016
void allocatePointer(Vector< RefCountedPtr< T >> &a_data) const
Allocate pointer but not any memory blocks.
Definition: CD_AmrMeshImplem.H:303
void allocate(Vector< RefCountedPtr< ParticleData< T >>> &a_particles, const std::string a_realm) const
Template class for generic allocation of particle data.
Definition: CD_AmrMeshImplem.H:237
void transferCoveredParticlesVoxels(ParticleContainer< P > &a_particlesFrom, ParticleContainer< P > &a_particlesTo, const phase::which_phase &a_phase) const
Function which transferse particles from one particle container to another if they fall inside the EB...
Definition: CD_AmrMeshImplem.H:922
EBAMRParticleMesh & getParticleMesh(const std::string a_realm, const phase::which_phase a_phase) const
Get EBAMRParticleMesh operator.
Definition: CD_AmrMesh.cpp:3133
void alias(Vector< T * > &a_alias, const Vector< RefCountedPtr< T >> &a_data) const
Turn smart-pointer data structure into regular-pointer data structure.
Definition: CD_AmrMeshImplem.H:209
void deallocate(Vector< T * > &a_data) const
Deallocate data.
Definition: CD_AmrMeshImplem.H:161
const Vector< int > & getRefinementRatios() const
Get refinement ratios.
Definition: CD_AmrMesh.cpp:2924
const Vector< RefCountedPtr< LevelTiles > > & getLevelTiles(const std::string a_realm) const
Get the tiled space representation.
Definition: CD_AmrMesh.cpp:3050
const Vector< ProblemDomain > & getDomains() const
Get domains.
Definition: CD_AmrMesh.cpp:2946
Default class for holding LevelData<T> data across an EBAMR realm.
Definition: CD_EBAMRData.H:40
void setRealm(const std::string a_realm) noexcept
Sets the realm for this object.
Definition: CD_EBAMRDataImplem.H:142
Vector< RefCountedPtr< LevelData< T > > > & getData() noexcept
Get underlying data. Returns m_data.
Definition: CD_EBAMRDataImplem.H:114
const std::string getRealm() const noexcept
Returns the string identifier for whatever realm this data is supposed to be allocated over.
Definition: CD_EBAMRDataImplem.H:135
Class for handling particle-mesh operations with AMR.
Definition: CD_EBAMRParticleMesh.H:47
void interpolate(ParticleContainer< P > &a_particles, const EBAMRCellData &a_meshVectorField, const DepositionType a_interpType, const bool a_forceIrregNGP=false) const
Interpolate a scalar field onto the particle position.
Definition: CD_EBAMRParticleMeshImplem.H:612
void deposit(EBAMRCellData &a_meshData, const ParticleContainer< P > &a_particles, const DepositionType a_depositionType, const CoarseFineDeposition a_coarseFineDeposition, const bool a_forceIrregNGP=false)
Class for deposition of particles of a type P to the mesh. This does scalar quantities.
Definition: CD_EBAMRParticleMeshImplem.H:29
class for handling surface deposition of particles with EB and AMR.
Definition: CD_EBAMRSurfaceDeposition.H:29
void deposit(EBAMRIVData &a_meshData, const ParticleContainer< P > &a_particles) const noexcept
Deposit function. Deposits particle on surface.
Definition: CD_EBAMRSurfaceDepositionImplem.H:28
Templated class for holding particles on an AMR hierarchy with particle remapping.
Definition: CD_ParticleContainer.H:50
void define(const Vector< DisjointBoxLayout > &a_grids, const Vector< ProblemDomain > &a_domains, const Vector< Real > &a_dx, const Vector< int > &a_refRat, const Vector< ValidMask > &a_validMask, const Vector< RefCountedPtr< LevelTiles >> &a_levelTiles, const RealVect &a_probLo, const int a_blockingFactor, const int a_finestLevel, const std::string a_realm)
Define the container. This will do a clear-out of all particles.
Definition: CD_ParticleContainerImplem.H:77
void clear(AMRParticles< P > &a_particles) const
Clear particles on input data holder.
Definition: CD_ParticleContainerImplem.H:1712
void remap()
Remap over the entire AMR hierarchy.
Definition: CD_ParticleContainerImplem.H:973
void clearParticles()
Clear all particles.
Definition: CD_ParticleContainerImplem.H:1670
const std::string getRealm() const
Get the realm where this ParticleContainer lives.
Definition: CD_ParticleContainerImplem.H:240
bool isOrganizedByCell() const
Is cell-sorted or not.
Definition: CD_ParticleContainerImplem.H:224
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 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 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
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