OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
LossDataSink.cpp
Go to the documentation of this file.
1 //
2 // Class LossDataSink
3 // This class writes file attributes to describe phase space of loss files
4 //
5 // Copyright (c) 200x - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
6 // All rights reserved
7 //
8 // This file is part of OPAL.
9 //
10 // OPAL is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17 //
18 #include "Structure/LossDataSink.h"
19 
22 #include "Message/GlobalComm.h"
23 #include "OPALconfig.h"
25 #include "Utilities/Options.h"
26 #include "Utilities/Util.h"
27 #include "Utility/IpplInfo.h"
28 
29 #include <boost/filesystem.hpp>
30 
31 #include <cmath>
32 
33 extern Inform* gmsg;
34 
35 #define WRITE_FILEATTRIB_STRING( attribute, value ) { \
36  h5_int64_t h5err = H5WriteFileAttribString (H5file_m, attribute, value); \
37  if (h5err <= H5_ERR) { \
38  std::stringstream ss; \
39  ss << "failed to write string attribute " << attribute << " to file " << fn_m; \
40  throw GeneralClassicException(std::string(__func__), ss.str()); \
41  }\
42 }
43 #define WRITE_STEPATTRIB_FLOAT64( attribute, value, size ) { \
44  h5_int64_t h5err = H5WriteStepAttribFloat64 (H5file_m, attribute, value, size); \
45  if (h5err <= H5_ERR) { \
46  std::stringstream ss; \
47  ss << "failed to write float64 attribute " << attribute << " to file " << fn_m; \
48  throw GeneralClassicException(std::string(__func__), ss.str()); \
49  }\
50 }
51 #define WRITE_STEPATTRIB_INT64( attribute, value, size ) { \
52  h5_int64_t h5err = H5WriteStepAttribInt64 (H5file_m, attribute, value, size); \
53  if (h5err <= H5_ERR) { \
54  std::stringstream ss; \
55  ss << "failed to write int64 attribute " << attribute << " to file " << fn_m; \
56  throw GeneralClassicException(std::string(__func__), ss.str()); \
57  }\
58 }
59 #define WRITE_DATA_FLOAT64( name, value ) { \
60  h5_int64_t h5err = H5PartWriteDataFloat64 (H5file_m, name, value); \
61  if (h5err <= H5_ERR) { \
62  std::stringstream ss; \
63  ss << "failed to write float64 data " << name << " to file " << fn_m; \
64  throw GeneralClassicException(std::string(__func__), ss.str()); \
65  }\
66 }
67 #define WRITE_DATA_INT64( name, value ) { \
68  h5_int64_t h5err = H5PartWriteDataInt64 (H5file_m, name, value); \
69  if (h5err <= H5_ERR) { \
70  std::stringstream ss; \
71  ss << "failed to write int64 data " << name << " to file " << fn_m; \
72  throw GeneralClassicException(std::string(__func__), ss.str()); \
73  }\
74 }
75 #define SET_STEP() { \
76  h5_int64_t h5err = H5SetStep (H5file_m, H5call_m); \
77  if (h5err <= H5_ERR) { \
78  std::stringstream ss; \
79  ss << "failed to set step " << H5call_m << " in file " << fn_m; \
80  throw GeneralClassicException(std::string(__func__), ss.str()); \
81  }\
82 }
83 #define GET_NUM_STEPS() { \
84  H5call_m = H5GetNumSteps( H5file_m ); \
85  if (H5call_m <= H5_ERR) { \
86  std::stringstream ss; \
87  ss << "failed to get number of steps of file " << fn_m; \
88  throw GeneralClassicException(std::string(__func__), ss.str()); \
89  }\
90 }
91 #define SET_NUM_PARTICLES( num ) { \
92  h5_int64_t h5err = H5PartSetNumParticles (H5file_m, num); \
93  if (h5err <= H5_ERR) { \
94  std::stringstream ss; \
95  ss << "failed to set number of particles to " << num << " in step " << H5call_m << " in file " << fn_m; \
96  throw GeneralClassicException(std::string(__func__), ss.str()); \
97  }\
98 }
99 
100 #define OPEN_FILE( fname, mode, props ) { \
101  H5file_m = H5OpenFile (fname, mode, props); \
102  if (H5file_m == (h5_file_t)H5_ERR) { \
103  std::stringstream ss; \
104  ss << "failed to open file " << fn_m; \
105  throw GeneralClassicException(std::string(__func__), ss.str()); \
106  }\
107 }
108 #define CLOSE_FILE() { \
109  h5_int64_t h5err = H5CloseFile (H5file_m); \
110  if (h5err <= H5_ERR) { \
111  std::stringstream ss; \
112  ss << "failed to close file " << fn_m; \
113  throw GeneralClassicException(std::string(__func__), ss.str()); \
114  }\
115 }
116 
117 namespace {
118  void f64transform(const std::vector<OpalParticle> &particles,
119  unsigned int startIdx,
120  unsigned int numParticles,
121  h5_float64_t *buffer,
122  std::function<h5_float64_t(const OpalParticle&)> select) {
123  std::transform(particles.begin() + startIdx,
124  particles.begin() + startIdx + numParticles,
125  buffer, select);
126  }
127  void i64transform(const std::vector<OpalParticle> &particles,
128  unsigned int startIdx,
129  unsigned int numParticles,
130  h5_int64_t *buffer,
131  std::function<h5_int64_t(const OpalParticle&)> select) {
132  std::transform(particles.begin() + startIdx,
133  particles.begin() + startIdx + numParticles,
134  buffer, select);
135  }
136 
137  void cminmax(double &min, double &max, double val) {
138  if (-val > min) {
139  min = -val;
140  } else if (val > max) {
141  max = val;
142  }
143  }
144 }
145 
147  outputName_m(""),
148  spos_m(0.0),
149  refTime_m(0.0),
150  tmean_m(0.0),
151  trms_m(0.0),
152  nTotal_m(0),
153  RefPartR_m(0.0),
154  RefPartP_m(0.0),
155  rmin_m(0.0),
156  rmax_m(0.0),
157  rmean_m(0.0),
158  pmean_m(0.0),
159  rrms_m(0.0),
160  prms_m(0.0),
161  rprms_m(0.0),
162  normEmit_m(0.0),
163  rsqsum_m(0.0),
164  psqsum_m(0.0),
165  rpsum_m(0.0),
166  eps2_m(0.0),
167  eps_norm_m(0.0),
168  fac_m(0.0)
169  { }
170 
171 LossDataSink::LossDataSink(std::string outfn, bool hdf5Save, CollectionType collectionType):
172  h5hut_mode_m(hdf5Save),
173  H5file_m(0),
174  outputName_m(outfn),
175  H5call_m(0),
176  collectionType_m(collectionType)
177 {
178  particles_m.clear();
179  turnNumber_m.clear();
180  bunchNumber_m.clear();
181 
184  "LossDataSink::LossDataSink",
185  "You must select an OPTION to save Loss data files\n"
186  "Please, choose 'ENABLEHDF5=TRUE' or 'ASCIIDUMP=TRUE'");
187  }
188 
190 
191  if (OpalData::getInstance()->hasBunchAllocated()) {
193  }
194 }
195 
197  h5hut_mode_m(rhs.h5hut_mode_m),
198  H5file_m(rhs.H5file_m),
199  outputName_m(rhs.outputName_m),
200  H5call_m(rhs.H5call_m),
201  RefPartR_m(rhs.RefPartR_m),
202  RefPartP_m(rhs.RefPartP_m),
203  globalTrackStep_m(rhs.globalTrackStep_m),
204  refTime_m(rhs.refTime_m),
205  spos_m(rhs.spos_m),
206  collectionType_m(rhs.collectionType_m)
207 {
208  particles_m.clear();
209  turnNumber_m.clear();
210  bunchNumber_m.clear();
211 }
212 
213 LossDataSink::~LossDataSink() noexcept(false) {
214  if (H5file_m) {
215  CLOSE_FILE ();
216  H5file_m = 0;
217  }
218  Ippl::Comm->barrier();
219 }
220 
221 void LossDataSink::openH5(h5_int32_t mode) {
222  h5_prop_t props = H5CreateFileProp ();
223  MPI_Comm comm = Ippl::getComm();
224  H5SetPropFileMPIOCollective (props, &comm);
225  OPEN_FILE (fn_m.c_str(), mode, props);
226  H5CloseProp (props);
227 }
228 
229 
231 
232  // Write file attributes to describe phase space to H5 file.
233  std::stringstream OPAL_version;
234  OPAL_version << OPAL_PROJECT_NAME << " " << OPAL_PROJECT_VERSION << " # git rev. " << Util::getGitRevision();
235  WRITE_FILEATTRIB_STRING("OPAL_version", OPAL_version.str().c_str());
236 
237  WRITE_FILEATTRIB_STRING("SPOSUnit", "m");
238  WRITE_FILEATTRIB_STRING("TIMEUnit", "s");
239  WRITE_FILEATTRIB_STRING("RefPartRUnit", "m");
240  WRITE_FILEATTRIB_STRING("RefPartPUnit", "#beta#gamma");
241  WRITE_FILEATTRIB_STRING("GlobalTrackStepUnit", "1");
242 
243  WRITE_FILEATTRIB_STRING("centroidUnit", "m");
244  WRITE_FILEATTRIB_STRING("RMSXUnit", "m");
245  WRITE_FILEATTRIB_STRING("MEANPUnit", "#beta#gamma");
246  WRITE_FILEATTRIB_STRING("RMSPUnit", "#beta#gamma");
247  WRITE_FILEATTRIB_STRING("#varepsilonUnit", "m rad");
248  WRITE_FILEATTRIB_STRING("#varepsilon-geomUnit", "m rad");
249  WRITE_FILEATTRIB_STRING("ENERGYUnit", "MeV");
250  WRITE_FILEATTRIB_STRING("dEUnit", "MeV");
251  WRITE_FILEATTRIB_STRING("TotalChargeUnit", "C");
252  WRITE_FILEATTRIB_STRING("TotalMassUnit", "MeV");
253 
254  WRITE_FILEATTRIB_STRING("idUnit", "1");
255  WRITE_FILEATTRIB_STRING("xUnit", "m");
256  WRITE_FILEATTRIB_STRING("yUnit", "m");
257  WRITE_FILEATTRIB_STRING("zUnit", "m");
258  WRITE_FILEATTRIB_STRING("pxUnit", "#beta#gamma");
259  WRITE_FILEATTRIB_STRING("pyUnit", "#beta#gamma");
260  WRITE_FILEATTRIB_STRING("pzUnit", "#beta#gamma");
261  WRITE_FILEATTRIB_STRING("qUnit", "C");
262  WRITE_FILEATTRIB_STRING("mUnit", "MeV");
263 
264  WRITE_FILEATTRIB_STRING("turnUnit", "1");
265  WRITE_FILEATTRIB_STRING("bunchNumUnit", "1");
266 
267  WRITE_FILEATTRIB_STRING("timeUnit", "s");
268  WRITE_FILEATTRIB_STRING("meanTimeUnit", "s");
269  WRITE_FILEATTRIB_STRING("rmsTimeUnit", "s");
270 
272  WRITE_FILEATTRIB_STRING("type", "temporal");
273  } else {
274  WRITE_FILEATTRIB_STRING("type", "spatial");
275  }
276 }
277 
278 
280  bool hasTurn = hasTurnInformations();
281  if (Ippl::myNode() == 0) {
282  os_m << "# x (m), y (m), z (m), px ( ), py ( ), pz ( ), id";
283  if (hasTurn) {
284  os_m << ", turn ( ), bunchNumber ( )";
285  }
286  os_m << ", time (s)" << std::endl;
287  }
288 }
289 
291  const Vector_t &p,
292  double time,
293  double spos,
294  long long globalTrackStep
295  ) {
296  RefPartR_m.push_back(x);
297  RefPartP_m.push_back(p);
298  globalTrackStep_m.push_back((h5_int64_t)globalTrackStep);
299  spos_m.push_back(spos);
300  refTime_m.push_back(time);
301 }
302 
303 void LossDataSink::addParticle(const OpalParticle &particle, const boost::optional<std::pair<int, short>> &turnBunchNumPair) {
304  if (turnBunchNumPair) {
305  if (!particles_m.empty() && turnNumber_m.empty()) {
306  throw GeneralClassicException("LossDataSink::addParticle",
307  "Either no particle or all have turn number and bunch number");
308  }
309  turnNumber_m.push_back(turnBunchNumPair.get().first);
310  bunchNumber_m.push_back(turnBunchNumPair.get().second);
311  }
312 
313  particles_m.push_back(particle);
314 }
315 
316 void LossDataSink::save(unsigned int numSets, OpalData::OPENMODE openMode) {
317 
318  if (outputName_m.empty()) return;
319  if (hasNoParticlesToDump()) return;
320 
321  if (openMode == OpalData::OPENMODE::UNDEFINED) {
322  openMode = OpalData::getInstance()->getOpenMode();
323  }
324 
325  namespace fs = boost::filesystem;
326  if (h5hut_mode_m) {
327 
328  fn_m = outputName_m + std::string(".h5");
329  *gmsg << level2 << "Save " << fn_m << endl;
330  if (openMode == OpalData::OPENMODE::WRITE || !fs::exists(fn_m)) {
331  openH5();
332  writeHeaderH5();
333  } else {
334  openH5(H5_O_APPENDONLY);
335  GET_NUM_STEPS ();
336  }
337 
338  for (unsigned int i = 0; i < numSets; ++ i) {
339  saveH5(i);
340  }
341  CLOSE_FILE ();
342  H5file_m = 0;
343 
344  } else {
345 
346  fn_m = outputName_m + std::string(".loss");
347  *gmsg << level2 << "Save " << fn_m << endl;
348  if (openMode == OpalData::OPENMODE::WRITE || !fs::exists(fn_m)) {
349  openASCII();
351  } else {
352  appendASCII();
353  }
354  saveASCII();
355  closeASCII();
356  }
357 
358  Ippl::Comm->barrier();
359 
360  particles_m.clear();
361  turnNumber_m.clear();
362  bunchNumber_m.clear();
363  spos_m.clear();
364  refTime_m.clear();
365  RefPartR_m.clear();
366  RefPartP_m.clear();
367  globalTrackStep_m.clear();
368 }
369 
370 // Note: This was changed to calculate the global number of dumped particles
371 // because there are two cases to be considered:
372 // 1. ALL nodes have 0 lost particles -> nothing to be done.
373 // 2. Some nodes have 0 lost particles, some not -> H5 can handle that but all
374 // nodes HAVE to participate, otherwise H5 waits endlessly for a response from
375 // the nodes that didn't enter the saveH5 function. -DW
377 
378  size_t nLoc = particles_m.size();
379 
380  reduce(nLoc, nLoc, OpAddAssign());
381 
382  return nLoc == 0;
383 }
384 
386 
387  bool hasTurnInformation = !turnNumber_m.empty();
388 
389  allreduce(hasTurnInformation, 1, std::logical_or<bool>());
390 
391  return hasTurnInformation > 0;
392 }
393 
394 void LossDataSink::saveH5(unsigned int setIdx) {
395  size_t startIdx = 0, endIdx = 0;
396  size_t nLoc = particles_m.size();
397  if (setIdx + 1 < startSet_m.size()) {
398  startIdx = startSet_m[setIdx];
399  endIdx = startSet_m[setIdx + 1];
400  nLoc = endIdx - startIdx;
401  }
402 
403  std::unique_ptr<size_t[]> locN(new size_t[Ippl::getNodes()]);
404  std::unique_ptr<size_t[]> globN(new size_t[Ippl::getNodes()]);
405 
406  for (int i = 0; i < Ippl::getNodes(); i++) {
407  globN[i] = locN[i] = 0;
408  }
409 
410  locN[Ippl::myNode()] = nLoc;
411  reduce(locN.get(), locN.get() + Ippl::getNodes(), globN.get(), OpAddAssign());
412 
413  DistributionMoments engine;
414  engine.compute(particles_m.begin() + startIdx, particles_m.begin() + endIdx);
415 
417  SET_STEP ();
418  SET_NUM_PARTICLES (nLoc);
419 
420  if (setIdx < spos_m.size()) {
421  WRITE_STEPATTRIB_FLOAT64 ("SPOS", &(spos_m[setIdx]), 1);
422  WRITE_STEPATTRIB_FLOAT64 ("TIME", &(refTime_m[setIdx]), 1);
423  WRITE_STEPATTRIB_FLOAT64 ("RefPartR", (h5_float64_t *)&(RefPartR_m[setIdx]), 3);
424  WRITE_STEPATTRIB_FLOAT64 ("RefPartP", (h5_float64_t *)&(RefPartP_m[setIdx]), 3);
425  WRITE_STEPATTRIB_INT64("GlobalTrackStep", &(globalTrackStep_m[setIdx]), 1);
426  }
427 
428  Vector_t tmpVector;
429  double tmpDouble;
430  WRITE_STEPATTRIB_FLOAT64("centroid", (tmpVector = engine.getMeanPosition(), &tmpVector[0]), 3);
431  WRITE_STEPATTRIB_FLOAT64("RMSX", (tmpVector = engine.getStandardDeviationPosition(), &tmpVector[0]), 3);
432  WRITE_STEPATTRIB_FLOAT64("MEANP", (tmpVector = engine.getMeanMomentum(), &tmpVector[0]), 3);
433  WRITE_STEPATTRIB_FLOAT64("RMSP", (tmpVector = engine.getStandardDeviationMomentum(), &tmpVector[0]), 3);
434  WRITE_STEPATTRIB_FLOAT64("#varepsilon", (tmpVector = engine.getNormalizedEmittance(), &tmpVector[0]), 3);
435  WRITE_STEPATTRIB_FLOAT64("#varepsilon-geom", (tmpVector = engine.getGeometricEmittance(), &tmpVector[0]), 3);
436  WRITE_STEPATTRIB_FLOAT64("ENERGY", (tmpDouble = engine.getMeanKineticEnergy(), &tmpDouble), 1);
437  WRITE_STEPATTRIB_FLOAT64("dE", (tmpDouble = engine.getStdKineticEnergy(), &tmpDouble), 1);
438  WRITE_STEPATTRIB_FLOAT64("TotalCharge", (tmpDouble = engine.getTotalCharge(), &tmpDouble), 1);
439  WRITE_STEPATTRIB_FLOAT64("TotalMass", (tmpDouble = engine.getTotalMass(), &tmpDouble), 1);
440  WRITE_STEPATTRIB_FLOAT64("meanTime", (tmpDouble = engine.getMeanTime(), &tmpDouble), 1);
441  WRITE_STEPATTRIB_FLOAT64("rmsTime", (tmpDouble = engine.getStdTime(), &tmpDouble), 1);
442 
443  // Write all data
444  std::vector<char> buffer(nLoc * sizeof(h5_float64_t));
445  h5_float64_t *f64buffer = nLoc > 0? reinterpret_cast<h5_float64_t*>(&buffer[0]) : nullptr;
446  h5_int64_t *i64buffer = nLoc > 0? reinterpret_cast<h5_int64_t*>(&buffer[0]) : nullptr;
447 
448  ::i64transform(particles_m, startIdx, nLoc, i64buffer,
449  [](const OpalParticle &particle) { return particle.getId(); });
450  WRITE_DATA_INT64 ("id", i64buffer);
451  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
452  [](const OpalParticle &particle) { return particle.getX(); });
453  WRITE_DATA_FLOAT64 ("x", f64buffer);
454  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
455  [](const OpalParticle &particle) { return particle.getY(); });
456  WRITE_DATA_FLOAT64 ("y", f64buffer);
457  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
458  [](const OpalParticle &particle) { return particle.getZ(); });
459  WRITE_DATA_FLOAT64 ("z", f64buffer);
460  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
461  [](const OpalParticle &particle) { return particle.getPx(); });
462  WRITE_DATA_FLOAT64 ("px", f64buffer);
463  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
464  [](const OpalParticle &particle) { return particle.getPy(); });
465  WRITE_DATA_FLOAT64 ("py", f64buffer);
466  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
467  [](const OpalParticle &particle) { return particle.getPz(); });
468  WRITE_DATA_FLOAT64 ("pz", f64buffer);
469  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
470  [](const OpalParticle &particle) { return particle.getCharge(); });
471  WRITE_DATA_FLOAT64 ("q", f64buffer);
472  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
473  [](const OpalParticle &particle) { return particle.getMass(); });
474  WRITE_DATA_FLOAT64 ("m", f64buffer);
475 
476  if (hasTurnInformations()) {
477  std::copy(turnNumber_m.begin() + startIdx,
478  turnNumber_m.begin() + startIdx + nLoc,
479  i64buffer);
480  WRITE_DATA_INT64 ("turn", i64buffer);
481 
482  std::copy(bunchNumber_m.begin() + startIdx,
483  bunchNumber_m.begin() + startIdx + nLoc,
484  i64buffer);
485  WRITE_DATA_INT64 ("bunchNumber", i64buffer);
486  }
487 
488  ::f64transform(particles_m, startIdx, nLoc, f64buffer,
489  [](const OpalParticle &particle) { return particle.getTime(); });
490  WRITE_DATA_FLOAT64 ("time", f64buffer);
491 
492  ++ H5call_m;
493 }
494 
496 
497  /*
498  ASCII output
499  */
501  bool hasTurn = hasTurnInformations();
502  if (Ippl::Comm->myNode() == 0) {
503  const unsigned partCount = particles_m.size();
504 
505  for (unsigned i = 0; i < partCount; i++) {
506  const OpalParticle& particle = particles_m[i];
507  os_m << particle.getX() << " ";
508  os_m << particle.getY() << " ";
509  os_m << particle.getZ() << " ";
510  os_m << particle.getPx() << " ";
511  os_m << particle.getPy() << " ";
512  os_m << particle.getPz() << " ";
513  os_m << particle.getId() << " ";
514  if (hasTurn) {
515  os_m << turnNumber_m[i] << " ";
516  os_m << bunchNumber_m[i] << " ";
517  }
518  os_m << particle.getTime()
519  << std::endl;
520  }
521 
522  int notReceived = Ippl::getNodes() - 1;
523  while (notReceived > 0) {
524  unsigned dataBlocks = 0;
525  int node = COMM_ANY_NODE;
526  Message *rmsg = Ippl::Comm->receive_block(node, tag);
527  if (rmsg == 0) {
528  ERRORMSG("LossDataSink: Could not receive from client nodes output." << endl);
529  }
530  notReceived--;
531  rmsg->get(&dataBlocks);
532  rmsg->get(&hasTurn);
533  for (unsigned i = 0; i < dataBlocks; i++) {
534  long id;
535  size_t bunchNum, turn;
536  double rx, ry, rz, px, py, pz, time;
537 
538  os_m << (rmsg->get(&rx), rx) << " ";
539  os_m << (rmsg->get(&ry), ry) << " ";
540  os_m << (rmsg->get(&rz), rz) << " ";
541  os_m << (rmsg->get(&px), px) << " ";
542  os_m << (rmsg->get(&py), py) << " ";
543  os_m << (rmsg->get(&pz), pz) << " ";
544  os_m << (rmsg->get(&id), id) << " ";
545  if (hasTurn) {
546  os_m << (rmsg->get(&turn), turn) << " ";
547  os_m << (rmsg->get(&bunchNum), bunchNum) << " ";
548  }
549  os_m << (rmsg->get(&time), time)
550  << std::endl;
551  }
552  delete rmsg;
553  }
554  } else {
555  Message *smsg = new Message();
556  const unsigned msgsize = particles_m.size();
557  smsg->put(msgsize);
558  smsg->put(hasTurn);
559  for (unsigned i = 0; i < msgsize; i++) {
560  const OpalParticle& particle = particles_m[i];
561  smsg->put(particle.getX());
562  smsg->put(particle.getY());
563  smsg->put(particle.getZ());
564  smsg->put(particle.getPx());
565  smsg->put(particle.getPy());
566  smsg->put(particle.getPz());
567  smsg->put(particle.getId());
568  if (hasTurn) {
569  smsg->put(turnNumber_m[i]);
570  smsg->put(bunchNumber_m[i]);
571  }
572  smsg->put(particle.getTime());
573  }
574  bool res = Ippl::Comm->send(smsg, 0, tag);
575  if (!res) {
576  ERRORMSG("LossDataSink Ippl::Comm->send(smsg, 0, tag) failed " << endl);
577  }
578  }
579 }
580 
600 void LossDataSink::splitSets(unsigned int numSets) {
601  if (numSets <= 1 ||
602  particles_m.size() == 0) return;
603 
604  const size_t nLoc = particles_m.size();
605  size_t avgNumPerSet = nLoc / numSets;
606  std::vector<size_t> numPartsInSet(numSets, avgNumPerSet);
607  for (unsigned int j = 0; j < (nLoc - numSets * avgNumPerSet); ++ j) {
608  ++ numPartsInSet[j];
609  }
610  startSet_m.resize(numSets + 1, 0);
611 
612  std::vector<double> data(2 * numSets, 0.0);
613  double* meanT = &data[0];
614  double* numParticles = &data[numSets];
615  std::vector<double> timeRange(numSets, 0.0);
616  double maxT = particles_m[0].getTime();
617 
618  for (unsigned int iteration = 0; iteration < 2; ++ iteration) {
619  size_t partIdx = 0;
620  for (unsigned int j = 0; j < numSets; ++ j) {
621 
622  const size_t &numThisSet = numPartsInSet[j];
623  for (size_t k = 0; k < numThisSet; ++ k, ++ partIdx) {
624  meanT[j] += particles_m[partIdx].getTime();
625  maxT = std::max(maxT, particles_m[partIdx].getTime());
626  }
627  numParticles[j] = numThisSet;
628  }
629 
630  allreduce(&(data[0]), 2 * numSets, std::plus<double>());
631 
632  for (unsigned int j = 0; j < numSets; ++ j) {
633  meanT[j] /= numParticles[j];
634  }
635 
636  for (unsigned int j = 0; j < numSets - 1; ++ j) {
637  timeRange[j] = 0.5 * (meanT[j] + meanT[j + 1]);
638  }
639  timeRange[numSets - 1] = maxT;
640 
641  std::fill(numPartsInSet.begin(),
642  numPartsInSet.end(),
643  0);
644 
645  size_t setNum = 0;
646  size_t idxPrior = 0;
647  for (size_t idx = 0; idx < nLoc; ++ idx) {
648  if (particles_m[idx].getTime() > timeRange[setNum]) {
649  numPartsInSet[setNum] = idx - idxPrior;
650  idxPrior = idx;
651  ++ setNum;
652  }
653  }
654  numPartsInSet[numSets - 1] = nLoc - idxPrior;
655  }
656 
657  for (unsigned int i = 0; i < numSets; ++ i) {
658  startSet_m[i + 1] = startSet_m[i] + numPartsInSet[i];
659  }
660 }
661 
663  SetStatistics stat;
664  double part[6];
665 
666  const unsigned int totalSize = 45;
667  double plainData[totalSize];
668  double rminmax[6] = {};
669 
670  Util::KahanAccumulation data[totalSize];
671  Util::KahanAccumulation *localCentroid = data + 1;
672  Util::KahanAccumulation *localMoments = data + 7;
673  Util::KahanAccumulation *localOthers = data + 43;
674 
675  size_t startIdx = 0;
676  size_t nLoc = particles_m.size();
677  if (setIdx + 1 < startSet_m.size()) {
678  startIdx = startSet_m[setIdx];
679  nLoc = startSet_m[setIdx + 1] - startSet_m[setIdx];
680  }
681 
682  data[0].sum = nLoc;
683 
684  unsigned int idx = startIdx;
685  for (unsigned long k = 0; k < nLoc; ++ k, ++ idx) {
686  const OpalParticle& particle = particles_m[idx];
687 
688  part[0] = particle.getX();
689  part[1] = particle.getPx();
690  part[2] = particle.getY();
691  part[3] = particle.getPy();
692  part[4] = particle.getZ();
693  part[5] = particle.getPz();
694 
695  for (int i = 0; i < 6; i++) {
696  localCentroid[i] += part[i];
697  for (int j = 0; j <= i; j++) {
698  localMoments[i * 6 + j] += part[i] * part[j];
699  }
700  }
701  localOthers[0] += particle.getTime();
702  localOthers[1] += std::pow(particle.getTime(), 2);
703 
704  ::cminmax(rminmax[0], rminmax[1], particle.getX());
705  ::cminmax(rminmax[2], rminmax[3], particle.getY());
706  ::cminmax(rminmax[4], rminmax[5], particle.getZ());
707  }
708 
709  for (int i = 0; i < 6; i++) {
710  for (int j = 0; j < i; j++) {
711  localMoments[j * 6 + i] = localMoments[i * 6 + j];
712  }
713  }
714 
715  for (unsigned int i = 0; i < totalSize; ++ i) {
716  plainData[i] = data[i].sum;
717  }
718 
719  new_reduce(plainData, totalSize, std::plus<double>());
720  new_reduce(rminmax, 6, std::greater<double>());
721 
722  if (Ippl::myNode() != 0) return stat;
723  if (plainData[0] == 0.0) return stat;
724 
725  double *centroid = plainData + 1;
726  double *moments = plainData + 7;
727  double *others = plainData + 43;
728 
729  stat.outputName_m = outputName_m;
730  stat.spos_m = spos_m[setIdx];
731  stat.refTime_m = refTime_m[setIdx];
732  stat.RefPartR_m = RefPartR_m[setIdx];
733  stat.RefPartP_m = RefPartP_m[setIdx];
734  stat.nTotal_m = (unsigned long)std::round(plainData[0]);
735 
736  for (unsigned int i = 0 ; i < 3u; i++) {
737  stat.rmean_m(i) = centroid[2 * i] / stat.nTotal_m;
738  stat.pmean_m(i) = centroid[(2 * i) + 1] / stat.nTotal_m;
739  stat.rsqsum_m(i) = (moments[2 * i * 6 + 2 * i] -
740  stat.nTotal_m * std::pow(stat.rmean_m(i), 2));
741  stat.psqsum_m(i) = std::max(0.0,
742  moments[(2 * i + 1) * 6 + (2 * i) + 1] -
743  stat.nTotal_m * std::pow(stat.pmean_m(i), 2));
744  stat.rpsum_m(i) = (moments[(2 * i) * 6 + (2 * i) + 1] -
745  stat.nTotal_m * stat.rmean_m(i) * stat.pmean_m(i));
746  }
747  stat.tmean_m = others[0] / stat.nTotal_m;
748  stat.trms_m = std::sqrt(std::max(0.0, (others[1] / stat.nTotal_m - std::pow(stat.tmean_m, 2))));
749 
750  stat.eps2_m = ((stat.rsqsum_m * stat.psqsum_m - stat.rpsum_m * stat.rpsum_m) /
751  (1.0 * stat.nTotal_m * stat.nTotal_m));
752 
753  stat.rpsum_m /= stat.nTotal_m;
754 
755  for (unsigned int i = 0 ; i < 3u; i++) {
756  stat.rrms_m(i) = std::sqrt(std::max(0.0, stat.rsqsum_m(i)) / stat.nTotal_m);
757  stat.prms_m(i) = std::sqrt(std::max(0.0, stat.psqsum_m(i)) / stat.nTotal_m);
758  stat.eps_norm_m(i) = std::sqrt(std::max(0.0, stat.eps2_m(i)));
759  double tmp = stat.rrms_m(i) * stat.prms_m(i);
760  stat.fac_m(i) = (tmp == 0) ? 0.0 : 1.0 / tmp;
761  stat.rmin_m(i) = -rminmax[2 * i];
762  stat.rmax_m(i) = rminmax[2 * i + 1];
763  }
764 
765  stat.rprms_m = stat.rpsum_m * stat.fac_m;
766 
767  return stat;
768 }
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
#define GET_NUM_STEPS()
#define OPEN_FILE(fname, mode, props)
#define SET_STEP()
#define WRITE_DATA_FLOAT64(name, value)
#define WRITE_STEPATTRIB_INT64(attribute, value, size)
#define WRITE_FILEATTRIB_STRING(attribute, value)
#define SET_NUM_PARTICLES(num)
#define WRITE_STEPATTRIB_FLOAT64(attribute, value, size)
#define WRITE_DATA_INT64(name, value)
Inform * gmsg
Definition: Main.cpp:62
#define CLOSE_FILE()
CollectionType
Definition: LossDataSink.h:72
#define OPAL_PROJECT_VERSION
Definition: OPALconfig.h:5
#define OPAL_PROJECT_NAME
Definition: OPALconfig.h:2
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
const int COMM_ANY_NODE
Definition: Communicate.h:40
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
Definition: GlobalComm.hpp:55
void new_reduce(const T *input, T *output, int count, Op op, int root=0)
Definition: GlobalComm.hpp:477
#define IPPL_APP_CYCLE
Definition: Tags.h:103
#define IPPL_APP_TAG3
Definition: Tags.h:96
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
bool enableHDF5
If true HDF5 files are written.
Definition: Options.cpp:81
std::string getGitRevision()
Definition: Util.cpp:18
FRONT * fs
Definition: hypervolume.cpp:59
void setOpenMode(OPENMODE openMode)
Definition: OpalData.cpp:348
OPENMODE getOpenMode() const
Definition: OpalData.cpp:352
void checkAndAddOutputFileName(const std::string &outfn)
checks the output file names of all items to avoid duplicates
Definition: OpalData.cpp:664
OPENMODE
Enum for writing to files.
Definition: OpalData.h:64
static OpalData * getInstance()
Definition: OpalData.cpp:195
Vector_t getStandardDeviationMomentum() const
double getMeanKineticEnergy() const
Vector_t getStandardDeviationPosition() const
double getTotalCharge() const
Vector_t getMeanPosition() const
void compute(const std::vector< OpalParticle >::const_iterator &, const std::vector< OpalParticle >::const_iterator &)
double getStdKineticEnergy() const
Vector_t getNormalizedEmittance() const
double getTotalMass() const
Vector_t getMeanMomentum() const
double getMeanTime() const
Vector_t getGeometricEmittance() const
double getPy() const
Get vertical momentum (no dimension).
Definition: OpalParticle.h:213
double getPz() const
Get relative momentum error (no dimension).
Definition: OpalParticle.h:219
double getY() const
Get vertical displacement in m.
Definition: OpalParticle.h:195
double getCharge() const
Get charge in Coulomb.
Definition: OpalParticle.h:243
double getZ() const
Get longitudinal displacement c*t in m.
Definition: OpalParticle.h:201
double getMass() const
Get mass in GeV/c^2.
Definition: OpalParticle.h:249
double getTime() const
Get time.
Definition: OpalParticle.h:237
int64_t getId() const
Get the id of the particle.
Definition: OpalParticle.h:176
double getPx() const
Get horizontal momentum (no dimension).
Definition: OpalParticle.h:207
double getX() const
Get horizontal position in m.
Definition: OpalParticle.h:189
Vector_t eps_norm_m
Definition: LossDataSink.h:60
Vector_t rmax_m
Definition: LossDataSink.h:49
Vector_t RefPartP_m
Definition: LossDataSink.h:47
std::string outputName_m
Definition: LossDataSink.h:40
Vector_t prms_m
Definition: LossDataSink.h:53
Vector_t pmean_m
Definition: LossDataSink.h:51
Vector_t psqsum_m
Definition: LossDataSink.h:57
double tmean_m
Definition: LossDataSink.h:43
Vector_t rmean_m
Definition: LossDataSink.h:50
unsigned long nTotal_m
Definition: LossDataSink.h:45
Vector_t rsqsum_m
Definition: LossDataSink.h:56
Vector_t eps2_m
Definition: LossDataSink.h:59
Vector_t rrms_m
Definition: LossDataSink.h:52
Vector_t fac_m
Definition: LossDataSink.h:61
Vector_t RefPartR_m
Definition: LossDataSink.h:46
Vector_t rpsum_m
Definition: LossDataSink.h:58
Vector_t rmin_m
Definition: LossDataSink.h:48
double refTime_m
Definition: LossDataSink.h:42
Vector_t rprms_m
Definition: LossDataSink.h:54
std::vector< size_t > turnNumber_m
Definition: LossDataSink.h:160
std::vector< Vector_t > RefPartR_m
Definition: LossDataSink.h:162
void addReferenceParticle(const Vector_t &x, const Vector_t &p, double time, double spos, long long globalTrackStep)
void openASCII()
Definition: LossDataSink.h:108
h5_file_t H5file_m
used to write out data in H5hut mode
Definition: LossDataSink.h:151
void addParticle(const OpalParticle &, const boost::optional< std::pair< int, short int >> &turnBunchNumPair=boost::none)
~LossDataSink() noexcept(false)
void writeHeaderH5()
std::string fn_m
Definition: LossDataSink.h:142
std::vector< double > refTime_m
Definition: LossDataSink.h:165
CollectionType collectionType_m
Definition: LossDataSink.h:170
std::string outputName_m
Definition: LossDataSink.h:153
void writeHeaderASCII()
std::ofstream os_m
Definition: LossDataSink.h:148
std::vector< Vector_t > RefPartP_m
Definition: LossDataSink.h:163
h5_int64_t H5call_m
Current record, or time step, of H5 file.
Definition: LossDataSink.h:156
std::vector< size_t > bunchNumber_m
Definition: LossDataSink.h:159
std::vector< double > spos_m
Definition: LossDataSink.h:166
void openH5(h5_int32_t mode=H5_O_WRONLY)
SetStatistics computeSetStatistics(unsigned int setIdx)
void splitSets(unsigned int numSets)
std::vector< OpalParticle > particles_m
Definition: LossDataSink.h:158
void save(unsigned int numSets=1, OpalData::OPENMODE openMode=OpalData::OPENMODE::UNDEFINED)
bool hasTurnInformations() const
void appendASCII()
Definition: LossDataSink.h:115
void saveH5(unsigned int setIdx)
std::vector< h5_int64_t > globalTrackStep_m
Definition: LossDataSink.h:164
LossDataSink()=default
void closeASCII()
Definition: LossDataSink.h:127
bool hasNoParticlesToDump() const
std::vector< unsigned long > startSet_m
Definition: LossDataSink.h:168
long double sum
Definition: Util.h:188
bool send(Message *, int node, int tag, bool delmsg=true)
Message * receive_block(int &node, int &tag)
void barrier(void)
Message & put(const T &val)
Definition: Message.h:406
Message & get(const T &cval)
Definition: Message.h:476
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
Definition: Inform.h:42
static MPI_Comm getComm()
Definition: IpplInfo.h:152
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84