File indexing completed on 2026-06-15 07:53:17
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
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 #include "FinalStateHistoManager.hh"
0067
0068 #include "G4RootAnalysisManager.hh"
0069
0070
0071 #include "tools_histo_flair.hh"
0072
0073 #include "G4DynamicParticle.hh"
0074 #include "G4Exception.hh"
0075 #include "G4ParticleTable.hh"
0076 #include "G4ios.hh"
0077 #include "g4hntools_defs.hh"
0078
0079
0080
0081 FinalStateHistoManager::FinalStateHistoManager()
0082 : fOutputFileName("all_secondaries"),
0083 fRootOutputFileName(fOutputFileName + ".root"),
0084 fFlairOutputFileName(fOutputFileName + ".hist"),
0085 fNumBins(90),
0086 fMinKineticEnergy(10. * keV),
0087 fMaxKineticEnergy(10. * TeV),
0088 fFunctionName("none"),
0089 fBinSchemeName("log"),
0090 fRootEnergyUnit("MeV"),
0091 fNucleiZMax(25),
0092 fNucleiAMax(50),
0093 fNumEvents(0),
0094 fAnalysisManager(G4RootAnalysisManager::Instance()),
0095 fNucleiZScoreIndex(0),
0096 fNucleiAScoreIndex(1)
0097 {
0098
0099
0100
0101
0102 }
0103
0104
0105
0106
0107
0108 void FinalStateHistoManager::Book()
0109 {
0110
0111 if (!fAnalysisManager->OpenFile(fRootOutputFileName)) {
0112 G4ExceptionDescription msg;
0113 msg << "Booking histograms: cannot open file " << fRootOutputFileName << G4endl;
0114 G4Exception("FinalStateHistoManager::Book", "Cannot open file", FatalException, msg);
0115 }
0116 G4cout << "### FinalStateHistoManager::Book: Successfully opended file " << fRootOutputFileName
0117 << " for dumping histograms." << G4endl;
0118
0119
0120 const G4int nucleiZHistoIndex = fAnalysisManager->CreateH1(
0121 "nucleiZ", "Residual nuclei distribution in Z", fNucleiZMax, 0.5, fNucleiZMax + 0.5);
0122 auto nucleiZHistoWrapper = std::make_unique<G4H1Wrapper>(fAnalysisManager, nucleiZHistoIndex);
0123 fNucleiData.insert(std::make_pair(fNucleiZScoreIndex, std::move(nucleiZHistoWrapper)));
0124
0125 const G4int nucleiAHistoIndex = fAnalysisManager->CreateH1(
0126 "nucleiA", "Residual nuclei distribution in A", fNucleiAMax, 0.5, fNucleiAMax + 0.5);
0127 auto nucleiAHistoWrapper = std::make_unique<G4H1Wrapper>(fAnalysisManager, nucleiAHistoIndex);
0128 fNucleiData.insert(std::make_pair(fNucleiAScoreIndex, std::move(nucleiAHistoWrapper)));
0129 }
0130
0131
0132
0133
0134 void FinalStateHistoManager::BeginOfEvent()
0135 {
0136 fNumEvents++;
0137 }
0138
0139
0140
0141
0142 void FinalStateHistoManager::ScoreSecondary(const G4DynamicParticle* const secondary)
0143 {
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 const auto& particle = secondary->GetDefinition();
0157
0158
0159
0160
0161
0162 const auto found = fParticleData.find(secondary->GetPDGcode());
0163
0164 G4H1Wrapper* particleHistoWrapper = nullptr;
0165
0166 if (found != fParticleData.end()) {
0167 particleHistoWrapper = found->second.get();
0168 }
0169
0170 else {
0171 const G4String& particleName = particle->GetParticleName();
0172 const G4int particlePDG = secondary->GetPDGcode();
0173
0174 const G4String histoTitle = (particlePDG == 0 ? G4String("Particle pdg==0 spectrum")
0175 : particleName + G4String(" spectrum"));
0176 const G4int histoIndex =
0177 fAnalysisManager->CreateH1(particleName, histoTitle, fNumBins, fMinKineticEnergy,
0178 fMaxKineticEnergy, fRootEnergyUnit, fFunctionName, fBinSchemeName);
0179 auto histoWrapper = std::make_unique<G4H1Wrapper>(fAnalysisManager, histoIndex);
0180 particleHistoWrapper = histoWrapper.get();
0181 fParticleData.insert(std::make_pair(particlePDG, std::move(histoWrapper)));
0182 }
0183
0184
0185 const G4double kineticEnergy = secondary->GetKineticEnergy();
0186 particleHistoWrapper->Fill(kineticEnergy, 1.);
0187
0188
0189 if (particle->GetParticleType() == "nucleus") {
0190
0191 const G4double Z = particle->GetPDGCharge() / eplus;
0192 fNucleiData[fNucleiZScoreIndex]->Fill(Z, 1.);
0193
0194
0195 const G4double A = particle->GetBaryonNumber();
0196 fNucleiData[fNucleiAScoreIndex]->Fill(A, 1.);
0197 }
0198
0199
0200 }
0201
0202
0203
0204
0205 void FinalStateHistoManager::EndOfEvent()
0206 {
0207 for (const auto& particleIt : fParticleData) {
0208 particleIt.second->EndOfEvent();
0209 }
0210 for (const auto& nucleiScoreIt : fNucleiData) {
0211 nucleiScoreIt.second->EndOfEvent();
0212 }
0213 }
0214
0215
0216
0217
0218 void FinalStateHistoManager::EndOfRun() const
0219 {
0220
0221
0222
0223 std::map<G4String, const G4H1Wrapper*> particlesHistos;
0224
0225 for (const auto& particleIt : fParticleData) {
0226 const G4int particlePdg = particleIt.first;
0227 const G4String particleName =
0228 G4ParticleTable::GetParticleTable()->FindParticle(particlePdg)->GetParticleName();
0229
0230 const G4H1Wrapper* const particleHisto = particleIt.second.get();
0231 particlesHistos.insert(std::make_pair(particleName, particleHisto));
0232 }
0233
0234
0235
0236 G4cout << "========================================================" << G4endl;
0237 G4cout << "Number of events " << fNumEvents << G4endl << G4endl;
0238 for (const auto& particleIt : particlesHistos) {
0239
0240
0241 const G4int count = particleIt.second->GetG4H1()->sum_all_bin_heights();
0242
0243 const G4double averageCount = static_cast<G4double>(count) / fNumEvents;
0244
0245 G4cout << "Average (per event) number of " << particleIt.first << " "
0246 << averageCount << G4endl;
0247 }
0248 G4cout << "========================================================" << G4endl;
0249 G4cout << G4endl;
0250
0251
0252 DumpAllG4H1IntoRootFile();
0253
0254
0255 DumpAllG4H1IntoFlairFile(particlesHistos);
0256
0257
0258 fAnalysisManager->CloseFile();
0259 fAnalysisManager->Clear();
0260 }
0261
0262
0263
0264
0265 void FinalStateHistoManager::DumpAllG4H1IntoRootFile() const
0266 {
0267 if (!fAnalysisManager->Write()) {
0268 G4ExceptionDescription message;
0269 message << "Could not write ROOT file.";
0270 G4Exception("FinalStateHistoManager::EndOfRun()", "I/O Error", FatalException, message);
0271 }
0272 G4cout << "### All histograms saved to " << fRootOutputFileName << G4endl;
0273 }
0274
0275
0276
0277
0278 void FinalStateHistoManager::DumpAllG4H1IntoFlairFile(
0279 const std::map<G4String, const G4H1Wrapper*>& particlesHistos) const
0280 {
0281 std::ofstream output;
0282 output.open(fFlairOutputFileName, std::ios_base::out);
0283 G4int indexInOutputFile = 1;
0284
0285
0286 for (const auto& particleIt : particlesHistos) {
0287 const G4String& histoName = particleIt.first;
0288 const auto& histo = particleIt.second->GetG4H1();
0289
0290 tools::histo::flair::dumpG4H1HistoInFlairFormat(
0291 output, indexInOutputFile, histoName, histo, tools::histo::flair::Abscissa::KineticEnergy,
0292 fBinSchemeName, fNumEvents, particleIt.second->GetSumSquaredEventTotals(),
0293 particleIt.second->GetSumSquaredEventInRangeTotals());
0294 ++indexInOutputFile;
0295 }
0296
0297
0298 for (const auto& plotIt : fNucleiData) {
0299 const auto& histo = plotIt.second->GetG4H1();
0300 const G4String& histoName = (plotIt.first == fNucleiZScoreIndex ? "nucleiZ" : "nucleiA");
0301 const auto& abscissaKind =
0302 (plotIt.first == fNucleiZScoreIndex ? tools::histo::flair::Abscissa::Z
0303 : tools::histo::flair::Abscissa::A);
0304
0305 tools::histo::flair::dumpG4H1HistoInFlairFormat(
0306 output, indexInOutputFile, histoName, histo, abscissaKind, fBinSchemeName, fNumEvents,
0307 plotIt.second->GetSumSquaredEventTotals(), plotIt.second->GetSumSquaredEventInRangeTotals());
0308 ++indexInOutputFile;
0309 }
0310
0311 output.close();
0312 G4cout << "### All histograms saved to " << fFlairOutputFileName << G4endl;
0313 }
0314
0315