OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestEmittedFromFile.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2
3#include <algorithm>
4#include <array>
5#include <cmath>
6#include <cstdio>
7#include <fstream>
8#include <memory>
9
11#include "Ippl.h"
13#include "Physics/Physics.h"
15#include "Utility/IpplTimings.h"
16
17class EmittedFromFileTest : public ::testing::Test {
18protected:
19 static void SetUpTestSuite() {
20 int argc = 0;
21 char** argv = nullptr;
22 ippl::initialize(argc, argv);
23 }
24
25 static void TearDownTestSuite() { ippl::finalize(); }
26
27 void SetUp() override {
28 nr = 8;
29 ippl::Vector<double, 3> rmin = -1.0;
30 ippl::Vector<double, 3> rmax = 1.0;
31 ippl::Vector<double, 3> origin = rmin;
32 ippl::Vector<double, 3> hr = (rmax - rmin) / ippl::Vector<double, 3>(nr);
33 std::array<bool, 3> decomp = {false, false, true};
34
35 ippl::NDIndex<3> domain;
36 for (unsigned i = 0; i < 3; ++i) {
37 domain[i] = ippl::Index(nr[i]);
38 }
39
40 auto fc = std::make_shared<FieldContainer_t>(
41 hr, rmin, rmax, decomp, domain, origin, isAllPeriodic_m);
42
43 Mesh_t<3> mesh(domain, hr, origin);
44 FieldLayout_t<3> fl(MPI_COMM_WORLD, domain, decomp, isAllPeriodic_m);
45
46 pc = std::make_shared<ParticleContainer<double, 3>>(mesh, fl);
47 bunchStateHandler = std::make_shared<BunchStateHandler>();
48 pc->setBunchStateHandler(bunchStateHandler);
49 tempFilename = "emittedfromfile_test_input.dat";
50 }
51
52 void TearDown() override {
53 if (!tempFilename.empty()) {
54 std::remove(tempFilename.c_str());
55 }
56 }
57
58 void allocate(size_t globalCapacity) {
59 const int nranks = std::max(1, ippl::Comm->size());
60 const size_t nranksU = static_cast<size_t>(nranks);
61 const size_t localCapacity = globalCapacity / nranksU + 2 * nranksU + 1;
62 pc->allocateParticles(localCapacity);
63 }
64
65 size_t globalParticleCount() const {
66 unsigned long local = static_cast<unsigned long>(pc->getLocalNum());
67 unsigned long global = 0;
68 MPI_Allreduce(&local, &global, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
69 return static_cast<size_t>(global);
70 }
71
73 std::ofstream out(tempFilename);
74 ASSERT_TRUE(out.is_open());
75 out << "# x [m] px [betax gamma] y [m] py [betay gamma] "
76 "t [s] pz [betaz gamma] Bin Number\n";
77 out << "1.0e-3 1.0e-1 2.0e-3 2.0e-1 -2.0e-12 3.0e-1 1\n";
78 out << "3.0e-3 4.0e-1 4.0e-3 5.0e-1 -1.0e-12 6.0e-1 1\n";
79 }
80
82 std::ofstream out(tempFilename);
83 ASSERT_TRUE(out.is_open());
84 out << "3\n";
85 out << "x px y py t pz\n";
86 out << "1.0e-3 0.0 2.0e-3 0.0 -2.0e-12 2.0e-1\n";
87 out << "3.0e-3 0.0 4.0e-3 0.0 -5.0e-13 4.0e-1\n";
88 out << "5.0e-3 0.0 6.0e-3 0.0 -1.0e-12 6.0e-1\n";
89 }
90
91 std::shared_ptr<ParticleContainer<double, 3>> pc;
92 std::shared_ptr<BunchStateHandler> bunchStateHandler;
93 ippl::Vector<int, 3> nr;
94 bool isAllPeriodic_m = true;
95 std::string tempFilename;
96};
97
98TEST_F(EmittedFromFileTest, ParsesOldOpalDumpAndProvidesReferenceMomentum) {
99 writeOldOpalDump();
100 allocate(4);
101
102 auto fc = std::shared_ptr<FieldContainer_t>();
103 EmittedFromFile sampler(pc, fc, tempFilename);
104 sampler.setEmissionOffsets(
105 Vector_t<double, 3>(0.0, 0.0, 0.0), Vector_t<double, 3>(0.01, 0.02, 0.03), 0.0, "NONE");
106
107 size_t requested = 0;
108 sampler.generateParticles(requested, nr);
109
110 EXPECT_EQ(requested, static_cast<size_t>(2));
111 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(0));
112 ASSERT_TRUE(sampler.hasInitialReferenceMomentum());
113
115 EXPECT_DOUBLE_EQ(refP[0], 0.25 + 0.01);
116 EXPECT_DOUBLE_EQ(refP[1], 0.35 + 0.02);
117 EXPECT_DOUBLE_EQ(refP[2], 0.45 + 0.03);
118 EXPECT_DOUBLE_EQ(sampler.getEmissionTime(), 1.0e-12);
119 EXPECT_DOUBLE_EQ(sampler.getGlobalTimeShift(), 0.5e-12);
120 EXPECT_DOUBLE_EQ(sampler.getEmissionTimeStep(), 1.0e-14);
121}
122
123TEST_F(EmittedFromFileTest, EmitsSortedRecordsWithFractionalDtAndHalfStepDrift) {
124 writeCountHeaderDump();
125 allocate(4);
126
127 auto fc = std::shared_ptr<FieldContainer_t>();
128 EmittedFromFile sampler(pc, fc, tempFilename);
129 sampler.setEmissionOffsets(
130 Vector_t<double, 3>(0.1, 0.2, 0.3), Vector_t<double, 3>(0.0), 0.0, "NONE");
131
132 size_t requested = 0;
133 sampler.generateParticles(requested, nr);
134 ASSERT_EQ(requested, static_cast<size_t>(3));
135
136 const double tStart = -sampler.getGlobalTimeShift();
137 sampler.emitParticles(tStart, 1.0e-12);
138 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(2));
139
140 if (ippl::Comm->size() == 1) {
141 auto Rview_d = pc->R.getView();
142 auto Pview_d = pc->P.getView();
143 auto dtView_d = pc->dt.getView();
144 auto Rview = Kokkos::create_mirror_view(Rview_d);
145 auto Pview = Kokkos::create_mirror_view(Pview_d);
146 auto dtView = Kokkos::create_mirror_view(dtView_d);
147 Kokkos::deep_copy(Rview, Rview_d);
148 Kokkos::deep_copy(Pview, Pview_d);
149 Kokkos::deep_copy(dtView, dtView_d);
150
151 const double firstDt = 1.0e-12;
152 const double secondDt = 0.5e-12;
153 const double firstGamma = std::sqrt(1.0 + 0.4 * 0.4);
154 const double secondGamma = std::sqrt(1.0 + 0.6 * 0.6);
155
156 EXPECT_NEAR(dtView(0), firstDt, 1.0e-18);
157 EXPECT_NEAR(dtView(1), secondDt, 1.0e-18);
158
159 EXPECT_DOUBLE_EQ(Pview(0)[2], 0.4);
160 EXPECT_DOUBLE_EQ(Pview(1)[2], 0.6);
161 EXPECT_NEAR(Rview(0)[0], 0.103, 1.0e-15);
162 EXPECT_NEAR(Rview(0)[1], 0.204, 1.0e-15);
163 EXPECT_NEAR(Rview(0)[2], 0.3 + 0.5 * Physics::c * firstDt * 0.4 / firstGamma, 1.0e-15);
164 EXPECT_NEAR(Rview(1)[2], 0.3 + 0.5 * Physics::c * secondDt * 0.6 / secondGamma, 1.0e-15);
165 }
166
167 sampler.emitParticles(tStart + 1.0e-12, 1.0e-12);
168 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(3));
169 EXPECT_TRUE(sampler.isEmissionDone(tStart + 2.0e-12));
170
171 sampler.emitParticles(tStart + 2.0e-12, 1.0e-12);
172 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(3));
173}
174
175TEST_F(EmittedFromFileTest, HonorsRequestedParticleLimitBeforeSorting) {
176 writeCountHeaderDump();
177 allocate(4);
178
179 auto fc = std::shared_ptr<FieldContainer_t>();
180 EmittedFromFile sampler(pc, fc, tempFilename);
181 sampler.setEmissionOffsets(Vector_t<double, 3>(0.0), Vector_t<double, 3>(0.0), 0.0, "NONE");
182
183 size_t requested = 2;
184 sampler.generateParticles(requested, nr);
185 EXPECT_EQ(requested, static_cast<size_t>(2));
186
188 EXPECT_DOUBLE_EQ(refP[0], 0.0);
189 EXPECT_DOUBLE_EQ(refP[1], 0.0);
190 EXPECT_DOUBLE_EQ(refP[2], 0.3);
191
192 sampler.emitParticles(-sampler.getGlobalTimeShift(), 3.0e-12);
193 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(2));
194}
195
196TEST_F(EmittedFromFileTest, RejectsOverdueBirthTimesInsteadOfPreAgingParticles) {
197 writeCountHeaderDump();
198 allocate(4);
199
200 auto fc = std::shared_ptr<FieldContainer_t>();
201 EmittedFromFile sampler(pc, fc, tempFilename);
202 sampler.setEmissionOffsets(Vector_t<double, 3>(0.0), Vector_t<double, 3>(0.0), 0.0, "NONE");
203
204 size_t requested = 0;
205 sampler.generateParticles(requested, nr);
206
207 EXPECT_THROW(sampler.emitParticles(1.0e-12, 1.0e-12), OpalException);
208 EXPECT_EQ(globalParticleCount(), static_cast<size_t>(0));
209}
210
211TEST_F(EmittedFromFileTest, RejectsUnsupportedEmissionModel) {
212 writeOldOpalDump();
213 allocate(4);
214
215 auto fc = std::shared_ptr<FieldContainer_t>();
216 EmittedFromFile sampler(pc, fc, tempFilename);
217 sampler.setEmissionOffsets(Vector_t<double, 3>(0.0), Vector_t<double, 3>(0.0), 0.0, "ASTRA");
218
219 size_t requested = 0;
220 EXPECT_THROW(sampler.generateParticles(requested, nr), OpalException);
221}
ippl::Vector< T, Dim > Vector_t
Defines an emitted file distribution with old-OPAL time-column semantics.
const int nr
ippl::FieldLayout< Dim > FieldLayout_t
Definition PBunchDefs.h:25
ippl::UniformCartesian< double, 3 > Mesh_t
Definition PBunchDefs.h:18
TEST_F(EmittedFromFileTest, ParsesOldOpalDumpAndProvidesReferenceMomentum)
std::shared_ptr< BunchStateHandler > bunchStateHandler
ippl::Vector< int, 3 > nr
void allocate(size_t globalCapacity)
size_t globalParticleCount() const
std::shared_ptr< ParticleContainer< double, 3 > > pc
Reads old-OPAL emitted distribution dumps and emits particles by file time.
void emitParticles(double t, double dt) override
Emits all file records whose birth times fall into the current step.
double getGlobalTimeShift() const override
Returns the global time shift needed to center old-OPAL file times.
bool hasInitialReferenceMomentum() const override
Reports whether an initial reference momentum is available.
Vector_t< double, 3 > getInitialReferenceMomentum() const override
Returns the average initial reference momentum from selected records.
bool isEmissionDone(double) const override
Returns whether all file records in the inventory have been emitted.
double getEmissionTime() const
Returns the total emission time spanned by selected file records.
double getEmissionTimeStep() const override
Returns the preferred emission time step.
void generateParticles(size_t &numberOfParticles, Vector_t< double, 3 > nr) override
Reads the selected file records and builds the birth-time inventory.
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