Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-11 08:09:11

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 Scorer.cc
0027 /// \brief Implementation of the Scorer class
0028 
0029 #include "Scorer.hh"
0030 
0031 #include "InterPulseAction.hh"
0032 #include "PrimaryGeneratorAction.hh"
0033 #include "PulseAction.hh"
0034 #include "TimeStepAction.hh"
0035 
0036 #include "G4AnalysisManager.hh"
0037 #include "G4DNAEventScheduler.hh"
0038 #include "G4DNAScavengerMaterial.hh"
0039 #include "G4Event.hh"
0040 #include "G4PhysicalConstants.hh"
0041 #include "G4RunManager.hh"
0042 #include "G4Scheduler.hh"
0043 #include "G4UIcmdWithADoubleAndUnit.hh"
0044 #include "G4UIcmdWithAnInteger.hh"
0045 #include "G4VChemistryWorld.hh"
0046 
0047 #include <G4EventManager.hh>
0048 #include <G4MolecularConfiguration.hh>
0049 #include <G4SystemOfUnits.hh>
0050 #include <globals.hh>
0051 
0052 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0053 
0054 // Dose
0055 Dose::Dose()
0056   : G4UImessenger(),
0057     fpDoseDir(new G4UIdirectory("/scorer/Dose/")),
0058     fpAddDoseCutOff(new G4UIcmdWithADoubleAndUnit("/scorer/Dose/cutoff", this)),
0059     fpAddDoseToAbort(new G4UIcmdWithADoubleAndUnit("/scorer/Dose/abortedDose", this))
0060 {
0061   fpDoseDir->SetGuidance("Dose scorer commands");
0062 }
0063 
0064 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0065 
0066 void Dose::SetNewValue(G4UIcommand* command, G4String newValue)
0067 {
0068   if (command == fpAddDoseCutOff.get()) {
0069     fDosesCutOff = G4UIcmdWithADoubleAndUnit::GetNewDoubleValue(newValue);
0070   }
0071   if (command == fpAddDoseToAbort.get()) {
0072     fDosesToAbort = G4UIcmdWithADoubleAndUnit::GetNewDoubleValue(newValue);
0073   }
0074 }
0075 
0076 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0077 
0078 template<>
0079 void Scorer<Dose>::SetChemistryWorld(G4VChemistryWorld* pChemistryWorld)
0080 {
0081   fpChemistryWorld = pChemistryWorld;
0082 }
0083 
0084 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0085 
0086 template<>
0087 G4VChemistryWorld* Scorer<Dose>::GetChemistryWorld() const
0088 {
0089   return fpChemistryWorld;
0090 }
0091 
0092 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0093 
0094 template<>
0095 void Scorer<Dose>::clear()
0096 {
0097   fpScorer->fCumulatedDose = 0.;
0098   fpScorer->fPulseMax = 0;
0099 }
0100 
0101 template<>
0102 void Scorer<Dose>::Initialize(G4HCofThisEvent* HCE)
0103 {
0104   clear();
0105   fpEvtMap = new G4THitsMap<G4double>(GetMultiFunctionalDetector()->GetName(),
0106                                       GetName());
0107   if (fHCID < 0) {
0108     fHCID = GetCollectionID(0);
0109   }
0110   HCE->AddHitsCollection(fHCID, (G4VHitsCollection*)fpEvtMap);
0111 
0112   fPulseActionInfo =
0113     dynamic_cast<const InterPulseAction*>(G4RunManager::GetRunManager()
0114                                           ->GetUserTrackingAction());
0115 }
0116 
0117 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0118 
0119 template<>
0120 void Scorer<Dose>::EndOfEvent(G4HCofThisEvent*)
0121 {
0122   if (!G4RunManager::GetRunManager()->GetCurrentEvent()->IsAborted()) {
0123     fpEvtMap->add(0, fpScorer->fDosesCutOff);
0124   }
0125   fpScorer->fCumulatedDose = 0.;
0126   fpScorer->fPulseMax = 0;
0127 }
0128 
0129 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0130 
0131 template<>
0132 G4bool Scorer<Dose>::ProcessHits(G4Step* aStep, G4TouchableHistory*)
0133 {
0134   auto currentEvent = G4EventManager::GetEventManager();
0135   const G4Track* track = aStep->GetTrack();
0136   auto boundingBox = fpChemistryWorld->GetChemistryBoundary();
0137 
0138   G4double V = boundingBox->Volume() / cm3;
0139   G4double edep = aStep->GetTotalEnergyDeposit();
0140   if (edep == 0.) {
0141     return false;
0142   }
0143   G4double eToGray = (0.001 * V * 6.242e+18);
0144   if (eToGray != 0) {
0145     (fpScorer->fCumulatedDose) += ((edep) / eV) / eToGray;
0146   }
0147   if (track->GetParentID() == 0 && aStep->IsFirstStepInVolume()) {
0148     auto pulseInfo = dynamic_cast<PulseInfo*>(track->GetUserInformation());
0149     if (pulseInfo != nullptr) {
0150       auto delayedTime = pulseInfo->GetDelayedTime();
0151       if (fpScorer->fPulseMax < delayedTime) {
0152         fpScorer->fPulseMax = delayedTime;
0153       }
0154     }
0155     G4double DoseInGray = fpScorer->fCumulatedDose;
0156     if (DoseInGray > fpScorer->fDosesCutOff / gray) {
0157       G4cout << "______________________________________________________________"
0158              << G4endl;
0159       auto name = currentEvent->GetConstCurrentEvent()
0160                     ->GetPrimaryVertex()
0161                     ->GetPrimary()
0162                     ->GetParticleDefinition()
0163                     ->GetParticleName();
0164       auto energy = currentEvent->GetConstCurrentEvent()
0165                     ->GetPrimaryVertex()->GetPrimary()->GetKineticEnergy();
0166 
0167       G4cout << "Beam line            : " << "(" << name << ", " << energy
0168              << " MeV)" << G4endl;
0169       G4cout << "Cut-off dose         : " << fpScorer->fDosesCutOff / gray
0170              << " Gy" << G4endl;
0171       G4cout << "Stop at actual dose  : " << DoseInGray << " Gy" << G4endl;
0172       if (fPulseActionInfo != nullptr) {
0173         auto numberOfPulse = fPulseActionInfo->GetNumberOfPulse();
0174         auto DIT = fPulseActionInfo->GetPulsePeriod();
0175         G4cout << "DIT                  : " << DIT / CLHEP::ms << " ms" << G4endl;
0176         G4cout << "Pulse number         : " << numberOfPulse << G4endl;
0177       }
0178 
0179       const auto generatorAction = static_cast<const PrimaryGeneratorAction*>(
0180         G4RunManager::GetRunManager()->GetUserPrimaryGeneratorAction());
0181       const auto particleGun = generatorAction->GetSPGun();
0182       auto NumberOfParticlesGeneratedinOneEvent = particleGun->GetNumberOfParticles();
0183 
0184       G4cout << "Beam duration        : " << fpScorer->fPulseMax / second
0185              << " s" << G4endl;
0186       if(fpScorer->fPulseMax != 0){
0187         G4cout << "Actual dose rate     : "
0188                << DoseInGray / (fpScorer->fPulseMax / second) << " Gy/s"
0189                << G4endl;
0190       }else{
0191         G4cout << "Actual dose rate     : " << "infinite"
0192                << G4endl;
0193       }
0194 
0195       G4cout << "Track number         : "
0196              << NumberOfParticlesGeneratedinOneEvent
0197                   - currentEvent->GetStackManager()->GetNUrgentTrack() - 1
0198              << " tracks" << G4endl;
0199       G4cout << "Irradiated volume    : " << V * 1e+12  // convert cm3 to um3
0200              << " um3 (" << 2 * boundingBox->halfSideLengthInX() / um << " x "
0201              << 2 * boundingBox->halfSideLengthInY() / um << " x "
0202              << 2 * boundingBox->halfSideLengthInZ() / um << ")" << G4endl;
0203       auto ChemComponent = fpChemistryWorld->GetChemicalComponent();
0204       for (const auto& it : ChemComponent) {
0205         if (fH2O == it.first) continue;
0206         if (fOHm == it.first) continue;
0207         if (it.first == fH3Op) {
0208           G4cout << "pH                   : "
0209                  << -std::log10(it.second * (mole * liter)) << G4endl;
0210           continue;
0211         }
0212         G4cout << it.first->GetName() << "                : "
0213                << it.second * (mole * liter) << " M "
0214                << G4endl;
0215       }
0216 
0217       G4cout << "Total deposit energy : "
0218              << fpScorer->fCumulatedDose * eToGray << " eV" << G4endl;
0219       G4double DoseAbort;
0220       if (fpScorer->fDosesToAbort == 0) {
0221         DoseAbort = fpScorer->fDosesCutOff / gray
0222                   + 0.5 * fpScorer->fDosesCutOff / gray;
0223       }
0224       else {
0225         DoseAbort = fpScorer->fDosesToAbort / gray;
0226       }
0227 
0228       G4cout << "Dose to abort        : " << DoseAbort << " Gy" << G4endl;
0229       if (DoseInGray > DoseAbort) {
0230         G4cout << "Abort this beam line (" << name << ", " << energy
0231                << " MeV) at actual dose: " << DoseInGray << " Gy" << G4endl;
0232         G4RunManager::GetRunManager()->AbortEvent();
0233       }
0234       G4cout << "______________________________________________________________"
0235              << G4endl;
0236       auto myTrack = ((G4Track*)track);
0237       myTrack->SetTrackStatus(fStopAndKill);
0238       auto secondaries = track->GetStep()->GetSecondaryInCurrentStep();
0239       if (!secondaries->empty()) {
0240         for (auto it : *(secondaries)) {
0241           if (it != nullptr) {
0242             ((G4Track*)it)->SetTrackStatus(fStopAndKill);
0243           }
0244         }
0245       }
0246       currentEvent->GetStackManager()->ClearUrgentStack();
0247     }
0248   }
0249   return true;
0250 }
0251 
0252 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0253 
0254 // Gvalues
0255 Gvalues::Gvalues()
0256   : G4UImessenger(),
0257     fTimeLimit(G4Scheduler::Instance()->GetEndTime()),
0258     fSpeciesdir(new G4UIdirectory("/scorer/Gvalues/")),
0259     fTimeBincmd(new G4UIcmdWithAnInteger("/scorer/Gvalues/nOfTimeBins", this)),
0260     fAddTimeToRecordcmd(new G4UIcmdWithADoubleAndUnit("/scorer/Gvalues/addTimeToRecord", this))
0261 {
0262   fSpeciesdir->SetGuidance("ScoreSpecies commands");
0263 }
0264 
0265 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0266 
0267 void Gvalues::SetNewValue(G4UIcommand* command, G4String newValue)
0268 {
0269   if (command == fAddTimeToRecordcmd.get()) {
0270     G4double cmdTime = fAddTimeToRecordcmd->GetNewDoubleValue(newValue);
0271     if (fTimeLimit >= cmdTime) {
0272       AddTimeToRecord(cmdTime);
0273     }
0274     else {
0275       AddTimeToRecord(fTimeLimit);
0276     }
0277   }
0278   if (command == fTimeBincmd.get()) {
0279     G4int cmdBins = fTimeBincmd->GetNewIntValue(newValue);
0280     G4double timeMin = 1 * ps;
0281     G4double timeMax = G4Scheduler::Instance()->GetEndTime() - timeMin;
0282     G4double timeLogMin = std::log10(timeMin);
0283     G4double timeLogMax = std::log10(timeMax);
0284     for (int i = 0; i <= cmdBins; i++) {
0285       AddTimeToRecord(std::pow(10, timeLogMin + i * (timeLogMax - timeLogMin) / cmdBins));
0286     }
0287   }
0288 }
0289 
0290 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0291 void Gvalues::
0292 WriteInfo(G4VAnalysisManager* analysisManager, const std::string& out)
0293 {
0294   G4int NtupleID = analysisManager->CreateNtuple("info", "Simulation");
0295   analysisManager->CreateNtupleDColumn(NtupleID, "Dose");
0296   analysisManager->FinishNtuple(NtupleID);
0297   analysisManager->FillNtupleDColumn(NtupleID, 0, std::stod(out));
0298   analysisManager->AddNtupleRow(NtupleID);
0299 }
0300 
0301 void Gvalues::WriteGvalues(G4VAnalysisManager* analysisManager)
0302 {
0303   G4int NtupleID = analysisManager->CreateNtuple("Gvalue", "Gvalue");
0304   analysisManager->CreateNtupleIColumn(NtupleID, "speciesID");
0305   analysisManager->CreateNtupleIColumn(NtupleID, "number");
0306   analysisManager->CreateNtupleIColumn(NtupleID, "nEvent");
0307   analysisManager->CreateNtupleSColumn(NtupleID, "speciesName");
0308   analysisManager->CreateNtupleDColumn(NtupleID, "time");
0309   analysisManager->CreateNtupleDColumn(NtupleID, "sumG");
0310   analysisManager->CreateNtupleDColumn(NtupleID, "sumG2");
0311   analysisManager->CreateNtupleDColumn(NtupleID, "TotalDose");
0312   analysisManager->CreateNtupleDColumn(NtupleID, "TotalDose2");
0313   analysisManager->CreateNtupleDColumn(NtupleID, "TotalDoseRate");
0314   analysisManager->CreateNtupleDColumn(NtupleID, "TotalDoseRate2");
0315   analysisManager->FinishNtuple(NtupleID);
0316 
0317   for (const auto& it_map1 : fSpeciesInfoPerTime) {
0318     const InnerSpeciesMap& map2 = it_map1.second;
0319     for (auto it_map2 : map2) {
0320       double time = it_map1.first;
0321       auto species = it_map2.first;
0322       const G4String& name = species->GetName();
0323       int molID = it_map2.first->GetMoleculeID();
0324       auto number = it_map2.second.fNumber;
0325       double G = it_map2.second.fG;
0326       double G2 = it_map2.second.fG2;
0327 
0328       analysisManager->FillNtupleIColumn(NtupleID, 0, molID);  // MolID
0329       analysisManager->FillNtupleIColumn(NtupleID, 1, number);  // Number
0330       analysisManager->FillNtupleIColumn(NtupleID, 2, fNEvent);  // Total nb events
0331       analysisManager->FillNtupleSColumn(NtupleID, 3, name);  // molName
0332       analysisManager->FillNtupleDColumn(NtupleID, 4, time);  // time
0333       analysisManager->FillNtupleDColumn(NtupleID, 5, G);  // G
0334       analysisManager->FillNtupleDColumn(NtupleID, 6, G2);  // G2
0335       analysisManager->FillNtupleDColumn(NtupleID, 7, fTotalDose);
0336       analysisManager->FillNtupleDColumn(NtupleID, 8, fTotalDose2);
0337       analysisManager->FillNtupleDColumn(NtupleID, 9, fTotalDoseRate);
0338       analysisManager->FillNtupleDColumn(NtupleID, 10, fTotalDoseRate2);
0339       analysisManager->AddNtupleRow(NtupleID);
0340     }
0341   }
0342 }
0343 
0344 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0345 void Gvalues::
0346 WriteWithAnalysisManager(G4VAnalysisManager* analysisManager, const std::string& out)
0347 {
0348   WriteInfo(analysisManager, out);
0349   WriteGvalues(analysisManager);
0350   // fRunID++;
0351 }
0352 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0353 
0354 template<>
0355 void Scorer<Gvalues>::clear()
0356 {
0357   fpEvtMap->clear();
0358   fpScorer->fNEvent = 0;
0359   fpScorer->fEdep = 0;
0360   fpScorer->fSpeciesInfoPerTime.clear();
0361 }
0362 
0363 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0364 
0365 template<>
0366 void Scorer<Gvalues>::Initialize(G4HCofThisEvent* HCE)
0367 {
0368   fpEvtMap = new G4THitsMap<G4double>(GetMultiFunctionalDetector()->GetName(), GetName());
0369   if (fHCID < 0) {
0370     fHCID = GetCollectionID(0);
0371   }
0372   HCE->AddHitsCollection(fHCID, (G4VHitsCollection*)fpEvtMap);
0373 }
0374 
0375 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0376 
0377 template<>
0378 void Scorer<Gvalues>::SetChemistryWorld(G4VChemistryWorld* pChemistryWorld)
0379 {
0380   fpChemistryWorld = pChemistryWorld;
0381 }
0382 
0383 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0384 
0385 template<>
0386 G4VChemistryWorld* Scorer<Gvalues>::GetChemistryWorld() const
0387 {
0388   return fpChemistryWorld;
0389 }
0390 
0391 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0392 
0393 template<>
0394 G4bool Scorer<Gvalues>::ProcessHits(G4Step* aStep, G4TouchableHistory*)
0395 {
0396   const G4Track* track = aStep->GetTrack();
0397   auto pulseInfo = dynamic_cast<PulseInfo*>(track->GetUserInformation());
0398   if (pulseInfo != nullptr) {
0399     auto delayedTime = pulseInfo->GetDelayedTime();
0400     if (fpScorer->fPulseMax < delayedTime) {
0401       fpScorer->fPulseMax = delayedTime;
0402     }
0403   }
0404 
0405   G4double edep = aStep->GetTotalEnergyDeposit();
0406   if (edep == 0.) {
0407     return FALSE;
0408   }
0409   edep *= aStep->GetPreStepPoint()->GetWeight();  // (Particle Weight)
0410   G4int index = GetIndex(aStep);
0411   fpEvtMap->add(index, edep);
0412   (fpScorer->fEdep) += edep;
0413   return TRUE;
0414 }
0415 
0416 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0417 
0418 template<>
0419 void Scorer<Gvalues>::SaveScavengerChange()
0420 {
0421   auto pScavengerMaterial =
0422     dynamic_cast<G4DNAScavengerMaterial*>(G4Scheduler::Instance()->GetScavengerMaterial());
0423   if (pScavengerMaterial == nullptr) {
0424     G4ExceptionDescription errMsg;
0425     errMsg << "pScavengerMaterial == nullptr";
0426     G4Exception("Scorer<Gvalues>::SaveScavengerChange()", "SaveScavengerChange",
0427                 FatalErrorInArgument, errMsg);
0428   }
0429   auto scavengerList = pScavengerMaterial->GetScavengerList();
0430   auto V = fpChemistryWorld->GetChemistryBoundary()->Volume();
0431   auto iniC = fpChemistryWorld->GetChemicalComponent();
0432 
0433   G4double eToGray = (0.001 * V * 6.242e+18);
0434   if (eToGray != 0) {
0435     G4double dose = 1000 * (fpScorer->fEdep / eV) / eToGray;  // in Gy
0436     for (const auto& it : scavengerList) {
0437       if (it == fH2O || fH3Op == it || fOHm == it) {
0438         continue;
0439       }
0440       for (auto time_mol : fpScorer->fTimeToRecord) {
0441         int64_t n_mol = pScavengerMaterial->GetNMoleculesAtTime(it, time_mol);
0442         if (n_mol < 0) {
0443           G4ExceptionDescription errMsg;
0444           errMsg << "SaveScavengerChange()::N molecules not valid < 0 : " << it->GetName()
0445                  << " N : " << n_mol << G4endl;
0446           G4Exception("", "N<0", FatalException, errMsg);
0447         }
0448 
0449         Gvalues::SpeciesInfo& molInfo =
0450           fpScorer->fSpeciesInfoPerTime[time_mol][it];
0451         molInfo.fNumber += n_mol;
0452         if (V > 0) {
0453           auto concentration = n_mol / (Avogadro * V /*mm3 to L*/);
0454           // auto percentage = 10*100*(iniC[it]-concentration)*(mole*liter)/0.0013; //in %
0455           // air/10 Gy
0456           auto inuM = (iniC[it] - concentration) * (mole * liter) * 1e6;  // in uM
0457 
0458           if (dose > 0) {
0459             G4double gValue = inuM / dose;  // in uM
0460             molInfo.fG += gValue;
0461             molInfo.fG2 += gValue * gValue;
0462           }
0463         }
0464       }
0465     }
0466   }
0467 }
0468 
0469 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0470 
0471 template<>
0472 void Scorer<Gvalues>::SaveMoleculeCounter()
0473 {
0474   if (fpEventScheduler == nullptr) {
0475     G4Exception("fpEventScheduler == nullptr",
0476                 "Scorer<Gvalues>::SaveMoleculeCounter()",
0477                 FatalException, "fpEventScheduler == nullptr");
0478   }
0479   else {
0480     auto counterMap = fpEventScheduler->GetCounterMap();
0481     if (counterMap.empty()) {
0482       G4Exception("No counter", "Scorer<Gvalues>::SaveMoleculeCounter()",
0483                   JustWarning, "CounterMap is not used");
0484       return;
0485     }
0486     for (const auto& map_mol : counterMap) {
0487       auto time_mol = map_mol.first;
0488       for (auto it_mol : map_mol.second) {
0489         auto molecule = it_mol.first;
0490         if (molecule == fO2) {
0491           continue;
0492         }
0493         int n_mol = it_mol.second;
0494 
0495         if (n_mol < 0) {
0496           G4ExceptionDescription errMsg;
0497           errMsg << "N molecules not valid < 0 " << " molecule : "
0498                  << it_mol.first->GetName()
0499                  << " N : " << n_mol << G4endl;
0500           G4Exception("", "N<0", FatalException, errMsg);
0501         }
0502 
0503         if (fpScorer->fEdep > 0) {
0504           Gvalues::SpeciesInfo& molInfo =
0505             fpScorer->fSpeciesInfoPerTime[time_mol][molecule];
0506           molInfo.fNumber += n_mol;
0507           G4double gValue = (n_mol / (fpScorer->fEdep / eV)) * 100.;
0508           // G4double gValue = n_mol;
0509           molInfo.fG += gValue;
0510           molInfo.fG2 += gValue * gValue;
0511         }
0512       }
0513     }
0514 
0515     auto boundingBox = fpChemistryWorld->GetChemistryBoundary();
0516     G4double V = boundingBox->Volume() / cm3;
0517     G4double eToGray = (0.001 * V * 6.242e+18);
0518     if (eToGray != 0) {
0519       G4double dose = (fpScorer->fEdep / eV) / eToGray;  // in Gy
0520       if (fpScorer->fPulseMax != 0) {
0521         G4double doseRate = dose / (fpScorer->fPulseMax / second);
0522         fpScorer->fTotalDose += dose;
0523         fpScorer->fTotalDose2 += dose * dose;
0524         fpScorer->fTotalDoseRate += doseRate;
0525         fpScorer->fTotalDoseRate2 += doseRate * doseRate;
0526       }
0527     }
0528   }
0529 }
0530 
0531 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0532 
0533 template<>
0534 void Scorer<Gvalues>::EndOfEvent(G4HCofThisEvent*)
0535 {
0536   if (G4EventManager::GetEventManager()->GetConstCurrentEvent()->IsAborted()) {
0537     fpScorer->fEdep = 0.;
0538     fpEventScheduler->ResetCounter();
0539     return;
0540   }
0541 
0542   SaveScavengerChange();
0543   SaveMoleculeCounter();
0544 
0545   ++(fpScorer->fNEvent);
0546   fpScorer->fEdep = 0.;
0547 
0548   fpEventScheduler->ResetCounter();
0549 }
0550 
0551 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0552 
0553 template<>
0554 void Scorer<Gvalues>::AbsorbResultsFromWorkerScorer(G4VPrimitiveScorer* workerScorer)
0555 {
0556   auto right = dynamic_cast<Scorer<Gvalues>*>(dynamic_cast<G4VPrimitiveScorer*>(workerScorer));
0557 
0558   if (right == nullptr) {
0559     return;
0560   }
0561   if (right == this) {
0562     return;
0563   }
0564   auto it_map1 = right->fpScorer->fSpeciesInfoPerTime.begin();
0565   auto end_map1 = right->fpScorer->fSpeciesInfoPerTime.end();
0566 
0567   for (; it_map1 != end_map1; ++it_map1) {
0568     Gvalues::InnerSpeciesMap& map2 = it_map1->second;
0569     auto it_map2 = map2.begin();
0570     auto end_map2 = map2.end();
0571 
0572     for (; it_map2 != end_map2; ++it_map2) {
0573       Gvalues::SpeciesInfo& molInfo =
0574         fpScorer->fSpeciesInfoPerTime[it_map1->first][it_map2->first];
0575       molInfo.fNumber += it_map2->second.fNumber;
0576       molInfo.fG += it_map2->second.fG;
0577       molInfo.fG2 += it_map2->second.fG2;
0578     }
0579   }
0580 
0581   // dose
0582   fpScorer->fTotalDose += right->fpScorer->fTotalDose;
0583   fpScorer->fTotalDose2 += right->fpScorer->fTotalDose2;
0584   right->fpScorer->fTotalDose = 0;
0585   right->fpScorer->fTotalDose2 = 0.;
0586 
0587   // dose rate
0588   fpScorer->fTotalDoseRate += right->fpScorer->fTotalDoseRate;
0589   fpScorer->fTotalDoseRate2 += right->fpScorer->fTotalDoseRate2;
0590   right->fpScorer->fTotalDoseRate = 0;
0591   right->fpScorer->fTotalDoseRate2 = 0.;
0592 
0593   right->fpScorer->fSpeciesInfoPerTime.clear();
0594   fpScorer->fNEvent += right->fpScorer->fNEvent;
0595   right->fpScorer->fNEvent = 0;
0596   right->fpScorer->fEdep = 0.;
0597 }
0598 
0599 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
0600 
0601 template<>
0602 void Scorer<Gvalues>::OutputAndClear(const std::string& dose)
0603 {
0604   if (G4Threading::IsWorkerThread()) {
0605     return;
0606   }
0607   G4VAnalysisManager* analysisManager = G4AnalysisManager::Instance();
0608   if (analysisManager != nullptr) {
0609     this->fpScorer->WriteWithAnalysisManager(analysisManager, dose);
0610   }
0611   fpScorer->fNEvent = 0;
0612   fpScorer->fSpeciesInfoPerTime.clear();
0613 }
0614 
0615 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....