OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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//
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
33extern 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
128namespace {
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
180LossDataSink::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
221 if (H5file_m) {
222 CLOSE_FILE();
223 H5file_m = 0;
224 }
225}
226
227void 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
329void LossDataSink::save(unsigned int numSets, OpalData::OpenMode openMode) {
330 if (outputName_m.empty())
331 return;
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();
345 } else {
346 openH5(H5_O_APPENDONLY);
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
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
405void 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
645void 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
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}
#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:70
#define CLOSE_FILE()
CollectionType
Definition: LossDataSink.h:71
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
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
const int COMM_ANY_NODE
Definition: Communicate.h:40
#define IPPL_APP_CYCLE
Definition: Tags.h:103
#define IPPL_APP_TAG3
Definition: Tags.h:96
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
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
bool computePercentiles
Definition: Options.cpp:111
bool enableHDF5
If true HDF5 files are written.
Definition: Options.cpp:81
std::string getGitRevision()
Definition: Util.cpp:33
double function(PyOpalObjectNS::PyOpalObject< C > pyobject, double t)
FRONT * fs
Definition: hypervolume.cpp:59
void checkAndAddOutputFileName(const std::string &outfn)
checks the output file names of all items to avoid duplicates
Definition: OpalData.cpp:680
OpenMode getOpenMode() const
Definition: OpalData.cpp:353
static OpalData * getInstance()
Definition: OpalData.cpp:196
OpenMode
Enum for writing to files.
Definition: OpalData.h:64
void setOpenMode(OpenMode openMode)
Definition: OpalData.cpp:349
Vector_t getStandardDeviationMomentum() const
Vector_t get99Percentile() const
double getMeanKineticEnergy() const
Vector_t getStandardDeviationPosition() const
Vector_t getNormalizedEmittance95Percentile() const
Vector_t getNormalizedEmittance68Percentile() const
double getTotalCharge() const
Vector_t getNormalizedEmittance99_99Percentile() const
Vector_t getNormalizedEmittance99Percentile() const
Vector_t getMeanPosition() const
Vector_t get99_99Percentile() 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
Vector_t getMaxR() const
Vector_t get95Percentile() const
Vector_t get68Percentile() 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:59
Vector_t rmax_m
Definition: LossDataSink.h:48
Vector_t RefPartP_m
Definition: LossDataSink.h:46
std::string outputName_m
Definition: LossDataSink.h:39
Vector_t prms_m
Definition: LossDataSink.h:52
Vector_t pmean_m
Definition: LossDataSink.h:50
Vector_t psqsum_m
Definition: LossDataSink.h:56
double tmean_m
Definition: LossDataSink.h:42
Vector_t rmean_m
Definition: LossDataSink.h:49
unsigned long nTotal_m
Definition: LossDataSink.h:44
Vector_t rsqsum_m
Definition: LossDataSink.h:55
Vector_t eps2_m
Definition: LossDataSink.h:58
Vector_t rrms_m
Definition: LossDataSink.h:51
Vector_t fac_m
Definition: LossDataSink.h:60
Vector_t RefPartR_m
Definition: LossDataSink.h:45
Vector_t rpsum_m
Definition: LossDataSink.h:57
Vector_t rmin_m
Definition: LossDataSink.h:47
double refTime_m
Definition: LossDataSink.h:41
Vector_t rprms_m
Definition: LossDataSink.h:53
std::vector< size_t > turnNumber_m
Definition: LossDataSink.h:159
std::vector< Vector_t > RefPartR_m
Definition: LossDataSink.h:161
void addReferenceParticle(const Vector_t &x, const Vector_t &p, double time, double spos, long long globalTrackStep)
void openASCII()
Definition: LossDataSink.h:107
h5_file_t H5file_m
used to write out data in H5hut mode
Definition: LossDataSink.h:149
~LossDataSink() noexcept(false)
void writeHeaderH5()
std::vector< double > refTime_m
Definition: LossDataSink.h:164
CollectionType collectionType_m
Definition: LossDataSink.h:169
std::string outputName_m
Definition: LossDataSink.h:152
void writeHeaderASCII()
void save(unsigned int numSets=1, OpalData::OpenMode openMode=OpalData::OpenMode::UNDEFINED)
std::ofstream os_m
Definition: LossDataSink.h:146
std::vector< Vector_t > RefPartP_m
Definition: LossDataSink.h:162
h5_int64_t H5call_m
Current record, or time step, of H5 file.
Definition: LossDataSink.h:155
std::vector< size_t > bunchNumber_m
Definition: LossDataSink.h:158
std::string fileName_m
Definition: LossDataSink.h:140
std::vector< double > spos_m
Definition: LossDataSink.h:165
void addParticle(const OpalParticle &, const boost::optional< std::pair< int, short int > > &turnBunchNumPair=boost::none)
void openH5(h5_int32_t mode=H5_O_WRONLY)
SetStatistics computeSetStatistics(unsigned int setIdx)
void splitSets(unsigned int numSets)
In Opal-T monitors can be traversed several times.
std::vector< OpalParticle > particles_m
Definition: LossDataSink.h:157
bool hasTurnInformations() const
void appendASCII()
Definition: LossDataSink.h:114
void saveH5(unsigned int setIdx)
std::vector< h5_int64_t > globalTrackStep_m
Definition: LossDataSink.h:163
LossDataSink()=default
void closeASCII()
Definition: LossDataSink.h:126
bool hasNoParticlesToDump() const
std::vector< unsigned long > startSet_m
Definition: LossDataSink.h:167
long double sum
Definition: Util.h:234
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