OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
DumpEMFields.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//
20#include <filesystem>
21#include <fstream>
24#include "Physics/Units.h"
26#include "Utilities/Util.h"
27
28extern Inform* gmsg;
29
30std::unordered_set<std::unique_ptr<DumpEMFields>> DumpEMFields::dumpsSet_m;
31
33 : Action(SIZE, "DUMPEMFIELDS",
34 "The \"DUMPEMFIELDS\" statement dumps a field map to a user-defined "
35 "field file, for checking that fields are generated correctly. "
36 "The fields are written out on a grid in space and time.") {
37 // would be nice if "steps" could be integer
39 Attributes::makeString("FILE_NAME", "Name of the file to which field data is dumped");
40
42 "COORDINATE_SYSTEM", "Choose to use CARTESIAN or CYLINDRICAL coordinates",
43 {"CARTESIAN", "CYLINDRICAL"}, "CARTESIAN");
44
46 Attributes::makeReal("X_START", "(Cartesian) Start point in the grid in x [m]");
47
48 itsAttr[DX] = Attributes::makeReal("DX", "(Cartesian) Grid step size in x [m]");
49
50 itsAttr[X_STEPS] = Attributes::makeReal("X_STEPS", "(Cartesian) Number of steps in x");
51
53 "Y_START", "(Cartesian) Start point in the grid in y (vertical) [m]");
54
55 itsAttr[DY] = Attributes::makeReal("DY", "(Cartesian) Grid step size in y [m]");
56
57 itsAttr[Y_STEPS] = Attributes::makeReal("Y_STEPS", "(Cartesian) Number of steps in y");
58
59 itsAttr[Z_START] = Attributes::makeReal("Z_START", "Start point in the grid in z [m]");
60
61 itsAttr[DZ] = Attributes::makeReal("DZ", "Grid step size in z [m]");
62
63 itsAttr[Z_STEPS] = Attributes::makeReal("Z_STEPS", "Number of steps in z");
64
65 itsAttr[T_START] = Attributes::makeReal("T_START", "Start point in the grid in time [ns]");
66
67 itsAttr[DT] = Attributes::makeReal("DT", "Grid step size in time [ns]");
68
69 itsAttr[T_STEPS] = Attributes::makeReal("T_STEPS", "Number of steps in time");
70
72 Attributes::makeReal("R_START", "(Cylindrical) Start point in the grid in radius [m]");
73
74 itsAttr[DR] = Attributes::makeReal("DR", "(Cylindrical) Grid step size in radius [m]");
75
76 itsAttr[R_STEPS] = Attributes::makeReal("R_STEPS", "(Cylindrical) Number of steps in radius");
77
79 Attributes::makeReal("PHI_START", "(Cylindrical) Start point in the grid in phi [rad]");
80
81 itsAttr[DPHI] = Attributes::makeReal("DPHI", "(Cylindrical) Grid step size in phi [rad]");
82
83 itsAttr[PHI_STEPS] = Attributes::makeReal("PHI_STEPS", "(Cylindrical) Number of steps in phi");
84
86 "CYL_ORIGIN_X", "(Cylindrical) The X coordinate of the origin [m]. Default=0", 0.0);
87
89 "CYL_ORIGIN_Y", "(Cylindrical) The Y coordinate of the origin [m]. Default=0", 0.0);
90
92 "CYL_ORIGIN_Z", "(Cylindrical) The Z coordinate of the origin [m]. Default=0", 0.0);
93
95}
96
97DumpEMFields::DumpEMFields(const std::string& name, DumpEMFields* parent) : Action(name, parent) {}
98
99DumpEMFields* DumpEMFields::clone(const std::string& name) {
100 auto* dumper = new DumpEMFields(name, this);
101 if (grid_m != nullptr) {
102 dumper->grid_m.reset(grid_m->clone());
103 }
104 dumper->filename_m = filename_m;
105 dumper->coordinates_m = coordinates_m;
106 dumper->cylindricalOrigin_m = cylindricalOrigin_m;
107 return dumper;
108}
109
111 static const std::map<std::string, CoordinateSystem> stringCoordinateSystem_s = {
112 {"CARTESIAN", CoordinateSystem::CARTESIAN},
113 {"CYLINDRICAL", CoordinateSystem::CYLINDRICAL}};
114 coordinates_m = stringCoordinateSystem_s.at(Attributes::getString(itsAttr[COORDINATE_SYSTEM]));
115}
116
118 buildGrid();
119 // the routine for action (OpalParser/OpalParser) calls execute and then
120 // deletes 'this'; so we must build a copy that lasts until the field maps
121 // are constructed and we are ready for tracking (which is when the field
122 // maps are written). Hence the clone call below.
123 dumpsSet_m.insert(std::unique_ptr<DumpEMFields>(this->clone("")));
124}
125
127 std::vector<double> spacing(4);
128 std::vector<int> gridSize(4);
129 std::vector<double> origin(4);
132 origin[0] = Attributes::getReal(itsAttr[X_START]);
133 spacing[0] = Attributes::getReal(itsAttr[DX]);
134 const double nx = Attributes::getReal(itsAttr[X_STEPS]);
135 checkInt(nx, "X_STEPS");
136 gridSize[0] = nx;
137
138 origin[1] = Attributes::getReal(itsAttr[Y_START]);
139 spacing[1] = Attributes::getReal(itsAttr[DY]);
140 const double ny = Attributes::getReal(itsAttr[Y_STEPS]);
141 checkInt(ny, "Y_STEPS");
142 gridSize[1] = ny;
143
144 origin[2] = Attributes::getReal(itsAttr[Z_START]);
145 spacing[2] = Attributes::getReal(itsAttr[DZ]);
146 const double nz = Attributes::getReal(itsAttr[Z_STEPS]);
147 checkInt(nz, "Z_STEPS");
148 gridSize[2] = nz;
149 } else /* CoordinateSystem::CYLINDRICAL */ {
150 origin[0] = Attributes::getReal(itsAttr[R_START]);
151 spacing[0] = Attributes::getReal(itsAttr[DR]);
152 const double rSteps = Attributes::getReal(itsAttr[R_STEPS]);
153 checkInt(rSteps, "R_STEPS");
154 gridSize[0] = rSteps;
155
157 spacing[1] = Attributes::getReal(itsAttr[DPHI]);
158 const double nphi = Attributes::getReal(itsAttr[PHI_STEPS]);
159 checkInt(nphi, "PHI_STEPS");
160 gridSize[1] = nphi;
161
162 origin[2] = Attributes::getReal(itsAttr[Y_START]);
163 spacing[2] = Attributes::getReal(itsAttr[DY]);
164 const double ny = Attributes::getReal(itsAttr[Y_STEPS]);
165 checkInt(ny, "Y_STEPS");
166 gridSize[2] = ny;
167 }
168
169 origin[3] = Attributes::getReal(itsAttr[T_START]);
170 spacing[3] = Attributes::getReal(itsAttr[DT]);
171 const double nt = Attributes::getReal(itsAttr[T_STEPS]);
172 checkInt(nt, "T_STEPS");
173 gridSize[3] = nt;
174
175 grid_m = std::make_unique<interpolation::NDGrid>(4, &gridSize[0], &spacing[0], &origin[0]);
176
181}
182
183void DumpEMFields::writeFields(const std::set<std::shared_ptr<Component>>& elements) {
184 for (auto& item : dumpsSet_m) {
185 item->writeFieldThis(elements);
186 }
187 dumpsSet_m.clear();
188}
189
190void DumpEMFields::checkInt(double value, const std::string& name, const double tolerance) {
191 value += tolerance; // prevent rounding error
192 if (std::abs(std::floor(value) - value) > 2 * tolerance) {
193 throw OpalException(
194 "DumpEMFields::checkInt",
195 "Value for " + name + " should be an integer but a real value was found");
196 }
197 if (std::floor(value) < 0.5) {
198 throw OpalException("DumpEMFields::checkInt", "Value for " + name + " should be 1 or more");
199 }
200}
201
202void DumpEMFields::writeHeader(std::ofstream& fout) const {
203 fout << grid_m->end().toInteger() << "\n";
205 fout << 1 << " x [m]\n";
206 fout << 2 << " y [m]\n";
207 fout << 3 << " z [m]\n";
208 fout << 4 << " t [ns]\n";
209 fout << 5 << " Bx [T]\n";
210 fout << 6 << " By [T]\n";
211 fout << 7 << " Bz [T]\n";
212 fout << 8 << " Ex [MV/m]\n";
213 fout << 9 << " Ey [MV/m]\n";
214 fout << 10 << " Ez [MV/m]\n";
215 } else /*CoordinateSystem::CYLINDRICAL*/ {
216 fout << 1 << " r [m]\n";
217 fout << 2 << " phi [deg]\n";
218 fout << 3 << " y [m]\n";
219 fout << 4 << " t [ns]\n";
220 fout << 5 << " Br [T]\n";
221 fout << 6 << " Bphi [T]\n";
222 fout << 7 << " By [T]\n";
223 fout << 8 << " Er [MV/m]\n";
224 fout << 9 << " Ephi [MV/m]\n";
225 fout << 10 << " Ey [MV/m]\n";
226 }
227 fout << 0 << std::endl;
228}
229
231 const std::set<std::shared_ptr<Component>>& elements, const Vector_t<double, 3>& point,
232 const double& time, std::ofstream& fout) const {
233 // Translate the coordinate if necessary
236 Vector_t<double, 3> localPoint = point;
238 // point is (r, phi, y), but result and origin is (x, y, z) - y is vertical
239 localPoint[0] = std::cos(point[1]) * point[0] + cylindricalOrigin_m[0];
240 localPoint[2] = std::sin(point[1]) * point[0] + cylindricalOrigin_m[2];
241 localPoint[1] = point[2] + cylindricalOrigin_m[1];
242 }
243 // Collect the fields
244 for (auto& element : elements) {
245 auto transform = element->getCSTrafoGlobal2Local();
246 Vector_t<double, 3> localR = transform.transformTo(localPoint);
247 Vector_t<double, 3> localB{};
248 Vector_t<double, 3> localE{};
249 element->apply(localR, {}, time, localE, localB);
250 transform.invert();
251 localB = transform.rotateTo(localB);
252 localE = transform.rotateTo(localE);
253 E += localE;
254 B += localB;
255 }
256 // Translate the results and output them
257 Vector_t<double, 3> Bout = B;
258 Vector_t<double, 3> Eout = E;
260 // point and field out is (r, phi, y), but field in is (x, y, z) - y is vertical
261 Bout[0] = B[0] * std::cos(point[1]) + B[2] * std::sin(point[1]);
262 Bout[1] = -B[0] * std::sin(point[1]) + B[2] * std::cos(point[1]);
263 Bout[2] = B[1];
264 Eout[0] = E[0] * std::cos(point[1]) + E[2] * std::sin(point[1]);
265 Eout[1] = -E[0] * std::sin(point[1]) + E[2] * std::cos(point[1]);
266 Eout[2] = E[1];
267 fout << point[0] << " " << point[1] * Units::rad2deg << " " << point[2] << " " << time
268 << " ";
269 } else {
270 fout << point[0] << " " << point[1] << " " << point[2] << " " << time << " ";
271 }
272 fout << Bout[0] << " " << Bout[1] << " " << Bout[2] << " ";
273 fout << Eout[0] * Units::Vpm2MVpm << " " << Eout[1] * Units::Vpm2MVpm << " "
274 << Eout[2] * Units::Vpm2MVpm << "\n";
275}
276
277void DumpEMFields::writeFieldThis(const std::set<std::shared_ptr<Component>>& elements) {
278 if (grid_m == nullptr) {
279 throw OpalException(
280 "DumpEMFields::writeFieldThis",
281 "The grid was nullptr; there was a problem with the "
282 "DumpEMFields initialisation.");
283 }
284
285 *gmsg << level5 << *this << endl;
286
287 std::string fname;
288 if (std::filesystem::path(filename_m).is_absolute() == true) {
289 fname = filename_m;
290 } else {
291 fname = Util::combineFilePath(
293 }
294
295 std::vector<double> point_std(4);
296 Vector_t<double, 3> point(0., 0., 0.);
297 std::ofstream fout;
298 fout.open(fname.c_str(), std::ofstream::out);
299 if (!fout.good()) {
300 throw OpalException(
301 "DumpEMFields::writeFieldThis", "Failed to open DumpEMFields file " + filename_m);
302 }
303 // set precision
304 writeHeader(fout);
305 for (interpolation::Mesh::Iterator it = grid_m->begin(); it < grid_m->end(); ++it) {
306 it.getPosition(&point_std[0]);
307 for (size_t i = 0; i < 3; ++i) {
308 point[i] = point_std[i];
309 }
310 double time = point_std[3];
311 writeFieldLine(elements, point, time, fout);
312 }
313 if (failWrite_m) { // For unit tests only - force a write failure if required
314 fout.setstate(std::ios::badbit);
315 }
316 if (!fout.good()) {
317 throw OpalException(
318 "DumpEMFields::writeFieldThis",
319 "Something went wrong during writing " + filename_m);
320 }
321 fout.close();
322}
323
324void DumpEMFields::print(std::ostream& os) const {
325 os << "* ************* D U M P E M F I E L D S ****************************************** "
326 << std::endl;
327 os << "* File name: '" << filename_m << "'\n";
329 os << "* Coordinate system: " << Attributes::getString(itsAttr[COORDINATE_SYSTEM]) << '\n'
330 << "* X_START = " << Attributes::getReal(itsAttr[X_START]) << " [m]\n"
331 << "* DX = " << Attributes::getReal(itsAttr[DX]) << " [m]\n"
332 << "* X_STEPS = " << Attributes::getReal(itsAttr[X_STEPS]) << '\n'
333 << "* Y_START = " << Attributes::getReal(itsAttr[Y_START]) << " [m]\n"
334 << "* DY = " << Attributes::getReal(itsAttr[DY]) << " [m]\n"
335 << "* Y_STEPS = " << Attributes::getReal(itsAttr[Y_STEPS]) << '\n'
336 << "* Z_START = " << Attributes::getReal(itsAttr[Z_START]) << " [m]\n"
337 << "* DZ = " << Attributes::getReal(itsAttr[DZ]) << " [m]\n"
338 << "* Z_STEPS = " << Attributes::getReal(itsAttr[Z_STEPS]) << '\n';
339 } else /*if (coordinates_m == CoordinateSystem::CYLINDRICAL)*/ {
340 os << "* Coordinate system: " << Attributes::getString(itsAttr[COORDINATE_SYSTEM]) << '\n'
341 << "* R_START = " << Attributes::getReal(itsAttr[R_START]) << " [m]\n"
342 << "* DR = " << Attributes::getReal(itsAttr[DR]) << " [m]\n"
343 << "* R_STEPS = " << Attributes::getReal(itsAttr[R_STEPS]) << '\n'
344 << "* PHI_START = " << Attributes::getReal(itsAttr[PHI_START]) << " [rad]\n"
345 << "* DPHI = " << Attributes::getReal(itsAttr[DPHI]) << " [rad]\n"
346 << "* PHI_STEPS = " << Attributes::getReal(itsAttr[PHI_STEPS]) << '\n'
347 << "* Y_START = " << Attributes::getReal(itsAttr[Y_START]) << " [m]\n"
348 << "* DY = " << Attributes::getReal(itsAttr[DY]) << " [m]\n"
349 << "* Y_STEPS = " << Attributes::getReal(itsAttr[Y_STEPS]) << '\n';
350 }
351 os << "* T_START = " << Attributes::getReal(itsAttr[T_START]) << " [ns]\n"
352 << "* DT = " << Attributes::getReal(itsAttr[DT]) << " [ns]\n"
353 << "* T_STEPS = " << Attributes::getReal(itsAttr[T_STEPS]) << '\n';
354 os << "* ********************************************************************************** "
355 << std::endl;
356}
Inform * gmsg
Definition changes.cpp:7
ippl::Vector< T, Dim > Vector_t
Inform * gmsg
Definition changes.cpp:7
elements
Definition IndexMap.cpp:168
@ SIZE
Definition IndexMap.cpp:179
The base class for all OPAL actions.
Definition Action.h:29
void execute() override
DumpEMFields * clone(const std::string &name) override
static std::unordered_set< std::unique_ptr< DumpEMFields > > dumpsSet_m
void print(std::ostream &os) const override
virtual void buildGrid()
Vector_t< double, 3 > cylindricalOrigin_m
void parseCoordinateSystem()
static void checkInt(double value, const std::string &name, double tolerance=1e-9)
std::string filename_m
static void writeFields(const std::set< std::shared_ptr< Component > > &elements)
CoordinateSystem coordinates_m
void writeHeader(std::ofstream &fout) const
void writeFieldLine(const std::set< std::shared_ptr< Component > > &elements, const Vector_t< double, 3 > &point, const double &time, std::ofstream &fout) const
std::unique_ptr< interpolation::NDGrid > grid_m
virtual void writeFieldThis(const std::set< std::shared_ptr< Component > > &elements)
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition Object.cpp:169
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:210
static OpalData * getInstance()
Definition OpalData.cpp:193
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:567
double getReal(const Attribute &attr)
Return real value.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
constexpr double Vpm2MVpm
Definition Units.h:125
constexpr double rad2deg
Definition Units.h:146
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:193