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