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
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
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
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 */
547 int tag = Ippl::Comm->next_tag(IPPL_APP_TAG3, IPPL_APP_CYCLE);
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)
#define CLOSE_FILE()
CollectionType
Inform * gmsg
Definition Main.cpp:70
void allreduce(const T *input, T *output, int count, Op op)
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
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)
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
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
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
Vector_t getMeanMomentum() const
Vector_t get95Percentile() const
Vector_t get68Percentile() const
Vector_t getGeometricEmittance() const
double getPy() const
Get vertical momentum (no dimension).
double getPz() const
Get relative momentum error (no dimension).
double getY() const
Get vertical displacement in m.
double getCharge() const
Get charge in Coulomb.
double getZ() const
Get longitudinal displacement c*t in m.
double getMass() const
Get mass in GeV/c^2.
double getTime() const
Get time.
int64_t getId() const
Get the id of the particle.
double getPx() const
Get horizontal momentum (no dimension).
double getX() const
Get horizontal position in m.
Vector_t eps_norm_m
Vector_t rmax_m
Vector_t RefPartP_m
std::string outputName_m
Vector_t prms_m
Vector_t pmean_m
Vector_t psqsum_m
Vector_t rmean_m
unsigned long nTotal_m
Vector_t rsqsum_m
Vector_t eps2_m
Vector_t normEmit_m
Vector_t rrms_m
Vector_t fac_m
Vector_t RefPartR_m
Vector_t rpsum_m
Vector_t rmin_m
Vector_t rprms_m
std::vector< size_t > turnNumber_m
std::vector< Vector_t > RefPartR_m
void addReferenceParticle(const Vector_t &x, const Vector_t &p, double time, double spos, long long globalTrackStep)
h5_file_t H5file_m
used to write out data in H5hut mode
~LossDataSink() noexcept(false)
std::vector< double > refTime_m
CollectionType collectionType_m
std::string outputName_m
void writeHeaderASCII()
void save(unsigned int numSets=1, OpalData::OpenMode openMode=OpalData::OpenMode::UNDEFINED)
std::ofstream os_m
std::vector< Vector_t > RefPartP_m
h5_int64_t H5call_m
Current record, or time step, of H5 file.
std::vector< size_t > bunchNumber_m
std::string fileName_m
std::vector< double > spos_m
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)
std::vector< OpalParticle > particles_m
bool hasTurnInformations() const
void appendASCII()
void saveH5(unsigned int setIdx)
std::vector< h5_int64_t > globalTrackStep_m
LossDataSink()=default
void closeASCII()
bool hasNoParticlesToDump() const
std::vector< unsigned long > startSet_m
long double sum
Definition Util.h:234
Message & put(const T &val)
Definition Message.h:406
Message & get(const T &cval)
Definition Message.h:476
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
Vektor< double, 3 > Vector_t