OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
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) 2026, 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
21#include "BuildInfo.h"
24#include "Utilities/Options.h"
25#include "Utilities/Util.h"
26#include "Utility/IpplInfo.h"
27
28#include <algorithm>
29#include <array>
30#include <cmath>
31#include <filesystem>
32#include <functional>
33#include <limits>
34#include <numeric>
35#include <sstream>
36#include <tuple>
37
38extern Inform* gmsg;
39
40void LossDataSink::writeFileAttribString(const char* attribute, const char* value) {
41 const h5_int64_t h5err = H5WriteFileAttribString(H5file_m, attribute, value);
42
43 if (h5err <= H5_ERR) {
44 std::stringstream ss;
45 ss << "failed to write string attribute " << attribute << " to file " << fileName_m;
46 throw GeneralOpalException("LossDataSink::writeFileAttribString", ss.str());
47 }
48}
49
51 const char* attribute, const h5_float64_t* value, h5_int64_t size) {
52 const h5_int64_t h5err = H5WriteStepAttribFloat64(H5file_m, attribute, value, size);
53
54 if (h5err <= H5_ERR) {
55 std::stringstream ss;
56 ss << "failed to write float64 attribute " << attribute << " to file " << fileName_m;
57 throw GeneralOpalException("LossDataSink::writeStepAttribFloat64", ss.str());
58 }
59}
60
62 const char* attribute, const h5_int64_t* value, h5_int64_t size) {
63 const h5_int64_t h5err = H5WriteStepAttribInt64(H5file_m, attribute, value, size);
64
65 if (h5err <= H5_ERR) {
66 std::stringstream ss;
67 ss << "failed to write int64 attribute " << attribute << " to file " << fileName_m;
68 throw GeneralOpalException("LossDataSink::writeStepAttribInt64", ss.str());
69 }
70}
71
72void LossDataSink::writeDataFloat64(const char* name, const h5_float64_t* value) {
73 const h5_int64_t h5err = H5PartWriteDataFloat64(H5file_m, name, value);
74
75 if (h5err <= H5_ERR) {
76 std::stringstream ss;
77 ss << "failed to write float64 data " << name << " to file " << fileName_m;
78 throw GeneralOpalException("LossDataSink::writeDataFloat64", ss.str());
79 }
80}
81
82void LossDataSink::writeDataInt64(const char* name, const h5_int64_t* value) {
83 const h5_int64_t h5err = H5PartWriteDataInt64(H5file_m, name, value);
84
85 if (h5err <= H5_ERR) {
86 std::stringstream ss;
87 ss << "failed to write int64 data " << name << " to file " << fileName_m;
88 throw GeneralOpalException("LossDataSink::writeDataInt64", ss.str());
89 }
90}
91
93 const h5_int64_t h5err = H5SetStep(H5file_m, H5call_m);
94
95 if (h5err <= H5_ERR) {
96 std::stringstream ss;
97 ss << "failed to set step " << H5call_m << " in file " << fileName_m;
98 throw GeneralOpalException("LossDataSink::setStep", ss.str());
99 }
100}
101
103 H5call_m = H5GetNumSteps(H5file_m);
104
105 if (H5call_m <= H5_ERR) {
106 std::stringstream ss;
107 ss << "failed to get number of steps of file " << fileName_m;
108 throw GeneralOpalException("LossDataSink::getNumSteps", ss.str());
109 }
110}
111
112void LossDataSink::setNumParticles(h5_int64_t num) {
113 const h5_int64_t h5err = H5PartSetNumParticles(H5file_m, num);
114
115 if (h5err <= H5_ERR) {
116 std::stringstream ss;
117 ss << "failed to set number of particles to " << num << " in step " << H5call_m
118 << " in file " << fileName_m;
119 throw GeneralOpalException("LossDataSink::setNumParticles", ss.str());
120 }
121}
122
123void LossDataSink::openFile(const char* fname, h5_int32_t mode, h5_prop_t props) {
124 H5file_m = H5OpenFile(fname, mode, props);
125
126 if (H5file_m == static_cast<h5_file_t>(H5_ERR)) {
127 std::stringstream ss;
128 ss << "failed to open file " << fileName_m;
129 throw GeneralOpalException("LossDataSink::openFile", ss.str());
130 }
131}
132
134 const h5_int64_t h5err = H5CloseFile(H5file_m);
135
136 if (h5err <= H5_ERR) {
137 std::stringstream ss;
138 ss << "failed to close file " << fileName_m;
139 throw GeneralOpalException("LossDataSink::closeFile", ss.str());
140 }
141
142 H5file_m = 0;
143}
144
145namespace {
146 constexpr double percentileOneSigmaNormalDist = 0.6826894921370859;
147
148 constexpr double percentileTwoSigmasNormalDist = 0.9544997361036416;
149
150 constexpr double percentileThreeSigmasNormalDist = 0.9973002039367398;
151
152 constexpr double percentileFourSigmasNormalDist = 0.9999366575163338;
153
154 int percentileParticleCount(unsigned long nTotal, double fraction) {
155 const double value = std::floor(static_cast<double>(nTotal) * fraction + 0.5);
156
157 if (value > static_cast<double>(std::numeric_limits<int>::max())) {
158 std::stringstream ss;
159 ss << "Percentile particle count " << value << " does not fit into int.";
160
161 throw GeneralOpalException("LossDataSink::computeSetPercentiles", ss.str());
162 }
163
164 return static_cast<int>(value);
165 }
166
167 using OneDPhaseSpace_t = std::array<double, 2>;
168 using OneDIterator_t = std::vector<OneDPhaseSpace_t>::iterator;
169
170 void f64transform(
171 const std::vector<OpalParticle>& particles, size_t startIdx, size_t numParticles,
172 h5_float64_t* buffer, std::function<h5_float64_t(const OpalParticle&)> select) {
173 std::transform(
174 particles.begin() + startIdx, particles.begin() + startIdx + numParticles, buffer,
175 select);
176 }
177
178 void i64transform(
179 const std::vector<OpalParticle>& particles, size_t startIdx, size_t numParticles,
180 h5_int64_t* buffer, std::function<h5_int64_t(const OpalParticle&)> select) {
181 std::transform(
182 particles.begin() + startIdx, particles.begin() + startIdx + numParticles, buffer,
183 select);
184 }
185
186 std::pair<double, OneDIterator_t> determinePercentileRange(
187 const OneDIterator_t& begin, const OneDIterator_t& end,
188 const std::vector<int>& globalAccumulatedHistogram,
189 const std::vector<int>& localAccumulatedHistogram, unsigned int dimension,
190 int numRequiredParticles, double meanR) {
191 const unsigned int numBins = globalAccumulatedHistogram.size() / 3;
192
193 double percentile = 0.0;
194 OneDIterator_t endPercentile = end;
195
196 for (unsigned int i = 1; i < numBins; ++i) {
197 const unsigned int idx = dimension * numBins + i;
198
199 if (globalAccumulatedHistogram[idx] > numRequiredParticles) {
200 OneDIterator_t beginBin = begin + localAccumulatedHistogram[idx - 1];
201 OneDIterator_t endBin = begin + localAccumulatedHistogram[idx];
202
203 int numMissingParticles =
204 numRequiredParticles - globalAccumulatedHistogram[idx - 1];
205
206 unsigned int shift = 2;
207 while (numMissingParticles == 0 && idx >= shift) {
208 beginBin = begin + localAccumulatedHistogram[idx - shift];
209 numMissingParticles =
210 numRequiredParticles - globalAccumulatedHistogram[idx - shift];
211 ++shift;
212 }
213
214 std::vector<unsigned int> numParticlesInBin(ippl::Comm->size() + 1, 0);
215 numParticlesInBin[ippl::Comm->rank() + 1] =
216 static_cast<unsigned int>(endBin - beginBin);
217
218 ippl::Comm->allreduce(
219 &(numParticlesInBin[1]), ippl::Comm->size(), std::plus<unsigned int>());
220
221 std::partial_sum(
222 numParticlesInBin.begin(), numParticlesInBin.end(),
223 numParticlesInBin.begin());
224
225 std::vector<double> positions(numParticlesInBin.back(), 0.0);
226
227 std::transform(
228 beginBin, endBin, positions.begin() + numParticlesInBin[ippl::Comm->rank()],
229 [meanR](const OneDPhaseSpace_t& particle) {
230 return std::abs(particle[0] - meanR);
231 });
232
233 if (!positions.empty()) {
234 ippl::Comm->allreduce(positions.data(), positions.size(), std::plus<double>());
235
236 std::sort(positions.begin(), positions.end());
237
238 const auto rhs = static_cast<std::size_t>(std::min<int>(
239 numMissingParticles, static_cast<int>(positions.size()) - 1));
240
241 const auto lhs = rhs == 0 ? 0 : rhs - 1;
242
243 percentile = 0.5 * (positions[lhs] + positions[rhs]);
244 }
245
246 for (OneDIterator_t it = beginBin; it != endBin; ++it) {
247 if (std::abs((*it)[0] - meanR) > percentile) {
248 return std::make_pair(percentile, it);
249 }
250 }
251
252 endPercentile = endBin;
253 break;
254 }
255 }
256
257 return std::make_pair(percentile, endPercentile);
258 }
259
260 double computeNormalizedEmittance(const OneDIterator_t& begin, const OneDIterator_t& end) {
261 double localStatistics[] = {0.0, 0.0, 0.0, 0.0};
262
263 localStatistics[0] = static_cast<double>(end - begin);
264
265 for (OneDIterator_t it = begin; it < end; ++it) {
266 const OneDPhaseSpace_t& rp = *it;
267
268 localStatistics[1] += rp[0];
269 localStatistics[2] += rp[1];
270 localStatistics[3] += rp[0] * rp[1];
271 }
272
273 ippl::Comm->allreduce(localStatistics, 4, std::plus<double>());
274
275 const double numParticles = localStatistics[0];
276
277 if (numParticles == 0.0) {
278 return 0.0;
279 }
280
281 const double perParticle = 1.0 / numParticles;
282 const double meanR = localStatistics[1] * perParticle;
283 const double meanP = localStatistics[2] * perParticle;
284 const double RP = localStatistics[3] * perParticle;
285
286 double varianceStatistics[] = {0.0, 0.0};
287
288 for (OneDIterator_t it = begin; it < end; ++it) {
289 const OneDPhaseSpace_t& rp = *it;
290
291 varianceStatistics[0] += std::pow(rp[0] - meanR, 2);
292 varianceStatistics[1] += std::pow(rp[1] - meanP, 2);
293 }
294
295 ippl::Comm->allreduce(varianceStatistics, 2, std::plus<double>());
296
297 const double stdR = std::sqrt(varianceStatistics[0] / numParticles);
298 const double stdP = std::sqrt(varianceStatistics[1] / numParticles);
299
300 const double sumRP = RP - meanR * meanP;
301 const double squaredEps = std::pow(stdR * stdP, 2) - std::pow(sumRP, 2);
302
303 return std::sqrt(std::max(squaredEps, 0.0));
304 }
305
306 void computeSetPercentiles(
307 const std::vector<OpalParticle>& particles, size_t startIdx, size_t nLoc,
308 SetStatistics& stat) {
309 if (!Options::computePercentiles || stat.nTotal_m < 100) {
310 return;
311 }
312
313 unsigned int numBins = static_cast<unsigned int>(
314 3.5 * std::pow(3.0, std::log10(static_cast<double>(stat.nTotal_m))));
315
316 numBins = std::max(1u, numBins);
317
318 std::vector<gsl_histogram*> histograms(3, nullptr);
319
320 Vector_t<double, 3> maxR(0.0);
321
322 for (unsigned int d = 0; d < 3; ++d) {
323 maxR(d) =
324 1.0000001
325 * std::max(stat.rmax_m(d) - stat.rmean_m(d), stat.rmean_m(d) - stat.rmin_m(d));
326
327 if (maxR(d) <= 0.0) {
328 maxR(d) = 1.0e-30;
329 }
330
331 histograms[d] = gsl_histogram_alloc(numBins);
332 gsl_histogram_set_ranges_uniform(histograms[d], 0.0, maxR(d));
333 }
334
335 for (size_t k = 0; k < nLoc; ++k) {
336 const OpalParticle& particle = particles[startIdx + k];
337
338 for (unsigned int d = 0; d < 3; ++d) {
339 gsl_histogram_increment(histograms[d], std::abs(particle[2 * d] - stat.rmean_m(d)));
340 }
341 }
342
343 std::vector<int> localHistogramValues(3 * (numBins + 1), 0);
344 std::vector<int> globalHistogramValues(3 * (numBins + 1), 0);
345
346 for (unsigned int d = 0; d < 3; ++d) {
347 int accumulated = 0;
348
349 for (unsigned int j = 0; j < numBins; ++j) {
350 accumulated += static_cast<int>(gsl_histogram_get(histograms[d], j));
351 localHistogramValues[d * (numBins + 1) + j + 1] = accumulated;
352 }
353
354 gsl_histogram_free(histograms[d]);
355 }
356
357 ippl::Comm->allreduce(
358 localHistogramValues.data(), globalHistogramValues.data(), 3 * (numBins + 1),
359 std::plus<int>());
360
361 const int numParticles68 =
362 percentileParticleCount(stat.nTotal_m, percentileOneSigmaNormalDist);
363
364 const int numParticles95 =
365 percentileParticleCount(stat.nTotal_m, percentileTwoSigmasNormalDist);
366
367 const int numParticles99 =
368 percentileParticleCount(stat.nTotal_m, percentileThreeSigmasNormalDist);
369
370 const int numParticles99_99 =
371 percentileParticleCount(stat.nTotal_m, percentileFourSigmasNormalDist);
372
373 for (unsigned int d = 0; d < 3; ++d) {
374 std::vector<OneDPhaseSpace_t> oneDPhaseSpace(nLoc);
375
376 for (size_t k = 0; k < nLoc; ++k) {
377 const OpalParticle& particle = particles[startIdx + k];
378
379 oneDPhaseSpace[k][0] = particle[2 * d];
380 oneDPhaseSpace[k][1] = particle[2 * d + 1];
381 }
382
383 std::sort(
384 oneDPhaseSpace.begin(), oneDPhaseSpace.end(),
385 [d, &stat](const OneDPhaseSpace_t& left, const OneDPhaseSpace_t& right) {
386 return std::abs(left[0] - stat.rmean_m(d))
387 < std::abs(right[0] - stat.rmean_m(d));
388 });
389
390 OneDIterator_t endSixtyEight = oneDPhaseSpace.end();
391 OneDIterator_t endNinetyFive = oneDPhaseSpace.end();
392 OneDIterator_t endNinetyNine = oneDPhaseSpace.end();
393 OneDIterator_t endNinetyNine_NinetyNine = oneDPhaseSpace.end();
394
395 std::tie(stat.sixtyEightPercentile_m(d), endSixtyEight) = determinePercentileRange(
396 oneDPhaseSpace.begin(), oneDPhaseSpace.end(), globalHistogramValues,
397 localHistogramValues, d, numParticles68, stat.rmean_m(d));
398
399 std::tie(stat.ninetyFivePercentile_m(d), endNinetyFive) = determinePercentileRange(
400 oneDPhaseSpace.begin(), oneDPhaseSpace.end(), globalHistogramValues,
401 localHistogramValues, d, numParticles95, stat.rmean_m(d));
402
403 std::tie(stat.ninetyNinePercentile_m(d), endNinetyNine) = determinePercentileRange(
404 oneDPhaseSpace.begin(), oneDPhaseSpace.end(), globalHistogramValues,
405 localHistogramValues, d, numParticles99, stat.rmean_m(d));
406
407 std::tie(stat.ninetyNine_NinetyNinePercentile_m(d), endNinetyNine_NinetyNine) =
408 determinePercentileRange(
409 oneDPhaseSpace.begin(), oneDPhaseSpace.end(), globalHistogramValues,
410 localHistogramValues, d, numParticles99_99, stat.rmean_m(d));
411
413 computeNormalizedEmittance(oneDPhaseSpace.begin(), endSixtyEight);
414
416 computeNormalizedEmittance(oneDPhaseSpace.begin(), endNinetyFive);
417
419 computeNormalizedEmittance(oneDPhaseSpace.begin(), endNinetyNine);
420
422 computeNormalizedEmittance(oneDPhaseSpace.begin(), endNinetyNine_NinetyNine);
423 }
424 }
425
426} // namespace
427
429 : outputName_m(""),
430 spos_m(0.0),
431 refTime_m(0.0),
432 tmean_m(0.0),
433 trms_m(0.0),
434 totalCharge_m(0.0),
435 totalMass_m(0.0),
436 meanKineticEnergy_m(0.0),
437 stdKineticEnergy_m(0.0),
438 meanGamma_m(0.0),
439 nTotal_m(0),
440 RefPartR_m(0.0),
441 RefPartP_m(0.0),
442 rmin_m(0.0),
443 rmax_m(0.0),
444 rmean_m(0.0),
445 pmean_m(0.0),
446 rrms_m(0.0),
447 prms_m(0.0),
448 rprms_m(0.0),
449 normEmit_m(0.0),
450 geomEmit_m(0.0),
451 maxR_m(0.0),
452 rsqsum_m(0.0),
453 psqsum_m(0.0),
454 rpsum_m(0.0),
455 eps2_m(0.0),
456 eps_norm_m(0.0),
457 fac_m(0.0),
458 sixtyEightPercentile_m(0.0),
459 ninetyFivePercentile_m(0.0),
460 ninetyNinePercentile_m(0.0),
461 ninetyNine_NinetyNinePercentile_m(0.0),
462 normalizedEps68Percentile_m(0.0),
463 normalizedEps95Percentile_m(0.0),
464 normalizedEps99Percentile_m(0.0),
465 normalizedEps99_99Percentile_m(0.0) {}
466
467LossDataSink::LossDataSink(std::string outfn, bool hdf5Save, CollectionType collectionType)
468 : h5hut_mode_m(hdf5Save),
469 H5file_m(0),
470 outputName_m(outfn),
471 H5call_m(0),
472 collectionType_m(collectionType) {
473 particles_m.clear();
474 turnNumber_m.clear();
475 bunchNumber_m.clear();
476
479 "LossDataSink::LossDataSink",
480 "You must select an OPTION to save Loss data files\n"
481 "Please, choose 'ENABLEHDF5=TRUE' or 'ASCIIDUMP=TRUE'");
482 }
483
485
486 if (OpalData::getInstance()->hasBunchAllocated()) {
488 }
489}
490
492 : h5hut_mode_m(rhs.h5hut_mode_m),
493 H5file_m(0),
494 outputName_m(rhs.outputName_m),
495 H5call_m(rhs.H5call_m),
496 RefPartR_m(rhs.RefPartR_m),
497 RefPartP_m(rhs.RefPartP_m),
498 globalTrackStep_m(rhs.globalTrackStep_m),
499 refTime_m(rhs.refTime_m),
500 spos_m(rhs.spos_m),
501 collectionType_m(rhs.collectionType_m) {
502 particles_m.clear();
503 turnNumber_m.clear();
504 bunchNumber_m.clear();
505}
506
508 if (H5file_m) {
509 closeFile();
510 }
511
512 if (ippl::Comm != nullptr) {
513 ippl::Comm->barrier();
514 }
515}
516
517void LossDataSink::openH5(h5_int32_t mode) {
518 h5_prop_t props = H5CreateFileProp();
519 MPI_Comm comm = ippl::Comm->getCommunicator();
520 H5SetPropFileMPIOCollective(props, &comm);
521 openFile(fileName_m.c_str(), mode, props);
522 H5CloseProp(props);
523}
524
526 // Write file attributes to describe phase space to H5 file.
527 std::stringstream OPAL_version;
528 OPAL_version << buildinfo::project_name << " " << buildinfo::project_version << " # git rev. "
530 writeFileAttribString("OPAL_version", OPAL_version.str().c_str());
531
532 writeFileAttribString("SPOSUnit", "m");
533 writeFileAttribString("TIMEUnit", "s");
534 writeFileAttribString("RefPartRUnit", "m");
535 writeFileAttribString("RefPartPUnit", "#beta#gamma");
536 writeFileAttribString("GlobalTrackStepUnit", "1");
537
538 writeFileAttribString("centroidUnit", "m");
539 writeFileAttribString("RMSXUnit", "m");
540 writeFileAttribString("MEANPUnit", "#beta#gamma");
541 writeFileAttribString("RMSPUnit", "#beta#gamma");
542 writeFileAttribString("#varepsilonUnit", "m rad");
543 writeFileAttribString("#varepsilon-geomUnit", "m rad");
544 writeFileAttribString("maxRUnit", "m");
545 writeFileAttribString("ENERGYUnit", "MeV");
546 writeFileAttribString("dEUnit", "MeV");
547 writeFileAttribString("TotalChargeUnit", "C");
548 writeFileAttribString("TotalMassUnit", "MeV");
549
550 writeFileAttribString("idUnit", "1");
551 writeFileAttribString("xUnit", "m");
552 writeFileAttribString("yUnit", "m");
553 writeFileAttribString("zUnit", "m");
554 writeFileAttribString("pxUnit", "#beta#gamma");
555 writeFileAttribString("pyUnit", "#beta#gamma");
556 writeFileAttribString("pzUnit", "#beta#gamma");
557 writeFileAttribString("qUnit", "C");
558 writeFileAttribString("mUnit", "MeV");
559
560 writeFileAttribString("turnUnit", "1");
561 writeFileAttribString("bunchNumUnit", "1");
562
563 writeFileAttribString("timeUnit", "s");
564 writeFileAttribString("meanTimeUnit", "s");
565 writeFileAttribString("rmsTimeUnit", "s");
566
568 writeFileAttribString("68-percentileUnit", "m");
569 writeFileAttribString("95-percentileUnit", "m");
570 writeFileAttribString("99-percentileUnit", "m");
571 writeFileAttribString("99_99-percentileUnit", "m");
572 writeFileAttribString("normalizedEps68PercentileUnit", "m rad");
573 writeFileAttribString("normalizedEps95PercentileUnit", "m rad");
574 writeFileAttribString("normalizedEps99PercentileUnit", "m rad");
575 writeFileAttribString("normalizedEps99_99PercentileUnit", "m rad");
576 }
577
579 writeFileAttribString("type", "temporal");
580 } else {
581 writeFileAttribString("type", "spatial");
582 }
583}
584
586 bool hasTurn = hasTurnInformations();
587 if (ippl::Comm->rank() == 0) {
588 os_m << "# x (m), y (m), z (m), px ( ), py ( ), pz ( ), id";
589 if (hasTurn) {
590 os_m << ", turn ( ), bunchNumber ( )";
591 }
592 os_m << ", time (s)" << std::endl;
593 }
594}
595
597 const Vector_t<double, 3>& x, const Vector_t<double, 3>& p, double time, double spos,
598 long long globalTrackStep) {
599 RefPartR_m.push_back(x);
600 RefPartP_m.push_back(p);
601 globalTrackStep_m.push_back((h5_int64_t)globalTrackStep);
602 spos_m.push_back(spos);
603 refTime_m.push_back(time);
604}
605
607 const OpalParticle& particle,
608 const std::optional<std::pair<int, short>>& turnBunchNumPair) {
609 if (turnBunchNumPair) {
610 if (turnNumber_m.size() != particles_m.size()) {
612 "LossDataSink::addParticle",
613 "Either all particles or no particles must have turn number and bunch number");
614 }
615
616 turnNumber_m.push_back(turnBunchNumPair.value().first);
617 bunchNumber_m.push_back(turnBunchNumPair.value().second);
618
619 } else {
620 if (!turnNumber_m.empty()) {
622 "LossDataSink::addParticle",
623 "Either all particles or no particles must have turn number and bunch number");
624 }
625 }
626
627 particles_m.push_back(particle);
628}
629
630void LossDataSink::save(unsigned int numSets, OpalData::OpenMode openMode) {
631 if (outputName_m.empty()) return;
632 if (hasNoParticlesToDump()) return;
633
634 if (openMode == OpalData::OpenMode::UNDEFINED) {
635 openMode = OpalData::getInstance()->getOpenMode();
636 }
637
638 namespace fs = std::filesystem;
639 if (h5hut_mode_m) {
640 fileName_m = outputName_m + std::string(".h5");
641 if (openMode == OpalData::OpenMode::WRITE || !fs::exists(fileName_m)) {
642 openH5();
644 } else {
645 openH5(H5_O_APPENDONLY);
646 getNumSteps();
647 }
648
649 splitSets(numSets);
650
651 for (unsigned int i = 0; i < numSets; ++i) {
652 saveH5(i);
653 }
654 closeFile();
655
656 } else {
657 fileName_m = outputName_m + std::string(".loss");
658 if (openMode == OpalData::OpenMode::WRITE || !fs::exists(fileName_m)) {
659 openASCII();
661 } else {
662 appendASCII();
663 }
664 saveASCII();
665 closeASCII();
666 }
667 *gmsg << level2 << "Save '" << fileName_m << "'" << endl;
668
669 ippl::Comm->barrier();
670
671 particles_m.clear();
672 turnNumber_m.clear();
673 bunchNumber_m.clear();
674 spos_m.clear();
675 refTime_m.clear();
676 RefPartR_m.clear();
677 RefPartP_m.clear();
678 globalTrackStep_m.clear();
679 startSet_m.clear();
680}
681
682// Note: This was changed to calculate the global number of dumped particles
683// because there are two cases to be considered:
684// 1. ALL nodes have 0 lost particles -> nothing to be done.
685// 2. Some nodes have 0 lost particles, some not -> H5 can handle that but all
686// nodes HAVE to participate, otherwise H5 waits endlessly for a response from
687// the nodes that didn't enter the saveH5 function. -DW
689 const unsigned long long nLocal = static_cast<unsigned long long>(particles_m.size());
690
691 unsigned long long nGlobal = 0;
692 ippl::Comm->allreduce(&nLocal, &nGlobal, 1, std::plus<unsigned long long>());
693
694 return nGlobal == 0;
695}
696
698 bool hasTurnInformation = !turnNumber_m.empty();
699
700 ippl::Comm->allreduce(hasTurnInformation, 1, std::logical_or<bool>());
701
702 return hasTurnInformation > 0;
703}
704
705void LossDataSink::saveH5(unsigned int setIdx) {
706 size_t nLoc = particles_m.size();
707 size_t startIdx = 0;
708 size_t endIdx = nLoc;
709 if (setIdx + 1 < startSet_m.size()) {
710 startIdx = startSet_m[setIdx];
711 endIdx = startSet_m[setIdx + 1];
712 nLoc = endIdx - startIdx;
713 }
714
715 SetStatistics stat = computeSetStatistics(setIdx);
716
717 if (stat.nTotal_m == 0) {
718 return;
719 }
720
721 const bool hasTurn = hasTurnInformations();
722
723 if (hasTurn
724 && (turnNumber_m.size() < startIdx + nLoc || bunchNumber_m.size() < startIdx + nLoc)) {
726 "LossDataSink::saveH5",
727 "Turn/bunch information is globally present, but this rank does not have "
728 "turn/bunch data for all particles in this loss set.");
729 }
730
732 setStep();
733 setNumParticles(static_cast<h5_int64_t>(nLoc));
734
735 if (setIdx < spos_m.size()) {
736 writeStepAttribFloat64("SPOS", &(spos_m[setIdx]), 1);
737 }
738
739 if (setIdx < refTime_m.size()) {
740 writeStepAttribFloat64("TIME", &(refTime_m[setIdx]), 1);
741 }
742
743 if (setIdx < RefPartR_m.size()) {
744 Vector_t<double, 3> refPartR = RefPartR_m[setIdx];
745 writeStepAttribFloat64("RefPartR", &refPartR[0], 3);
746 }
747
748 if (setIdx < RefPartP_m.size()) {
749 Vector_t<double, 3> refPartP = RefPartP_m[setIdx];
750 writeStepAttribFloat64("RefPartP", &refPartP[0], 3);
751 }
752
753 if (setIdx < globalTrackStep_m.size()) {
754 writeStepAttribInt64("GlobalTrackStep", &(globalTrackStep_m[setIdx]), 1);
755 }
756
757 Vector_t<double, 3> tmpVector;
758 double tmpDouble;
759
760 tmpVector = stat.rmean_m;
761 writeStepAttribFloat64("centroid", &tmpVector[0], 3);
762
763 tmpVector = stat.rrms_m;
764 writeStepAttribFloat64("RMSX", &tmpVector[0], 3);
765
766 tmpVector = stat.pmean_m;
767 writeStepAttribFloat64("MEANP", &tmpVector[0], 3);
768
769 tmpVector = stat.prms_m;
770 writeStepAttribFloat64("RMSP", &tmpVector[0], 3);
771
772 tmpVector = stat.eps_norm_m;
773 writeStepAttribFloat64("#varepsilon", &tmpVector[0], 3);
774
775 tmpVector = stat.geomEmit_m;
776 writeStepAttribFloat64("#varepsilon-geom", &tmpVector[0], 3);
777
778 tmpDouble = stat.meanKineticEnergy_m;
779 writeStepAttribFloat64("ENERGY", &tmpDouble, 1);
780
781 tmpDouble = stat.stdKineticEnergy_m;
782 writeStepAttribFloat64("dE", &tmpDouble, 1);
783
784 tmpDouble = stat.totalCharge_m;
785 writeStepAttribFloat64("TotalCharge", &tmpDouble, 1);
786
787 tmpDouble = stat.totalMass_m;
788 writeStepAttribFloat64("TotalMass", &tmpDouble, 1);
789
790 tmpDouble = stat.tmean_m;
791 writeStepAttribFloat64("meanTime", &tmpDouble, 1);
792
793 tmpDouble = stat.trms_m;
794 writeStepAttribFloat64("rmsTime", &tmpDouble, 1);
795
797 tmpVector = stat.sixtyEightPercentile_m;
798 writeStepAttribFloat64("68-percentile", &tmpVector[0], 3);
799
800 tmpVector = stat.ninetyFivePercentile_m;
801 writeStepAttribFloat64("95-percentile", &tmpVector[0], 3);
802
803 tmpVector = stat.ninetyNinePercentile_m;
804 writeStepAttribFloat64("99-percentile", &tmpVector[0], 3);
805
806 tmpVector = stat.ninetyNine_NinetyNinePercentile_m;
807 writeStepAttribFloat64("99_99-percentile", &tmpVector[0], 3);
808
809 tmpVector = stat.normalizedEps68Percentile_m;
810 writeStepAttribFloat64("normalizedEps68Percentile", &tmpVector[0], 3);
811
812 tmpVector = stat.normalizedEps95Percentile_m;
813 writeStepAttribFloat64("normalizedEps95Percentile", &tmpVector[0], 3);
814
815 tmpVector = stat.normalizedEps99Percentile_m;
816 writeStepAttribFloat64("normalizedEps99Percentile", &tmpVector[0], 3);
817
818 tmpVector = stat.normalizedEps99_99Percentile_m;
819 writeStepAttribFloat64("normalizedEps99_99Percentile", &tmpVector[0], 3);
820 }
821
822 tmpVector = stat.maxR_m;
823 writeStepAttribFloat64("maxR", &tmpVector[0], 3);
824
825 // Write all data
826 std::vector<h5_float64_t> f64bufferStorage(std::max<size_t>(nLoc, 1));
827 std::vector<h5_int64_t> i64bufferStorage(std::max<size_t>(nLoc, 1));
828
829 h5_float64_t* f64buffer = f64bufferStorage.data();
830 h5_int64_t* i64buffer = i64bufferStorage.data();
831
832 ::i64transform(particles_m, startIdx, nLoc, i64buffer, [](const OpalParticle& particle) {
833 return particle.getId();
834 });
835 writeDataInt64("id", i64buffer);
836
837 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
838 return particle.getX();
839 });
840 writeDataFloat64("x", f64buffer);
841
842 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
843 return particle.getY();
844 });
845 writeDataFloat64("y", f64buffer);
846
847 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
848 return particle.getZ();
849 });
850 writeDataFloat64("z", f64buffer);
851
852 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
853 return particle.getPx();
854 });
855 writeDataFloat64("px", f64buffer);
856
857 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
858 return particle.getPy();
859 });
860 writeDataFloat64("py", f64buffer);
861
862 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
863 return particle.getPz();
864 });
865 writeDataFloat64("pz", f64buffer);
866
867 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
868 return particle.getCharge();
869 });
870 writeDataFloat64("q", f64buffer);
871
872 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
873 return particle.getMass();
874 });
875 writeDataFloat64("m", f64buffer);
876
877 if (hasTurn) {
878 std::copy(
879 turnNumber_m.begin() + startIdx, turnNumber_m.begin() + startIdx + nLoc, i64buffer);
880 writeDataInt64("turn", i64buffer);
881
882 std::copy(
883 bunchNumber_m.begin() + startIdx, bunchNumber_m.begin() + startIdx + nLoc,
884 i64buffer);
885 writeDataInt64("bunchNumber", i64buffer);
886 }
887
888 ::f64transform(particles_m, startIdx, nLoc, f64buffer, [](const OpalParticle& particle) {
889 return particle.getTime();
890 });
891 writeDataFloat64("time", f64buffer);
892
893 ++H5call_m;
894}
895
897 const bool hasTurn = hasTurnInformations();
898
899 if (hasTurn
900 && (turnNumber_m.size() != particles_m.size()
901 || bunchNumber_m.size() != particles_m.size())) {
903 "LossDataSink::saveASCII",
904 "Turn/bunch information is globally present, but this rank does not have "
905 "turn/bunch data for all particles.");
906 }
907
908 constexpr int tagCount = 43001;
909 constexpr int tagDouble = 43002;
910 constexpr int tagInt = 43003;
911
912 MPI_Comm comm = ippl::Comm->getCommunicator();
913
914 const int rank = ippl::Comm->rank();
915 const int size = ippl::Comm->size();
916
917 const std::size_t nLoc = particles_m.size();
918 const std::size_t nIntColumns = hasTurn ? 3 : 1;
919
920 auto packDoubleData = [&]() {
921 std::vector<double> data(7 * nLoc);
922
923 for (std::size_t i = 0; i < nLoc; ++i) {
924 const OpalParticle& particle = particles_m[i];
925
926 data[7 * i + 0] = particle.getX();
927 data[7 * i + 1] = particle.getY();
928 data[7 * i + 2] = particle.getZ();
929 data[7 * i + 3] = particle.getPx();
930 data[7 * i + 4] = particle.getPy();
931 data[7 * i + 5] = particle.getPz();
932 data[7 * i + 6] = particle.getTime();
933 }
934
935 return data;
936 };
937
938 auto packIntegerData = [&]() {
939 std::vector<long long> data(nIntColumns * nLoc);
940
941 for (std::size_t i = 0; i < nLoc; ++i) {
942 const OpalParticle& particle = particles_m[i];
943
944 data[nIntColumns * i + 0] = static_cast<long long>(particle.getId());
945
946 if (hasTurn) {
947 data[nIntColumns * i + 1] = static_cast<long long>(turnNumber_m[i]);
948
949 data[nIntColumns * i + 2] = static_cast<long long>(bunchNumber_m[i]);
950 }
951 }
952
953 return data;
954 };
955
956 auto writeRecords = [&](const std::vector<double>& doubleData,
957 const std::vector<long long>& integerData, std::size_t count) {
958 for (std::size_t i = 0; i < count; ++i) {
959 os_m << doubleData[7 * i + 0] << " ";
960 os_m << doubleData[7 * i + 1] << " ";
961 os_m << doubleData[7 * i + 2] << " ";
962 os_m << doubleData[7 * i + 3] << " ";
963 os_m << doubleData[7 * i + 4] << " ";
964 os_m << doubleData[7 * i + 5] << " ";
965 os_m << integerData[nIntColumns * i + 0] << " ";
966
967 if (hasTurn) {
968 os_m << integerData[nIntColumns * i + 1] << " ";
969 os_m << integerData[nIntColumns * i + 2] << " ";
970 }
971
972 os_m << doubleData[7 * i + 6] << std::endl;
973 }
974 };
975
976 if (rank == 0) {
977 std::vector<double> localDoubleData = packDoubleData();
978 std::vector<long long> localIntegerData = packIntegerData();
979
980 writeRecords(localDoubleData, localIntegerData, nLoc);
981
982 for (int src = 1; src < size; ++src) {
983 unsigned long long remoteCount = 0;
984
985 MPI_Recv(
986 &remoteCount, 1, MPI_UNSIGNED_LONG_LONG, src, tagCount, comm,
987 MPI_STATUS_IGNORE);
988
989 std::vector<double> remoteDoubleData(7 * remoteCount);
990 std::vector<long long> remoteIntegerData(nIntColumns * remoteCount);
991
992 if (remoteCount > 0) {
993 MPI_Recv(
994 remoteDoubleData.data(), static_cast<int>(remoteDoubleData.size()),
995 MPI_DOUBLE, src, tagDouble, comm, MPI_STATUS_IGNORE);
996
997 MPI_Recv(
998 remoteIntegerData.data(), static_cast<int>(remoteIntegerData.size()),
999 MPI_LONG_LONG, src, tagInt, comm, MPI_STATUS_IGNORE);
1000 }
1001
1002 writeRecords(remoteDoubleData, remoteIntegerData, remoteCount);
1003 }
1004 } else {
1005 const unsigned long long localCount = static_cast<unsigned long long>(nLoc);
1006
1007 MPI_Send(&localCount, 1, MPI_UNSIGNED_LONG_LONG, 0, tagCount, comm);
1008
1009 if (localCount > 0) {
1010 std::vector<double> localDoubleData = packDoubleData();
1011 std::vector<long long> localIntegerData = packIntegerData();
1012
1013 MPI_Send(
1014 localDoubleData.data(), static_cast<int>(localDoubleData.size()), MPI_DOUBLE, 0,
1015 tagDouble, comm);
1016
1017 MPI_Send(
1018 localIntegerData.data(), static_cast<int>(localIntegerData.size()),
1019 MPI_LONG_LONG, 0, tagInt, comm);
1020 }
1021 }
1022
1023 ippl::Comm->barrier();
1024}
1025
1045void LossDataSink::splitSets(unsigned int numSets) {
1046 startSet_m.clear();
1047
1048 if (numSets <= 1 || particles_m.empty()) {
1049 return;
1050 }
1051
1052 const size_t nLoc = particles_m.size();
1053 size_t avgNumPerSet = nLoc / numSets;
1054
1055 std::vector<size_t> numPartsInSet(numSets, avgNumPerSet);
1056 for (unsigned int j = 0; j < (nLoc - numSets * avgNumPerSet); ++j) {
1057 ++numPartsInSet[j];
1058 }
1059
1060 startSet_m.resize(numSets + 1, 0);
1061
1062 std::vector<double> data(2 * numSets, 0.0);
1063 double* meanT = data.data();
1064 double* numParticles = data.data() + numSets;
1065
1066 std::vector<double> timeRange(numSets, 0.0);
1067
1068 for (unsigned int iteration = 0; iteration < 2; ++iteration) {
1069 std::fill(data.begin(), data.end(), 0.0);
1070 std::fill(timeRange.begin(), timeRange.end(), 0.0);
1071
1072 double maxT = particles_m[0].getTime();
1073
1074 size_t partIdx = 0;
1075 for (unsigned int j = 0; j < numSets; ++j) {
1076 const size_t numThisSet = numPartsInSet[j];
1077
1078 for (size_t k = 0; k < numThisSet && partIdx < nLoc; ++k, ++partIdx) {
1079 meanT[j] += particles_m[partIdx].getTime();
1080 maxT = std::max(maxT, particles_m[partIdx].getTime());
1081 }
1082
1083 numParticles[j] = static_cast<double>(numThisSet);
1084 }
1085
1086 ippl::Comm->allreduce(data.data(), 2 * numSets, std::plus<double>());
1087
1088 for (unsigned int j = 0; j < numSets; ++j) {
1089 if (numParticles[j] > 0.0) {
1090 meanT[j] /= numParticles[j];
1091 }
1092 }
1093
1094 for (unsigned int j = 0; j < numSets - 1; ++j) {
1095 timeRange[j] = 0.5 * (meanT[j] + meanT[j + 1]);
1096 }
1097 timeRange[numSets - 1] = maxT;
1098
1099 std::fill(numPartsInSet.begin(), numPartsInSet.end(), 0);
1100
1101 size_t setNum = 0;
1102 size_t idxPrior = 0;
1103
1104 for (size_t idx = 0; idx < nLoc && setNum + 1 < numSets; ++idx) {
1105 if (particles_m[idx].getTime() > timeRange[setNum]) {
1106 numPartsInSet[setNum] = idx - idxPrior;
1107 idxPrior = idx;
1108 ++setNum;
1109 }
1110 }
1111
1112 numPartsInSet[numSets - 1] = nLoc - idxPrior;
1113 }
1114
1115 for (unsigned int i = 0; i < numSets; ++i) {
1116 startSet_m[i + 1] = startSet_m[i] + numPartsInSet[i];
1117 }
1118}
1119
1121 SetStatistics stat;
1122 double part[6];
1123
1124 // Layout:
1125 // 0 : number of particles
1126 // 1..6 : sums of x, px, y, py, z, pz
1127 // 7..42 : 6x6 second moments
1128 // 43 : time sum
1129 // 44 : time^2 sum
1130 // 45 : total charge
1131 // 46 : total mass
1132 // 47 : kinetic energy sum
1133 // 48 : kinetic energy^2 sum
1134 // 49 : gamma sum
1135 const unsigned int totalSize = 50;
1136
1137 double plainData[totalSize] = {};
1138 double rMinMax[6];
1139
1140 for (unsigned int i = 0; i < 6; ++i) {
1141 rMinMax[i] = std::numeric_limits<double>::lowest();
1142 }
1143
1144 Util::KahanAccumulation data[totalSize] = {};
1145 Util::KahanAccumulation* localCentroid = data + 1;
1146 Util::KahanAccumulation* localMoments = data + 7;
1147 Util::KahanAccumulation* localOthers = data + 43;
1148
1149 size_t startIdx = 0;
1150 size_t nLoc = particles_m.size();
1151
1152 if (setIdx + 1 < startSet_m.size()) {
1153 startIdx = startSet_m[setIdx];
1154 nLoc = startSet_m[setIdx + 1] - startSet_m[setIdx];
1155 }
1156
1157 data[0].sum = static_cast<double>(nLoc);
1158
1159 size_t idx = startIdx;
1160
1161 for (size_t k = 0; k < nLoc; ++k, ++idx) {
1162 const OpalParticle& particle = particles_m[idx];
1163
1164 part[0] = particle.getX();
1165 part[1] = particle.getPx();
1166 part[2] = particle.getY();
1167 part[3] = particle.getPy();
1168 part[4] = particle.getZ();
1169 part[5] = particle.getPz();
1170
1171 for (int i = 0; i < 6; ++i) {
1172 localCentroid[i] += part[i];
1173 for (int j = 0; j <= i; ++j) {
1174 localMoments[i * 6 + j] += part[i] * part[j];
1175 }
1176 }
1177
1178 for (unsigned int d = 0; d < 3; ++d) {
1179 const double r = part[2 * d];
1180
1181 rMinMax[2 * d] = std::max(rMinMax[2 * d], -r);
1182 rMinMax[2 * d + 1] = std::max(rMinMax[2 * d + 1], r);
1183 }
1184
1185 const double time = particle.getTime();
1186
1187 const double gamma = Util::getGamma(particle.getP());
1188 const double eKin = Util::getKineticEnergy(particle.getP(), particle.getMass());
1189
1190 localOthers[0] += time;
1191 localOthers[1] += time * time;
1192 localOthers[2] += particle.getCharge();
1193 localOthers[3] += particle.getMass();
1194 localOthers[4] += eKin;
1195 localOthers[5] += eKin * eKin;
1196 localOthers[6] += gamma;
1197 }
1198
1199 for (int i = 0; i < 6; ++i) {
1200 for (int j = 0; j < i; ++j) {
1201 localMoments[j * 6 + i] = localMoments[i * 6 + j];
1202 }
1203 }
1204
1205 for (unsigned int i = 0; i < totalSize; ++i) {
1206 plainData[i] = data[i].sum;
1207 }
1208
1209 ippl::Comm->allreduce(plainData, totalSize, std::plus<double>());
1210 ippl::Comm->allreduce(rMinMax, 6, std::greater<double>());
1211
1212 if (plainData[0] == 0.0) {
1213 return stat;
1214 }
1215
1216 double* centroid = plainData + 1;
1217 double* moments = plainData + 7;
1218 double* others = plainData + 43;
1219
1221
1222 if (setIdx < spos_m.size()) {
1223 stat.spos_m = spos_m[setIdx];
1224 }
1225
1226 if (setIdx < refTime_m.size()) {
1227 stat.refTime_m = refTime_m[setIdx];
1228 }
1229
1230 if (setIdx < RefPartR_m.size()) {
1231 stat.RefPartR_m = RefPartR_m[setIdx];
1232 }
1233
1234 if (setIdx < RefPartP_m.size()) {
1235 stat.RefPartP_m = RefPartP_m[setIdx];
1236 }
1237
1238 stat.nTotal_m = static_cast<unsigned long>(std::round(plainData[0]));
1239
1240 for (unsigned int i = 0; i < 3u; ++i) {
1241 stat.rmean_m(i) = centroid[2 * i] / stat.nTotal_m;
1242 stat.pmean_m(i) = centroid[2 * i + 1] / stat.nTotal_m;
1243
1244 stat.rsqsum_m(i) =
1245 moments[(2 * i) * 6 + 2 * i] - stat.nTotal_m * std::pow(stat.rmean_m(i), 2);
1246
1247 stat.psqsum_m(i) =
1248 moments[(2 * i + 1) * 6 + 2 * i + 1] - stat.nTotal_m * std::pow(stat.pmean_m(i), 2);
1249
1250 stat.psqsum_m(i) = std::max(0.0, stat.psqsum_m(i));
1251
1252 stat.rpsum_m(i) = moments[(2 * i) * 6 + 2 * i + 1]
1253 - stat.nTotal_m * stat.rmean_m(i) * stat.pmean_m(i);
1254 }
1255
1256 stat.tmean_m = others[0] / stat.nTotal_m;
1257 stat.trms_m = std::sqrt(std::max(0.0, others[1] / stat.nTotal_m - std::pow(stat.tmean_m, 2)));
1258
1259 stat.totalCharge_m = others[2];
1260 stat.totalMass_m = others[3];
1261
1262 stat.meanKineticEnergy_m = others[4] / stat.nTotal_m;
1263
1264 Util::KahanAccumulation localKineticEnergyVariance = {};
1265
1266 size_t varianceIdx = startIdx;
1267 for (size_t k = 0; k < nLoc; ++k, ++varianceIdx) {
1268 const OpalParticle& particle = particles_m[varianceIdx];
1269
1270 const double eKin = Util::getKineticEnergy(particle.getP(), particle.getMass());
1271
1272 const double diff = eKin - stat.meanKineticEnergy_m;
1273 localKineticEnergyVariance += diff * diff;
1274 }
1275
1276 double kineticEnergyVariance[] = {static_cast<double>(localKineticEnergyVariance.sum)};
1277
1278 ippl::Comm->allreduce(kineticEnergyVariance, 1, std::plus<double>());
1279
1280 stat.stdKineticEnergy_m = std::sqrt(std::max(0.0, kineticEnergyVariance[0] / stat.nTotal_m));
1281
1282 stat.meanGamma_m = others[6] / stat.nTotal_m;
1283
1284 stat.eps2_m = (stat.rsqsum_m * stat.psqsum_m - stat.rpsum_m * stat.rpsum_m)
1285 / (1.0 * stat.nTotal_m * stat.nTotal_m);
1286
1287 stat.rpsum_m /= stat.nTotal_m;
1288
1289 const double betaGamma = std::sqrt(std::max(0.0, stat.meanGamma_m * stat.meanGamma_m - 1.0));
1290
1291 for (unsigned int i = 0; i < 3u; ++i) {
1292 stat.rrms_m(i) = std::sqrt(std::max(0.0, stat.rsqsum_m(i)) / stat.nTotal_m);
1293 stat.prms_m(i) = std::sqrt(std::max(0.0, stat.psqsum_m(i)) / stat.nTotal_m);
1294
1295 stat.eps_norm_m(i) = std::sqrt(std::max(0.0, stat.eps2_m(i)));
1296
1297 stat.geomEmit_m(i) = betaGamma > 0.0 ? stat.eps_norm_m(i) / betaGamma : 0.0;
1298
1299 const double tmp = stat.rrms_m(i) * stat.prms_m(i);
1300 stat.fac_m(i) = tmp == 0.0 ? 0.0 : 1.0 / tmp;
1301
1302 stat.rmin_m(i) = -rMinMax[2 * i];
1303 stat.rmax_m(i) = rMinMax[2 * i + 1];
1304 stat.maxR_m(i) =
1305 std::max(std::abs(stat.rmin_m(i)), std::abs(stat.rmax_m(i))); // stat.rmax_m(i);
1306 }
1307
1308 stat.rprms_m = stat.rpsum_m * stat.fac_m;
1309
1310 computeSetPercentiles(particles_m, startIdx, nLoc, stat);
1311
1312 return stat;
1313}
Inform * gmsg
Definition changes.cpp:7
ippl::Vector< T, Dim > Vector_t
void gsl_histogram_free(gsl_histogram *h)
Free a histogram allocated by gsl_histogram_alloc.
void gsl_histogram_increment(gsl_histogram *h, double x)
Increment the bin containing x by 1.
void gsl_histogram_set_ranges_uniform(gsl_histogram *h, double xmin, double xmax)
Set uniform bin edges over .
gsl_histogram * gsl_histogram_alloc(size_t n)
Allocate a 1D histogram with n bins.
double gsl_histogram_get(const gsl_histogram *h, size_t i)
Get the bin count for index i.
Inform * gmsg
Definition changes.cpp:7
CollectionType
std::vector< Vector_t< double, 3 > > RefPartR_m
std::vector< size_t > turnNumber_m
h5_file_t H5file_m
used to write out data in H5hut mode
~LossDataSink() noexcept(false)
size_t size() const
void setNumParticles(h5_int64_t num)
std::vector< double > refTime_m
void writeStepAttribFloat64(const char *attribute, const h5_float64_t *value, h5_int64_t size)
CollectionType collectionType_m
void addReferenceParticle(const Vector_t< double, 3 > &x, const Vector_t< double, 3 > &p, double time, double spos, long long globalTrackStep)
std::string outputName_m
void writeHeaderASCII()
void save(unsigned int numSets=1, OpalData::OpenMode openMode=OpalData::OpenMode::UNDEFINED)
std::ofstream os_m
h5_int64_t H5call_m
Current record, or time step, of H5 file.
void openFile(const char *fname, h5_int32_t mode, h5_prop_t props)
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
void writeStepAttribInt64(const char *attribute, const h5_int64_t *value, h5_int64_t size)
void writeFileAttribString(const char *attribute, const char *value)
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
std::vector< Vector_t< double, 3 > > RefPartP_m
void appendASCII()
void writeDataFloat64(const char *name, const h5_float64_t *value)
void saveH5(unsigned int setIdx)
void writeDataInt64(const char *name, const h5_int64_t *value)
std::vector< h5_int64_t > globalTrackStep_m
LossDataSink()=default
void closeASCII()
bool hasNoParticlesToDump() const
std::vector< unsigned long > startSet_m
void checkAndAddOutputFileName(const std::string &outfn)
checks the output file names of all items to avoid duplicates
Definition OpalData.cpp:577
OpenMode getOpenMode() const
Definition OpalData.cpp:300
static OpalData * getInstance()
Definition OpalData.cpp:193
OpenMode
Enum for writing to files.
Definition OpalData.h:58
void setOpenMode(OpenMode openMode)
Definition OpalData.cpp:298
double getPy() const
Get vertical momentum (no dimension).
double getPz() const
Get relative momentum error (no dimension).
const Vector_t< double, 3 > & getP() const
Get momentum.
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.
bool computePercentiles
Definition Options.cpp:107
bool enableHDF5
If true HDF5 files are written.
Definition Options.cpp:83
double getGamma(ippl::Vector< double, 3 > p)
Definition Util.h:44
double getKineticEnergy(ippl::Vector< double, 3 > p, double mass)
Definition Util.h:53
std::string getGitRevision()
Definition Util.cpp:32
Vector_t< double, 3 > rprms_m
Vector_t< double, 3 > normalizedEps68Percentile_m
double stdKineticEnergy_m
Vector_t< double, 3 > eps2_m
Vector_t< double, 3 > rsqsum_m
Vector_t< double, 3 > maxR_m
std::string outputName_m
Vector_t< double, 3 > RefPartR_m
Vector_t< double, 3 > RefPartP_m
Vector_t< double, 3 > rrms_m
Vector_t< double, 3 > ninetyNinePercentile_m
Vector_t< double, 3 > ninetyFivePercentile_m
Vector_t< double, 3 > eps_norm_m
Vector_t< double, 3 > ninetyNine_NinetyNinePercentile_m
Vector_t< double, 3 > geomEmit_m
Vector_t< double, 3 > rmax_m
Vector_t< double, 3 > prms_m
double meanKineticEnergy_m
double totalMass_m
double totalCharge_m
double meanGamma_m
unsigned long nTotal_m
Vector_t< double, 3 > sixtyEightPercentile_m
Vector_t< double, 3 > pmean_m
Vector_t< double, 3 > fac_m
Vector_t< double, 3 > normalizedEps95Percentile_m
Vector_t< double, 3 > psqsum_m
Vector_t< double, 3 > rpsum_m
Vector_t< double, 3 > normalizedEps99Percentile_m
Vector_t< double, 3 > normalizedEps99_99Percentile_m
Vector_t< double, 3 > rmin_m
Vector_t< double, 3 > rmean_m
long double sum
Definition Util.h:205