OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestParticleContainer.cpp
Go to the documentation of this file.
1
17#include <gtest/gtest.h>
18#include <mpi.h>
19
20#include <array>
21#include <cmath>
22#include <cstdint>
23#include <memory>
24#include <vector>
25
26#include "Ippl.h"
30#include "Utilities/Options.h"
31
32namespace {
33
35
36 class ParticleContainerTest : public ::testing::Test {
37 protected:
38 static void SetUpTestSuite() {
39 int argc = 0;
40 char** argv = nullptr;
41 ippl::initialize(argc, argv);
42 }
43
44 static void TearDownTestSuite() { ippl::finalize(); }
45
48 std::shared_ptr<PC_t> makeContainer() {
49 ippl::Vector<int, 3> nr = 8;
50 ippl::Vector<double, 3> rmin = -4.0;
51 ippl::Vector<double, 3> rmax = 4.0;
52 ippl::Vector<double, 3> origin = rmin;
53 ippl::Vector<double, 3> hr = (rmax - rmin) / ippl::Vector<double, 3>(nr);
54 std::array<bool, 3> decomp = {true, true, true};
55
56 ippl::NDIndex<3> domain;
57 for (unsigned i = 0; i < 3; i++) {
58 domain[i] = ippl::Index(nr[i]);
59 }
60
61 Mesh_t<3> mesh(domain, hr, origin);
62 FieldLayout_t<3> fl(MPI_COMM_WORLD, domain, decomp, true);
63
64 std::shared_ptr<PC_t> pc = std::make_shared<PC_t>(mesh, fl);
65 pc->setBunchStateHandler(std::make_shared<BunchStateHandler>());
66 return pc;
67 }
68
70 void createParticlesAt(
71 std::shared_ptr<PC_t>& pc, const std::vector<std::array<double, 3>>& positions,
72 double dtVal = 1e-12, double pz = 0.1) {
73 const size_t n = positions.size();
74 if (n == 0) return;
75
76 pc->createParticles(n);
77
78 auto R_host = pc->R.getHostMirror();
79 auto P_host = pc->P.getHostMirror();
80 auto dt_host = pc->dt.getHostMirror();
81
82 for (size_t i = 0; i < n; ++i) {
83 R_host(i)[0] = positions[i][0];
84 R_host(i)[1] = positions[i][1];
85 R_host(i)[2] = positions[i][2];
86 P_host(i)[0] = 0.0;
87 P_host(i)[1] = 0.0;
88 P_host(i)[2] = pz;
89 dt_host(i) = dtVal;
90 }
91
92 Kokkos::deep_copy(pc->R.getView(), R_host);
93 Kokkos::deep_copy(pc->P.getView(), P_host);
94 Kokkos::deep_copy(pc->dt.getView(), dt_host);
95 Kokkos::fence();
96 }
97 };
98
99 // ================================================================
100 // Charge / Mass – SingleValue mode
101 // ================================================================
102
103 TEST_F(ParticleContainerTest, ChargeMass_SingleValueMode_SetAndRead) {
105 auto pc = makeContainer();
106
107 ASSERT_EQ(pc->getQMStorageMode(), PC_t::QMStorageMode::SingleValue);
108
109 const double qExpected = 1.6e-19;
110 const double mExpected = 0.938272;
111
112 pc->setQ(qExpected);
113 pc->setM(mExpected);
114
115 auto qView = pc->getQView();
116 auto mView = pc->getMView();
117
118 ASSERT_EQ(qView.extent(0), 1u);
119 ASSERT_EQ(mView.extent(0), 1u);
120
121 auto q_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), qView);
122 auto m_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), mView);
123
124 EXPECT_DOUBLE_EQ(q_host(0), qExpected);
125 EXPECT_DOUBLE_EQ(m_host(0), mExpected);
126 }
127
128 // ================================================================
129 // Charge / Mass – Attributes mode
130 // ================================================================
131
132 TEST_F(ParticleContainerTest, ChargeMass_AttributeMode_SetAndRead) {
134 auto pc = makeContainer();
135
136 ASSERT_EQ(pc->getQMStorageMode(), PC_t::QMStorageMode::Attributes);
137
138 constexpr size_t nPart = 8;
139 pc->createParticles(nPart);
140 Kokkos::fence();
141
142 const double qExpected = -1.6e-19;
143 const double mExpected = 0.000511;
144
145 pc->setQ(qExpected);
146 pc->setM(mExpected);
147
148 auto q_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->getQView());
149 auto m_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->getMView());
150
151 for (size_t i = 0; i < nPart; ++i) {
152 EXPECT_DOUBLE_EQ(q_host(i), qExpected) << "particle " << i;
153 EXPECT_DOUBLE_EQ(m_host(i), mExpected) << "particle " << i;
154 }
155 }
156
157 // ================================================================
158 // dt scaling round-trip – SingleValue mode
159 // ================================================================
160
161 TEST_F(ParticleContainerTest, DtScaling_RoundTrip_SingleValueMode) {
163 auto pc = makeContainer();
164
165 const double q = 1.6e-19;
166 pc->setQ(q);
167
168 constexpr size_t nPart = 16;
169 const double dtOrig = 1e-12;
170 std::vector<std::array<double, 3>> positions(nPart, {0.0, 0.0, 0.0});
171 createParticlesAt(pc, positions, dtOrig);
172
173 pc->scaleDtByCharge();
174
175 auto dt_scaled = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
176 for (size_t i = 0; i < nPart; ++i) {
177 EXPECT_NEAR(dt_scaled(i), dtOrig * q, 1e-44) << "particle " << i;
178 }
179
180 pc->unscaleDtByCharge();
181
182 auto dt_back = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
183 for (size_t i = 0; i < nPart; ++i) {
184 EXPECT_NEAR(dt_back(i), dtOrig, 1e-20) << "particle " << i;
185 }
186 }
187
188 // ================================================================
189 // dt scaling round-trip – Attributes mode
190 // ================================================================
191
192 TEST_F(ParticleContainerTest, DtScaling_RoundTrip_AttributeMode) {
194 auto pc = makeContainer();
195
196 constexpr size_t nPart = 16;
197 const double dtOrig = 1e-12;
198 std::vector<std::array<double, 3>> positions(nPart, {0.0, 0.0, 0.0});
199 createParticlesAt(pc, positions, dtOrig);
200
201 const double q = 1.6e-19;
202 pc->setQ(q);
203
204 pc->scaleDtByCharge();
205
206 auto dt_scaled = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
207 for (size_t i = 0; i < nPart; ++i) {
208 EXPECT_NEAR(dt_scaled(i), dtOrig * q, 1e-44) << "particle " << i;
209 }
210
211 pc->unscaleDtByCharge();
212
213 auto dt_back = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
214 for (size_t i = 0; i < nPart; ++i) {
215 EXPECT_NEAR(dt_back(i), dtOrig, 1e-20) << "particle " << i;
216 }
217 }
218
219 // ================================================================
220 // Moments & MinMax – empty container (no NaN / crash)
221 // ================================================================
222
223 TEST_F(ParticleContainerTest, MomentsAndMinMax_EmptyContainer_NoNaN) {
225 auto pc = makeContainer();
226
227 ASSERT_EQ(pc->getLocalNum(), 0u);
228
229 pc->updateMoments();
230 pc->computeMinMaxR();
231
232 auto meanR = pc->getMeanR();
233 auto rmsR = pc->getRmsR();
234 auto minR = pc->getMinR();
235 auto maxR = pc->getMaxR();
236
237 for (unsigned d = 0; d < 3; ++d) {
238 EXPECT_TRUE(std::isfinite(meanR[d])) << "meanR[" << d << "]";
239 EXPECT_TRUE(std::isfinite(rmsR[d])) << "rmsR[" << d << "]";
240 EXPECT_TRUE(std::isfinite(minR[d])) << "minR[" << d << "]";
241 EXPECT_TRUE(std::isfinite(maxR[d])) << "maxR[" << d << "]";
242 EXPECT_LE(minR[d], maxR[d]) << "min > max at dim " << d;
243 }
244 }
245
246 // ================================================================
247 // Moments – known symmetric data → mean ≈ 0, rms ≈ 1
248 // ================================================================
249
250 TEST_F(ParticleContainerTest, Moments_KnownSymmetricData) {
252 auto pc = makeContainer();
253
254 std::vector<std::array<double, 3>> positions;
255 if (ippl::Comm->rank() == 0) {
256 positions = {{1.0, 1.0, 1.0}, {-1.0, -1.0, -1.0}, {1.0, -1.0, 1.0}, {-1.0, 1.0, -1.0}};
257 }
258 createParticlesAt(pc, positions);
259 pc->setM(1.0);
260
261 pc->updateMoments();
262
263 auto meanR = pc->getMeanR();
264 for (unsigned d = 0; d < 3; ++d) {
265 EXPECT_NEAR(meanR[d], 0.0, 1e-14) << "meanR[" << d << "]";
266 }
267
268 auto rmsR = pc->getRmsR();
269 for (unsigned d = 0; d < 3; ++d) {
270 EXPECT_NEAR(rmsR[d], 1.0, 1e-14) << "rmsR[" << d << "]";
271 }
272 }
273
274 // ================================================================
275 // MinMax R – known particle positions
276 // ================================================================
277
278 TEST_F(ParticleContainerTest, MinMaxR_KnownPositions) {
280 auto pc = makeContainer();
281
282 std::vector<std::array<double, 3>> positions;
283 if (ippl::Comm->rank() == 0) {
284 positions = {{1.0, 2.0, 3.0}, {-0.5, -1.5, 0.0}, {0.0, 0.0, -2.0}};
285 }
286 createParticlesAt(pc, positions);
287
288 pc->computeMinMaxR();
289
290 auto minR = pc->getMinR();
291 auto maxR = pc->getMaxR();
292
293 EXPECT_NEAR(minR[0], -0.5, 1e-14);
294 EXPECT_NEAR(minR[1], -1.5, 1e-14);
295 EXPECT_NEAR(minR[2], -2.0, 1e-14);
296
297 EXPECT_NEAR(maxR[0], 1.0, 1e-14);
298 EXPECT_NEAR(maxR[1], 2.0, 1e-14);
299 EXPECT_NEAR(maxR[2], 3.0, 1e-14);
300 }
301
302 // ================================================================
303 // markParticlesOutside – edge cases
304 // ================================================================
305
306 TEST_F(ParticleContainerTest, MarkParticlesOutside_NegativeSigma_ReturnsZero) {
308 auto pc = makeContainer();
309
310 std::vector<std::array<double, 3>> positions = {{{0.0, 0.0, 0.0}}};
311 createParticlesAt(pc, positions);
312 pc->setM(1.0);
313
314 size_t localBefore = pc->getLocalNum();
315 auto marked = pc->markParticlesOutside(-1.0);
316
317 EXPECT_EQ(marked, 0u);
318 EXPECT_EQ(pc->getLocalNum(), localBefore);
319 }
320
321 TEST_F(ParticleContainerTest, MarkParticlesOutside_ZeroSigma_ReturnsZero) {
323 auto pc = makeContainer();
324
325 std::vector<std::array<double, 3>> positions = {{{0.0, 0.0, 0.0}}};
326 createParticlesAt(pc, positions);
327 pc->setM(1.0);
328
329 size_t localBefore = pc->getLocalNum();
330 auto marked = pc->markParticlesOutside(0.0);
331
332 EXPECT_EQ(marked, 0u);
333 EXPECT_EQ(pc->getLocalNum(), localBefore);
334 }
335
336 TEST_F(ParticleContainerTest, MarkParticlesOutside_EmptyContainer_ReturnsZero) {
338 auto pc = makeContainer();
339
340 ASSERT_EQ(pc->getLocalNum(), 0u);
341 auto marked = pc->markParticlesOutside(3.0);
342 EXPECT_EQ(marked, 0u);
343 }
344
345 // ================================================================
346 // markParticlesOutside + deleteInvalidParticles – known outlier removal
347 // ================================================================
348
349 TEST_F(ParticleContainerTest, MarkAndDeleteInvalidParticles_KnownOutlierRemoval) {
351 auto pc = makeContainer();
352
353 // 10 cluster particles near origin + 1 outlier on rank 0.
354 // Non-rank-0 processes get a single particle at the origin so that all
355 // ranks satisfy nLocal > 0 (avoids mismatched collective in getTotalNum).
356 std::vector<std::array<double, 3>> positions;
357 if (ippl::Comm->rank() == 0) {
358 positions = {
359 {0.10, 0.10, 0.10}, {-0.10, -0.10, -0.10}, {0.05, 0.05, 0.05},
360 {-0.05, -0.05, -0.05}, {0.10, -0.10, 0.05}, {-0.10, 0.10, -0.05},
361 {0.08, 0.03, 0.07}, {-0.08, -0.03, -0.07}, {0.02, 0.09, 0.04},
362 {-0.02, -0.09, -0.04}, {3.50, 3.50, 3.50} // outlier – well beyond 2σ
363 };
364 } else {
365 positions = {{{0.0, 0.0, 0.0}}};
366 }
367 createParticlesAt(pc, positions);
368 pc->setM(1.0);
369
370 size_t totalBefore = pc->getTotalNum();
371 auto marked = pc->markParticlesOutside(2.0);
372
373 EXPECT_EQ(marked, 1u);
374
375 auto destroyed = pc->deleteInvalidParticles();
376 EXPECT_EQ(destroyed, marked);
377
378 size_t totalAfter = pc->getTotalNum();
379 EXPECT_EQ(totalAfter + destroyed, totalBefore);
380 }
381
382 TEST_F(ParticleContainerTest, ImageChargeMirrorTransform_AllParticles_RoundTrip) {
384 auto pc = makeContainer();
385 std::vector<std::array<double, 3>> positions = {
386 {0.1, -0.2, 0.0}, {0.0, 0.3, 0.4}, {-0.2, 0.1, -0.5}};
387 const double dtOrig = 2.5e-12;
388 const double qOrig = 1.6e-19;
389 createParticlesAt(pc, positions, dtOrig);
390 pc->setQ(qOrig);
391
392 // Build dedicated rho fields for baseline and image-charge deposition.
393 ippl::Vector<int, 3> nr = 8;
394 ippl::Vector<double, 3> rmin = -4.0;
395 ippl::Vector<double, 3> rmax = 4.0;
396 ippl::Vector<double, 3> origin = rmin;
397 ippl::Vector<double, 3> hr = (rmax - rmin) / ippl::Vector<double, 3>(nr);
398 std::array<bool, 3> decomp = {true, true, true};
399 ippl::NDIndex<3> domain;
400 for (unsigned i = 0; i < 3; ++i) {
401 domain[i] = ippl::Index(nr[i]);
402 }
403 Mesh_t<3> mesh(domain, hr, origin);
404 FieldLayout_t<3> fl(MPI_COMM_WORLD, domain, decomp, true);
405 Field_t<3> rhoBaseline;
406 Field_t<3> rhoImage;
407 rhoBaseline.initialize(mesh, fl);
408 rhoImage.initialize(mesh, fl);
409 rhoBaseline = 0.0;
410 rhoImage = 0.0;
411
412 constexpr double zPlane = 0.125;
413 ImageChargeScatterController<double, 3> baselineController(false, zPlane);
414 ImageChargeScatterController<double, 3> imageController(true, zPlane);
415
416 auto R_before_view =
417 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->R.getView());
418 auto dt_before_view =
419 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
420 auto q_before_view =
421 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->getQView());
422 std::vector<std::array<double, 3>> R_before(pc->getLocalNum());
423 std::vector<double> dt_before(pc->getLocalNum(), 0.0);
424 for (size_t i = 0; i < pc->getLocalNum(); ++i) {
425 R_before[i][0] = R_before_view(i)[0];
426 R_before[i][1] = R_before_view(i)[1];
427 R_before[i][2] = R_before_view(i)[2];
428 dt_before[i] = dt_before_view(i);
429 }
430 const double q_before = q_before_view(0);
431
432 // Run the exact production path: primary-only and primary+image scatter.
433 baselineController.scatterPrimaryAndImage(pc, pc->R, rhoBaseline);
434 imageController.scatterPrimaryAndImage(pc, pc->R, rhoImage);
435 Kokkos::fence();
436
437 // Particle state must be restored after image scatter.
438 auto R_after = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->R.getView());
439 auto dt_after = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->dt.getView());
440 auto q_after = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->getQView());
441 for (size_t i = 0; i < pc->getLocalNum(); ++i) {
442 for (unsigned d = 0; d < 3; ++d) {
443 EXPECT_NEAR(R_after(i)[d], R_before[i][d], 1e-14);
444 }
445 EXPECT_NEAR(dt_after(i), dt_before[i], 1e-20);
446 }
447 EXPECT_NEAR(q_after(0), q_before, 1e-30);
448
449 // Verify image scatter actually changes deposited rho versus baseline.
450 auto rhoBaseHost =
451 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), rhoBaseline.getView());
452 auto rhoImgHost =
453 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), rhoImage.getView());
454 bool rhoDiffers = false;
455 for (size_t i = 0; i < rhoBaseHost.extent(0) && !rhoDiffers; ++i) {
456 for (size_t j = 0; j < rhoBaseHost.extent(1) && !rhoDiffers; ++j) {
457 for (size_t k = 0; k < rhoBaseHost.extent(2); ++k) {
458 if (std::abs(rhoBaseHost(i, j, k) - rhoImgHost(i, j, k)) > 0.0) {
459 rhoDiffers = true;
460 break;
461 }
462 }
463 }
464 }
465 EXPECT_TRUE(rhoDiffers);
466 }
467
468 // ================================================================
469 // allocateParticles — pre-allocates capacity, throws on non-empty container
470 // ================================================================
471
472 TEST_F(ParticleContainerTest, AllocateParticles_ReservesCapacityAndKeepsLocalNumZero) {
474 auto pc = makeContainer();
475 ASSERT_EQ(pc->R.size(), 0u);
476
477 constexpr size_t nReserve = 1024;
478 pc->allocateParticles(nReserve);
479
480 // Logical particle count stays at 0 — alloc only reserves underlying capacity.
481 EXPECT_EQ(pc->getLocalNum(), 0u);
482 // Underlying view capacity is at least the requested size (overalloc may give more).
483 EXPECT_GE(pc->R.size(), nReserve);
484 EXPECT_GE(pc->P.size(), nReserve);
485 EXPECT_GE(pc->dt.size(), nReserve);
486
487 // Calling allocateParticles on a non-empty container must throw — alloc is destructive.
488 EXPECT_THROW(pc->allocateParticles(nReserve), OpalException);
489 }
490
491 // ================================================================
492 // createParticles — non-destructive grow preserves existing data
493 // ================================================================
494
495 TEST_F(ParticleContainerTest, CreateParticles_GrowPreservesExistingData) {
497 auto pc = makeContainer();
498
499 // Step 1: pre-allocate a small capacity, fill with a known pattern.
500 constexpr size_t nFirst = 8;
501 pc->allocateParticles(nFirst);
502 pc->createParticles(nFirst);
503 ASSERT_EQ(pc->getLocalNum(), nFirst);
504
505 auto P_host = pc->P.getHostMirror();
506 for (size_t i = 0; i < nFirst; ++i) {
507 P_host(i) = ippl::Vector<double, 3>(double(i), double(2 * i), double(3 * i));
508 }
509 Kokkos::deep_copy(pc->P.getView(), P_host);
510 Kokkos::fence();
511
512 // Step 2: force a capacity grow by adding more particles than the buffer holds.
513 const size_t capBefore = pc->R.size();
514 const size_t nSecond = capBefore + 16;
515 pc->createParticles(nSecond);
516
517 EXPECT_EQ(pc->getLocalNum(), nFirst + nSecond);
518 EXPECT_GE(pc->R.size(), nFirst + nSecond);
519
520 // Step 3: verify the original pattern in the first nFirst slots survived the grow.
521 auto P_after = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->P.getView());
522 for (size_t i = 0; i < nFirst; ++i) {
523 EXPECT_DOUBLE_EQ(P_after(i)[0], double(i)) << "particle " << i;
524 EXPECT_DOUBLE_EQ(P_after(i)[1], double(2 * i)) << "particle " << i;
525 EXPECT_DOUBLE_EQ(P_after(i)[2], double(3 * i)) << "particle " << i;
526 }
527 }
528
529 // ================================================================
530 // deleteInvalidParticles — removes marked InvalidMask entries and resets the mask
531 // ================================================================
532
533 TEST_F(ParticleContainerTest, DeleteInvalidParticles_RemovesMarkedAndResetsMask) {
535 auto pc = makeContainer();
536
537 constexpr size_t nPart = 10;
538 std::vector<std::array<double, 3>> positions(nPart);
539 for (size_t i = 0; i < nPart; ++i) {
540 positions[i] = {double(i) * 0.1, 0.0, 0.0};
541 }
542 createParticlesAt(pc, positions);
543 ASSERT_EQ(pc->getLocalNum(), nPart);
544
545 // Mark every other particle invalid (5 of 10) — kill those at even indices.
546 auto invalid_host = pc->InvalidMask.getHostMirror();
547 size_type expectedDestroy = 0;
548 for (size_t i = 0; i < nPart; ++i) {
549 const bool kill = (i % 2 == 0);
550 invalid_host(i) = kill;
551 if (kill) ++expectedDestroy;
552 }
553 Kokkos::deep_copy(pc->InvalidMask.getView(), invalid_host);
554
555 const size_type expectedGlobalDestroy = pc->getTotalNum() / 2;
556 const size_type destroyed = pc->deleteInvalidParticles();
557 EXPECT_EQ(destroyed, expectedGlobalDestroy);
558 EXPECT_EQ(pc->getLocalNum(), nPart - expectedDestroy);
559
560 auto resetHost =
561 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->InvalidMask.getView());
562 for (size_t i = 0; i < pc->getLocalNum(); ++i) {
563 EXPECT_FALSE(resetHost(i));
564 }
565 }
566
567 TEST_F(ParticleContainerTest, CreateParticles_ResetsInvalidMaskForNewParticles) {
569 auto pc = makeContainer();
570
571 constexpr size_t nPart = 6;
572 pc->createParticles(nPart);
573 const size_t totalBeforeDelete = pc->getTotalNum();
574 pc->InvalidMask = true;
575 Kokkos::fence();
576 ASSERT_EQ(pc->deleteInvalidParticles(), totalBeforeDelete);
577 ASSERT_EQ(pc->getLocalNum(), 0u);
578
579 pc->createParticles(nPart);
580 auto invalidHost =
581 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->InvalidMask.getView());
582 for (size_t i = 0; i < pc->getLocalNum(); ++i) {
583 EXPECT_FALSE(invalidHost(i));
584 }
585 }
586
587 // ================================================================
588 // ID assignment — IDs follow the IPPL strided rank-interleave scheme
589 // ================================================================
590
591 TEST_F(ParticleContainerTest, CreateParticles_AssignsStridedIDs) {
593 auto pc = makeContainer();
594
595 constexpr size_t nPart = 32;
596 pc->createParticles(nPart);
597 ASSERT_EQ(pc->getLocalNum(), nPart);
598
599 auto idHost = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), pc->ID.getView());
600
601 const auto rank = static_cast<std::int64_t>(ippl::Comm->rank());
602 const auto nRanks = static_cast<std::int64_t>(ippl::Comm->size());
603
604 for (size_t i = 0; i < nPart; ++i) {
605 EXPECT_EQ(idHost(i), rank + nRanks * static_cast<std::int64_t>(i)) << "particle " << i;
606 }
607 }
608
609} // namespace
const int nr
ippl::FieldLayout< Dim > FieldLayout_t
Definition PBunchDefs.h:25
ippl::Field< double, Dim, ViewArgs... > Field_t
Definition PBunchDefs.h:28
ippl::UniformCartesian< double, 3 > Mesh_t
Definition PBunchDefs.h:18
ippl::detail::size_type size_type
TEST_F(MonitorTest, GetType)
Orchestrates primary and image-charge scatter deposition.
Container for all per-particle (and per-simulation) fields tracked during OPALX tracking.
bool useQMAttributes
Definition Options.cpp:109
constexpr double e
The value of.
Definition Physics.h:49