OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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
52template <class T, unsigned Dim>
54
55
56template <class T, unsigned Dim>
58
59
60template<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
84template<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
99template<class T, unsigned Dim>
100BoxLibLayout<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
109template<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
119template<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
130template<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
141template <class T, unsigned Dim>
142void 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
170template<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
184template<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 size_t lBegin = LocalNumPerLevel.begin(lev_min);
226 size_t lEnd = LocalNumPerLevel.end(lev_max);
227
228 /* in the case of regrid we might lose a level
229 * and therefore the level counter is invalidated
230 */
231 if ( isRegrid ) {
232 lBegin = 0;
233 lEnd = LocalNum;
234 }
235
236
237 //loop trough particles and assign grid and level to each particle
238 //if particle doesn't belong to this process save the index of the particle to be sent
239 for (unsigned int ip = lBegin; ip < lEnd; ++ip) {
240 // old level
241 const size_t& lold = PData.Level[ip];
242
243// /*
244// * AMReX sets m_grid = -1 and m_lev = -1
245// */
246// PData.Level[ip] = -1;
247// PData.Grid[ip] = -1;
248
249 //check to which level and grid the particle belongs to
250 locateParticle(PData, ip, lev_min, lev_max, nGrow);
251
252 // The owner of the particle is the CPU owning the finest grid
253 // in state data that contains the particle.
254 const size_t& lnew = PData.Level[ip];
255
256 const unsigned int who = ParticleDistributionMap(lnew)[PData.Grid[ip]];
257
258 --LocalNumPerLevel[lold];
259
260 if (who != myN) {
261 // we lost the particle to another process
262 msgsend[who] = 1;
263 p2n.insert(std::pair<unsigned, unsigned>(who, ip));
264 } else {
265 /* if we still own the particle it may have moved to
266 * another level
267 */
268 ++LocalNumPerLevel[lnew];
269 }
270 }
271
272 //reduce message count so every node knows how many messages to receive
273 allreduce(msgsend.data(), msgrecv.data(), N, std::plus<int>());
274
276
277 typename std::multimap<unsigned, unsigned>::iterator i = p2n.begin();
278
279 Format *format = PData.getFormat();
280
281 std::vector<MPI_Request> requests;
282 std::vector<MsgBuffer*> buffers;
283
284 //create a message and send particles to nodes they belong to
285 while (i!=p2n.end()) {
286 unsigned cur_destination = i->first;
287
288 MsgBuffer *msgbuf = new MsgBuffer(format, p2n.count(i->first));
289
290 for (; i!=p2n.end() && i->first == cur_destination; ++i) {
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
324 //receive new particles
325 for (int k = 0; k<msgrecv[myN]; ++k) {
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 /* pBeginIdx is the start index of the new particle data
334 * pEndIdx is the last index of the new particle data
335 */
336 size_t pBeginIdx = LocalNum;
337
338 LocalNum += PData.getSingleMessage(*msg);
339
340 size_t pEndIdx = LocalNum;
341
342 for (size_t idx = pBeginIdx; idx < pEndIdx; ++idx)
343 ++LocalNumPerLevel[ PData.Level[idx] ];
344
345 delete msg;
346 msg = recvbuf.get();
347 }
348 }
349
350 //wait for communication to finish and clean up buffers
351 MPI_Request* requests_ptr = requests.empty()? static_cast<MPI_Request*>(0): &(requests[0]);
352 MPI_Waitall(requests.size(), requests_ptr, MPI_STATUSES_IGNORE);
353 for (unsigned int j = 0; j<buffers.size(); ++j) {
354 delete buffers[j];
355 }
356
357 delete format;
358
359 // there is extra work to do if there are multipple nodes, to distribute
360 // the particle layout data to all nodes
361 //TODO: do we need info on how many particles are on each node?
362
363 //save how many total particles we have
364 size_t TotalNum = 0;
365 allreduce(&LocalNum, &TotalNum, 1, std::plus<size_t>());
366
367 // update our particle number counts
368 PData.setTotalNum(TotalNum); // set the total atom count
369 PData.setLocalNum(LocalNum); // set the number of local atoms
370
371 // final check
372 if ( LocalNum != LocalNumPerLevel.getLocalNumAllLevel() )
373 throw OpalException("BoxLibLayout::update()",
374 "Local #particles disagrees with sum over levels");
375
376 if ( !PData.isForbidTransform() ) {
377 // undo domain transformation + undo Lorentz transform
378 PData.domainMapping(true);
379 }
380}
381
382
383// Function from AMReX adjusted to work with Ippl AmrParticleBase class
384//get the cell where particle is located - uses AmrParticleBase object and particle id
385template <class T, unsigned Dim>
388 const unsigned int ip,
389 int lev) const
390{
391 return Index(p.R[ip], lev);
392}
393
394//get the cell where particle is located - uses the particle position vector R
395template <class T, unsigned Dim>
398 int lev) const
399{
400 AmrIntVect_t iv;
401 const AmrGeometry_t& geom = Geom(lev);
402
403 D_TERM(iv[0]=floor((R[0]-geom.ProbLo(0))/geom.CellSize(0));,
404 iv[1]=floor((R[1]-geom.ProbLo(1))/geom.CellSize(1));,
405 iv[2]=floor((R[2]-geom.ProbLo(2))/geom.CellSize(2)););
406
407 iv += geom.Domain().smallEnd();
408
409 return iv;
410}
411
412
413template <class T, unsigned Dim>
414void BoxLibLayout<T, Dim>::buildLevelMask(int lev, const int ncells) {
415 int covered = 0;
416 int notcovered = 1;
417 int physbnd = 1;
418 int interior = 0;
419
420 if ( lev >= (int)masks_m.size() )
421 masks_m.resize(lev + 1);
422
423 masks_m[lev].reset(new mask_t(ParticleBoxArray(lev),
424 ParticleDistributionMap(lev), 1, 1));
425
426 masks_m[lev]->setVal(1, 1);
427
428 mask_t tmp_mask(ParticleBoxArray(lev),
429 ParticleDistributionMap(lev),
430 1, ncells);
431
432 tmp_mask.setVal(0, ncells);
433
434 tmp_mask.BuildMask(Geom(lev).Domain(), Geom(lev).periodicity(),
435 covered, notcovered, physbnd, interior);
436
437 tmp_mask.FillBoundary(Geom(lev).periodicity());
438
439 for (amrex::MFIter mfi(tmp_mask); mfi.isValid(); ++mfi) {
440 const AmrBox_t& bx = mfi.validbox();
441 const int* lo = bx.loVect();
442 const int* hi = bx.hiVect();
443
444 basefab_t& mfab = (*masks_m[lev])[mfi];
445 const basefab_t& fab = tmp_mask[mfi];
446
447 for (int i = lo[0]; i <= hi[0]; ++i) {
448 for (int j = lo[1]; j <= hi[1]; ++j) {
449 for (int k = lo[2]; k <= hi[2]; ++k) {
450 int total = 0;
451
452 for (int ii = i - ncells; ii <= i + ncells; ++ii) {
453 for (int jj = j - ncells; jj <= j + ncells; ++jj) {
454 for (int kk = k - ncells; kk <= k + ncells; ++kk) {
455 AmrIntVect_t iv(ii, jj, kk);
456 total += fab(iv);
457 }
458 }
459 }
460
461 AmrIntVect_t iv(i, j, k);
462 if (total == 0) {
463 mfab(iv) = 0;
464 }
465 }
466 }
467 }
468 }
469
470 masks_m[lev]->FillBoundary(Geom(lev).periodicity());
471}
472
473
474template <class T, unsigned Dim>
476 PAssert(lev < (int)masks_m.size());
477 masks_m[lev].reset(nullptr);
478}
479
480
481template <class T, unsigned Dim>
482const std::unique_ptr<typename BoxLibLayout<T, Dim>::mask_t>&
484 if ( lev >= (int)masks_m.size() ) {
485 throw OpalException("BoxLibLayout::getLevelMask()",
486 "Unable to access level " + std::to_string(lev) + ".");
487 }
488 return masks_m[lev];
489}
490
491
492// template <class T, unsigned Dim>
493// int BoxLibLayout<T, Dim>::getTileIndex(const AmrIntVect_t& iv, const Box& box, Box& tbx) {
494// if (do_tiling == false) {
495// tbx = box;
496// return 0;
497// } else {
498// //
499// // This function must be consistent with FabArrayBase::buildTileArray function!!!
500// //
501// auto tiling_1d = [](int i, int lo, int hi, int tilesize,
502// int& ntile, int& tileidx, int& tlo, int& thi) {
503// int ncells = hi-lo+1;
504// ntile = std::max(ncells/tilesize, 1);
505// int ts_right = ncells/ntile;
506// int ts_left = ts_right+1;
507// int nleft = ncells - ntile*ts_right;
508// int ii = i - lo;
509// int nbndry = nleft*ts_left;
510// if (ii < nbndry) {
511// tileidx = ii / ts_left; // tiles on the left of nbndry have size of ts_left
512// tlo = lo + tileidx * ts_left;
513// thi = tlo + ts_left - 1;
514// } else {
515// tileidx = nleft + (ii-nbndry) / ts_right; // tiles on the right: ts_right
516// tlo = lo + tileidx * ts_right + nleft;
517// thi = tlo + ts_right - 1;
518// }
519// };
520// const AmrIntVect_t& small = box.smallEnd();
521// const AmrIntVect_t& big = box.bigEnd();
522// AmrIntVect_t ntiles, ivIndex, tilelo, tilehi;
523//
524// D_TERM(int iv0 = std::min(std::max(iv[0], small[0]), big[0]);,
525// int iv1 = std::min(std::max(iv[1], small[1]), big[1]);,
526// int iv2 = std::min(std::max(iv[2], small[2]), big[2]););
527//
528// D_TERM(tiling_1d(iv0, small[0], big[0], tile_size[0], ntiles[0], ivIndex[0], tilelo[0], tilehi[0]);,
529// tiling_1d(iv1, small[1], big[1], tile_size[1], ntiles[1], ivIndex[1], tilelo[1], tilehi[1]);,
530// tiling_1d(iv2, small[2], big[2], tile_size[2], ntiles[2], ivIndex[2], tilelo[2], tilehi[2]););
531//
532// tbx = Box(tilelo, tilehi);
533//
534// return D_TERM(ivIndex[0], + ntiles[0]*ivIndex[1], + ntiles[0]*ntiles[1]*ivIndex[2]);
535// }
536// }
537
538
539//sets the grid and level where particle belongs - returns false if particle is outside the domain
540template <class T, unsigned Dim>
542 const unsigned int ip,
543 int lev_min,
544 int lev_max,
545 int nGrow) const
546{
547
548 if (lev_max == -1)
549 lev_max = finestLevel();
550
551 PAssert(lev_max <= finestLevel());
552
553 PAssert(nGrow == 0 || (nGrow >= 0 && lev_min == lev_max));
554
555 std::vector< std::pair<int, AmrBox_t> > isects;
556
557 for (int lev = lev_max; lev >= lev_min; lev--)
558 {
559 const AmrIntVect_t& iv = Index(p, ip, lev);
560 const AmrGrid_t& ba = ParticleBoxArray(lev);
561 PAssert(ba.ixType().cellCentered());
562
563 if (lev == (int)p.Level[ip]) {
564 // The fact that we are here means this particle does not belong to any finer grids.
565 if (0 <= p.Grid[ip] && p.Grid[ip] < ba.size()) {
566 const AmrBox_t& bx = ba.getCellCenteredBox(p.Grid[ip]);
567 const AmrBox_t& gbx = amrex::grow(bx,nGrow);
568 if (gbx.contains(iv)) {
569// if (bx != pld.m_gridbox || !pld.m_tilebox.contains(iv)) {
570// pld.m_tile = getTileIndex(iv, bx, pld.m_tilebox);
571// pld.m_gridbox = bx;
572// }
573 return true;
574 }
575 }
576 }
577
578 ba.intersections(AmrBox_t(iv, iv), isects, true, nGrow);
579
580 if (!isects.empty()) {
581 p.Level[ip] = lev;
582 p.Grid[ip] = isects[0].first;
583
584 return true;
585 }
586 }
587 return false;
588}
589
590
591//Function from AMReX adjusted to work with Ippl AmrParticleBase class
592//Checks/sets whether the particle has crossed a periodic boundary in such a way
593//that it is on levels lev_min and higher.
594template <class T, unsigned Dim>
596 const unsigned int ip,
597 int lev_min,
598 int lev_max) const
599{
600 if (!Geom(0).isAnyPeriodic()) return false;
601
602 if (lev_max == -1)
603 lev_max = finestLevel();
604
605 PAssert(lev_max <= finestLevel());
606 //
607 // Create a copy "dummy" particle to check for periodic outs.
608 //
609 SingleParticlePos_t R = p.R[ip];
610
611 if (PeriodicShift(R)) {
612 std::vector< std::pair<int, AmrBox_t> > isects;
613
614 for (int lev = lev_max; lev >= lev_min; lev--) {
615 const AmrIntVect_t& iv = Index(R, lev);
616 const AmrGrid_t& ba = ParticleBoxArray(lev);
617
618 ba.intersections(AmrBox_t(iv,iv),isects,true,0);
619
620 if (!isects.empty()) {
621 D_TERM(p.R[ip][0] = R[0];,
622 p.R[ip][1] = R[1];,
623 p.R[ip][2] = R[2];);
624
625 p.Level[ip] = lev;
626 p.Grid[ip] = isects[0].first;
627
628 return true;
629 }
630 }
631 }
632
633 return false;
634}
635
636
637// Function from AMReX adjusted to work with Ippl AmrParticleBase class
638// Returns true if the particle was shifted.
639template <class T, unsigned Dim>
641{
642 //
643 // This routine should only be called when Where() returns false.
644 //
645 //
646 // We'll use level 0 stuff since ProbLo/ProbHi are the same for every level.
647 //
648 const AmrGeometry_t& geom = Geom(0);
649 const AmrBox_t& dmn = geom.Domain();
650 const AmrIntVect_t& iv = Index(R, 0);
651 bool shifted = false;
652
653 for (int i = 0; i < AMREX_SPACEDIM; i++) {
654 if (!geom.isPeriodic(i)) continue;
655
656 if (iv[i] > dmn.bigEnd(i)) {
657 if (R[i] == geom.ProbHi(i)) {
658 //
659 // Don't let particles lie exactly on the domain face.
660 // Force the particle to be outside the domain so the
661 // periodic shift will bring it back inside.
662 //
663 R[i] += .125*geom.CellSize(i);
664 }
665 R[i] -= geom.ProbLength(i);
666
667 if (R[i] <= geom.ProbLo(i))
668 //
669 // This can happen due to precision issues.
670 //
671 R[i] += .125*geom.CellSize(i);
672
673 PAssert(R[i] >= geom.ProbLo(i));
674
675 shifted = true;
676
677 } else if (iv[i] < dmn.smallEnd(i)) {
678 if (R[i] == geom.ProbLo(i)) {
679 //
680 // Don't let particles lie exactly on the domain face.
681 // Force the particle to be outside the domain so the
682 // periodic shift will bring it back inside.
683 //
684 R[i] -= .125*geom.CellSize(i);
685 }
686 R[i] += geom.ProbLength(i);
687
688 if (R[i] >= geom.ProbHi(i)) {
689 //
690 // This can happen due to precision issues.
691 //
692 R[i] -= .125*geom.CellSize(i);
693 }
694 PAssert(R[i] <= geom.ProbHi(i));
695
696 shifted = true;
697 }
698 }
699 //
700 // The particle may still be outside the domain in the case
701 // where we aren't periodic on the face out which it travelled.
702 //
703 return shifted;
704}
705
706
707template <class T, unsigned Dim>
710 const unsigned int ip,
711 int lev_min, int lev_max, int nGrow) const
712{
713 bool outside = D_TERM( p.R[ip](0) < AmrGeometry_t::ProbLo(0)
714 || p.R[ip](0) >= AmrGeometry_t::ProbHi(0),
715 || p.R[ip](1) < AmrGeometry_t::ProbLo(1)
716 || p.R[ip](1) >= AmrGeometry_t::ProbHi(1),
717 || p.R[ip](2) < AmrGeometry_t::ProbLo(2)
718 || p.R[ip](2) >= AmrGeometry_t::ProbHi(2));
719
720 bool success = false;
721
722 if (outside) {
723 // Note that EnforcePeriodicWhere may shift the particle if it is successful.
724 success = EnforcePeriodicWhere(p, ip, lev_min, lev_max);
725 if (!success && lev_min == 0) {
726 // The particle has left the domain; invalidate it.
727 p.destroy(1, ip);
728 success = true;
729
730 /* We shouldn't lose particles since they are mapped to be within
731 * [-1, 1]^3.
732 */
733 throw OpalException("BoxLibLayout::locateParticle()",
734 "We're losing particles although we shouldn't");
735
736 }
737 } else {
738 success = Where(p, ip, lev_min, lev_max);
739 }
740
741 if (!success) {
742 success = (nGrow > 0) && Where(p, ip, lev_min, lev_min, nGrow);
743 }
744
745 if (!success) {
746 std::stringstream ss;
747 ss << "Invalid particle with ID " << ip << " at position " << p.R[ip] << ".";
748 throw OpalException("BoxLibLayout::locateParticle()", ss.str());
749 }
750}
751
752
753// overwritten functions
754template <class T, unsigned Dim>
756 return level <= this->maxLevel_m && !m_ba[level].empty() && !m_dmap[level].empty();
757}
758
759
760template <class T, unsigned Dim>
762 return this->finestLevel_m;
763}
764
765
766template <class T, unsigned Dim>
768 return this->maxLevel_m;
769}
770
771
772template <class T, unsigned Dim>
775 return refRatio_m[level];
776}
777
778
779template <class T, unsigned Dim>
781 int maxval = 0;
782 for (int n = 0; n<AMREX_SPACEDIM; n++)
783 maxval = std::max(maxval, refRatio_m[level][n]);
784 return maxval;
785}
786
787
788template <class T, unsigned Dim>
790 int maxGridSize,
791 double dh) {
792 // physical box (in meters)
793 AmrDomain_t real_box;
794 for (int d = 0; d < AMREX_SPACEDIM; ++d) {
795
796 PAssert(lowerBound[d] < 0);
797 PAssert(upperBound[d] > 0);
798
799 real_box.setLo(d, lowerBound[d] * (1.0 + dh));
800 real_box.setHi(d, upperBound[d] * (1.0 + dh));
801 }
802
803 AmrGeometry_t::ProbDomain(real_box);
804
805 // define underlying box for physical domain
806 AmrIntVect_t domain_lo(0 , 0, 0);
807 AmrIntVect_t domain_hi(nGridPoints - 1, nGridPoints - 1, nGridPoints - 1);
808 const AmrBox_t domain(domain_lo, domain_hi);
809
810 // use Cartesian coordinates
811 int coord = 0;
812
813 // Dirichlet boundary conditions
814 int is_per[AMREX_SPACEDIM];
815 for (int i = 0; i < AMREX_SPACEDIM; i++)
816 is_per[i] = 0;
817
818 AmrGeometry_t geom;
819 geom.define(domain, &real_box, coord, is_per);
820
821 AmrGrid_t ba;
822 ba.define(domain);
823 // break the BoxArrays at both levels into max_grid_size^3 boxes
824 ba.maxSize(maxGridSize);
825
826 AmrProcMap_t dmap;
827 dmap.define(ba, Ippl::getNodes());
828
829 // set protected ParGDB member variables
830 this->m_geom.resize(1);
831 this->m_geom[0] = geom;
832
833 this->m_dmap.resize(1);
834 this->m_dmap[0] = dmap;
835
836 this->m_ba.resize(1);
837 this->m_ba[0] = ba;
838
839 this->m_nlevels = ba.size();
840}
841
842#endif
const unsigned Dim
#define P_SPATIAL_TRANSFER_TAG
Definition Tags.h:82
#define P_LAYOUT_CYCLE
Definition Tags.h:86
void allreduce(const T *input, T *output, int count, Op op)
#define PAssert(c)
Definition PAssert.h:102
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition PETE.h:733
void setBoundingBox(double dh)
amr::AmrBox_t AmrBox_t
amr::AmrProcMapContainer_t AmrProcMapContainer_t
amr::AmrDomain_t AmrDomain_t
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
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
amr::AmrIntArray_t AmrIntArray_t
amr::AmrGeometry_t AmrGeometry_t
int maxLevel() const
amrex::BaseFab< int > basefab_t
amrex::FabArray< basefab_t > mask_t
amr::AmrGeomContainer_t AmrGeomContainer_t
bool PeriodicShift(SingleParticlePos_t R) const
amr::AmrGrid_t AmrGrid_t
void update(IpplParticleBase< BoxLibLayout< T, Dim > > &PData, const ParticleAttrib< char > *canSwap=0)
amr::AmrGridContainer_t AmrGridContainer_t
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
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.
int maxLevel_m
Maximum level allowed.
Definition Index.h:237
virtual MPI_Request raw_isend(void *, int, int, int)
virtual int raw_probe_receive(char *&, int &, int &)
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