OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
DumpEMFields.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, Chris Rogers
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * 1. Redistributions of source code must retain the above copyright notice,
7  * this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright notice,
9  * this list of conditions and the following disclaimer in the documentation
10  * and/or other materials provided with the distribution.
11  * 3. Neither the name of STFC nor the names of its contributors may be used to
12  * endorse or promote products derived from this software without specific
13  * prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 
29 #include <fstream>
30 
31 #include "Fields/Interpolation/NDGrid.h" // classic
32 #include "AbsBeamline/Component.h" // classic
34 #include "Attributes/Attributes.h"
36 
37 // extern Inform *gmsg;
38 
39 std::unordered_set<DumpEMFields*> DumpEMFields::dumpsSet_m;
40 
42 std::string("The \"DUMPEMFIELDS\" statement dumps a field map to a user-defined")+
43 std::string(" field file, for checking that fields are generated correctly.")+
44 std::string(" The fields are written out on a grid in space and time.");
45 
47  Action(20, "DUMPEMFIELDS", dumpemfields_docstring.c_str()),
48  grid_m(NULL), filename_m("") {
49  // would be nice if "steps" could be integer
51  ("X_START", "(Cartesian) Start point in the grid in x [m]");
53  ("DX", "(Cartesian) Grid step size in x [m]");
55  ("X_STEPS", "(Cartesian) Number of steps in x");
57  ("Y_START", "(Cartesian) Start point in the grid in y [m]");
59  ("DY", "(Cartesian) Grid step size in y [m]");
61  ("Y_STEPS", "(Cartesian) Number of steps in y");
63  ("Z_START", "Start point in the grid in z [m]");
65  ("DZ", "Grid step size in z [m]");
67  ("Z_STEPS", "Number of steps in z");
69  ("T_START", "Start point in the grid in time [ns]");
71  ("DT", "Grid step size in time [ns]");
73  ("T_STEPS", "Number of steps in time");
75  ("FILE_NAME", "Name of the file to which field data is dumped");
76  itsAttr[13] = Attributes::makeString("COORDINATE_SYSTEM",
77  "Choose to use 'Cartesian' or 'Cylindrical' coordinates");
79  ("R_START", "(Cylindrical) Start point in the grid in radius [m]");
81  ("DR", "(Cylindrical) Grid step size in radius [m]");
83  ("R_STEPS", "(Cylindrical) Number of steps in radius");
85  ("PHI_START", "(Cylindrical) Start point in the grid in phi [rad]");
87  ("DPHI", "(Cylindrical) Grid step size in phi [rad]");
89  ("PHI_STEPS", "(Cylindrical) Number of steps in phi");
90 }
91 
93  delete grid_m;
94  dumpsSet_m.erase(this);
95 }
96 
97 DumpEMFields* DumpEMFields::clone(const std::string &name) {
98  DumpEMFields* dumper = new DumpEMFields();
99  if (grid_m != NULL) {
100  dumper->grid_m = grid_m->clone();
101  }
102  dumper->filename_m = filename_m;
103  dumper->coordinates_m = coordinates_m;
104  if (dumpsSet_m.find(this) != dumpsSet_m.end()) {
105  dumpsSet_m.insert(dumper);
106  }
107  return dumper;
108 }
109 
111  if (!itsAttr[13]) {
113  return;
114  }
115  std::string coordStr = Attributes::getString(itsAttr[13]);
116  for (size_t i = 0; i < coordStr.size(); ++i) {
117  coordStr[i] = tolower(coordStr[i]);
118  }
119  if (coordStr == "cylindrical") {
121  } else if (coordStr == "cartesian") {
123  } else {
124  throw OpalException("DumpEMFields::parseCoordinateSystem",
125  std::string("Failed to parse '")+Attributes::getString(itsAttr[13])+
126  std::string("'. OPAL expected either 'cylindrical' or 'cartesian'."));
127  }
128 }
129 
131  buildGrid();
132  // the routine for action (OpalParser/OpalParser) calls execute and then
133  // deletes 'this'; so we must build a copy that lasts until the field maps
134  // are constructed and we are ready for tracking (which is when the field
135  // maps are written). Hence the clone call below.
136  dumpsSet_m.insert(this->clone(""));
137 }
138 
140  std::vector<double> spacing(4);
141  std::vector<double> origin(4);
142  std::vector<int> gridSize(4);
144 
145  if (coordinates_m == CYLINDRICAL) {
146  origin[0] = Attributes::getReal(itsAttr[14]);
147  spacing[0] = Attributes::getReal(itsAttr[15]);
148  double nr = Attributes::getReal(itsAttr[16]);
149  checkInt(nr, "R_STEPS");
150  gridSize[0] = nr;
151 
152  origin[1] = Attributes::getReal(itsAttr[17]);
153  spacing[1] = Attributes::getReal(itsAttr[18]);
154  double nphi = Attributes::getReal(itsAttr[19]);
155  checkInt(nphi, "PHI_STEPS");
156  gridSize[1] = nphi;
157  } else {
158  origin[0] = Attributes::getReal(itsAttr[0]);
159  spacing[0] = Attributes::getReal(itsAttr[1]);
160  double nx = Attributes::getReal(itsAttr[2]);
161  checkInt(nx, "X_STEPS");
162  gridSize[0] = nx;
163 
164  origin[1] = Attributes::getReal(itsAttr[3]);
165  spacing[1] = Attributes::getReal(itsAttr[4]);
166  double ny = Attributes::getReal(itsAttr[5]);
167  checkInt(ny, "Y_STEPS");
168  gridSize[1] = ny;
169  }
170  origin[2] = Attributes::getReal(itsAttr[6]);
171  spacing[2] = Attributes::getReal(itsAttr[7]);
172  double nz = Attributes::getReal(itsAttr[8]);
173  checkInt(nz, "Z_STEPS");
174  gridSize[2] = nz;
175 
176  origin[3] = Attributes::getReal(itsAttr[9]);
177  spacing[3] = Attributes::getReal(itsAttr[10]);
178  double nt = Attributes::getReal(itsAttr[11]);
179  checkInt(nt, "T_STEPS");
180  gridSize[3] = nt;
181 
182  if (grid_m != NULL) {
183  delete grid_m;
184  }
185 
186  grid_m = new interpolation::NDGrid(4, &gridSize[0], &spacing[0], &origin[0]);
187 
189 }
190 
193  for (dump_iter it = dumpsSet_m.begin(); it != dumpsSet_m.end(); ++it) {
194  (*it)->writeFieldThis(field);
195  }
196 }
197 
198 void DumpEMFields::checkInt(double real, std::string name, double tolerance) {
199  real += tolerance; // prevent rounding error
200  if (fabs(floor(real) - real) > 2*tolerance) {
201  throw OpalException("DumpEMFields::checkInt",
202  "Value for "+name+
203  " should be an integer but a real value was found");
204  }
205  if (floor(real) < 0.5) {
206  throw OpalException("DumpEMFields::checkInt",
207  "Value for "+name+" should be 1 or more");
208  }
209 }
210 
211 void DumpEMFields::writeHeader(std::ofstream& fout) const {
212  fout << grid_m->end().toInteger() << "\n";
213  if (coordinates_m == CYLINDRICAL) {
214  fout << 1 << " r [mm]\n";
215  fout << 2 << " phi [degree]\n";
216  } else {
217  fout << 1 << " x [mm]\n";
218  fout << 2 << " y [mm]\n";
219  }
220  fout << 3 << " z [mm]\n";
221  fout << 4 << " t [ns]\n";
222  if (coordinates_m == CYLINDRICAL) {
223  fout << 5 << " Br [kGauss]\n";
224  fout << 6 << " Bphi [kGauss]\n";
225  fout << 7 << " Bz [kGauss]\n";
226  fout << 8 << " Er [MV/m]\n";
227  fout << 9 << " Ephi [MV/m]\n";
228  fout << 10 << " Ez [MV/m]\n";
229  } else {
230  fout << 5 << " Bx [kGauss]\n";
231  fout << 6 << " By [kGauss]\n";
232  fout << 7 << " Bz [kGauss]\n";
233  fout << 8 << " Ex [MV/m]\n";
234  fout << 9 << " Ey [MV/m]\n";
235  fout << 10 << " Ez [MV/m]\n";
236  }
237  fout << 0 << std::endl;
238 }
239 
241  const Vector_t& pointIn,
242  const double& time,
243  std::ofstream& fout) const {
244  Vector_t centroid(0., 0., 0.);
245  Vector_t E(0., 0., 0.);
246  Vector_t B(0., 0., 0.);
247  Vector_t point = pointIn;
248  if (coordinates_m == CYLINDRICAL) {
249  // pointIn is r, phi, z
250  point[0] = cos(pointIn[1])*pointIn[0];
251  point[1] = sin(pointIn[1])*pointIn[0];
252  }
253 
254  field->apply(point, centroid, time, E, B);
255  Vector_t Bout = B;
256  Vector_t Eout = E;
257  if (coordinates_m == CYLINDRICAL) {
258  // pointIn is r, phi, z
259  Bout[0] = B[0]*cos(pointIn[1])+B[1]*sin(pointIn[1]);
260  Bout[1] = -B[0]*sin(pointIn[1])+B[1]*cos(pointIn[1]);
261  Eout[0] = E[0]*cos(pointIn[1])+E[1]*sin(pointIn[1]);
262  Eout[1] = -E[0]*sin(pointIn[1])+E[1]*cos(pointIn[1]);
263  fout << pointIn[0] << " " << pointIn[1]*DEGREE << " " << pointIn[2] << " " << time << " ";
264  } else {
265  fout << pointIn[0] << " " << pointIn[1] << " " << pointIn[2] << " " << time << " ";
266  }
267 
268  fout << Bout[0] << " " << Bout[1] << " " << Bout[2] << " ";
269  fout << Eout[0] << " " << Eout[1] << " " << Eout[2] << "\n";
270 }
271 
273  if (grid_m == NULL) {
274  throw OpalException("DumpEMFields::writeFieldThis",
275  "The grid was NULL; there was a problem with the DumpEMFields initialisation.");
276  }
277 
278  if (field == NULL) {
279  throw OpalException("DumpEMFields::writeFieldThis",
280  "The field to be written was NULL.");
281  }
282  std::vector<double> point_std(4);
283  Vector_t point(0., 0., 0.);
284  std::ofstream fout;
285  try {
286  fout.open(filename_m.c_str(), std::ofstream::out);
287  } catch (std::exception& exc) {
288  throw OpalException("DumpEMFields::writeFieldThis",
289  "Failed to open DumpEMFields file "+filename_m);
290  }
291  if (!fout.good()) {
292  throw OpalException("DumpEMFields::writeFieldThis",
293  "Failed to open DumpEMFields file "+filename_m);
294  }
295  // set precision
296  writeHeader(fout);
298  it < grid_m->end();
299  ++it) {
300  it.getPosition(&point_std[0]);
301  for (size_t i = 0; i < 3; ++i) {
302  point[i] = point_std[i];
303  }
304  double time = point_std[3];
305  writeFieldLine(field, point, time, fout);
306  }
307  if (!fout.good()) {
308  throw OpalException("DumpEMFields::writeFieldThis",
309  "Something went wrong during writing "+filename_m);
310  }
311  fout.close();
312 }
313 
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B)
Definition: Component.cpp:99
void parseCoordinateSystem()
The base class for all OPAL actions.
Definition: Action.h:30
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:815
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
const int nr
Definition: ClassicRandom.h:24
static std::unordered_set< DumpEMFields * > dumpsSet_m
Definition: DumpEMFields.h:118
void writeFieldLine(Component *field, const Vector_t &point, const double &time, std::ofstream &fout) const
std::string filename_m
Definition: DumpEMFields.h:115
virtual void execute()
std::vector< Attribute > itsAttr
The object attributes (see Attribute.hh).
Definition: Object.h:214
NDGrid * clone()
Definition: NDGrid.h:347
FLieGenerator< T, N > real(const FLieGenerator< std::complex< T >, N > &)
Take real part of a complex generator.
static void checkInt(double value, std::string name, double tolerance=1e-9)
Mesh::Iterator end() const
Definition: NDGrid.h:359
static std::string dumpemfields_docstring
Definition: DumpEMFields.h:119
static void writeFields(Component *field)
virtual void buildGrid()
static constexpr double DEGREE
Definition: DumpEMFields.h:121
virtual DumpEMFields * clone(const std::string &name)
virtual ~DumpEMFields()
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
const std::string name
CoordinateSystem coordinates_m
Definition: DumpEMFields.h:116
interpolation::NDGrid * grid_m
Definition: DumpEMFields.h:114
std::string::iterator iterator
Definition: MSLang.h:16
Interface for a single beam element.
Definition: Component.h:51
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:217
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:296
Mesh::Iterator begin() const
Definition: NDGrid.h:355
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:205
virtual void writeFieldThis(Component *field)
void writeHeader(std::ofstream &fout) const
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:816
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:307