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