OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
BoxLibLayout.hpp
Go to the documentation of this file.
1 //
2 // Class BoxLibLayout
3 // In contrast to AMReX, OPAL is optimized for the
4 // distribution of particles to cores. In AMReX the ParGDB object
5 // is responsible for the particle to core distribution. This
6 // layout is derived from this object and does all important
7 // bunch updates. It is the interface for AMReX and Ippl.
8 //
9 // In AMReX, the geometry, i.e. physical domain, is fixed
10 // during the whole computation. Particles leaving the domain
11 // would be deleted. In order to prevent this we map the particles
12 // onto the domain [-1, 1]^3. Furthermore, it makes sure
13 // that we have enougth grid points to represent the bunch
14 // when its charges are scattered on the grid for the self-field
15 // computation.
16 //
17 // The self-field computation and the particle-to-core update
18 // are performed in the particle mapped domain.
19 //
20 // Copyright (c) 2016 - 2020, Matthias Frey, Uldis Locans, Paul Scherrer Institut, Villigen PSI, Switzerland
21 // All rights reserved
22 //
23 // Implemented as part of the PhD thesis
24 // "Precise Simulations of Multibunches in High Intensity Cyclotrons"
25 //
26 // This file is part of OPAL.
27 //
28 // OPAL is free software: you can redistribute it and/or modify
29 // it under the terms of the GNU General Public License as published by
30 // the Free Software Foundation, either version 3 of the License, or
31 // (at your option) any later version.
32 //
33 // You should have received a copy of the GNU General Public License
34 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
35 //
36 #ifndef BoxLibLayout_HPP
37 #define BoxLibLayout_HPP
38 
39 #include "Amr/BoxLibLayout.h"
40 
41 #include "Algorithms/Vektor.h"
42 #include "Message/Format.h"
43 #include "Message/MsgBuffer.h"
44 #include "Utility/PAssert.h"
46 
47 #include <cmath>
48 #include <utility>
49 #include <vector>
50 
51 
52 template <class T, unsigned Dim>
54 
55 
56 template <class T, unsigned Dim>
58 
59 
60 template<class T, unsigned Dim>
62  : ParticleAmrLayout<T, Dim>(),
63  ParGDB(),
64  refRatio_m(0)
65 {
66  /* FIXME There might be a better solution
67  *
68  *
69  * Figure out the number of grid points in each direction
70  * such that all processes have some data at the beginning
71  *
72  * ( nGridPoints / maxGridSize ) ^3 = max. #procs
73  *
74  */
75  int nProcs = Ippl::getNodes();
76  int maxGridSize = 16;
77 
78  int nGridPoints = std::ceil( std::cbrt( nProcs ) ) * maxGridSize;
79 
80  this->initBaseBox_m(nGridPoints, maxGridSize);
81 }
82 
83 
84 template<class T, unsigned Dim>
86  : ParticleAmrLayout<T, Dim>(),
87  ParGDB(layout_p->m_geom,
88  layout_p->m_dmap,
89  layout_p->m_ba,
90  layout_p->m_rr)
91 {
92  this->maxLevel_m = layout_p->maxLevel_m;
93  refRatio_m.resize(layout_p->m_geom.size()-1);
94  for (int i = 0; i < refRatio_m.size(); ++i)
95  refRatio_m[i] = layout_p->refRatio(i);
96 }
97 
98 
99 template<class T, unsigned Dim>
100 BoxLibLayout<T, Dim>::BoxLibLayout(int nGridPoints, int maxGridSize)
101  : ParticleAmrLayout<T, Dim>(),
102  ParGDB(),
103  refRatio_m(0)
104 {
105  this->initBaseBox_m(nGridPoints, maxGridSize);
106 }
107 
108 
109 template<class T, unsigned Dim>
111  const AmrProcMap_t &dmap,
112  const AmrGrid_t &ba)
113  : ParticleAmrLayout<T, Dim>(),
114  ParGDB(geom, dmap, ba),
115  refRatio_m(0)
116 { }
117 
118 
119 template<class T, unsigned Dim>
121  const AmrProcMapContainer_t &dmap,
122  const AmrGridContainer_t &ba,
123  const AmrIntArray_t &rr)
124  : ParticleAmrLayout<T, Dim>(),
125  ParGDB(geom, dmap, ba, rr),
126  refRatio_m(0)
127 { }
128 
129 
130 template<class T, unsigned Dim>
132 
133  // cubic box
134  int nGridPoints = this->m_geom[0].Domain().length(0);
135  int maxGridSize = this->m_ba[0][0].length(0);
136 
137  this->initBaseBox_m(nGridPoints, maxGridSize, dh);
138 }
139 
140 
141 template <class T, unsigned Dim>
142 void BoxLibLayout<T, Dim>::setDomainRatio(const std::vector<double>& ratio) {
143 
144  static bool isCalled = false;
145 
146  if ( isCalled ) {
147  return;
148  }
149 
150  isCalled = true;
151 
152  if ( ratio.size() != Dim ) {
153  throw OpalException("BoxLibLayout::setDomainRatio() ",
154  "Length " + std::to_string(ratio.size()) +
155  " != " + std::to_string(Dim));
156  }
157 
158  for (unsigned int i = 0; i < Dim; ++i) {
159  if ( ratio[i] <= 0.0 ) {
160  throw OpalException("BoxLibLayout::setDomainRatio() ",
161  "The ratio has to be larger than zero.");
162  }
163 
164  lowerBound[i] *= ratio[i];
165  upperBound[i] *= ratio[i];
166  }
167 }
168 
169 
170 template<class T, unsigned Dim>
172  const ParticleAttrib<char>* /*canSwap*/)
173 {
174  /* Exit since we need AmrParticleBase with grids and levels for particles for this layout
175  * if IpplParticleBase is used something went wrong
176  */
177  throw OpalException("BoxLibLayout::update(IpplParticleBase, ParticleAttrib) ",
178  "Wrong update method called.");
179 }
180 
181 
182 // // Function from AMReX adjusted to work with Ippl AmrParticleBase class
183 // // redistribute the particles using BoxLibs ParGDB class to determine where particle should go
184 template<class T, unsigned Dim>
186  int lev_min, int lev_max, bool isRegrid)
187 {
188  // in order to avoid transforms when already done
189  if ( !PData.isForbidTransform() ) {
190  /* we need to update on Amr domain + boosted frame (Lorentz transform,
191  * has to be undone at end of function
192  */
193  PData.domainMapping();
194  }
195 
196  int nGrow = 0;
197 
198  unsigned N = Ippl::getNodes();
199  unsigned myN = Ippl::myNode();
200 
201  int theEffectiveFinestLevel = this->finestLevel();
202  while (!this->LevelDefined(theEffectiveFinestLevel)) {
203  theEffectiveFinestLevel--;
204  }
205 
206  if (lev_max == -1)
207  lev_max = theEffectiveFinestLevel;
208  else if ( lev_max > theEffectiveFinestLevel )
209  lev_max = theEffectiveFinestLevel;
210 
211  //loop trough the particles and assign the grid and level where each particle belongs
212  size_t LocalNum = PData.getLocalNum();
213 
214  auto& LocalNumPerLevel = PData.getLocalNumPerLevel();
215 
216  if ( LocalNum != LocalNumPerLevel.getLocalNumAllLevel() )
217  throw OpalException("BoxLibLayout::update()",
218  "Local #particles disagrees with sum over levels");
219 
220  std::multimap<unsigned, unsigned> p2n; //node ID, particle
221 
222  std::vector<int> msgsend(N);
223  std::vector<int> msgrecv(N);
224 
225  unsigned sent = 0;
226  size_t lBegin = LocalNumPerLevel.begin(lev_min);
227  size_t lEnd = LocalNumPerLevel.end(lev_max);
228 
229  /* in the case of regrid we might lose a level
230  * and therefore the level counter is invalidated
231  */
232  if ( isRegrid ) {
233  lBegin = 0;
234  lEnd = LocalNum;
235  }
236 
237 
238  //loop trough particles and assign grid and level to each particle
239  //if particle doesn't belong to this process save the index of the particle to be sent
240  for (unsigned int ip = lBegin; ip < lEnd; ++ip) {
241  // old level
242  const size_t& lold = PData.Level[ip];
243 
244 // /*
245 // * AMReX sets m_grid = -1 and m_lev = -1
246 // */
247 // PData.Level[ip] = -1;
248 // PData.Grid[ip] = -1;
249 
250  //check to which level and grid the particle belongs to
251  locateParticle(PData, ip, lev_min, lev_max, nGrow);
252 
253  // The owner of the particle is the CPU owning the finest grid
254  // in state data that contains the particle.
255  const size_t& lnew = PData.Level[ip];
256 
257  const unsigned int who = ParticleDistributionMap(lnew)[PData.Grid[ip]];
258 
259  --LocalNumPerLevel[lold];
260 
261  if (who != myN) {
262  // we lost the particle to another process
263  msgsend[who] = 1;
264  p2n.insert(std::pair<unsigned, unsigned>(who, ip));
265  sent++;
266  } else {
267  /* if we still own the particle it may have moved to
268  * another level
269  */
270  ++LocalNumPerLevel[lnew];
271  }
272  }
273 
274  //reduce message count so every node knows how many messages to receive
275  allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
276 
278 
279  typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
280 
281  Format *format = PData.getFormat();
282 
283  std::vector<MPI_Request> requests;
284  std::vector<MsgBuffer*> buffers;
285 
286  //create a message and send particles to nodes they belong to
287  while (i!=p2n.end()) {
288  unsigned cur_destination = i->first;
289 
290  MsgBuffer *msgbuf = new MsgBuffer(format, p2n.count(i->first));
291 
292  for (; i!=p2n.end() && i->first == cur_destination; ++i) {
293  Message msg;
294  PData.putMessage(msg, i->second);
295  PData.destroy(1, i->second);
296  msgbuf->add(&msg);
297  }
298 
299  MPI_Request request = Ippl::Comm->raw_isend(msgbuf->getBuffer(),
300  msgbuf->getSize(),
301  cur_destination, tag);
302 
303  //remember request and buffer so we can delete them later
304  requests.push_back(request);
305  buffers.push_back(msgbuf);
306 
307  }
308 
309  //destroy the particles that are sent to other domains
310  if ( LocalNum < PData.getDestroyNum() ) {
311  throw OpalException("BoxLibLayout::update()",
312  "Rank " + std::to_string(myN) +
313  " can't destroy more particles than possessed.");
314  } else {
315  LocalNum -= PData.getDestroyNum(); // update local num
316  PData.performDestroy();
317  }
318 
319  for (int lev = lev_min; lev <= lev_max; ++lev) {
320  if ( LocalNumPerLevel[lev] < 0 ) {
321  throw OpalException("BoxLibLayout::update()",
322  "Negative particle level count.");
323  }
324  }
325 
326  //receive new particles
327  for (int k = 0; k<msgrecv[myN]; ++k) {
328  int node = Communicate::COMM_ANY_NODE;
329  char *buffer = 0;
330  int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
331  MsgBuffer recvbuf(format, buffer, bufsize);
332 
333  Message *msg = recvbuf.get();
334  while (msg != 0) {
335  /* pBeginIdx is the start index of the new particle data
336  * pEndIdx is the last index of the new particle data
337  */
338  size_t pBeginIdx = LocalNum;
339 
340  LocalNum += PData.getSingleMessage(*msg);
341 
342  size_t pEndIdx = LocalNum;
343 
344  for (size_t idx = pBeginIdx; idx < pEndIdx; ++idx)
345  ++LocalNumPerLevel[ PData.Level[idx] ];
346 
347  delete msg;
348  msg = recvbuf.get();
349  }
350  }
351 
352  //wait for communication to finish and clean up buffers
353  MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
354  MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
355  for (unsigned int j = 0; j<buffers.size(); ++j) {
356  delete buffers[j];
357  }
358 
359  delete format;
360 
361  // there is extra work to do if there are multipple nodes, to distribute
362  // the particle layout data to all nodes
363  //TODO: do we need info on how many particles are on each node?
364 
365  //save how many total particles we have
366  size_t TotalNum = 0;
367  allreduce(&LocalNum, &TotalNum, 1, std::plus<size_t>());
368 
369  // update our particle number counts
370  PData.setTotalNum(TotalNum); // set the total atom count
371  PData.setLocalNum(LocalNum); // set the number of local atoms
372 
373  // final check
374  if ( LocalNum != LocalNumPerLevel.getLocalNumAllLevel() )
375  throw OpalException("BoxLibLayout::update()",
376  "Local #particles disagrees with sum over levels");
377 
378  if ( !PData.isForbidTransform() ) {
379  // undo domain transformation + undo Lorentz transform
380  PData.domainMapping(true);
381  }
382 }
383 
384 
385 // Function from AMReX adjusted to work with Ippl AmrParticleBase class
386 //get the cell where particle is located - uses AmrParticleBase object and particle id
387 template <class T, unsigned Dim>
390  const unsigned int ip,
391  int lev) const
392 {
393  return Index(p.R[ip], lev);
394 }
395 
396 //get the cell where particle is located - uses the particle position vector R
397 template <class T, unsigned Dim>
400  int lev) const
401 {
402  AmrIntVect_t iv;
403  const AmrGeometry_t& geom = Geom(lev);
404 
405  D_TERM(iv[0]=floor((R[0]-geom.ProbLo(0))/geom.CellSize(0));,
406  iv[1]=floor((R[1]-geom.ProbLo(1))/geom.CellSize(1));,
407  iv[2]=floor((R[2]-geom.ProbLo(2))/geom.CellSize(2)););
408 
409  iv += geom.Domain().smallEnd();
410 
411  return iv;
412 }
413 
414 
415 template <class T, unsigned Dim>
416 void BoxLibLayout<T, Dim>::buildLevelMask(int lev, const int ncells) {
417  int covered = 0;
418  int notcovered = 1;
419  int physbnd = 1;
420  int interior = 0;
421 
422  if ( lev >= (int)masks_m.size() )
423  masks_m.resize(lev + 1);
424 
425  masks_m[lev].reset(new mask_t(ParticleBoxArray(lev),
426  ParticleDistributionMap(lev), 1, 1));
427 
428  masks_m[lev]->setVal(1, 1);
429 
430  mask_t tmp_mask(ParticleBoxArray(lev),
431  ParticleDistributionMap(lev),
432  1, ncells);
433 
434  tmp_mask.setVal(0, ncells);
435 
436  tmp_mask.BuildMask(Geom(lev).Domain(), Geom(lev).periodicity(),
437  covered, notcovered, physbnd, interior);
438 
439  tmp_mask.FillBoundary(Geom(lev).periodicity());
440 
441  for (amrex::MFIter mfi(tmp_mask); mfi.isValid(); ++mfi) {
442  const AmrBox_t& bx = mfi.validbox();
443  const int* lo = bx.loVect();
444  const int* hi = bx.hiVect();
445 
446  basefab_t& mfab = (*masks_m[lev])[mfi];
447  const basefab_t& fab = tmp_mask[mfi];
448 
449  for (int i = lo[0]; i <= hi[0]; ++i) {
450  for (int j = lo[1]; j <= hi[1]; ++j) {
451  for (int k = lo[2]; k <= hi[2]; ++k) {
452  int total = 0;
453 
454  for (int ii = i - ncells; ii <= i + ncells; ++ii) {
455  for (int jj = j - ncells; jj <= j + ncells; ++jj) {
456  for (int kk = k - ncells; kk <= k + ncells; ++kk) {
457  AmrIntVect_t iv(ii, jj, kk);
458  total += fab(iv);
459  }
460  }
461  }
462 
463  AmrIntVect_t iv(i, j, k);
464  if (total == 0) {
465  mfab(iv) = 0;
466  }
467  }
468  }
469  }
470  }
471 
472  masks_m[lev]->FillBoundary(Geom(lev).periodicity());
473 }
474 
475 
476 template <class T, unsigned Dim>
478  PAssert(lev < (int)masks_m.size());
479  masks_m[lev].reset(nullptr);
480 }
481 
482 
483 template <class T, unsigned Dim>
484 const std::unique_ptr<typename BoxLibLayout<T, Dim>::mask_t>&
486  if ( lev >= (int)masks_m.size() ) {
487  throw OpalException("BoxLibLayout::getLevelMask()",
488  "Unable to access level " + std::to_string(lev) + ".");
489  }
490  return masks_m[lev];
491 }
492 
493 
494 // template <class T, unsigned Dim>
495 // int BoxLibLayout<T, Dim>::getTileIndex(const AmrIntVect_t& iv, const Box& box, Box& tbx) {
496 // if (do_tiling == false) {
497 // tbx = box;
498 // return 0;
499 // } else {
500 // //
501 // // This function must be consistent with FabArrayBase::buildTileArray function!!!
502 // //
503 // auto tiling_1d = [](int i, int lo, int hi, int tilesize,
504 // int& ntile, int& tileidx, int& tlo, int& thi) {
505 // int ncells = hi-lo+1;
506 // ntile = std::max(ncells/tilesize, 1);
507 // int ts_right = ncells/ntile;
508 // int ts_left = ts_right+1;
509 // int nleft = ncells - ntile*ts_right;
510 // int ii = i - lo;
511 // int nbndry = nleft*ts_left;
512 // if (ii < nbndry) {
513 // tileidx = ii / ts_left; // tiles on the left of nbndry have size of ts_left
514 // tlo = lo + tileidx * ts_left;
515 // thi = tlo + ts_left - 1;
516 // } else {
517 // tileidx = nleft + (ii-nbndry) / ts_right; // tiles on the right: ts_right
518 // tlo = lo + tileidx * ts_right + nleft;
519 // thi = tlo + ts_right - 1;
520 // }
521 // };
522 // const AmrIntVect_t& small = box.smallEnd();
523 // const AmrIntVect_t& big = box.bigEnd();
524 // AmrIntVect_t ntiles, ivIndex, tilelo, tilehi;
525 //
526 // D_TERM(int iv0 = std::min(std::max(iv[0], small[0]), big[0]);,
527 // int iv1 = std::min(std::max(iv[1], small[1]), big[1]);,
528 // int iv2 = std::min(std::max(iv[2], small[2]), big[2]););
529 //
530 // D_TERM(tiling_1d(iv0, small[0], big[0], tile_size[0], ntiles[0], ivIndex[0], tilelo[0], tilehi[0]);,
531 // tiling_1d(iv1, small[1], big[1], tile_size[1], ntiles[1], ivIndex[1], tilelo[1], tilehi[1]);,
532 // tiling_1d(iv2, small[2], big[2], tile_size[2], ntiles[2], ivIndex[2], tilelo[2], tilehi[2]););
533 //
534 // tbx = Box(tilelo, tilehi);
535 //
536 // return D_TERM(ivIndex[0], + ntiles[0]*ivIndex[1], + ntiles[0]*ntiles[1]*ivIndex[2]);
537 // }
538 // }
539 
540 
541 //sets the grid and level where particle belongs - returns false if particle is outside the domain
542 template <class T, unsigned Dim>
544  const unsigned int ip,
545  int lev_min,
546  int lev_max,
547  int nGrow) const
548 {
549 
550  if (lev_max == -1)
551  lev_max = finestLevel();
552 
553  PAssert(lev_max <= finestLevel());
554 
555  PAssert(nGrow == 0 || (nGrow >= 0 && lev_min == lev_max));
556 
557  std::vector< std::pair<int, AmrBox_t> > isects;
558 
559  for (int lev = lev_max; lev >= lev_min; lev--)
560  {
561  const AmrIntVect_t& iv = Index(p, ip, lev);
562  const AmrGrid_t& ba = ParticleBoxArray(lev);
563  PAssert(ba.ixType().cellCentered());
564 
565  if (lev == (int)p.Level[ip]) {
566  // The fact that we are here means this particle does not belong to any finer grids.
567  if (0 <= p.Grid[ip] && p.Grid[ip] < ba.size()) {
568  const AmrBox_t& bx = ba.getCellCenteredBox(p.Grid[ip]);
569  const AmrBox_t& gbx = amrex::grow(bx,nGrow);
570  if (gbx.contains(iv)) {
571 // if (bx != pld.m_gridbox || !pld.m_tilebox.contains(iv)) {
572 // pld.m_tile = getTileIndex(iv, bx, pld.m_tilebox);
573 // pld.m_gridbox = bx;
574 // }
575  return true;
576  }
577  }
578  }
579 
580  ba.intersections(AmrBox_t(iv, iv), isects, true, nGrow);
581 
582  if (!isects.empty()) {
583  p.Level[ip] = lev;
584  p.Grid[ip] = isects[0].first;
585 
586  return true;
587  }
588  }
589  return false;
590 }
591 
592 
593 //Function from AMReX adjusted to work with Ippl AmrParticleBase class
594 //Checks/sets whether the particle has crossed a periodic boundary in such a way
595 //that it is on levels lev_min and higher.
596 template <class T, unsigned Dim>
598  const unsigned int ip,
599  int lev_min,
600  int lev_max) const
601 {
602  if (!Geom(0).isAnyPeriodic()) return false;
603 
604  if (lev_max == -1)
605  lev_max = finestLevel();
606 
607  PAssert(lev_max <= finestLevel());
608  //
609  // Create a copy "dummy" particle to check for periodic outs.
610  //
611  SingleParticlePos_t R = p.R[ip];
612 
613  if (PeriodicShift(R)) {
614  std::vector< std::pair<int, AmrBox_t> > isects;
615 
616  for (int lev = lev_max; lev >= lev_min; lev--) {
617  const AmrIntVect_t& iv = Index(R, lev);
618  const AmrGrid_t& ba = ParticleBoxArray(lev);
619 
620  ba.intersections(AmrBox_t(iv,iv),isects,true,0);
621 
622  if (!isects.empty()) {
623  D_TERM(p.R[ip][0] = R[0];,
624  p.R[ip][1] = R[1];,
625  p.R[ip][2] = R[2];);
626 
627  p.Level[ip] = lev;
628  p.Grid[ip] = isects[0].first;
629 
630  return true;
631  }
632  }
633  }
634 
635  return false;
636 }
637 
638 
639 // Function from AMReX adjusted to work with Ippl AmrParticleBase class
640 // Returns true if the particle was shifted.
641 template <class T, unsigned Dim>
643 {
644  //
645  // This routine should only be called when Where() returns false.
646  //
647  //
648  // We'll use level 0 stuff since ProbLo/ProbHi are the same for every level.
649  //
650  const AmrGeometry_t& geom = Geom(0);
651  const AmrBox_t& dmn = geom.Domain();
652  const AmrIntVect_t& iv = Index(R, 0);
653  bool shifted = false;
654 
655  for (int i = 0; i < AMREX_SPACEDIM; i++) {
656  if (!geom.isPeriodic(i)) continue;
657 
658  if (iv[i] > dmn.bigEnd(i)) {
659  if (R[i] == geom.ProbHi(i)) {
660  //
661  // Don't let particles lie exactly on the domain face.
662  // Force the particle to be outside the domain so the
663  // periodic shift will bring it back inside.
664  //
665  R[i] += .125*geom.CellSize(i);
666  }
667  R[i] -= geom.ProbLength(i);
668 
669  if (R[i] <= geom.ProbLo(i))
670  //
671  // This can happen due to precision issues.
672  //
673  R[i] += .125*geom.CellSize(i);
674 
675  PAssert(R[i] >= geom.ProbLo(i));
676 
677  shifted = true;
678 
679  } else if (iv[i] < dmn.smallEnd(i)) {
680  if (R[i] == geom.ProbLo(i)) {
681  //
682  // Don't let particles lie exactly on the domain face.
683  // Force the particle to be outside the domain so the
684  // periodic shift will bring it back inside.
685  //
686  R[i] -= .125*geom.CellSize(i);
687  }
688  R[i] += geom.ProbLength(i);
689 
690  if (R[i] >= geom.ProbHi(i)) {
691  //
692  // This can happen due to precision issues.
693  //
694  R[i] -= .125*geom.CellSize(i);
695  }
696  PAssert(R[i] <= geom.ProbHi(i));
697 
698  shifted = true;
699  }
700  }
701  //
702  // The particle may still be outside the domain in the case
703  // where we aren't periodic on the face out which it travelled.
704  //
705  return shifted;
706 }
707 
708 
709 template <class T, unsigned Dim>
712  const unsigned int ip,
713  int lev_min, int lev_max, int nGrow) const
714 {
715  bool outside = D_TERM( p.R[ip](0) < AmrGeometry_t::ProbLo(0)
716  || p.R[ip](0) >= AmrGeometry_t::ProbHi(0),
717  || p.R[ip](1) < AmrGeometry_t::ProbLo(1)
718  || p.R[ip](1) >= AmrGeometry_t::ProbHi(1),
719  || p.R[ip](2) < AmrGeometry_t::ProbLo(2)
720  || p.R[ip](2) >= AmrGeometry_t::ProbHi(2));
721 
722  bool success = false;
723 
724  if (outside) {
725  // Note that EnforcePeriodicWhere may shift the particle if it is successful.
726  success = EnforcePeriodicWhere(p, ip, lev_min, lev_max);
727  if (!success && lev_min == 0) {
728  // The particle has left the domain; invalidate it.
729  p.destroy(1, ip);
730  success = true;
731 
732  /* We shouldn't lose particles since they are mapped to be within
733  * [-1, 1]^3.
734  */
735  throw OpalException("BoxLibLayout::locateParticle()",
736  "We're losing particles although we shouldn't");
737 
738  }
739  } else {
740  success = Where(p, ip, lev_min, lev_max);
741  }
742 
743  if (!success) {
744  success = (nGrow > 0) && Where(p, ip, lev_min, lev_min, nGrow);
745  }
746 
747  if (!success) {
748  std::stringstream ss;
749  ss << "Invalid particle with ID " << ip << " at position " << p.R[ip] << ".";
750  throw OpalException("BoxLibLayout::locateParticle()", ss.str());
751  }
752 }
753 
754 
755 // overwritten functions
756 template <class T, unsigned Dim>
757 bool BoxLibLayout<T, Dim>::LevelDefined (int level) const {
758  return level <= this->maxLevel_m && !m_ba[level].empty() && !m_dmap[level].empty();
759 }
760 
761 
762 template <class T, unsigned Dim>
764  return this->finestLevel_m;
765 }
766 
767 
768 template <class T, unsigned Dim>
770  return this->maxLevel_m;
771 }
772 
773 
774 template <class T, unsigned Dim>
776  BoxLibLayout<T, Dim>::refRatio (int level) const {
777  return refRatio_m[level];
778 }
779 
780 
781 template <class T, unsigned Dim>
782 int BoxLibLayout<T, Dim>::MaxRefRatio (int level) const {
783  int maxval = 0;
784  for (int n = 0; n<AMREX_SPACEDIM; n++)
785  maxval = std::max(maxval, refRatio_m[level][n]);
786  return maxval;
787 }
788 
789 
790 template <class T, unsigned Dim>
792  int maxGridSize,
793  double dh) {
794  // physical box (in meters)
795  AmrDomain_t real_box;
796  for (int d = 0; d < AMREX_SPACEDIM; ++d) {
797 
798  PAssert(lowerBound[d] < 0);
799  PAssert(upperBound[d] > 0);
800 
801  real_box.setLo(d, lowerBound[d] * (1.0 + dh));
802  real_box.setHi(d, upperBound[d] * (1.0 + dh));
803  }
804 
805  AmrGeometry_t::ProbDomain(real_box);
806 
807  // define underlying box for physical domain
808  AmrIntVect_t domain_lo(0 , 0, 0);
809  AmrIntVect_t domain_hi(nGridPoints - 1, nGridPoints - 1, nGridPoints - 1);
810  const AmrBox_t domain(domain_lo, domain_hi);
811 
812  // use Cartesian coordinates
813  int coord = 0;
814 
815  // Dirichlet boundary conditions
816  int is_per[AMREX_SPACEDIM];
817  for (int i = 0; i < AMREX_SPACEDIM; i++)
818  is_per[i] = 0;
819 
820  AmrGeometry_t geom;
821  geom.define(domain, &real_box, coord, is_per);
822 
823  AmrGrid_t ba;
824  ba.define(domain);
825  // break the BoxArrays at both levels into max_grid_size^3 boxes
826  ba.maxSize(maxGridSize);
827 
828  AmrProcMap_t dmap;
829  dmap.define(ba, Ippl::getNodes());
830 
831  // set protected ParGDB member variables
832  this->m_geom.resize(1);
833  this->m_geom[0] = geom;
834 
835  this->m_dmap.resize(1);
836  this->m_dmap[0] = dmap;
837 
838  this->m_ba.resize(1);
839  this->m_ba[0] = ba;
840 
841  this->m_nlevels = ba.size();
842 }
843 
844 #endif
void clearLevelMask(int lev)
amr::AmrGeometry_t AmrGeometry_t
Definition: BoxLibLayout.h:66
int maxLevel() const
bool add(Message *)
Definition: MsgBuffer.cpp:44
void buildLevelMask(int lev, const int ncells=1)
AmrIntVect_t refRatio(int level) const
AmrIntVect_t Index(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int level) const
static int myNode()
Definition: IpplInfo.cpp:691
void * getBuffer()
Definition: MsgBuffer.h:54
amr::AmrIntArray_t AmrIntArray_t
Definition: BoxLibLayout.h:72
amrex::BaseFab< int > basefab_t
Definition: BoxLibLayout.h:77
amr::AmrProcMapContainer_t AmrProcMapContainer_t
Definition: BoxLibLayout.h:69
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
bool LevelDefined(int level) const
Definition: TSVMeta.h:24
bool empty() const
Definition: Message.h:300
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
int getSize()
Definition: MsgBuffer.h:50
Definition: Index.h:236
void setBoundingBox(double dh)
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
std::string::iterator iterator
Definition: MSLang.h:15
amr::AmrGrid_t AmrGrid_t
Definition: BoxLibLayout.h:65
amrex::FabArray< basefab_t > mask_t
Definition: BoxLibLayout.h:78
static int getNodes()
Definition: IpplInfo.cpp:670
amr::AmrBox_t AmrBox_t
Definition: BoxLibLayout.h:74
bool EnforcePeriodicWhere(AmrParticleBase< BoxLibLayout< T, Dim > > &prt, const unsigned int ip, int lev_min=0, int lev_max=-1) const
static Communicate * Comm
Definition: IpplInfo.h:84
The base class for all OPAL exceptions.
Definition: OpalException.h:28
int finestLevel() const
amr::AmrDomain_t AmrDomain_t
Definition: BoxLibLayout.h:73
#define P_SPATIAL_TRANSFER_TAG
Definition: Tags.h:82
void locateParticle(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int lev_min, int lev_max, int nGrow) const
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
void update(IpplParticleBase< BoxLibLayout< T, Dim > > &PData, const ParticleAttrib< char > *canSwap=0)
const unsigned Dim
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
const std::unique_ptr< mask_t > & getLevelMask(int lev) const
amr::AmrIntVect_t AmrIntVect_t
Definition: BoxLibLayout.h:70
bool Where(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int lev_min=0, int lev_max=-1, int nGrow=0) const
bool PeriodicShift(SingleParticlePos_t R) const
Definition: Format.h:27
int MaxRefRatio(int level) const
amr::AmrGeomContainer_t AmrGeomContainer_t
Definition: BoxLibLayout.h:67
Message * get()
Definition: MsgBuffer.cpp:71
amr::AmrProcMap_t AmrProcMap_t
Definition: BoxLibLayout.h:64
int maxLevel_m
Maximum level allowed.
#define PAssert(c)
Definition: PAssert.h:102
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Definition: PETE.h:728
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
amr::AmrGridContainer_t AmrGridContainer_t
Definition: BoxLibLayout.h:68
void initBaseBox_m(int nGridPoints, int maxGridSize, double dh=0.04)
void setDomainRatio(const std::vector< double > &ratio)
amrex::Box AmrBox_t
Definition: AmrDefs.h:50
AmrIntVectContainer_t refRatio_m
Definition: BoxLibLayout.h:377