File indexing completed on 2025-04-10 08:05:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #include "tools_histo_flair.hh"
0044
0045 #include "G4SystemOfUnits.hh"
0046 #include "G4UnitsTable.hh"
0047 #include "G4ios.hh"
0048
0049 #include <cstring>
0050 #include <fstream>
0051 #include <iomanip>
0052 #include <memory>
0053 #include <stdarg.h>
0054 #include <stdlib.h>
0055
0056
0057
0058 namespace tools
0059 {
0060 namespace histo
0061 {
0062 namespace flair
0063 {
0064
0065
0066
0067
0068 G4String getAbscissaName(const Abscissa abscissaKind)
0069 {
0070 G4String abscissaName = "";
0071 if (abscissaKind == Abscissa::KineticEnergy) {
0072 abscissaName = "kE";
0073 }
0074 else if (abscissaKind == Abscissa::Z) {
0075 abscissaName = "Z";
0076 }
0077 else if (abscissaKind == Abscissa::A) {
0078 abscissaName = "A";
0079 }
0080 return abscissaName;
0081 }
0082
0083
0084
0085
0086 G4String getAbscissaUnit(const Abscissa abscissaKind)
0087 {
0088 G4String abscissaUnit = "";
0089 if (abscissaKind == Abscissa::KineticEnergy) {
0090 abscissaUnit = "GeV";
0091 }
0092 return abscissaUnit;
0093 }
0094
0095
0096
0097
0098 G4double getAbscissaUnitValue(const Abscissa abscissaKind)
0099 {
0100 G4double abscissaUnitValue = 1.;
0101 if (abscissaKind == Abscissa::KineticEnergy) {
0102 abscissaUnitValue = G4UnitDefinition::GetValueOf(getAbscissaUnit(Abscissa::KineticEnergy));
0103 }
0104 return abscissaUnitValue;
0105 }
0106
0107
0108
0109
0110
0111
0112 G4String sformat(const char* fmt, ...)
0113 {
0114 std::unique_ptr<char[]> formatted;
0115 G4int n = (G4int)strlen(fmt) * 2;
0116 while (true) {
0117
0118 formatted.reset(new char[n]);
0119 strcpy(&formatted[0], fmt);
0120 va_list ap;
0121 va_start(ap, fmt);
0122 G4int final_n = vsnprintf(&formatted[0], n, fmt, ap);
0123 va_end(ap);
0124 if (final_n < 0 || final_n >= n) {
0125 n += std::abs(final_n - n + 1);
0126 }
0127 else {
0128 break;
0129 }
0130 }
0131 return G4String(formatted.get());
0132 }
0133
0134
0135
0136
0137 G4double computeError(const G4double mean, const G4double sumSquares, const G4int numEvents)
0138 {
0139 const G4double var = std::max(0., sumSquares / numEvents - mean * mean);
0140 const G4double err =
0141 ((mean != 0. && numEvents > 1) ? std::sqrt(var / (numEvents - 1)) / mean : 1.);
0142
0143 return err * 100.;
0144 }
0145
0146
0147
0148
0149 void dumpG4H1HistoInFlairFormat(std::ofstream& output, const G4int indexInOutputFile,
0150 const G4String& histoName, G4H1* const histo,
0151 const Abscissa abscissaKind, const G4String& binSchemeName,
0152 const G4int numEvents, const G4double sumSquaredEventTotals,
0153 const G4double sumSquaredEventInRangeTotals)
0154 {
0155 const G4bool isProfile = false;
0156 dumpG4H1InFlairFormat(output, indexInOutputFile, histoName, histo, abscissaKind, binSchemeName,
0157 numEvents, isProfile, sumSquaredEventTotals, sumSquaredEventInRangeTotals);
0158 }
0159
0160
0161
0162
0163 void dumpG4H1ProfileInFlairFormat(std::ofstream& output, const G4int indexInOutputFile,
0164 const G4String& histoName, G4H1* const histo,
0165 const Abscissa abscissaKind, const G4String& binSchemeName)
0166 {
0167 const G4bool isProfile = true;
0168 const G4int numEvents = 1;
0169 dumpG4H1InFlairFormat(output, indexInOutputFile, histoName, histo, abscissaKind, binSchemeName,
0170 numEvents, isProfile);
0171 }
0172
0173
0174
0175
0176 void dumpG4H1InFlairFormat(std::ofstream& output, const G4int indexInOutputFile,
0177 const G4String& histoName, G4H1* const histo,
0178 const Abscissa abscissaKind, const G4String& binSchemeName,
0179 const G4int numEvents, const G4bool isProfile,
0180 const G4double sumSquaredEventTotals,
0181 const G4double sumSquaredEventInRangeTotals)
0182 {
0183 const G4int numBins = histo->axis().bins();
0184 const G4double minAbscissa = histo->axis().lower_edge();
0185 const G4double maxAbscissa = histo->axis().upper_edge();
0186
0187 const G4String abscissaName = getAbscissaName(abscissaKind);
0188 const G4String abscissaUnit = getAbscissaUnit(abscissaKind);
0189 const G4double abscissaUnitValue = getAbscissaUnitValue(abscissaKind);
0190
0191
0192 if (indexInOutputFile != 1) {
0193 output << G4endl << G4endl;
0194 }
0195 output << std::left << std::setw(13) << "# Detector: " << indexInOutputFile << " " << histoName
0196 << G4endl;
0197 output << std::left << std::setw(13) << "# Dim: " << histo->get_dimension() << G4endl;
0198 output << std::left << std::setw(13) << "# Entries: " << numEvents << G4endl;
0199
0200 if (!isProfile) {
0201
0202 const G4double total = static_cast<G4double>(histo->sum_all_bin_heights()) / numEvents;
0203 const G4double totalError = computeError(total, sumSquaredEventTotals, numEvents);
0204 output << std::left << std::setw(13)
0205 << "# Total: " << sformat("%-15g [1/pr] +/- %6.2f [%] \n", total, totalError);
0206
0207
0208 const G4double inRange = static_cast<G4double>(histo->sum_bin_heights()) / numEvents;
0209 const G4double inRangeError = computeError(inRange, sumSquaredEventInRangeTotals, numEvents);
0210 output << std::left << std::setw(13)
0211 << "# InRange: " << sformat("%-15g [1/pr] +/- %6.2f [%] \n", inRange, inRangeError);
0212
0213
0214 const G4double underflow = static_cast<G4double>(histo->bins_sum_w().at(0)) / numEvents;
0215 const G4double underflowError = computeError(underflow, histo->bins_sum_w2().at(0), numEvents);
0216 output << std::left << std::setw(13)
0217 << "# Under: " << sformat("%-15g [1/pr] +/- %6.2f [%] \n", underflow, underflowError);
0218
0219
0220 const G4double overflow =
0221 static_cast<G4double>(histo->bins_sum_w().at(numBins + 1)) / numEvents;
0222 const G4double overflowError =
0223 computeError(overflow, histo->bins_sum_w2().at(numBins + 1), numEvents);
0224 output << std::left << std::setw(13)
0225 << "# Over: " << sformat("%-15g [1/pr] +/- %6.2f [%] \n", overflow, overflowError);
0226 }
0227
0228
0229 output << std::left << std::setw(13) << "# Log: " << binSchemeName << G4endl;
0230 output << std::left << std::setw(13) << "# Histogram: " << numBins << " "
0231 << minAbscissa / abscissaUnitValue << " " << maxAbscissa / abscissaUnitValue << " ["
0232 << abscissaUnit << "]" << G4endl;
0233
0234 output << std::left << std::setw(13) << "# Column: "
0235 << "1 " << abscissaName << "_min "
0236 << "[" << abscissaUnit << "]" << G4endl;
0237 output << std::left << std::setw(13) << "# Column: "
0238 << "2 " << abscissaName << "_max "
0239 << "[" << abscissaUnit << "]" << G4endl;
0240 output << std::left << std::setw(13) << "# Column: "
0241 << "3 dN/d(" << abscissaName << ") "
0242 << "[1" << (abscissaUnit.empty() ? "" : ("/" + abscissaUnit)) << "/pr]" << G4endl;
0243 if (!isProfile) {
0244 output << std::left << std::setw(13) << "# Column: "
0245 << "4 error "
0246 << "[%]" << G4endl;
0247 }
0248
0249
0250 for (G4int binIndex = 0; binIndex < numBins; ++binIndex) {
0251 const G4double mean = histo->bin_height(binIndex) / numEvents;
0252 const G4double err = computeError(mean, histo->bins_sum_w2().at(binIndex + 1), numEvents);
0253
0254
0255 if (!isProfile) {
0256 output << sformat("%15g %15g %15g %6.2f\n",
0257 histo->axis().bin_lower_edge(binIndex) / abscissaUnitValue,
0258 histo->axis().bin_upper_edge(binIndex) / abscissaUnitValue,
0259 mean / histo->axis().bin_width(binIndex) * abscissaUnitValue, err);
0260 }
0261
0262 else {
0263 output << sformat("%15g %15g %15g\n",
0264 histo->axis().bin_lower_edge(binIndex) / abscissaUnitValue,
0265 histo->axis().bin_upper_edge(binIndex) / abscissaUnitValue,
0266 mean / histo->axis().bin_width(binIndex) * abscissaUnitValue);
0267 }
0268 }
0269 }
0270
0271 }
0272 }
0273 }
0274
0275