File indexing completed on 2026-09-12 08:29:24
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 #include "RunAction.hh"
0030
0031 #include "DetectorConstruction.hh"
0032 #include "HistoManager.hh"
0033 #include "MuCrossSections.hh"
0034 #include "PrimaryGeneratorAction.hh"
0035
0036 #include "G4EmCalculator.hh"
0037 #include "G4PhysicalConstants.hh"
0038 #include "G4ProductionCutsTable.hh"
0039 #include "G4Run.hh"
0040 #include "G4RunManager.hh"
0041 #include "G4SystemOfUnits.hh"
0042 #include "G4UnitsTable.hh"
0043 #include "Randomize.hh"
0044
0045
0046
0047 RunAction::RunAction(DetectorConstruction* det, PrimaryGeneratorAction* prim, HistoManager* HistM)
0048 : G4UserRunAction(), fDetector(det), fPrimary(prim), fProcCounter(0), fHistoManager(HistM)
0049 {
0050 fMucs = new MuCrossSections();
0051 }
0052
0053
0054
0055 RunAction::~RunAction()
0056 {
0057 delete fMucs;
0058 }
0059
0060
0061
0062 void RunAction::BeginOfRunAction(const G4Run* aRun)
0063 {
0064 G4cout << "### Run " << aRun->GetRunID() << " start." << G4endl;
0065
0066
0067 CLHEP::HepRandom::showEngineStatus();
0068
0069 fProcCounter = new ProcessesCount();
0070 fHistoManager->Book();
0071 }
0072
0073
0074
0075 void RunAction::CountProcesses(const G4String& procName)
0076 {
0077
0078 size_t n = fProcCounter->size();
0079 for (size_t i = 0; i < n; ++i) {
0080 if ((*fProcCounter)[i]->GetName() == procName) {
0081 (*fProcCounter)[i]->Count();
0082 return;
0083 }
0084 }
0085 OneProcessCount* count = new OneProcessCount(procName);
0086 count->Count();
0087 fProcCounter->push_back(count);
0088 }
0089
0090
0091
0092 void RunAction::EndOfRunAction(const G4Run* aRun)
0093 {
0094 G4int NbOfEvents = aRun->GetNumberOfEvent();
0095 if (NbOfEvents == 0) return;
0096
0097
0098 G4int prec = G4cout.precision(2);
0099
0100 const G4Material* material = fDetector->GetMaterial();
0101 G4double length = fDetector->GetSize();
0102 G4double density = material->GetDensity();
0103
0104 G4String particle = fPrimary->GetParticleGun()->GetParticleDefinition()->GetParticleName();
0105 G4double energy = fPrimary->GetParticleGun()->GetParticleEnergy();
0106
0107 G4cout << "\n The run consists of " << NbOfEvents << " " << particle << " of "
0108 << G4BestUnit(energy, "Energy") << " through " << G4BestUnit(length, "Length") << " of "
0109 << material->GetName() << " (density: " << G4BestUnit(density, "Volumic Mass") << ")"
0110 << G4endl;
0111
0112
0113 G4double countTot = 0.;
0114 G4cout << "\n Number of process calls --->";
0115 for (size_t i = 0; i < fProcCounter->size(); ++i) {
0116 G4String procName = (*fProcCounter)[i]->GetName();
0117 if (procName != "Transportation") {
0118 G4int count = (*fProcCounter)[i]->GetCounter();
0119 G4cout << "\t" << procName << " : " << count;
0120 countTot += count;
0121 }
0122 }
0123
0124
0125
0126 G4double totalCrossSection = countTot / (NbOfEvents * length);
0127 G4double MeanFreePath = 1. / totalCrossSection;
0128 G4double massCrossSection = totalCrossSection / density;
0129
0130 G4cout.precision(5);
0131 G4cout << "\n Simulation: "
0132 << "total CrossSection = " << totalCrossSection * cm << " /cm"
0133 << "\t MeanFreePath = " << G4BestUnit(MeanFreePath, "Length")
0134 << "\t massicCrossSection = " << massCrossSection * g / cm2 << " cm2/g" << G4endl;
0135
0136
0137
0138 if (particle == "mu+" || particle == "mu-") {
0139 totalCrossSection = 0.;
0140 for (size_t i = 0; i < fProcCounter->size(); ++i) {
0141 G4String procName = (*fProcCounter)[i]->GetName();
0142 if (procName != "Transportation") {
0143 totalCrossSection += ComputeTheory(procName, NbOfEvents);
0144 FillCrossSectionHisto(procName, NbOfEvents);
0145 }
0146 }
0147
0148 MeanFreePath = 1. / totalCrossSection;
0149 massCrossSection = totalCrossSection / density;
0150
0151 G4cout << " Theory: "
0152 << "total CrossSection = " << totalCrossSection * cm << " /cm"
0153 << "\t MeanFreePath = " << G4BestUnit(MeanFreePath, "Length")
0154 << "\t massicCrossSection = " << massCrossSection * g / cm2 << " cm2/g" << G4endl;
0155 }
0156
0157
0158 G4cout.precision(prec);
0159
0160
0161 size_t n = fProcCounter->size();
0162 for (size_t i = 0; i < n; ++i) {
0163 delete (*fProcCounter)[i];
0164 }
0165 delete fProcCounter;
0166
0167 fHistoManager->Save();
0168
0169
0170
0171 }
0172
0173
0174
0175 G4double RunAction::ComputeTheory(const G4String& process, G4int NbOfMu)
0176 {
0177 const G4Material* material = fDetector->GetMaterial();
0178 G4double ekin = fPrimary->GetParticleGun()->GetParticleEnergy();
0179 G4double particleMass = fPrimary->GetParticleGun()->GetParticleDefinition()->GetPDGMass();
0180
0181 G4int id = 0;
0182 G4double cut = 1.e-10 * ekin;
0183 if (process == "muIoni") {
0184 id = 11;
0185 cut = GetEnergyCut(material, 1);
0186 }
0187 else if (process == "muPairProd") {
0188 id = 12;
0189 cut = 2 * (GetEnergyCut(material, 1) + electron_mass_c2);
0190 }
0191 else if (process == "muBrems") {
0192 id = 13;
0193 cut = GetEnergyCut(material, 0);
0194 }
0195 else if (process == "muonNuclear") {
0196 id = 14;
0197 cut = 100 * MeV;
0198 }
0199 else if (process == "muToMuonPairProd") {
0200 id = 18;
0201 cut = 2 * particleMass;
0202 }
0203 if (id == 0) {
0204 return 0.;
0205 }
0206
0207 G4int nbOfBins = 100;
0208
0209 G4double binMin = std::log10(cut / ekin);
0210 G4double binMax = 0.;
0211 G4double binWidth = (binMax - binMin) / G4double(nbOfBins);
0212
0213
0214
0215 G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();
0216
0217 G4H1* histoTh = 0;
0218 if (fHistoManager->HistoExist(id)) {
0219 histoTh = analysisManager->GetH1(fHistoManager->GetHistoID(id));
0220 nbOfBins = fHistoManager->GetNbins(id);
0221 binMin = fHistoManager->GetVmin(id);
0222 binMax = fHistoManager->GetVmax(id);
0223 binWidth = fHistoManager->GetBinWidth(id);
0224 }
0225
0226
0227
0228
0229
0230
0231 G4double lgeps, etransf, sigmaE, dsigma;
0232 G4double sigmaTot = 0.;
0233 const G4double ln10 = std::log(10.);
0234 G4double length = fDetector->GetSize();
0235
0236
0237
0238
0239 for (G4int ibin = 0; ibin < nbOfBins; ibin++) {
0240 lgeps = binMin + (ibin + 0.5) * binWidth;
0241 etransf = ekin * std::pow(10., lgeps);
0242 sigmaE = fMucs->CR_Macroscopic(process, material, ekin, etransf);
0243 dsigma = sigmaE * etransf * binWidth * ln10;
0244 if (etransf > cut) sigmaTot += dsigma;
0245 if (histoTh) {
0246 G4double NbProcess = NbOfMu * length * dsigma;
0247 histoTh->fill(lgeps, NbProcess);
0248 }
0249 }
0250
0251
0252
0253 return sigmaTot;
0254 }
0255
0256
0257
0258 void RunAction::FillCrossSectionHisto(const G4String& process, G4int)
0259 {
0260 const G4Material* material = fDetector->GetMaterial();
0261 G4double ekin = fPrimary->GetParticleGun()->GetParticleEnergy();
0262 G4ParticleDefinition* particle = fPrimary->GetParticleGun()->GetParticleDefinition();
0263 G4double particleMass = particle->GetPDGMass();
0264
0265 G4EmCalculator emCal;
0266
0267 G4int id = 0;
0268 G4double cut = 1.e-10 * ekin;
0269 if (process == "muIoni") {
0270 id = 21;
0271 cut = GetEnergyCut(material, 1);
0272 }
0273 else if (process == "muPairProd") {
0274 id = 22;
0275 cut = 2 * (GetEnergyCut(material, 1) + electron_mass_c2);
0276 }
0277 else if (process == "muBrems") {
0278 id = 23;
0279 cut = GetEnergyCut(material, 0);
0280 }
0281 else if (process == "muonNuclear") {
0282 id = 24;
0283 cut = 100 * MeV;
0284 }
0285 else if (process == "muToMuonPairProd") {
0286 id = 28;
0287 cut = 2 * particleMass;
0288 }
0289 if (id == 0) {
0290 return;
0291 }
0292
0293 G4int nbOfBins = 100;
0294 G4double binMin = cut;
0295 G4double binMax = ekin;
0296 G4double binWidth = (binMax - binMin) / G4double(nbOfBins);
0297
0298 G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();
0299
0300 G4H1* histoTh = 0;
0301 if (fHistoManager->HistoExist(id)) {
0302 histoTh = analysisManager->GetH1(fHistoManager->GetHistoID(id));
0303 nbOfBins = fHistoManager->GetNbins(id);
0304 binMin = fHistoManager->GetVmin(id);
0305 binMax = fHistoManager->GetVmax(id);
0306 binWidth = fHistoManager->GetBinWidth(id);
0307 }
0308
0309 G4double sigma, primaryEnergy;
0310
0311 for (G4int ibin = 0; ibin < nbOfBins; ibin++) {
0312 primaryEnergy = binMin + (ibin + 0.5) * binWidth;
0313 sigma = emCal.GetCrossSectionPerVolume(primaryEnergy, particle, process, material);
0314 if (histoTh) {
0315 histoTh->fill(primaryEnergy, sigma);
0316 }
0317 }
0318 }
0319
0320
0321
0322 G4double RunAction::GetEnergyCut(const G4Material* material, G4int idParticle)
0323 {
0324 G4ProductionCutsTable* table = G4ProductionCutsTable::GetProductionCutsTable();
0325
0326 size_t index = 0;
0327 while ((table->GetMaterialCutsCouple(index)->GetMaterial() != material)
0328 && (index < table->GetTableSize()))
0329 index++;
0330
0331 return (*(table->GetEnergyCutsVector(idParticle)))[index];
0332 }
0333
0334