OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestOpalFlatTop.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <mpi.h>
3
4#include <algorithm>
5#include <array>
6#include <cmath>
7#include <memory>
8#include <vector>
9
11#include "Ippl.h"
13#include "Physics/Physics.h"
15
16class OpalFlatTopTest : public ::testing::Test {
17protected:
18 static void SetUpTestSuite() {
19 int argc = 0;
20 char** argv = nullptr;
21 ippl::initialize(argc, argv);
22 }
23
24 static void TearDownTestSuite() { ippl::finalize(); }
25
26 void SetUp() override {
27 nr = 32;
28 ippl::Vector<double, 3> rmin = -4.0;
29 ippl::Vector<double, 3> rmax = 4.0;
30 ippl::Vector<double, 3> origin = rmin;
31 ippl::Vector<double, 3> hr = (rmax - rmin) / ippl::Vector<double, 3>(nr);
32 std::array<bool, 3> decomp = {false, false, true};
33
34 ippl::NDIndex<3> domain;
35 for (unsigned i = 0; i < 3; ++i) {
36 domain[i] = ippl::Index(this->nr[i]);
37 }
38
39 fc = std::make_shared<FieldContainer_t>(
40 hr, rmin, rmax, decomp, domain, origin, this->isAllPeriodic_m);
41
42 Mesh_t<3> mesh(domain, hr, origin);
43 FieldLayout_t<3> fl(MPI_COMM_WORLD, domain, decomp, this->isAllPeriodic_m);
44 pc = std::make_shared<ParticleContainer<double, 3>>(mesh, fl);
45
46 bunchStateHandler = std::make_shared<BunchStateHandler>();
47 pc->setBunchStateHandler(bunchStateHandler);
48 }
49
50 size_t globalLocalNum() const {
51 size_t local = pc->getLocalNum();
52 size_t global = 0;
53 MPI_Allreduce(&local, &global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
54 return global;
55 }
56
57 std::shared_ptr<ParticleContainer<double, 3>> pc;
58 std::shared_ptr<FieldContainer_t> fc;
59 std::shared_ptr<BunchStateHandler> bunchStateHandler;
60 ippl::Vector<int, 3> nr;
61 bool isAllPeriodic_m = true;
62};
63
64TEST_F(OpalFlatTopTest, BuildsSortedInventoryWithExactSizeAndEmissionBounds) {
65 const Vector_t<double, 3> sigmaR = {0.5, 0.5, 0.0};
66 const Vector_t<double, 3> cutoff = {4.0, 4.0, 4.0};
67 OpalFlatTop sampler(
68 pc, fc,
69 /*emitting=*/true,
70 /*sigmaTFall=*/0.15,
71 /*sigmaTRise=*/0.25, cutoff,
72 /*tPulseLengthFWHM=*/1.2, sigmaR);
73
74 size_t totalParticles = 1001;
75 const size_t nranks = static_cast<size_t>(std::max(1, ippl::Comm->size()));
76 pc->allocateParticles(totalParticles / nranks + 2 * nranks + 16);
77
78 sampler.generateParticles(totalParticles, nr);
79
80 const auto& birthTimes = sampler.getBirthTimes();
81 ASSERT_EQ(birthTimes.size(), totalParticles);
82 EXPECT_TRUE(std::is_sorted(birthTimes.begin(), birthTimes.end()));
83 EXPECT_GE(birthTimes.front(), -0.5 * sampler.getEmissionTime() - 1.0e-15);
84 EXPECT_LE(birthTimes.back(), 0.5 * sampler.getEmissionTime() + 1.0e-15);
85 EXPECT_DOUBLE_EQ(sampler.getGlobalTimeShift(), 0.5 * sampler.getEmissionTime());
86 EXPECT_DOUBLE_EQ(sampler.getEmissionTimeStep(), sampler.getEmissionTime() / 100.0);
87
88 EXPECT_EQ(sampler.getNextGlobalIndex(), 0u);
89 EXPECT_EQ(globalLocalNum(), 0u);
90}
91
92TEST_F(OpalFlatTopTest, EmitsAllInventoryWithVariableDtAndNoRemainderLoss) {
93 const Vector_t<double, 3> sigmaR = {0.5, 0.5, 0.0};
94 const Vector_t<double, 3> cutoff = {4.0, 4.0, 4.0};
95 OpalFlatTop sampler(
96 pc, fc,
97 /*emitting=*/true,
98 /*sigmaTFall=*/0.1,
99 /*sigmaTRise=*/0.1, cutoff,
100 /*tPulseLengthFWHM=*/1.0, sigmaR);
101 sampler.setEmissionOffsets(0.0, Vector_t<double, 3>({0.0, 0.0, 0.1}), 0.0, "NONE");
102
103 const size_t totalParticles = 1007;
104 const size_t nranks = static_cast<size_t>(std::max(1, ippl::Comm->size()));
105 pc->allocateParticles(totalParticles / nranks + 2 * nranks + 16);
106
107 size_t mutableTotal = totalParticles;
108 sampler.generateParticles(mutableTotal, nr);
109
110 double t = -sampler.getGlobalTimeShift();
111 const double dts[] = {0.07, 0.11, 0.05, 0.13};
112 for (int step = 0; step < 1000 && !sampler.isEmissionDone(t); ++step) {
113 const double dt = dts[step % 4];
114 sampler.emitParticles(t, dt);
115 t += dt;
116 }
117
118 EXPECT_TRUE(sampler.isEmissionDone(t));
119 EXPECT_EQ(sampler.getNextGlobalIndex(), totalParticles);
120 EXPECT_EQ(globalLocalNum(), totalParticles);
121}
122
123TEST_F(OpalFlatTopTest, RejectsOverdueBirthTimesInsteadOfPreAgingParticles) {
124 const Vector_t<double, 3> sigmaR = {0.5, 0.5, 0.0};
125 const Vector_t<double, 3> cutoff = {4.0, 4.0, 4.0};
126 OpalFlatTop sampler(
127 pc, fc,
128 /*emitting=*/true,
129 /*sigmaTFall=*/1.0e-12,
130 /*sigmaTRise=*/1.0e-12, cutoff,
131 /*tPulseLengthFWHM=*/4.0e-12, sigmaR);
132
133 const Vector_t<double, 3> P0 = {0.0, 0.0, 0.1};
134 sampler.setEmissionOffsets(0.0, P0, 0.0, "NONE");
135 sampler.setBirthTimesForTest({-4.0e-13, 1.0e-13, 4.0e-13, 9.0e-13});
136
137 const size_t nranks = static_cast<size_t>(std::max(1, ippl::Comm->size()));
138 pc->allocateParticles(4 / nranks + 2 * nranks + 8);
139
140 EXPECT_THROW(sampler.emitParticles(0.0, 5.0e-13), OpalException);
141 EXPECT_EQ(sampler.getNextGlobalIndex(), 0u);
142 EXPECT_EQ(globalLocalNum(), 0u);
143}
144
145TEST_F(OpalFlatTopTest, UsesStoredBirthTimesForParticleDtAndZCorrection) {
146 const Vector_t<double, 3> sigmaR = {0.5, 0.5, 0.0};
147 const Vector_t<double, 3> cutoff = {4.0, 4.0, 4.0};
148 OpalFlatTop sampler(
149 pc, fc,
150 /*emitting=*/true,
151 /*sigmaTFall=*/1.0e-12,
152 /*sigmaTRise=*/1.0e-12, cutoff,
153 /*tPulseLengthFWHM=*/4.0e-12, sigmaR);
154
155 const Vector_t<double, 3> P0 = {0.0, 0.0, 0.1};
156 sampler.setEmissionOffsets(0.0, P0, 0.0, "NONE");
157 sampler.setBirthTimesForTest({1.0e-13, 4.0e-13, 9.0e-13});
158
159 const size_t nranks = static_cast<size_t>(std::max(1, ippl::Comm->size()));
160 pc->allocateParticles(3 / nranks + 2 * nranks + 8);
161
162 sampler.emitParticles(0.0, 5.0e-13);
163
164 const size_t totalNew = 2;
165 const size_t rank = static_cast<size_t>(ippl::Comm->rank());
166 const size_t base = totalNew / nranks;
167 const size_t rem = totalNew % nranks;
168 const size_t nlocalExpected = base + (rank < rem ? 1 : 0);
169 const size_t localOffset = rank * base + std::min(rank, rem);
170
171 ASSERT_EQ(pc->getLocalNum(), nlocalExpected);
172
173 auto RviewDevice = pc->R.getView();
174 auto PviewDevice = pc->P.getView();
175 auto dtviewDevice = pc->dt.getView();
176 auto Rview = Kokkos::create_mirror_view(RviewDevice);
177 auto Pview = Kokkos::create_mirror_view(PviewDevice);
178 auto dtview = Kokkos::create_mirror_view(dtviewDevice);
179 Kokkos::deep_copy(Rview, RviewDevice);
180 Kokkos::deep_copy(Pview, PviewDevice);
181 Kokkos::deep_copy(dtview, dtviewDevice);
182
183 const std::vector<double> birthTimes = {1.0e-13, 4.0e-13};
184 const double gamma = std::sqrt(1.0 + P0[2] * P0[2]);
185 const double betaZ = P0[2] / gamma;
186
187 for (size_t i = 0; i < nlocalExpected; ++i) {
188 const double expectedDt = 5.0e-13 - birthTimes[localOffset + i];
189 EXPECT_NEAR(dtview(i), expectedDt, 1.0e-18);
190 EXPECT_DOUBLE_EQ(Pview(i)[0], P0[0]);
191 EXPECT_DOUBLE_EQ(Pview(i)[1], P0[1]);
192 EXPECT_DOUBLE_EQ(Pview(i)[2], P0[2]);
193 EXPECT_NEAR(Rview(i)[2], 0.5 * betaZ * Physics::c * expectedDt, 1.0e-12);
194 }
195
196 EXPECT_EQ(sampler.getNextGlobalIndex(), totalNew);
197 EXPECT_EQ(globalLocalNum(), totalNew);
198}
199
200TEST_F(OpalFlatTopTest, ProvidesOldOpalInitialReferenceMomentum) {
201 const Vector_t<double, 3> sigmaR = {0.5, 0.5, 0.0};
202 const Vector_t<double, 3> cutoff = {4.0, 4.0, 4.0};
203 OpalFlatTop sampler(
204 pc, fc,
205 /*emitting=*/true,
206 /*sigmaTFall=*/1.0e-12,
207 /*sigmaTRise=*/1.0e-12, cutoff,
208 /*tPulseLengthFWHM=*/4.0e-12, sigmaR);
209
210 const Vector_t<double, 3> P0 = {0.01, 0.02, 0.1};
211 sampler.setEmissionOffsets(0.0, P0, 0.0, "NONE");
212 EXPECT_TRUE(sampler.hasInitialReferenceMomentum());
213 EXPECT_DOUBLE_EQ(sampler.getInitialReferenceMomentum()[0], P0[0]);
214 EXPECT_DOUBLE_EQ(sampler.getInitialReferenceMomentum()[1], P0[1]);
215 EXPECT_DOUBLE_EQ(sampler.getInitialReferenceMomentum()[2], P0[2]);
216
217 sampler.setEmissionOffsets(0.0, P0, 0.0, "ASTRA");
219 EXPECT_DOUBLE_EQ(refP[0], 0.0);
220 EXPECT_DOUBLE_EQ(refP[1], 0.0);
221 EXPECT_DOUBLE_EQ(refP[2], 0.5 * std::sqrt(dot(P0, P0)));
222}
ippl::Vector< T, Dim > Vector_t
const int nr
OPAL-like flat-top emission sampler with precomputed birth times.
ippl::FieldLayout< Dim > FieldLayout_t
Definition PBunchDefs.h:25
ippl::UniformCartesian< double, 3 > Mesh_t
Definition PBunchDefs.h:18
TEST_F(OpalFlatTopTest, BuildsSortedInventoryWithExactSizeAndEmissionBounds)
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:95
std::shared_ptr< ParticleContainer< double, 3 > > pc
static void TearDownTestSuite()
std::shared_ptr< BunchStateHandler > bunchStateHandler
ippl::Vector< int, 3 > nr
void SetUp() override
static void SetUpTestSuite()
std::shared_ptr< FieldContainer_t > fc
size_t globalLocalNum() const
Implements an old-OPAL-compatible flat-top emitter with precomputed birth times.
Definition OpalFlatTop.h:43
double getGlobalTimeShift() const override
Returns the global time shift needed to center old-OPAL pulse times.
double getEmissionTimeStep() const override
Returns the preferred emission time step.
void setBirthTimesForTest(std::vector< double > birthTimes)
Replaces the birth-time inventory for tests.
const std::vector< double > & getBirthTimes() const
Returns the sorted global birth-time inventory.
void generateParticles(size_t &numberOfParticles, Vector_t< double, 3 > nr) override
Builds the global birth-time inventory for the requested particles.
size_t getNextGlobalIndex() const
Returns the next global inventory index to be emitted.
void emitParticles(double t, double dt) override
Emits all particles whose birth times fall into the current step.
bool hasInitialReferenceMomentum() const override
Reports that this sampler provides an initial reference momentum.
bool isEmissionDone(double) const override
Returns whether all precomputed particles have been emitted.
Vector_t< double, 3 > getInitialReferenceMomentum() const override
Returns the initial reference momentum used by the tracker.
double getEmissionTime() const
Returns the total emission time.
void setEmissionOffsets(ippl::Vector< double, 3 > R0, ippl::Vector< double, 3 > P0, double t0, const std::string &emissionModel="NONE")
constexpr double c
The velocity of light in m/s.
Definition Physics.h:60