23#include "OPALconfig.h"
43#define WRITE_FILEATTRIB_STRING(attribute, value) \
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()); \
52#define WRITE_STEPATTRIB_FLOAT64(attribute, value, size) \
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()); \
61#define WRITE_STEPATTRIB_INT64(attribute, value, size) \
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()); \
70#define WRITE_DATA_FLOAT64(name, value) \
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()); \
79#define WRITE_DATA_INT64(name, value) \
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()); \
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()); \
97#define GET_NUM_STEPS() \
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()); \
106#define SET_NUM_PARTICLES(num) \
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()); \
117#define OPEN_FILE(fname, mode, props) \
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()); \
126#define CLOSE_FILE() \
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()); \
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) {
142 particles.begin() + startIdx, particles.begin() + startIdx + numParticles, buffer,
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) {
150 particles.begin() + startIdx, particles.begin() + startIdx + numParticles, buffer,
154 void cminmax(
double&
min,
double&
max,
double val) {
157 }
else if (val >
max) {
189 : h5hut_mode_m(hdf5Save),
193 collectionType_m(collectionType) {
200 "LossDataSink::LossDataSink",
201 "You must select an OPTION to save Loss data files\n"
202 "Please, choose 'ENABLEHDF5=TRUE' or 'ASCIIDUMP=TRUE'");
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),
222 collectionType_m(rhs.collectionType_m) {
236 h5_prop_t props = H5CreateFileProp();
238 H5SetPropFileMPIOCollective(props, &comm);
245 std::stringstream OPAL_version;
246 OPAL_version << OPAL_PROJECT_NAME <<
" " << OPAL_PROJECT_VERSION <<
" # git rev. "
305 os_m <<
"# x (m), y (m), z (m), px ( ), py ( ), pz ( ), id";
307 os_m <<
", turn ( ), bunchNumber ( )";
309 os_m <<
", time (s)" << std::endl;
314 const Vector_t& x,
const Vector_t& p,
double time,
double spos,
long long globalTrackStep) {
323 const OpalParticle& particle,
const std::optional<std::pair<int, short>>& turnBunchNumPair) {
324 if (turnBunchNumPair) {
327 "LossDataSink::addParticle",
328 "Either no particle or all have turn number and bunch number");
347 namespace fs = std::filesystem;
358 for (
unsigned int i = 0; i < numSets; ++i) {
384 spos_m = std::vector<double>();
408 allreduce(hasTurnInformation, 1, std::logical_or<bool>());
410 return hasTurnInformation > 0;
415 size_t startIdx = 0, endIdx = nLoc;
419 nLoc = endIdx - startIdx;
426 globN[i] = locN[i] = 0;
439 if (setIdx <
spos_m.size()) {
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);
476 "normalizedEps68Percentile",
479 "normalizedEps95Percentile",
482 "normalizedEps99Percentile",
485 "normalizedEps99_99Percentile",
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;
497 return particle.
getId();
501 return particle.
getX();
505 return particle.
getY();
509 return particle.
getZ();
513 return particle.
getPx();
517 return particle.
getPy();
521 return particle.
getPz();
560 for (
unsigned i = 0; i < partCount; i++) {
577 while (notReceived > 0) {
578 unsigned dataBlocks = 0;
582 ERRORMSG(
"LossDataSink: Could not receive from client nodes output." <<
endl);
585 rmsg->
get(&dataBlocks);
587 for (
unsigned i = 0; i < dataBlocks; i++) {
589 size_t bunchNum, turn;
590 double rx, ry, rz, px, py, pz, time;
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) <<
" ";
600 os_m << (rmsg->
get(&turn), turn) <<
" ";
601 os_m << (rmsg->
get(&bunchNum), bunchNum) <<
" ";
603 os_m << (rmsg->
get(&time), time) << std::endl;
612 for (
unsigned i = 0; i < msgsize; i++) {
629 ERRORMSG(
"LossDataSink Ippl::Comm->send(smsg, 0, tag) failed " <<
endl);
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) {
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);
671 for (
unsigned int iteration = 0; iteration < 2; ++iteration) {
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) {
677 maxT = std::max(maxT,
particles_m[partIdx].getTime());
679 numParticles[j] = numThisSet;
682 allreduce(&(data[0]), 2 * numSets, std::plus<double>());
684 for (
unsigned int j = 0; j < numSets; ++j) {
685 meanT[j] /= numParticles[j];
688 for (
unsigned int j = 0; j < numSets - 1; ++j) {
689 timeRange[j] = 0.5 * (meanT[j] + meanT[j + 1]);
691 timeRange[numSets - 1] = maxT;
693 std::fill(numPartsInSet.begin(), numPartsInSet.end(), 0);
697 for (
size_t idx = 0; idx < nLoc; ++idx) {
698 if (
particles_m[idx].getTime() > timeRange[setNum]) {
699 numPartsInSet[setNum] = idx - idxPrior;
704 numPartsInSet[numSets - 1] = nLoc - idxPrior;
707 for (
unsigned int i = 0; i < numSets; ++i) {
716 const unsigned int totalSize = 45;
717 double plainData[totalSize];
718 double rminmax[6] = {};
734 unsigned int idx = startIdx;
735 for (
unsigned long k = 0; k < nLoc; ++k, ++idx) {
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();
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];
751 localOthers[0] += particle.
getTime();
752 localOthers[1] += std::pow(particle.
getTime(), 2);
754 ::cminmax(rminmax[0], rminmax[1], particle.
getX());
755 ::cminmax(rminmax[2], rminmax[3], particle.
getY());
756 ::cminmax(rminmax[4], rminmax[5], particle.
getZ());
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];
765 for (
unsigned int i = 0; i < totalSize; ++i) {
766 plainData[i] = data[i].
sum;
769 allreduce(plainData, totalSize, std::plus<double>());
770 allreduce(rminmax, 6, std::greater<double>());
772 if (plainData[0] == 0.0)
775 double* centroid = plainData + 1;
776 double* moments = plainData + 7;
777 double* others = plainData + 43;
784 stat.
nTotal_m = (
unsigned long)std::round(plainData[0]);
786 for (
unsigned int i = 0; i < 3u; i++) {
790 (moments[2 * i * 6 + 2 * i] - stat.
nTotal_m * std::pow(stat.
rmean_m(i), 2));
793 moments[(2 * i + 1) * 6 + (2 * i) + 1] - stat.
nTotal_m * std::pow(stat.
pmean_m(i), 2));
795 (moments[(2 * i) * 6 + (2 * i) + 1]
807 for (
unsigned int i = 0; i < 3u; 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];
#define OPEN_FILE(fname, mode, props)
#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)
void allreduce(const T *input, T *output, int count, Op op)
bool reduce(Communicate &, InputIterator, InputIterator, OutputIterator, const ReduceOp &, bool *IncludeVal=0)
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)
Inform & endl(Inform &inf)
bool enableHDF5
If true HDF5 files are written.
std::string getGitRevision()
void checkAndAddOutputFileName(const std::string &outfn)
checks the output file names of all items to avoid duplicates
OpenMode getOpenMode() const
static OpalData * getInstance()
OpenMode
Enum for writing to files.
void setOpenMode(OpenMode openMode)
Vector_t getStandardDeviationMomentum() const
Vector_t get99Percentile() const
double getMeanKineticEnergy() const
Vector_t getStandardDeviationPosition() const
Vector_t getNormalizedEmittance95Percentile() const
Vector_t getNormalizedEmittance68Percentile() const
double getTotalCharge() const
Vector_t getNormalizedEmittance99_99Percentile() const
Vector_t getNormalizedEmittance99Percentile() const
Vector_t getMeanPosition() const
Vector_t get99_99Percentile() const
void compute(const std::vector< OpalParticle >::const_iterator &, const std::vector< OpalParticle >::const_iterator &)
double getStdKineticEnergy() const
Vector_t getNormalizedEmittance() const
double getStdTime() const
double getTotalMass() const
Vector_t getMeanMomentum() const
Vector_t get95Percentile() const
Vector_t get68Percentile() const
double getMeanTime() 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.
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
void save(unsigned int numSets=1, OpalData::OpenMode openMode=OpalData::OpenMode::UNDEFINED)
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::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 saveH5(unsigned int setIdx)
std::vector< h5_int64_t > globalTrackStep_m
bool hasNoParticlesToDump() const
std::vector< unsigned long > startSet_m
bool send(Message *, int node, int tag, bool delmsg=true)
Message * receive_block(int &node, int &tag)
Message & put(const T &val)
Message & get(const T &cval)
int next_tag(int t, int s=1000)
static MPI_Comm getComm()
static Communicate * Comm