OPAL (Object Oriented Parallel Accelerator Library) 2022.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 "BoxLibLayout.h"
40
41#include "Message/Format.h"
42#include "Message/MsgBuffer.h"
43#include "Utility/PAssert.h"
45
46#include <cmath>
47
48template <class T, unsigned Dim>
50
51
52template <class T, unsigned Dim>
54
55
56template<class T, unsigned Dim>
59 ParGDB(),
60 refRatio_m(0)
61{
62 /* FIXME There might be a better solution
63 *
64 *
65 * Figure out the number of grid points in each direction
66 * such that all processes have some data at the beginning
67 *
68 * ( nGridPoints / maxGridSize ) ^3 = max. #procs
69 *
70 */
71 int nProcs = Ippl::getNodes();
72 int maxGridSize = 16;
73
74 int nGridPoints = std::ceil( std::cbrt( nProcs ) ) * maxGridSize;
75
76 this->initBaseBox_m(nGridPoints, maxGridSize);
77}
78
79
80template<class T, unsigned Dim>
83 ParGDB(layout_p->m_geom,
84 layout_p->m_dmap,
85 layout_p->m_ba,
86 layout_p->m_rr)
87{
88 this->maxLevel_m = layout_p->maxLevel_m;
89 refRatio_m.resize(layout_p->m_geom.size()-1);
90 for (int i = 0; i < refRatio_m.size(); ++i)
91 refRatio_m[i] = layout_p->refRatio(i);
92}
93
94
95template<class T, unsigned Dim>
96BoxLibLayout<T, Dim>::BoxLibLayout(int nGridPoints, int maxGridSize)
98 ParGDB(),
99 refRatio_m(0)
100{
101 this->initBaseBox_m(nGridPoints, maxGridSize);
102}
103
104
105template<class T, unsigned Dim>
107 const AmrProcMap_t &dmap,
108 const AmrGrid_t &ba)
109 : ParticleAmrLayout<T, Dim>(),
110 ParGDB(geom, dmap, ba),
111 refRatio_m(0)
112{ }
113
114
115template<class T, unsigned Dim>
117 const AmrProcMapContainer_t &dmap,
118 const AmrGridContainer_t &ba,
119 const AmrIntArray_t &rr)
120 : ParticleAmrLayout<T, Dim>(),
121 ParGDB(geom, dmap, ba, rr),
122 refRatio_m(0)
123{ }
124
125
126template<class T, unsigned Dim>
128
129 // cubic box
130 int nGridPoints = this->m_geom[0].Domain().length(0);
131 int maxGridSize = this->m_ba[0][0].length(0);
132
133 this->initBaseBox_m(nGridPoints, maxGridSize, dh);
134}
135
136
137template <class T, unsigned Dim>
138void BoxLibLayout<T, Dim>::setDomainRatio(const std::vector<double>& ratio) {
139
140 static bool isCalled = false;
141
142 if ( isCalled ) {
143 return;
144 }
145
146 isCalled = true;
147
148 if ( ratio.size() != Dim ) {
149 throw OpalException("BoxLibLayout::setDomainRatio() ",
150 "Length " + std::to_string(ratio.size()) +
151 " != " + std::to_string(Dim));
152 }
153
154 for (unsigned int i = 0; i < Dim; ++i) {
155 if ( ratio[i] <= 0.0 ) {
156 throw OpalException("BoxLibLayout::setDomainRatio() ",
157 "The ratio has to be larger than zero.");
158 }
159
160 lowerBound[i] *= ratio[i];
161 upperBound[i] *= ratio[i];
162 }
163}
164
165
166template<class T, unsigned Dim>
168 const ParticleAttrib<char>* /*canSwap*/)
169{
170 /* Exit since we need AmrParticleBase with grids and levels for particles for this layout
171 * if IpplParticleBase is used something went wrong
172 */
173 throw OpalException("BoxLibLayout::update(IpplParticleBase, ParticleAttrib) ",
174 "Wrong update method called.");
175}
176
177
178// // Function from AMReX adjusted to work with Ippl AmrParticleBase class
179// // redistribute the particles using BoxLibs ParGDB class to determine where particle should go
180template<class T, unsigned Dim>
182 int lev_min, int lev_max, bool isRegrid)
183{
184 // in order to avoid transforms when already done
185 if ( !PData.isForbidTransform() ) {
186 /* we need to update on Amr domain + boosted frame (Lorentz transform,
187 * has to be undone at end of function
188 */
189 PData.domainMapping();
190 }
191
192 int nGrow = 0;
193
194 unsigned N = Ippl::getNodes();
195 unsigned myN = Ippl::myNode();
196
197 int theEffectiveFinestLevel = this->finestLevel();
198 while (!this->LevelDefined(theEffectiveFinestLevel)) {
199 theEffectiveFinestLevel--;
200 }
201
202 if (lev_max == -1)
203 lev_max = theEffectiveFinestLevel;
204 else if ( lev_max > theEffectiveFinestLevel )
205 lev_max = theEffectiveFinestLevel;
206
207 //loop trough the particles and assign the grid and level where each particle belongs
208 size_t LocalNum = PData.getLocalNum();
209
210 auto& LocalNumPerLevel = PData.getLocalNumPerLevel();
211
212 if ( LocalNum != LocalNumPerLevel.getLocalNumAllLevel() )
213 throw OpalException("BoxLibLayout::update()",
214 "Local #particles disagrees with sum over levels");
215
216 std::multimap<unsigned, unsigned> p2n; //node ID, particle
217
218 std::vector<int> msgsend(N);
219 std::vector<int> msgrecv(N);
220
221 unsigned sent = 0;
222 size_t lBegin = LocalNumPerLevel.begin(lev_min);
223 size_t lEnd = LocalNumPerLevel.end(lev_max);
224
225 /* in the case of regrid we might lose a level
226 * and therefore the level counter is invalidated
227 */
228 if ( isRegrid ) {
229 lBegin = 0;
230 lEnd = LocalNum;
231 }
232
233
234 //loop trough particles and assign grid and level to each particle
235 //if particle doesn't belong to this process save the index of the particle to be sent
236 for (unsigned int ip = lBegin; ip < lEnd; ++ip) {
237 // old level
238 const size_t& lold = PData.Level[ip];
239
240// /*
241// * AMReX sets m_grid = -1 and m_lev = -1
242// */
243// PData.Level[ip] = -1;
244// PData.Grid[ip] = -1;
245
246 //check to which level and grid the particle belongs to
247 locateParticle(PData, ip, lev_min, lev_max, nGrow);
248
249 // The owner of the particle is the CPU owning the finest grid
250 // in state data that contains the particle.
251 const size_t& lnew = PData.Level[ip];
252
253 const unsigned int who = ParticleDistributionMap(lnew)[PData.Grid[ip]];
254
255 --LocalNumPerLevel[lold];
256
257 if (who != myN) {
258 // we lost the particle to another process
259 msgsend[who] = 1;
260 p2n.insert(std::pair<unsigned, unsigned>(who, ip));
261 sent++;
262 } else {
263 /* if we still own the particle it may have moved to
264 * another level
265 */
266 ++LocalNumPerLevel[lnew];
267 }
268 }
269
270 //reduce message count so every node knows how many messages to receive
271 allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
272
274
275 typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
276
277 Format *format = PData.getFormat();
278
279 std::vector<MPI_Request> requests;
280 std::vector<MsgBuffer*> buffers;
281
282 //create a message and send particles to nodes they belong to
283 while (i!=p2n.end())
284 {
285 unsigned cur_destination = i->first;
286
287 MsgBuffer *msgbuf = new MsgBuffer(format, p2n.count(i->first));
288
289 for (; i!=p2n.end() && i->first == cur_destination; ++i)
290 {
291 Message msg;
292 PData.putMessage(msg, i->second);
293 PData.destroy(1, i->second);
294 msgbuf->add(&msg);
295 }
296
297 MPI_Request request = Ippl::Comm->raw_isend(msgbuf->getBuffer(),
298 msgbuf->getSize(),
299 cur_destination, tag);
300
301 //remember request and buffer so we can delete them later
302 requests.push_back(request);
303 buffers.push_back(msgbuf);
304
305 }
306
307 //destroy the particles that are sent to other domains
308 if ( LocalNum < PData.getDestroyNum() )
309 throw OpalException("BoxLibLayout::update()",
310 "Rank " + std::to_string(myN) +
311 " can't destroy more particles than possessed.");
312 else {
313 LocalNum -= PData.getDestroyNum(); // update local num
314 PData.performDestroy();
315 }
316
317 for (int lev = lev_min; lev <= lev_max; ++lev) {
318 if ( LocalNumPerLevel[lev] < 0 )
319 throw OpalException("BoxLibLayout::update()",
320 "Negative particle level count.");
321 }
322
323 //receive new particles
324 for (int k = 0; k<msgrecv[myN]; ++k)
325 {
327 char *buffer = 0;
328 int bufsize = Ippl::Comm->raw_probe_receive(buffer, node, tag);
329 MsgBuffer recvbuf(format, buffer, bufsize);
330
331 Message *msg = recvbuf.get();
332 while (msg != 0)
333 {
334 /* pBeginIdx is the start index of the new particle data
335 * pEndIdx is the last index of the new particle data
336 */
337 size_t pBeginIdx = LocalNum;
338
339 LocalNum += PData.getSingleMessage(*msg);
340
341 size_t pEndIdx = LocalNum;
342
343 for (size_t idx = pBeginIdx; idx < pEndIdx; ++idx)
344 ++LocalNumPerLevel[ PData.Level[idx] ];
345
346 delete msg;
347 msg = recvbuf.get();
348 }
349 }
350
351 //wait for communication to finish and clean up buffers
352 MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
353 MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
354 for (unsigned int j = 0; j<buffers.size(); ++j)
355 {
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
387template <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
397template <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
415template <class T, unsigned Dim>
416void 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
476template <class T, unsigned Dim>
478 PAssert(lev < (int)masks_m.size());
479 masks_m[lev].reset(nullptr);
480}
481
482
483template <class T, unsigned Dim>
484const 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
542template <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 {
569 const AmrBox_t& bx = ba.getCellCenteredBox(p.Grid[ip]);
570 const AmrBox_t& gbx = amrex::grow(bx,nGrow);
571 if (gbx.contains(iv))
572 {
573// if (bx != pld.m_gridbox || !pld.m_tilebox.contains(iv)) {
574// pld.m_tile = getTileIndex(iv, bx, pld.m_tilebox);
575// pld.m_gridbox = bx;
576// }
577 return true;
578 }
579 }
580 }
581
582 ba.intersections(AmrBox_t(iv, iv), isects, true, nGrow);
583
584 if (!isects.empty())
585 {
586 p.Level[ip] = lev;
587 p.Grid[ip] = isects[0].first;
588
589 return true;
590 }
591 }
592 return false;
593}
594
595
596//Function from AMReX adjusted to work with Ippl AmrParticleBase class
597//Checks/sets whether the particle has crossed a periodic boundary in such a way
598//that it is on levels lev_min and higher.
599template <class T, unsigned Dim>
601 const unsigned int ip,
602 int lev_min,
603 int lev_max) const
604{
605 if (!Geom(0).isAnyPeriodic()) return false;
606
607 if (lev_max == -1)
608 lev_max = finestLevel();
609
610 PAssert(lev_max <= finestLevel());
611 //
612 // Create a copy "dummy" particle to check for periodic outs.
613 //
614 SingleParticlePos_t R = p.R[ip];
615
616 if (PeriodicShift(R))
617 {
618 std::vector< std::pair<int, AmrBox_t> > isects;
619
620 for (int lev = lev_max; lev >= lev_min; lev--)
621 {
622 const AmrIntVect_t& iv = Index(R, lev);
623 const AmrGrid_t& ba = ParticleBoxArray(lev);
624
625 ba.intersections(AmrBox_t(iv,iv),isects,true,0);
626
627 if (!isects.empty())
628 {
629 D_TERM(p.R[ip][0] = R[0];,
630 p.R[ip][1] = R[1];,
631 p.R[ip][2] = R[2];);
632
633 p.Level[ip] = lev;
634 p.Grid[ip] = isects[0].first;
635
636 return true;
637 }
638 }
639 }
640
641 return false;
642}
643
644
645// Function from AMReX adjusted to work with Ippl AmrParticleBase class
646// Returns true if the particle was shifted.
647template <class T, unsigned Dim>
649{
650 //
651 // This routine should only be called when Where() returns false.
652 //
653 //
654 // We'll use level 0 stuff since ProbLo/ProbHi are the same for every level.
655 //
656 const AmrGeometry_t& geom = Geom(0);
657 const AmrBox_t& dmn = geom.Domain();
658 const AmrIntVect_t& iv = Index(R, 0);
659 bool shifted = false;
660
661 for (int i = 0; i < AMREX_SPACEDIM; i++)
662 {
663 if (!geom.isPeriodic(i)) continue;
664
665 if (iv[i] > dmn.bigEnd(i))
666 {
667 if (R[i] == geom.ProbHi(i))
668 //
669 // Don't let particles lie exactly on the domain face.
670 // Force the particle to be outside the domain so the
671 // periodic shift will bring it back inside.
672 //
673 R[i] += .125*geom.CellSize(i);
674
675 R[i] -= geom.ProbLength(i);
676
677 if (R[i] <= geom.ProbLo(i))
678 //
679 // This can happen due to precision issues.
680 //
681 R[i] += .125*geom.CellSize(i);
682
683 PAssert(R[i] >= geom.ProbLo(i));
684
685 shifted = true;
686 }
687 else if (iv[i] < dmn.smallEnd(i))
688 {
689 if (R[i] == geom.ProbLo(i))
690 //
691 // Don't let particles lie exactly on the domain face.
692 // Force the particle to be outside the domain so the
693 // periodic shift will bring it back inside.
694 //
695 R[i] -= .125*geom.CellSize(i);
696
697 R[i] += geom.ProbLength(i);
698
699 if (R[i] >= geom.ProbHi(i))
700 //
701 // This can happen due to precision issues.
702 //
703 R[i] -= .125*geom.CellSize(i);
704
705 PAssert(R[i] <= geom.ProbHi(i));
706
707 shifted = true;
708 }
709 }
710 //
711 // The particle may still be outside the domain in the case
712 // where we aren't periodic on the face out which it travelled.
713 //
714 return shifted;
715}
716
717
718template <class T, unsigned Dim>
721 const unsigned int ip,
722 int lev_min, int lev_max, int nGrow) const
723{
724 bool outside = D_TERM( p.R[ip](0) < AmrGeometry_t::ProbLo(0)
725 || p.R[ip](0) >= AmrGeometry_t::ProbHi(0),
726 || p.R[ip](1) < AmrGeometry_t::ProbLo(1)
727 || p.R[ip](1) >= AmrGeometry_t::ProbHi(1),
728 || p.R[ip](2) < AmrGeometry_t::ProbLo(2)
729 || p.R[ip](2) >= AmrGeometry_t::ProbHi(2));
730
731 bool success = false;
732
733 if (outside)
734 {
735 // Note that EnforcePeriodicWhere may shift the particle if it is successful.
736 success = EnforcePeriodicWhere(p, ip, lev_min, lev_max);
737 if (!success && lev_min == 0)
738 {
739 // The particle has left the domain; invalidate it.
740 p.destroy(1, ip);
741 success = true;
742
743 /* We shouldn't lose particles since they are mapped to be within
744 * [-1, 1]^3.
745 */
746 throw OpalException("BoxLibLayout::locateParticle()",
747 "We're losing particles although we shouldn't");
748
749 }
750 }
751 else
752 {
753 success = Where(p, ip, lev_min, lev_max);
754 }
755
756 if (!success)
757 {
758 success = (nGrow > 0) && Where(p, ip, lev_min, lev_min, nGrow);
759 }
760
761 if (!success)
762 {
763 std::stringstream ss;
764 ss << "Invalid particle with ID " << ip << " at position " << p.R[ip] << ".";
765 throw OpalException("BoxLibLayout::locateParticle()", ss.str());
766 }
767}
768
769
770// overwritten functions
771template <class T, unsigned Dim>
773 return level <= this->maxLevel_m && !m_ba[level].empty() && !m_dmap[level].empty();
774}
775
776
777template <class T, unsigned Dim>
779 return this->finestLevel_m;
780}
781
782
783template <class T, unsigned Dim>
785 return this->maxLevel_m;
786}
787
788
789template <class T, unsigned Dim>
792{
793 return refRatio_m[level];
794}
795
796
797template <class T, unsigned Dim>
799 int maxval = 0;
800 for (int n = 0; n<AMREX_SPACEDIM; n++)
801 maxval = std::max(maxval, refRatio_m[level][n]);
802 return maxval;
803}
804
805
806template <class T, unsigned Dim>
808 int maxGridSize,
809 double dh)
810{
811 // physical box (in meters)
812 AmrDomain_t real_box;
813 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
814
815 PAssert(lowerBound[d] < 0);
816 PAssert(upperBound[d] > 0);
817
818 real_box.setLo(d, lowerBound[d] * (1.0 + dh));
819 real_box.setHi(d, upperBound[d] * (1.0 + dh));
820 }
821
822 AmrGeometry_t::ProbDomain(real_box);
823
824 // define underlying box for physical domain
825 AmrIntVect_t domain_lo(0 , 0, 0);
826 AmrIntVect_t domain_hi(nGridPoints - 1, nGridPoints - 1, nGridPoints - 1);
827 const AmrBox_t domain(domain_lo, domain_hi);
828
829 // use Cartesian coordinates
830 int coord = 0;
831
832 // Dirichlet boundary conditions
833 int is_per[AMREX_SPACEDIM];
834 for (int i = 0; i < AMREX_SPACEDIM; i++)
835 is_per[i] = 0;
836
837 AmrGeometry_t geom;
838 geom.define(domain, &real_box, coord, is_per);
839
840 AmrGrid_t ba;
841 ba.define(domain);
842 // break the BoxArrays at both levels into max_grid_size^3 boxes
843 ba.maxSize(maxGridSize);
844
845 AmrProcMap_t dmap;
846 dmap.define(ba, Ippl::getNodes());
847
848 // set protected ParGDB member variables
849 this->m_geom.resize(1);
850 this->m_geom[0] = geom;
851
852 this->m_dmap.resize(1);
853 this->m_dmap[0] = dmap;
854
855 this->m_ba.resize(1);
856 this->m_ba[0] = ba;
857
858 this->m_nlevels = ba.size();
859}
860
861#endif
const unsigned Dim
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
#define P_SPATIAL_TRANSFER_TAG
Definition: Tags.h:82
#define P_LAYOUT_CYCLE
Definition: Tags.h:86
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
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
#define PAssert(c)
Definition: PAssert.h:102
amrex::Box AmrBox_t
Definition: AmrDefs.h:50
std::string::iterator iterator
Definition: MSLang.h:16
void setBoundingBox(double dh)
amr::AmrBox_t AmrBox_t
Definition: BoxLibLayout.h:74
amr::AmrProcMapContainer_t AmrProcMapContainer_t
Definition: BoxLibLayout.h:69
amr::AmrDomain_t AmrDomain_t
Definition: BoxLibLayout.h:73
const std::unique_ptr< mask_t > & getLevelMask(int lev) const
void setDomainRatio(const std::vector< double > &ratio)
void locateParticle(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int lev_min, int lev_max, int nGrow) const
AmrIntVectContainer_t refRatio_m
Definition: BoxLibLayout.h:385
void buildLevelMask(int lev, const int ncells=1)
void initBaseBox_m(int nGridPoints, int maxGridSize, double dh=0.04)
bool LevelDefined(int level) const
void clearLevelMask(int lev)
amr::AmrIntVect_t AmrIntVect_t
Definition: BoxLibLayout.h:70
amr::AmrIntArray_t AmrIntArray_t
Definition: BoxLibLayout.h:72
amr::AmrGeometry_t AmrGeometry_t
Definition: BoxLibLayout.h:66
int maxLevel() const
amrex::BaseFab< int > basefab_t
Definition: BoxLibLayout.h:77
amrex::FabArray< basefab_t > mask_t
Definition: BoxLibLayout.h:78
amr::AmrGeomContainer_t AmrGeomContainer_t
Definition: BoxLibLayout.h:67
bool PeriodicShift(SingleParticlePos_t R) const
amr::AmrGrid_t AmrGrid_t
Definition: BoxLibLayout.h:65
void update(IpplParticleBase< BoxLibLayout< T, Dim > > &PData, const ParticleAttrib< char > *canSwap=0)
amr::AmrGridContainer_t AmrGridContainer_t
Definition: BoxLibLayout.h:68
bool EnforcePeriodicWhere(AmrParticleBase< BoxLibLayout< T, Dim > > &prt, const unsigned int ip, int lev_min=0, int lev_max=-1) const
AmrIntVect_t Index(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int level) const
int finestLevel() const
amr::AmrProcMap_t AmrProcMap_t
Definition: BoxLibLayout.h:64
int MaxRefRatio(int level) const
AmrIntVect_t refRatio(int level) const
bool Where(AmrParticleBase< BoxLibLayout< T, Dim > > &p, const unsigned int ip, int lev_min=0, int lev_max=-1, int nGrow=0) const
The base class for all OPAL exceptions.
Definition: OpalException.h:28
int maxLevel_m
Maximum level allowed.
Definition: Index.h:237
virtual MPI_Request raw_isend(void *, int, int, int)
Definition: Communicate.h:196
virtual int raw_probe_receive(char *&, int &, int &)
Definition: Communicate.h:208
Definition: Format.h:27
bool empty() const
Definition: Message.h:300
void * getBuffer()
Definition: MsgBuffer.h:54
bool add(Message *)
Definition: MsgBuffer.cpp:44
int getSize()
Definition: MsgBuffer.h:50
Message * get()
Definition: MsgBuffer.cpp:71
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6