OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestFromFile.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <mpi.h>
3#include <algorithm>
4#include <cstdio>
5#include <fstream>
6#include <memory>
7
10#include "Ippl.h"
12#include "Utility/IpplTimings.h"
13
14class FromFileTest : public ::testing::Test {
15protected:
16 static void SetUpTestSuite() {
17 int argc = 0;
18 char** argv = nullptr;
19 ippl::initialize(argc, argv);
20 }
21
22 static void TearDownTestSuite() { ippl::finalize(); }
23
24 void SetUp() override {
25 nr = 8;
26 ippl::Vector<double, 3> rmin = -1.0;
27 ippl::Vector<double, 3> rmax = 1.0;
28 ippl::Vector<double, 3> origin = rmin;
29 ippl::Vector<double, 3> hr = (rmax - rmin) / ippl::Vector<double, 3>(nr);
30 std::array<bool, 3> decomp = {false, false, true};
31
32 ippl::NDIndex<3> domain;
33 for (unsigned i = 0; i < 3; i++) {
34 domain[i] = ippl::Index(this->nr[i]);
35 }
36
37 auto fc = std::make_shared<FieldContainer_t>(
38 hr, rmin, rmax, decomp, domain, origin, this->isAllPeriodic_m);
39
40 Mesh_t<3> mesh(domain, hr, origin);
41 FieldLayout_t<3> fl(MPI_COMM_WORLD, domain, decomp, this->isAllPeriodic_m);
42
43 pc = std::make_shared<ParticleContainer<double, 3>>(mesh, fl);
44
45 bunchStateHandler = std::make_shared<BunchStateHandler>();
46 pc->setBunchStateHandler(bunchStateHandler);
47 tempFilename = "fromfile_test_input.dat";
48 }
49
50 void TearDown() override {
51 if (!tempFilename.empty()) {
52 std::remove(tempFilename.c_str());
53 }
54 }
55
57 // Strict format: N, then header, then data (comments/blanks skipped in data section)
58 std::ofstream out(tempFilename);
59 ASSERT_TRUE(out.is_open());
60
61 out << "5\n";
62 out << "x y z px py pz\n";
63
64 // Comment and blank lines in data section are skipped
65 out << "# This is a comment and must be skipped\n";
66 out << "\n";
67
68 // Five data lines with 6 columns each: x y z px py pz
69 out << "7.3797510200e-04 2.8811575176e-02 3.3682581175e-04 9.7591095318e-03 "
70 "3.3682581175e-04 -2.2083905829e-02\n";
71 out << "1.5399764838e-04 1.0245287933e-02 2.7921666726e-04 1.4009747125e-02 "
72 "2.7921666726e-04 4.9442454400e-02\n";
73 out << "6.1570316063e-05 6.5451409548e-04 2.0566658643e-03 4.6015050865e-02 "
74 "2.0566658643e-03 2.4489916771e-02\n";
75 out << "-8.5549718574e-04 -3.0244620065e-02 2.5710406506e-04 1.1943422591e-02 "
76 "2.5710406506e-04 -3.1888283063e-02\n";
77 out << "-4.0851931221e-04 -1.3879415332e-02 2.2037752464e-03 4.9513250233e-02 "
78 "2.2037752464e-03 1.4595333192e-02\n";
79
80 out.close();
81 }
82
84 const std::string& headerLine, const std::string& dataLine, size_t numParticles = 1) {
85 std::ofstream out(tempFilename);
86 ASSERT_TRUE(out.is_open());
87 out << numParticles << "\n";
88 out << headerLine << "\n";
89 out << dataLine << "\n";
90 out.close();
91 }
92
93 std::shared_ptr<ParticleContainer<double, 3>> pc;
94 std::shared_ptr<BunchStateHandler> bunchStateHandler;
95 ippl::Vector<int, 3> nr;
96 bool isAllPeriodic_m = true;
97 std::string tempFilename;
98};
99
100TEST_F(FromFileTest, GeneratesParticlesFromAsciiFile) {
101 writeSampleFile();
102
103 auto fc = std::shared_ptr<FieldContainer_t>();
104 FromFile sampler(pc, fc, tempFilename);
105
106 size_t requested = 10; // larger than available in file to test clamping
107
108 // Preallocate capacity so SamplingBase::computeLocalEmitCount
109 // can distribute up to the requested number of particles.
110 const int nranks = std::max(1, ippl::Comm->size());
111 const size_t nranksU = static_cast<size_t>(nranks);
112 const size_t maxLocalNum = requested / nranksU + 2 * nranksU + 1;
113 pc->allocateParticles(maxLocalNum);
114
115 sampler.generateParticles(requested, nr);
116
117 int rank;
118 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
119
120 // Sum local particles over all ranks
121 size_t localN = pc->getLocalNum();
122 size_t globalN = 0;
123 MPI_Allreduce(&localN, &globalN, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
124
125 EXPECT_EQ(globalN, 5u);
126
127 // Copy views to host space for GPU compatibility
128 auto Rview_d = pc->R.getView();
129 auto Pview_d = pc->P.getView();
130
131 auto Rview = Kokkos::create_mirror_view(Rview_d);
132 auto Pview = Kokkos::create_mirror_view(Pview_d);
133 Kokkos::deep_copy(Rview, Rview_d);
134 Kokkos::deep_copy(Pview, Pview_d);
135
136 if (localN > 0) {
137 // Just check that first local particle has finite values
138 EXPECT_TRUE(std::isfinite(Rview(0)[0]));
139 EXPECT_TRUE(std::isfinite(Rview(0)[1]));
140 EXPECT_TRUE(std::isfinite(Rview(0)[2]));
141 EXPECT_TRUE(std::isfinite(Pview(0)[0]));
142 EXPECT_TRUE(std::isfinite(Pview(0)[1]));
143 EXPECT_TRUE(std::isfinite(Pview(0)[2]));
144 }
145}
146
147TEST_F(FromFileTest, ParseHeader_ReorderedColumns) {
148 // Test parseHeader: header "py px pz y x z" => col0=py, col1=px, col2=pz, col3=y, col4=x,
149 // col5=z. Data "10 20 30 40 50 60" => x=50, y=40, z=60, px=20, py=10, pz=30.
150 writeFileWithHeader("py px pz y x z", "10 20 30 40 50 60");
151
152 auto fc = std::shared_ptr<FieldContainer_t>();
153 FromFile sampler(pc, fc, tempFilename);
154
155 size_t requested = 1;
156 sampler.generateParticles(requested, nr);
157
158 size_t localN = pc->getLocalNum();
159 if (localN > 0) {
160 auto Rview_d = pc->R.getView();
161 auto Pview_d = pc->P.getView();
162 auto Rview = Kokkos::create_mirror_view(Rview_d);
163 auto Pview = Kokkos::create_mirror_view(Pview_d);
164 Kokkos::deep_copy(Rview, Rview_d);
165 Kokkos::deep_copy(Pview, Pview_d);
166
167 EXPECT_DOUBLE_EQ(Rview(0)[0], 50.0); // x
168 EXPECT_DOUBLE_EQ(Rview(0)[1], 40.0); // y
169 EXPECT_DOUBLE_EQ(Rview(0)[2], 60.0); // z
170 EXPECT_DOUBLE_EQ(Pview(0)[0], 20.0); // px
171 EXPECT_DOUBLE_EQ(Pview(0)[1], 10.0); // py
172 EXPECT_DOUBLE_EQ(Pview(0)[2], 30.0); // pz
173 }
174}
175
176TEST_F(FromFileTest, ParseHeader_StandardOrderAndAlternateNames) {
177 writeFileWithHeader("x y z px/momentumx py/momentumy pz/momentumz", "1.0 2.0 3.0 4.0 5.0 6.0");
178
179 auto fc = std::shared_ptr<FieldContainer_t>();
180 FromFile sampler(pc, fc, tempFilename);
181
182 size_t requested = 1;
183 sampler.generateParticles(requested, nr);
184
185 size_t localN = pc->getLocalNum();
186 if (localN > 0) {
187 auto Rview_d = pc->R.getView();
188 auto Pview_d = pc->P.getView();
189 auto Rview = Kokkos::create_mirror_view(Rview_d);
190 auto Pview = Kokkos::create_mirror_view(Pview_d);
191 Kokkos::deep_copy(Rview, Rview_d);
192 Kokkos::deep_copy(Pview, Pview_d);
193
194 EXPECT_DOUBLE_EQ(Rview(0)[0], 1.0);
195 EXPECT_DOUBLE_EQ(Rview(0)[1], 2.0);
196 EXPECT_DOUBLE_EQ(Rview(0)[2], 3.0);
197 EXPECT_DOUBLE_EQ(Pview(0)[0], 4.0);
198 EXPECT_DOUBLE_EQ(Pview(0)[1], 5.0);
199 EXPECT_DOUBLE_EQ(Pview(0)[2], 6.0);
200 }
201}
const int nr
Defines the FromFile class used for reading particle phase space from ASCII files.
ippl::FieldLayout< Dim > FieldLayout_t
Definition PBunchDefs.h:25
ippl::UniformCartesian< double, 3 > Mesh_t
Definition PBunchDefs.h:18
TEST_F(FromFileTest, GeneratesParticlesFromAsciiFile)
void TearDown() override
static void TearDownTestSuite()
void SetUp() override
void writeSampleFile()
static void SetUpTestSuite()
ippl::Vector< int, 3 > nr
std::shared_ptr< BunchStateHandler > bunchStateHandler
void writeFileWithHeader(const std::string &headerLine, const std::string &dataLine, size_t numParticles=1)
std::shared_ptr< ParticleContainer< double, 3 > > pc
std::string tempFilename
Implements the sampling method for reading particle phase space from ASCII files.
Definition FromFile.h:31
void generateParticles(size_t &numberOfParticles, Vector_t< double, 3 > nr) override
Generates particles by reading from file.
Definition FromFile.cpp:234