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