Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 08:29:24

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /// \file RunAction.cc
0027 /// \brief Implementation of the RunAction class
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 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
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 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0054 
0055 RunAction::~RunAction()
0056 {
0057   delete fMucs;
0058 }
0059 
0060 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0061 
0062 void RunAction::BeginOfRunAction(const G4Run* aRun)
0063 {
0064   G4cout << "### Run " << aRun->GetRunID() << " start." << G4endl;
0065 
0066   // save Rndm status
0067   CLHEP::HepRandom::showEngineStatus();
0068 
0069   fProcCounter = new ProcessesCount();
0070   fHistoManager->Book();
0071 }
0072 
0073 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0074 
0075 void RunAction::CountProcesses(const G4String& procName)
0076 {
0077   // does the process  already encounted ?
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 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0091 
0092 void RunAction::EndOfRunAction(const G4Run* aRun)
0093 {
0094   G4int NbOfEvents = aRun->GetNumberOfEvent();
0095   if (NbOfEvents == 0) return;
0096 
0097   //  std::ios::fmtflags mode = G4cout.flags();
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   // total number of process calls
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   // compute totalCrossSection, meanFreePath and massicCrossSection
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   // compute theoretical predictions
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   //  G4cout.setf(mode,std::ios::floatfield);
0158   G4cout.precision(prec);
0159 
0160   // delete and remove all contents in fProcCounter
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   // show Rndm status
0170   // CLHEP::HepRandom::showEngineStatus();
0171 }
0172 
0173 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
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   // G4double binMin = -10.;
0209   G4double binMin = std::log10(cut / ekin);
0210   G4double binMax = 0.;
0211   G4double binWidth = (binMax - binMin) / G4double(nbOfBins);
0212 
0213   // create histo for theoretical crossSections, with same bining as simulation
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   // compute and plot differential crossSection, as function of energy transfert.
0227   // compute and return integrated crossSection for a given process.
0228   //(note: to compare with simulation, the integrated crossSection is function
0229   //        of the energy cut.)
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   // G4cout << "MU: " << process << " E= " << ekin
0237   //        <<"  binMin= " << binMin << " binW= " << binWidth << G4endl;
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   // return integrated crossSection
0252   //
0253   return sigmaTot;
0254 }
0255 
0256 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
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 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
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 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......