OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestDumpEMFields.cpp
Go to the documentation of this file.
1//
2// Class DumpEMFields
3// DumpEMFields dumps the dynamically changing fields of a Ring in a user-
4// defined grid.
5//
6// Copyright (c) 2017, Chris Rogers
7// All rights reserved
8//
9// This file is part of OPAL.
10//
11// OPAL is free software: you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation, either version 3 of the License, or
14// (at your option) any later version.
15//
16// You should have received a copy of the GNU General Public License
17// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
18//
19#include <filesystem>
20#include <fstream>
21#include <iostream>
22#include <set>
23#include <vector>
30#include "Fields/NullField.h"
32#include "Utilities/Util.h"
33#include "gtest/gtest.h"
34
35namespace {
36
41 class MockComponent : public Component {
42 public:
43 MockComponent() : Component("MockComponent"), field_m(std::make_unique<NullField>()) {}
44 MockComponent(const MockComponent& /*rhs*/)
45 : Component("MockComponent"), field_m(std::make_unique<NullField>()) {}
46 ~MockComponent() override = default;
47 void accept(BeamlineVisitor&) const override {}
48 ElementBase* clone() const override { return new MockComponent(*this); }
49 EMField& getField() override { return *field_m; }
50 EMField& getField() const override { return *field_m; }
51 bool apply(const std::shared_ptr<ParticleContainer_t>& /*pc*/) override { return false; }
52 bool apply(
53 const size_t& /*i*/, const double& /*t*/, Vector_t<double, 3>& /*E*/,
54 Vector_t<double, 3>& /*B*/) override {
55 return false;
56 }
57 bool apply(
58 const Vector_t<double, 3>& r, const Vector_t<double, 3>& /*P*/, const double& /*t*/,
60 if (r(0) < 0. || r(0) > 1. || r(1) < -1. || r(1) > 0. || r(2) < 0. || r(2) > 1.) {
61 return true; // isOutOfBounds
62 }
63 B(0) = r(0);
64 B(1) = r(1);
65 B(2) = r(2);
66 E(0) = -r(0);
67 E(1) = -r(1);
68 E(2) = -r(2);
69 return false; // NOT isOutOfBounds
70 }
72 const Vector_t<double, 3>& /*r*/, const Vector_t<double, 3>& /*P*/,
73 const double& /*t*/, Vector_t<double, 3>& /*E*/,
74 Vector_t<double, 3>& /*B*/) override {
75 return false;
76 }
77 void initialise(PartBunch_t*, double&, double&) override {}
78 void finalise() override {}
79 bool bends() const override { return true; }
80 void getFieldExtend(double&, double&) const override {}
81
82 BGeometryBase& getGeometry() override { return geometry_m; }
83 const BGeometryBase& getGeometry() const override { return geometry_m; }
84
85 NullGeometry geometry_m;
86 std::unique_ptr<NullField> field_m;
87 };
88
89 void setOneAttribute(DumpEMFields* dump, const std::string& name, const double value) {
90 Attributes::setReal(*dump->findAttribute(name), value);
91 }
92
93 void setAttributesCart(
94 DumpEMFields* dump, const double x0, const double dx, const double nx, const double y0,
95 const double dy, const double ny, const double z0, const double dz, const double nz,
96 const double t0, const double dt, const double nt, const std::string& filename) {
97 setOneAttribute(dump, "X_START", x0);
98 setOneAttribute(dump, "DX", dx);
99 setOneAttribute(dump, "X_STEPS", nx);
100 setOneAttribute(dump, "Y_START", y0);
101 setOneAttribute(dump, "DY", dy);
102 setOneAttribute(dump, "Y_STEPS", ny);
103 setOneAttribute(dump, "Z_START", z0);
104 setOneAttribute(dump, "DZ", dz);
105 setOneAttribute(dump, "Z_STEPS", nz);
106 setOneAttribute(dump, "T_START", t0);
107 setOneAttribute(dump, "DT", dt);
108 setOneAttribute(dump, "T_STEPS", nt);
109 Attributes::setString(*dump->findAttribute("FILE_NAME"), filename);
110 }
111
112 void setOriginCyl(DumpEMFields* dump, const double xc, const double yc, const double zc) {
113 setOneAttribute(dump, "CYL_ORIGIN_X", xc);
114 setOneAttribute(dump, "CYL_ORIGIN_Y", yc);
115 setOneAttribute(dump, "CYL_ORIGIN_Z", zc);
116 }
117
118 void setAttributesCyl(
119 DumpEMFields* dump, const double r0, const double dr, const double nr,
120 const double phi0, const double dphi, const double nphi, const double y0,
121 const double dy, const double ny, const double t0, const double dt, const double nt,
122 const std::string& filename) {
123 setOneAttribute(dump, "R_START", r0);
124 setOneAttribute(dump, "DR", dr);
125 setOneAttribute(dump, "R_STEPS", nr);
126 setOneAttribute(dump, "PHI_START", phi0);
127 setOneAttribute(dump, "DPHI", dphi);
128 setOneAttribute(dump, "PHI_STEPS", nphi);
129 setOneAttribute(dump, "Y_START", y0);
130 setOneAttribute(dump, "DY", dy);
131 setOneAttribute(dump, "Y_STEPS", ny);
132 setOneAttribute(dump, "T_START", t0);
133 setOneAttribute(dump, "DT", dt);
134 setOneAttribute(dump, "T_STEPS", nt);
135 Attributes::setString(*dump->findAttribute("FILE_NAME"), filename);
136 Attributes::setPredefinedString(*dump->findAttribute("COORDINATE_SYSTEM"), "cYLindriCAL");
137 }
138
139 TEST(TestDumpEMFields, ConstructorDestructor) {
140 // neither in the set and grid is null
141 const auto* dump1 = new DumpEMFields();
142 delete dump1;
143 // grid is not null and it is in the set
144 auto* dump2 = new DumpEMFields();
145 setAttributesCart(dump2, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., "/dev/null");
146 dump2->execute();
147 delete dump2;
149 }
150
151 void execute_throws(DumpEMFields* dump, const std::string& reason) {
152 try {
153 dump->execute();
154 EXPECT_TRUE(false) << reason;
155 } catch (OpalException&) {
156 // pass;
157 }
158 }
159
160 TEST(TestDumpEMFields, executeTest) {
161 gmsg = new Inform(nullptr, -1);
162 // dump the fields
163 DumpEMFields dump1;
164 execute_throws(&dump1, "should throw due to nsteps < 1");
165 setAttributesCart(&dump1, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., "/dev/null");
166 dump1.execute(); // should be okay (normal)
167 std::set<std::shared_ptr<Component>> elements;
168 elements.insert(std::make_shared<MockComponent>());
169 EXPECT_NO_THROW(DumpEMFields::writeFields(elements));
170 setAttributesCart(
171 &dump1, -1., -1., 1., -1., -1., 1., -1., -1., 1., 1., 1., 1., "/dev/null");
172 dump1.execute(); // should be okay (-ve step is okay)
173 setAttributesCart(
174 &dump1, -1., -1., 0., -1., -1., 1., -1., -1., 1., 1., 1., 1., "/dev/null");
175 execute_throws(&dump1, "should throw due to nsteps x < 1");
176 setAttributesCart(
177 &dump1, -1., -1., 1., -1., -1., 0., -1., -1., 1., 1., 1., 1., "/dev/null");
178 execute_throws(&dump1, "should throw due to nsteps y < 1");
179 setAttributesCart(
180 &dump1, -1., -1., 1., -1., -1., 1., -1., -1., 0., 1., 1., 1., "/dev/null");
181 execute_throws(&dump1, "should throw due to nsteps z < 1");
182 setAttributesCart(
183 &dump1, -1., -1., 1., -1., -1., 1., -1., -1., 1., 1., 1., 0., "/dev/null");
184 execute_throws(&dump1, "should throw due to nsteps t < 1");
185 setAttributesCart(
186 &dump1, -1., -1., 1., -1., -1., 1., -1., -1., 1.5, 2., 2., 1., "/dev/null");
187 execute_throws(&dump1, "should throw due to nsteps not integer");
189 }
190
191 void clear_files(std::set<std::string> const& files) {
192 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
193
194 for (const std::string& fname : files) {
195 std::filesystem::remove(Util::combineFilePath({auxDirectory, fname}));
196 }
197 }
198
199 TEST(TestDumpEMFields, writeFieldsCartTest) {
200 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
201 std::filesystem::create_directory(auxDirectory);
202 gmsg = new Inform(nullptr, -1);
203 std::string fname1 = "test5";
204 std::string fname2 = "test6";
205 std::string fname3 = "test7";
206 std::string fname4 = "test8";
207
208 clear_files({fname1, fname2, fname3, fname4});
209 DumpEMFields dump1;
210 setAttributesCart(&dump1, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., fname1);
211 dump1.execute();
212 DumpEMFields dump2;
213 setAttributesCart(&dump2, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., fname2);
214 dump2.execute();
215 DumpEMFields dump3;
216 setAttributesCart(&dump3, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., fname3);
217 // note we don't execute dump3; so it should not be written
218 DumpEMFields dump4;
219 setAttributesCart(&dump4, 0.1, 0.1, 3., -0.1, 0.2, 2., 0.2, 0.3, 2., 1., 1., 2., fname4);
220 dump4.execute();
221 std::set<std::shared_ptr<Component>> elements;
222 elements.insert(std::make_shared<MockComponent>());
223 try {
225 } catch (OpalException& exc) {
226 EXPECT_TRUE(false) << "Threw OpalException on writefields: " << exc.what() << std::endl;
227 }
228 std::ifstream fin1(Util::combineFilePath({auxDirectory, fname1}));
229 EXPECT_TRUE(fin1.good());
230 std::ifstream fin2(Util::combineFilePath({auxDirectory, fname2}));
231 EXPECT_TRUE(fin2.good());
232 std::ifstream fin3(Util::combineFilePath({auxDirectory, fname3}));
233 EXPECT_FALSE(fin3.good()); // does not exist
234 std::ifstream fin4(Util::combineFilePath({auxDirectory, fname4}));
235 EXPECT_TRUE(fin4.good());
236 int n_lines;
237 fin4 >> n_lines;
238 EXPECT_EQ(n_lines, 24);
239 std::string test_line;
240 for (size_t i = 0; i < 12; ++i) {
241 std::getline(fin4, test_line);
242 }
243 std::vector line(10, 0.);
244 for (size_t line_index = 0; line_index < 24; ++line_index) {
245 double tol = 1e-9;
246 for (size_t i = 0; i < 10; ++i) {
247 fin4 >> line[i];
248 }
249 if (line_index == 0) {
250 EXPECT_NEAR(line[0], 0.1, tol);
251 EXPECT_NEAR(line[1], -0.1, tol);
252 EXPECT_NEAR(line[2], 0.2, tol);
253 EXPECT_NEAR(line[3], 1., tol);
254 }
255 if (line[1] < 0.) {
256 EXPECT_NEAR(line[4], line[0], tol);
257 EXPECT_NEAR(line[5], line[1], tol);
258 EXPECT_NEAR(line[6], line[2], tol);
259 } else {
260 EXPECT_NEAR(line[4], 0., tol);
261 EXPECT_NEAR(line[5], 0., tol);
262 EXPECT_NEAR(line[6], 0., tol);
263 }
264 EXPECT_NEAR(line[7] * Units::MVpm2Vpm, -line[4], tol);
265 EXPECT_NEAR(line[8] * Units::MVpm2Vpm, -line[5], tol);
266 EXPECT_NEAR(line[9] * Units::MVpm2Vpm, -line[6], tol);
267 }
268 clear_files({fname1, fname2, fname3, fname4});
270 }
271
272 TEST(TestDumpEMFields, writeFieldsCylTest) {
273 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
274 std::filesystem::create_directory(auxDirectory);
275 gmsg = new Inform(nullptr, -1);
276
277 std::string fnameCyl = "testCyl";
278
279 clear_files({fnameCyl});
280 DumpEMFields dump;
281 setAttributesCyl(
282 &dump, 0.1, 0.1, 3., 90. * Units::deg2rad, 45. * Units::deg2rad, 16, 0.2, 0.3, 2.,
283 1., 1., 2., fnameCyl);
284 dump.execute();
285 // depending on execution order, this might write cartesian tests as well... never mind
286 std::set<std::shared_ptr<Component>> elements;
287 elements.insert(std::make_shared<MockComponent>());
288 try {
290 } catch (OpalException& exc) {
291 EXPECT_TRUE(false) << "Threw OpalException on writefields: " << exc.what() << std::endl;
292 }
293 std::ifstream fin(Util::combineFilePath({auxDirectory, fnameCyl}));
294 EXPECT_TRUE(fin.good());
295 int n_lines;
296 fin >> n_lines;
297 EXPECT_EQ(n_lines, 192);
298 std::string test_line;
299 for (size_t i = 0; i < 12; ++i) {
300 std::getline(fin, test_line);
301 }
302 std::vector line(10, 0.);
303 for (size_t line_index = 0; line_index < 24; ++line_index) {
304 constexpr double tol = 1e-9;
305 for (size_t i = 0; i < 10; ++i) {
306 fin >> line[i];
307 }
308 if (line_index == 0) {
309 EXPECT_NEAR(line[0], 0.1, tol);
310 EXPECT_NEAR(line[1], 90, tol);
311 EXPECT_NEAR(line[2], 0.2, tol);
312 EXPECT_NEAR(line[3], 1., tol);
313 }
314 while (line[1] > 360.) {
315 line[1] -= 360.;
316 }
317 if (line[1] < 90.) {
318 EXPECT_NEAR(line[4] * line[4] + line[5] * line[5], line[0] * line[0], tol);
319 EXPECT_NEAR(line[6], line[2], tol);
320 } else {
321 EXPECT_NEAR(line[4], 0., tol);
322 EXPECT_NEAR(line[5], 0., tol);
323 EXPECT_NEAR(line[6], 0., tol);
324 }
325 EXPECT_NEAR(line[7] * Units::MVpm2Vpm, -line[4], tol);
326 EXPECT_NEAR(line[8] * Units::MVpm2Vpm, -line[5], tol);
327 EXPECT_NEAR(line[9] * Units::MVpm2Vpm, -line[6], tol);
328 }
329 clear_files({fnameCyl});
330
331 // EXPECT_TRUE(false) << "Do DumpEMFields cylindrical documentation!";
333 }
334
335 TEST(TestDumpEMFields, writeFieldsCylOriginTest) {
336 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
337 std::filesystem::create_directory(auxDirectory);
338 gmsg = new Inform(nullptr, -1);
339
340 std::string fnameCyl1 = "testCyl1";
341 std::string fnameCyl2 = "testCyl2";
342
343 clear_files({fnameCyl1, fnameCyl2});
344 DumpEMFields dump1;
345 setAttributesCyl(
346 &dump1, 0.1, 0., 1., 45. * Units::deg2rad, 0., 1, -0.1, 0., 1., 1., 0., 1.,
347 fnameCyl1);
348 dump1.execute();
349 DumpEMFields dump2;
350 setAttributesCyl(
351 &dump2, 0.1, 0., 1., 45. * Units::deg2rad, 0., 1, -0.1, 0., 1., 1., 0., 1.,
352 fnameCyl2);
353 setOriginCyl(&dump2, 0.01, 0.02, 0.03);
354 dump2.execute();
355 // depending on execution order, this might write cartesian tests as well... never mind
356 std::set<std::shared_ptr<Component>> elements;
357 elements.insert(std::make_shared<MockComponent>());
358 try {
360 } catch (OpalException& exc) {
361 EXPECT_TRUE(false) << "Threw OpalException on writefields: " << exc.what() << std::endl;
362 }
363 // Read the origin (0,0,0) file
364 std::ifstream fin1(Util::combineFilePath({auxDirectory, fnameCyl1}));
365 EXPECT_TRUE(fin1.good());
366 int n_lines;
367 fin1 >> n_lines;
368 EXPECT_EQ(n_lines, 1);
369 std::string test_line;
370 for (size_t i = 0; i < 12; ++i) {
371 std::getline(fin1, test_line);
372 }
373 std::vector line1(10, 0.);
374 for (size_t i = 0; i < 10; ++i) {
375 fin1 >> line1[i];
376 }
377 // Read the origin (1,2,3) file
378 std::ifstream fin2(Util::combineFilePath({auxDirectory, fnameCyl2}));
379 EXPECT_TRUE(fin2.good());
380 fin2 >> n_lines;
381 EXPECT_EQ(n_lines, 1);
382 for (size_t i = 0; i < 12; ++i) {
383 std::getline(fin2, test_line);
384 }
385 std::vector line2(10, 0.);
386 for (size_t i = 0; i < 10; ++i) {
387 fin2 >> line2[i];
388 }
389 EXPECT_EQ(line1[0], line2[0]);
390 EXPECT_EQ(line1[1], line2[1]);
391 EXPECT_EQ(line1[2], line2[2]);
392 EXPECT_EQ(line1[3], line2[3]);
393 EXPECT_NE(line1[4], line2[4]);
394 EXPECT_NE(line1[5], line2[5]);
395 EXPECT_NE(line1[6], line2[6]);
396 EXPECT_NE(line1[7], line2[7]);
397 EXPECT_NE(line1[8], line2[8]);
398 EXPECT_NE(line1[9], line2[9]);
399 clear_files({fnameCyl1, fnameCyl2});
401 }
402
403 TEST(TestDumpEMFields, BadGrid) {
404 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
405 std::filesystem::create_directory(auxDirectory);
406 gmsg = new Inform(nullptr, -1);
407
408 std::string fnameCyl = "testCyl";
409
410 clear_files({fnameCyl});
411 DumpEMFields dump;
412 setAttributesCyl(
413 &dump, 0.1, 0.1, 3., 90. * Units::deg2rad, 45. * Units::deg2rad, 16, 0.2, 0.3, 2.,
414 1., 1., 2., fnameCyl);
415 dump.execute();
417 std::set<std::shared_ptr<Component>> elements;
418 elements.insert(std::make_shared<MockComponent>());
419 EXPECT_ANY_THROW(DumpEMFields::writeFields(elements));
421 }
422
423 TEST(TestDumpEMFields, CouldNotOpenFile) {
424 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
425 std::filesystem::create_directory(auxDirectory);
426 gmsg = new Inform(nullptr, -1);
427 std::string fnameCyl = "."; // Opening for write to a directory always fails
428 DumpEMFields dump;
429 setAttributesCyl(
430 &dump, 0.1, 0.1, 3., 90. * Units::deg2rad, 45. * Units::deg2rad, 16, 0.2, 0.3, 2.,
431 1., 1., 2., fnameCyl);
432 dump.execute();
433 std::set<std::shared_ptr<Component>> elements;
434 elements.insert(std::make_shared<MockComponent>());
435 EXPECT_ANY_THROW(DumpEMFields::writeFields(elements));
437 }
438
439 TEST(TestDumpEMFields, WriteFailure) {
440 std::string auxDirectory = OpalData::getInstance()->getAuxiliaryOutputDirectory();
441 std::filesystem::create_directory(auxDirectory);
442 gmsg = new Inform(nullptr, -1);
443 std::string fnameCyl = "testCyl";
444 DumpEMFields dump;
445 setAttributesCyl(
446 &dump, 0.1, 0.1, 3., 90. * Units::deg2rad, 45. * Units::deg2rad, 16, 0.2, 0.3, 2.,
447 1., 1., 2., fnameCyl);
448 dump.execute();
450 std::set<std::shared_ptr<Component>> elements;
451 elements.insert(std::make_shared<MockComponent>());
452 EXPECT_ANY_THROW(DumpEMFields::writeFields(elements));
454 }
455} // namespace
Inform * gmsg
Definition changes.cpp:7
Defines the abstract interface for a single beamline component in the accelerator model.
ippl::Vector< T, Dim > Vector_t
const int nr
elements
Definition IndexMap.cpp:168
TEST(IndexMapTest, RebuildsReferencePathModelFromOrderedRanges)
Abstract base class for accelerator geometry classes.
Definition Geometry.h:42
virtual bool applyToReferenceParticle(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B)
Apply to reference particle with position R and momemtum P.
virtual void finalise()=0
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField)=0
virtual EMField & getField()=0
Return field.
virtual void getFieldExtend(double &zBegin, double &zEnd) const =0
Return the field-support extent of the component.
virtual bool bends() const =0
virtual bool apply(const std::shared_ptr< ParticleContainer_t > &pc)
Apply to all particles. Kernel launch moved inside the function.
Definition Component.cpp:57
void execute() override
static void failWrite()
static void writeFields(const std::set< std::shared_ptr< Component > > &elements)
static void failGrid()
static void clearDumps()
Abstract base class for electromagnetic fields.
Definition EMField.h:171
virtual void accept(BeamlineVisitor &visitor) const =0
Apply visitor.
virtual ElementBase * clone() const =0
Return clone.
virtual BGeometryBase & getGeometry()=0
Get geometry.
A zero electromagnetic field.
Definition NullField.h:29
Geometry representing an identity transform.
virtual Attribute * findAttribute(const std::string &name)
Find an attribute by name.
Definition Object.cpp:56
static OpalData * getInstance()
Definition OpalData.cpp:193
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:567
virtual const std::string & what() const
Return the message string for the exception.
void setString(Attribute &attr, const std::string &val)
Set string value.
void setReal(Attribute &attr, double val)
Set real value.
void setPredefinedString(Attribute &attr, const std::string &val)
Set predefined string value.
constexpr double e
The value of.
Definition Physics.h:49
constexpr double MVpm2Vpm
Definition Units.h:128
constexpr double deg2rad
Definition Units.h:143
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:193
STL namespace.