Import Geant4 11.4.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2025-06-26 09:17:29 +02:00
parent 20a218bbe1
commit a499fb82e9
1941 changed files with 203285 additions and 95593 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-03-25 Ivana Hrivnacova (proccuts-V11-02-00)
## 2025-03-25 Ivana Hrivnacova (proccuts-V11-03-00)
- In G4ProductionCutsTable::UpdateCoupleTable:
Make sure that the couple tables are updated if userEnergyCuts
vectors are set
+3 -4
View File
@@ -1,12 +1,11 @@
# Category decay History
See `CONTRIBUTING.rst` for details of **required** info/format for each entry,
which **must** added in reverse chronological order (newest at the top).
It must **not** be used as a substitute for writing good git commit messages!
which **must** added in reverse chronological order (newest at the top). It must **not**
be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-04-03 Alvaro Tolosa-Delgado (decay-V11-02-00)
## 2025-04-03 Alvaro Tolosa-Delgado (decay-V11-03-00)
- Remove approximation in calculation of G4Decay path length, fix issue #2645
## 2021-12-10 Ben Morgan (decay-V11-00-00)
+50 -1
View File
@@ -6,7 +6,56 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-01-14 Ben Morgan (emdna-V11-02-18)
## 2025-05-28 Hoang Tran (emdna-V11-03-12)
- Fixed COVERTY issues on new moleculecounter imple
## 2025-05-20 Hoang Tran (emdna-V11-03-11)
- Fixed FPE on G4ChemReboundTransportation::calculateNextCoordinate
## 2025-05-19 Vladimir Ivanchenko (emdna-V11-03-10)
- G4DNARuddIonisationModel, G4DNABornIonisationModel1, G4DNABornIonisationModel2
fixed definition of the stationary code via G4EmParameters
## 2025-05-05 Hoang Tran (emdna-V11-03-09)
- Replaced the shared_ptr with unique_ptr and raw for manager counters.
## 2025-04-23 Hoang Tran (emdna-V11-03-08)
- Replaced the G4MoleculeCounter singleton with G4MoleculeCounterManager for managing counters.
## 2025-04-17 Vladimir Ivanchenko (emdna-V11-03-07)
- G4DNARuddIonisationDynamicModel - disable atomic deexcitation in stationary
mode, use G4VSItegration as a base class.
- G4DNABornIonisationModel - new implementation of the Born model using
G4DNASamplingTable class, use stationary and fast flags from EM parameters.
- G4DNABornIonisationModel1 - use stationary and fast flags from EM parameters.
- G4DNASamplingTable - new class allowing share sampling data between threads.
## 2025-04-01 Hoang Tran (emdna-V11-03-06)
- update IRT-syn model for high LET applications.
- Correct the G4DNAScavengerProcess for IRT-syn model
- Created G4ChemReboundTransportation to handle the rebound
transportation of the molecule.
## 2025-03-31 Hoang Tran (emdna-V11-03-05)
- G4PhysChemIO - removed G4Analysis class and G4analysismng module
dependency from G4emdna-utils
## 2025-03-12 Vladimir Ivanchenko (emdna-V11-03-04)
- G4DNARuddIonisationDynamicModel - minor fix for alpha particles
## 2025-02-26 Vladimir Ivanchenko (emdna-V11-03-03)
- G4DNARuddIonisationModel - added forgotten definition of stationary mode.
## 2025-02-24 Vladimir Ivanchenko (emdna-V11-03-02)
- G4DNARuddIonisationDynamicModel - use G4Track and not G4DynamicParticle, allow
to store radicals if chemistry is activated, update for ions with full electron
shell
## 2025-02-12 Vladimir Ivanchenko (emdna-V11-03-01)
- Added new G4DNARuddIonisationDynamicModel, which use charge from G4DynamicParticle.
The model is applicable for all ions.
## 2025-01-14 Ben Morgan (emdna-V11-03-00)
- Remove obsolete/commented references to G4AllocatorList.
## 2024-10-31 Hoang Tran (emdna-V11-02-17)
@@ -0,0 +1,68 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4MOLECULELOCATOR_HH
#define G4MOLECULELOCATOR_HH 1
#pragma once
#include "G4TouchableHandle.hh"
#include "G4ThreadLocalSingleton.hh"
#include <memory>
class G4Track;
class G4ITNavigator;
class G4MoleculeLocator final
{
friend class G4ThreadLocalSingleton<G4MoleculeLocator>;
public:
static G4MoleculeLocator* Instance();
~G4MoleculeLocator() = default;
private:
G4MoleculeLocator();
G4MoleculeLocator(const G4MoleculeLocator&) = delete;
G4MoleculeLocator(G4MoleculeLocator&&) = delete;
G4MoleculeLocator& operator=(const G4MoleculeLocator&) = delete;
G4MoleculeLocator& operator=(G4MoleculeLocator&&) = delete;
G4ThreadLocalStatic G4MoleculeLocator* fpInstance;
G4bool fIsInitialized{false};
std::unique_ptr<G4ITNavigator> fNavigator;
void Initialize();
public:
void LocateMoleculeSetStateAndTouchable(G4Track*);
G4TouchableHandle LocateMoleculeTrack(const G4Track*);
};
#endif
@@ -186,6 +186,12 @@ class G4Scheduler : public G4VScheduler, public G4VStateDependent
{
fpUserScavenger = std::move(scavengerMaterial);
}
inline G4bool IsInteractionStep(){
return fInteractionStep;
}
inline void SetInteractionStep(G4bool InteractionStep){
fInteractionStep = InteractionStep;
}
protected:
void DoProcess();
@@ -220,6 +226,7 @@ class G4Scheduler : public G4VScheduler, public G4VStateDependent
G4bool fUseDefaultTimeSteps;
G4double fTimeTolerance;
G4double fGlobalTime;
G4double fTmpGlobalTime;
G4double fStartTime;
G4double fStopTime;
G4double fEndTime;
@@ -48,6 +48,7 @@
#include "G4FastList.hh"
#include "G4ManyFastLists.hh"
#include "G4AllocatorList.hh"
#include "G4Track.hh"
#include "G4IT.hh"
@@ -75,13 +75,20 @@ class G4VDNAMesh
};
struct hashFunc
{
size_t operator()(const Index& k) const
{
size_t h1 = std::hash<G4int>()(k.x);
size_t h2 = std::hash<G4int>()(k.y);
size_t h3 = std::hash<G4int>()(k.z);
return (h1 ^ (h2 << 1)) ^ h3;
}
size_t operator()(const Index& k) const
{
size_t h1 = std::hash<G4int>()(k.x);
size_t h2 = std::hash<G4int>()(k.y);
size_t h3 = std::hash<G4int>()(k.z);
// Combine the hashes using a consistent and well-distributed technique
size_t seed = 0;
seed ^= h1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= h2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= h3 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
};
#endif
@@ -78,6 +78,7 @@ geant4_add_module(G4emdna-man
G4VUserBrownianAction.hh
G4VDNAMesh.hh
G4VUserPulseInfo.hh
G4MoleculeLocator.hh
SOURCES
G4AllITFinder.cc
G4ITBox.cc
@@ -127,7 +128,8 @@ geant4_add_module(G4emdna-man
G4VITTrackHolder.cc
G4VScheduler.cc
G4DNABoundingBox.cc
G4VUserPulseInfo.cc)
G4VUserPulseInfo.cc
G4MoleculeLocator.cc)
geant4_module_link_libraries(G4emdna-man
PUBLIC
@@ -0,0 +1,107 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4MoleculeLocator.hh"
#include "G4IT.hh"
#include "G4ITTransportationManager.hh"
#include "G4Track.hh"
#include "G4TrackingInformation.hh"
G4ThreadLocal G4MoleculeLocator* G4MoleculeLocator::fpInstance = nullptr;
G4MoleculeLocator::G4MoleculeLocator()
{
fNavigator = std::make_unique<G4ITNavigator>();
}
G4MoleculeLocator* G4MoleculeLocator::Instance()
{
if (fpInstance == nullptr) {
static G4ThreadLocalSingleton<G4MoleculeLocator> instance;
fpInstance = instance.Instance();
}
if (!fpInstance->fIsInitialized) {
fpInstance->Initialize();
}
return fpInstance;
}
void G4MoleculeLocator::Initialize()
{
fNavigator->SetWorldVolume(G4ITTransportationManager::GetTransportationManager()
->GetNavigatorForTracking()
->GetWorldVolume());
fIsInitialized = true;
}
G4TouchableHandle G4MoleculeLocator::LocateMoleculeTrack(const G4Track* pTrack)
{
G4IT* pITrack = GetIT(pTrack);
if (pITrack == nullptr) {
G4Exception("G4MoleculeLocator::LocateMoleculeSetStateAndTouchable", "NOT_AN_IT", FatalErrorInArgument,
"The track passed to this method appears to not hold an IT (molecule) object!");
}
std::unique_ptr<G4ITNavigatorState_Lock> tmpStateHolder;
if (pITrack->GetTrackingInfo()->GetNavigatorState() != nullptr)
fNavigator->SetNavigatorState(pITrack->GetTrackingInfo()->GetNavigatorState());
else {
fNavigator->NewNavigatorState();
tmpStateHolder = std::unique_ptr<G4ITNavigatorState_Lock>(fNavigator->GetNavigatorState());
// will be deleted once method goes out of scope
}
G4ThreeVector direction = pTrack->GetMomentumDirection();
fNavigator->LocateGlobalPointAndSetup(pTrack->GetPosition(), &direction, false, false);
G4TouchableHandle touchable = fNavigator->CreateTouchableHistory();
return touchable;
}
void G4MoleculeLocator::LocateMoleculeSetStateAndTouchable(G4Track* pTrack)
{
G4IT* pITrack = GetIT(pTrack);
if (pITrack == nullptr) {
G4Exception("G4MoleculeLocator::LocateMoleculeSetStateAndTouchable", "NOT_AN_IT", FatalErrorInArgument,
"The track passed to this method appears to not hold an IT (molecule) object!");
}
fNavigator->NewNavigatorState();
GetIT(pTrack)->GetTrackingInfo()->SetNavigatorState(fNavigator->GetNavigatorState());
G4ThreeVector direction = pTrack->GetMomentumDirection();
fNavigator->LocateGlobalPointAndSetup(pTrack->GetPosition(), &direction, false, false);
G4TouchableHandle touchable = fNavigator->CreateTouchableHistory();
pTrack->SetTouchableHandle(touchable);
pTrack->SetNextTouchableHandle(touchable);
}
@@ -155,6 +155,7 @@ void G4Scheduler::Create()
fDefinedMinTimeStep = -1.;
fReachedUserTimeLimit = false;
fStopTime = -1.;
fTmpGlobalTime = -1.;
fpMessenger = new G4SchedulerMessenger(this);
fReactionSet = G4ITReactionSet::Instance();
fMaxTimeStep = DBL_MAX;
@@ -378,6 +379,7 @@ G4double G4Scheduler::GetNextWatchedTime() const
void G4Scheduler::SynchronizeTracks()
{
fTmpGlobalTime = fGlobalTime;
fGlobalTime = fTrackContainer.GetNextTime();
G4double tmpGlobalTime = fGlobalTime;
G4double nextWatchedTime = -1;
@@ -499,7 +501,7 @@ void G4Scheduler::Stepping()
fTSTimeStep = DBL_MAX;
fILTimeStep = DBL_MAX;
fInteractionStep = false;
//fInteractionStep = false;
fReachedUserTimeLimit = false;
fITStepStatus = eUndefined;
@@ -612,7 +614,7 @@ void G4Scheduler::Stepping()
// Give the priority to the IL
{
fInteractionStep = true;
fReactionSet->CleanAllReaction();
//fReactionSet->CleanAllReaction();
fTimeStep = fILTimeStep;
fITStepStatus = eInteractionWithMedium;
fpStepProcessor->PrepareLeadingTracks();
@@ -64,6 +64,8 @@ G4FastListNode<G4Track>* G4FastList<G4Track>::__GetNode(G4Track* __track)
template<>
void G4FastList<G4Track>::DeleteObject(G4Track* __track)
{
if (G4AllocatorList::GetAllocatorListIfExist() == nullptr) return;
auto __step = const_cast<G4Step*>(__track->GetStep());
if (__step != nullptr)
{
@@ -23,22 +23,125 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
/*
* G4DNABornIonisationModel.hh
*
* Created on: 13 mai 2015
* Author: matkara
*/
// Created 25.03.2025 V.Ivanchenko
// on base of the G4DNABornIonisationModel1 of S.Incerti & M.Karamitros
//
// Simulation of ionisation for electrons and protons
//
#ifndef SOURCE_PROCESSES_ELECTROMAGNETIC_DNA_MODELS_INCLUDE_G4DNABORNIONISATIONMODEL_HH_
#define SOURCE_PROCESSES_ELECTROMAGNETIC_DNA_MODELS_INCLUDE_G4DNABORNIONISATIONMODEL_HH_
#ifndef G4DNABornIonisationModel_h
#define G4DNABornIonisationModel_h 1
#include "G4DNABornIonisationModel1.hh"
#include "G4DNABornIonisationModel2.hh"
#include "G4VEmModel.hh"
#include "G4VSIntegration.hh"
#include "G4ParticleChangeForGamma.hh"
#include "G4DNAWaterIonisationStructure.hh"
class G4DNAChemistryManager;
class G4VAtomDeexcitation;
class G4DNACrossSectionDataSet;
class G4DNASamplingTable;
class G4DNABornIonisationModel : public G4VEmModel, public G4VSIntegration
{
public:
G4DNABornIonisationModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "DNABornIonisationModel");
~G4DNABornIonisationModel() override;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
G4double ProbabilityDensityFunction(G4double ekin) override;
G4double CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin,
G4double emin,
G4double emax) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double tmin, G4double maxEnergy) override;
void StartTracking(G4Track*) override;
void SelectFasterComputation(G4bool input) { fasterCode = input; };
void SelectStationary(G4bool input) { statCode = input; };
void SelectSPScaling(G4bool input) { spScaling = input; };
G4DNABornIonisationModel & operator=(const G4DNABornIonisationModel &right) = delete;
G4DNABornIonisationModel(const G4DNABornIonisationModel&) = delete;
private:
void LoadData();
G4int SelectShell();
G4double SampleCumulative();
G4double SampleDifferential();
protected:
G4ParticleChangeForGamma* fParticleChangeForGamma;
private:
// Water density table
static const std::vector<G4double>* fpWaterDensity;
// data
static G4DNACrossSectionDataSet* xsdata_e;
static G4DNACrossSectionDataSet* xsdata_p;
G4DNACrossSectionDataSet* xsdata{nullptr};
// sampling data
static G4DNASamplingTable* sampling_e;
static G4DNASamplingTable* sampling_p;
G4DNASamplingTable* sampling;
const G4ParticleDefinition* fParticle{nullptr};
const G4Track* fTrack{nullptr};
G4DNAChemistryManager* fChemistry{nullptr};
// Deexcitation manager to produce fluo photons and e-
G4VAtomDeexcitation* fAtomDeexcitation;
// limits of x-section table
G4double fLowEnergy{0.0};
G4double fHighEnergy{0.0};
G4double fpLimitEnergy{0.0};
G4double feLimitEnergy{0.0};
// tracking cut
G4double fAbsorptionEnergy{0.0};
G4double fMass{0.0};
G4double fPrimaryEnergy{0.0};
G4double fMaxEnergy{0.0};
G4double fTemp[5] = {0.0};
G4int fSelectedShell{0};
G4int verbose{0};
G4bool isFirst{false};
G4bool isInitialised{false};
G4bool isElectron{false};
G4bool fasterCode{false};
G4bool statCode{false};
G4bool spScaling{true};
// Final state
G4DNAWaterIonisationStructure waterStructure;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#ifndef G4DNABornIonisationModel
#define G4DNABornIonisationModel G4DNABornIonisationModel1
//#define G4DNABornIonisationModel G4DNABornIonisationModel2
#endif
#endif /* SOURCE_PROCESSES_ELECTROMAGNETIC_DNA_MODELS_INCLUDE_G4DNABORNIONISATIONMODEL_HH_ */
@@ -43,6 +43,7 @@
#include "G4VAtomDeexcitation.hh"
#include "G4NistManager.hh"
class G4DNAChemistryManager;
class G4DNABornIonisationModel1 : public G4VEmModel
{
@@ -75,11 +76,12 @@ public:
G4int /*level*/,
const G4ParticleDefinition*,
G4double /*kineticEnergy*/) override;
void StartTracking(G4Track*) override;
G4double DifferentialCrossSection(G4ParticleDefinition * aParticleDefinition, G4double k, G4double energyTransfer, G4int shell);
G4double TransferedEnergy(G4ParticleDefinition * aParticleDefinition,
G4double incomingParticleEnergy, G4int shell, G4double random) ;
G4double incomingParticleEnergy, G4int shell, G4double random);
inline void SelectFasterComputation(G4bool input);
@@ -93,28 +95,27 @@ protected:
private:
G4bool fasterCode;
G4bool statCode;
G4bool spScaling;
G4bool fasterCode{false};
G4bool statCode{false};
G4bool spScaling{true};
// Water density table
const std::vector<G4double>* fpMolWaterDensity;
// Deexcitation manager to produce fluo photons and e-
G4VAtomDeexcitation* fAtomDeexcitation;
G4VAtomDeexcitation* fAtomDeexcitation;
const G4Track* fTrack{nullptr};
G4DNAChemistryManager* fChemistry{nullptr};
std::map<G4String,G4double,std::less<G4String> > lowEnergyLimit;
std::map<G4String,G4double,std::less<G4String> > highEnergyLimit;
// TODO :
// std::map<const G4ParticleDefinition*,std::pair<G4double,G4double> > fEnergyLimits;
G4bool isInitialised{false};
G4int verboseLevel;
// Cross section
using MapFile = std::map<G4String, G4String, std::less<G4String>>;
MapFile tableFile; // useful ?
@@ -163,29 +164,27 @@ private:
VecMap eProbaShellMap[6]; // for cumulated dcs
VecMap pProbaShellMap[6]; // for cumulated dcs
// Partial cross section
// Partial cross section
G4int RandomSelect(G4double energy,const G4String& particle );
};
inline void G4DNABornIonisationModel1::SelectFasterComputation (G4bool input)
{
fasterCode = input;
fasterCode = input;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline void G4DNABornIonisationModel1::SelectStationary (G4bool input)
{
statCode = input;
statCode = input;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline void G4DNABornIonisationModel1::SelectSPScaling (G4bool input)
{
spScaling = input;
spScaling = input;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -63,12 +63,13 @@ class G4DNAEventScheduler : public IEventScheduler
G4DNAEventScheduler& operator=(const G4DNAEventScheduler& right) = delete;
void Initialize(const G4DNABoundingBox& boundingBox, G4int pixel);
void InitializeInMesh();
void Voxelizing();
void Voxelizing(const G4DNABoundingBox& boundingBox);
void ReVoxelizing(G4int);
void SetEndTime(const G4double&);
G4double GetStartTime() const;
G4double GetEndTime() const;
G4double GetTimeStep() const;
G4double GetGlobalTime() const;
void SetStartTime(G4double time);
inline void SetVerbose(G4int verbose) { fVerbose = verbose; }
@@ -93,7 +94,8 @@ class G4DNAEventScheduler : public IEventScheduler
G4int GetPixels() const;
void SetUserMeshAction(std::unique_ptr<G4UserMeshAction>);
static G4bool CheckingReactionRadius(G4double resolution);
void ParticleBasedCounter();
void ResetCounter();
private:
G4int fVerbose = 0;
G4bool fInitialized = false;
@@ -38,6 +38,7 @@
#include "G4ITTrackHolder.hh"
#include "G4ITReaction.hh"
#include "G4ReferenceCast.hh"
#include <unordered_map>
class G4VDNAReactionModel;
class G4DNAMolecularReactionTable;
@@ -66,20 +67,19 @@ class G4DNAIndependentReactionTimeStepper : public G4VITTimeStepComputer
G4VDNAReactionModel* GetReactionModel();
std::unique_ptr<G4ITReactionChange> FindReaction(
G4ITReactionSet* pReactionSet, const G4double& currentStepTime = 0,
const G4double& previousStepTime = 0,
const G4bool& reachedUserStepTimeLimit = false);
G4ITReactionSet* pReactionSet,
G4double& currentStepTime,
const G4double globalTime);
void SetReactionProcess(G4VITReactionProcess* pReactionProcess);
void SetVerbose(G4int);
private:
void InitializeForNewTrack();
class Utils;
void CheckAndRecordResults(const Utils& utils);
void CheckAndRecordResults(G4double reactionTime, const Utils& utils);
G4double GetTimeToEncounter(const G4Track& trackA, const G4Track& trackB);
G4bool fHasAlreadyReachedNullTime = false;
const G4DNAMolecularReactionTable*& fMolecularReactionTable =
reference_cast<const G4DNAMolecularReactionTable*>(fpReactionTable);
G4VDNAReactionModel* fReactionModel = nullptr;
@@ -88,18 +88,24 @@ class G4DNAIndependentReactionTimeStepper : public G4VITTimeStepComputer
G4int fVerbose = 0;
G4double fRCutOff = G4IRTUtils::GetRCutOff();
G4VITReactionProcess* fpReactionProcess = nullptr;
std::map<G4int, G4ThreeVector> fSampledPositions;
std::vector<const G4Track *> fSecondaries;
std::unordered_map<G4int, G4ThreeVector> fSampledPositions;
std::set<G4int> fCheckedTracks;
void InitializeReactions(G4double currentGlobalTime);
G4bool fIsInitialized = false;
G4double GetNextReactionTime();
const G4ITReaction* GetNextReaction();
class Utils
{
public:
Utils(const G4Track& tA, const G4Track& tB);
~Utils() = default;
const G4Track& fTrackA;
const G4Track& fTrackB;
const G4Molecule* fpMoleculeA;
const G4Molecule* fpMoleculeB;
G4Track* fpTrackA{nullptr};
G4Track* fpTrackB{nullptr};
const G4Molecule* fpMoleculeA{nullptr};
const G4Molecule* fpMoleculeB{nullptr};
};
};
#endif
@@ -33,6 +33,7 @@ class G4DNAMolecularReactionTable;
class G4VDNAReactionModel;
class G4ITReactionSet;
class G4VITTimeStepComputer;
class G4DNAScavengerMaterial;
class G4DNAMakeReaction : public G4VITReactionProcess
{
@@ -59,5 +60,7 @@ protected:
G4VDNAReactionModel* fpReactionModel;
G4VITTimeStepComputer* fpTimeStepper;
G4double fTimeStep;
G4DNAScavengerMaterial* fpScavengerMaterial{nullptr};
};
#endif
@@ -0,0 +1,177 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Created 11.02.2025 V.Ivanchenko & M. Vologzhin
// on base of previous Rudd models
//
// Rudd model of ion ionisation using dynamic mass and charge of an ion
//
#ifndef G4DNARuddIonisationDynamicModel_h
#define G4DNARuddIonisationDynamicModel_h 1
#include "G4VEmModel.hh"
#include "G4VSIntegration.hh"
#include "G4ParticleChangeForGamma.hh"
#include "G4DNAWaterIonisationStructure.hh"
#include <vector>
class G4DNAChemistryManager;
class G4VAtomDeexcitation;
class G4DNACrossSectionDataSet;
class G4Pow;
class G4DNARuddIonisationDynamicModel : public G4VEmModel, public G4VSIntegration
{
public:
explicit G4DNARuddIonisationDynamicModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "DNARuddIonisationDynamicModel");
~G4DNARuddIonisationDynamicModel() override;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
G4double ProbabilityDensityFunction(G4double ekin) override;
G4double CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin,
G4double emin,
G4double emax) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double tmin,
G4double maxEnergy) override;
void StartTracking(G4Track*) override;
G4DNARuddIonisationDynamicModel & operator=
(const G4DNARuddIonisationDynamicModel &right) = delete;
G4DNARuddIonisationDynamicModel(const G4DNARuddIonisationDynamicModel&) = delete;
private:
void LoadData();
void SetParticle(const G4ParticleDefinition*);
G4int SelectShell();
G4double MaxEnergy();
G4double SampleElectronEnergy();
G4double CorrectionFactor();
G4double S_1s(G4double t,
G4double energyTransferred,
G4double slaterEffectiveChg,
G4double shellNumber);
G4double S_2s(G4double t,
G4double energyTransferred,
G4double slaterEffectiveChg,
G4double shellNumber);
G4double S_2p(G4double t,
G4double energyTransferred,
G4double slaterEffectiveChg,
G4double shellNumber);
G4double Rh(G4double t,
G4double energyTransferred,
G4double slaterEffectiveChg,
G4double shellNumber);
protected:
G4ParticleChangeForGamma* fParticleChangeForGamma{nullptr};
private:
// Water density table
static const std::vector<G4double>* fpWaterDensity;
// data for protons
static G4DNACrossSectionDataSet* xsdata_hydrogen;
static G4DNACrossSectionDataSet* xsdata_helium;
static G4DNACrossSectionDataSet* xsdata_p;
// run time data
G4DNACrossSectionDataSet* xsdata{nullptr};
const G4ParticleDefinition* fParticle{nullptr};
const G4Track* fTrack{nullptr};
G4DNAChemistryManager* fChemistry{nullptr};
G4Pow* fGpow;
//deexcitation manager to produce fluo photons and e-
G4VAtomDeexcitation* fAtomDeexcitation{nullptr};
// low-energy limit of proton x-section table
G4double fLowestEnergy{0.0};
// tracking cut
G4double fAbsorptionEnergy{0.0};
G4double fMass{0.0};
G4double fMassRate{1.0};
G4double fScaledEnergy{0.0};
G4double slaterEffectiveCharge[3] = {0.0};
G4double sCoefficient[3] = {0.0};
G4double fTemp[5] = {0.0};
G4double F1{0.0};
G4double F2{0.0};
G4double alphaConst{0.0};
G4double bEnergy{0.0};
G4double u{0.0};
G4double v{0.0};
G4double wc{0.0};
G4int fSelectedShell{0};
G4int verbose{0};
G4bool isFirst{false};
G4bool isInitialised{false};
G4bool isIon{false};
G4bool isHelium{false};
G4bool statCode{false};
G4bool useDNAWaterStructure{true};
// energy levels of water molecule
G4DNAWaterIonisationStructure waterStructure;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#endif
@@ -71,8 +71,6 @@ public:
G4double tmin,
G4double maxEnergy) override;
void SelectStationary(G4bool val) { statCode = val; };
// method for unit tests
G4double ComputeProbabilityFunction(const G4ParticleDefinition*, G4double kine,
G4double deltae, G4int shell);
@@ -3,7 +3,6 @@
# Define the Geant4 Module.
geant4_add_module(G4emdna-models
PUBLIC_HEADERS
G4ChemEquilibrium.hh
G4DNABornAngle.hh
G4DNABornExcitationModel.hh
G4DNABornExcitationModel1.hh
@@ -53,6 +52,7 @@ geant4_add_module(G4emdna-models
G4DNARPWBAIonisationModel.hh
G4DNARelativisticIonisationModel.hh
G4DNARuddAngle.hh
G4DNARuddIonisationDynamicModel.hh
G4DNARuddIonisationExtendedModel.hh
G4DNARuddIonisationModel.hh
G4DNASancheExcitationModel.hh
@@ -81,10 +81,10 @@ geant4_add_module(G4emdna-models
G4VLEPTSModel.hh
G4VUpdateSystemModel.hh
SOURCES
G4ChemEquilibrium.cc
G4DNABornAngle.cc
G4DNABornExcitationModel1.cc
G4DNABornExcitationModel2.cc
G4DNABornIonisationModel.cc
G4DNABornIonisationModel1.cc
G4DNABornIonisationModel2.cc
G4DNACPA100ElasticModel.cc
@@ -128,6 +128,7 @@ geant4_add_module(G4emdna-models
G4DNARPWBAIonisationModel.cc
G4DNARelativisticIonisationModel.cc
G4DNARuddAngle.cc
G4DNARuddIonisationDynamicModel.cc
G4DNARuddIonisationExtendedModel.cc
G4DNARuddIonisationModel.cc
G4DNASancheExcitationModel.cc
@@ -167,6 +168,7 @@ geant4_module_link_libraries(G4emdna-models
G4emlowenergy
G4emutils
G4globman
G4hepnumerics
G4heprandom
G4leptons
G4materials
@@ -0,0 +1,386 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#include "G4DNABornIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4EmParameters.hh"
#include "G4NistManager.hh"
#include "G4DNACrossSectionDataSet.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4DNABornAngle.hh"
#include "G4DNASamplingTable.hh"
#include "G4LogLogInterpolation.hh"
#include "G4DeltaAngle.hh"
#include "G4Log.hh"
#include "G4Exp.hh"
#include "G4Electron.hh"
#include "G4Proton.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACrossSectionDataSet* G4DNABornIonisationModel::xsdata_e = nullptr;
G4DNACrossSectionDataSet* G4DNABornIonisationModel::xsdata_p = nullptr;
G4DNASamplingTable* G4DNABornIonisationModel::sampling_e = nullptr;
G4DNASamplingTable* G4DNABornIonisationModel::sampling_p = nullptr;
const std::vector<G4double>* G4DNABornIonisationModel::fpWaterDensity = nullptr;
namespace
{
G4double scaleFactor = (1.e-22 / 3.343) * CLHEP::m*CLHEP::m;
G4double tolerance = 10*CLHEP::eV;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNABornIonisationModel::G4DNABornIonisationModel(const G4ParticleDefinition*,
const G4String& nam) :
G4VEmModel(nam)
{
SetDeexcitationFlag(true);
// Define default angular generator
SetAngularDistribution(new G4DNABornAngle());
fasterCode = G4EmParameters::Instance()->DNAFast();
if (nullptr == xsdata_p) {
isFirst = true;
LoadData();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNABornIonisationModel::~G4DNABornIonisationModel()
{
if (isFirst) {
delete xsdata_e;
xsdata_e = nullptr;
delete xsdata_p;
xsdata_p = nullptr;
delete sampling_e;
sampling_e = nullptr;
delete sampling_p;
sampling_p = nullptr;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::LoadData()
{
// initialisation of static data once
G4String fileElectron("dna/sigma_ionisation_e_born");
xsdata_e = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_e->LoadData(fileElectron);
G4String fileProton("dna/sigma_ionisation_p_born");
xsdata_p = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_p->LoadData(fileProton);
// to avoid possible threading problem fill this vector only once
auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
fpWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
G4bool verb = true;
sampling_e = new G4DNASamplingTable(100);
sampling_p = new G4DNASamplingTable(100);
if (fasterCode) {
G4String eb = "/dna/sigmadiff_cumulated_ionisation_e_born.dat";
sampling_e->LoadData(eb, CLHEP::eV, 1.0, verb);
G4String pb = "/dna/sigmadiff_cumulated_ionisation_p_born.dat";
sampling_p->LoadData(pb, CLHEP::eV, 1.0, verb);
} else {
G4String eb = "/dna/sigmadiff_ionisation_e_born.dat";
sampling_e->LoadData(eb, CLHEP::eV, scaleFactor, verb);
G4String pb = "/dna/sigmadiff_ionisation_p_born.dat";
sampling_p->LoadData(pb, CLHEP::eV, scaleFactor, verb);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
{
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
if (p == G4Electron::Electron()) {
fParticle = p;
xsdata = xsdata_e;
sampling = sampling_e;
fLowEnergy = 8*CLHEP::eV;
fHighEnergy = 1*CLHEP::MeV;
feLimitEnergy = 19*CLHEP::eV;
fAbsorptionEnergy = 6*CLHEP::eV;
fMass = CLHEP::electron_mass_c2;
isElectron = true;
} else if (p == G4Proton::Proton()) {
fParticle = p;
xsdata = xsdata_p;
sampling = sampling_p;
fLowEnergy = 100*CLHEP::keV;
fHighEnergy = 100*CLHEP::MeV;
fpLimitEnergy = 70*CLHEP::MeV;
fAbsorptionEnergy = 50*CLHEP::eV;
fMass = CLHEP::proton_mass_c2;
isElectron = false;
} else {
G4ExceptionDescription ed;
ed << "Born ionisation model is used for " << p->GetParticleName();
G4Exception("G4DNABornIonisationModel::Initialise","em0003",
FatalException, ed, " it is not available.");
}
verbose = G4EmParameters::Instance()->WorkerVerbose();
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
InitialiseIntegrator(0.1, 0.25, 1.05, 1*CLHEP::eV, 0.2*CLHEP::eV, 10*CLHEP::keV);
if (verbose > 1) {
G4cout << "Born ionisation model is initialized for "
<< fParticle->GetParticleName() << G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNABornIonisationModel::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition*,
G4double ekin, G4double, G4double)
{
// check if model is applicable for given material
G4double density = (material->GetIndex() < fpWaterDensity->size())
? (*fpWaterDensity)[material->GetIndex()] : 0.0;
if (0.0 == density) { return 0.0; }
// check on kinetic energy (not scaled energy) to stop low-energy ion
const G4double xSecMax = 1.e+10*CLHEP::barn;
if (ekin < fAbsorptionEnergy) { return xSecMax; }
G4double e = std::min(ekin, fHighEnergy);
G4double sigma = (e > fLowEnergy) ? xsdata->FindValue(e)
: xsdata->FindValue(fLowEnergy) * e / fLowEnergy;
sigma *= density;
// ICRU49 electronic SP scaling - ZF, SI
if (!isElectron && spScaling && e < fpLimitEnergy) {
const G4double A = 1.39241700556072800000e-9;
const G4double B = -8.52610412942622630000e-2;
sigma *= G4Exp(A*(ekin/CLHEP::eV) + B);
}
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel for " << fParticle->GetParticleName()
<< " Ekin(keV)=" << ekin/CLHEP::keV
<< " sigma(cm^2)=" << sigma/CLHEP::cm2 << G4endl;
}
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dynParticle,
G4double, G4double)
{
fPrimaryEnergy = dynParticle->GetKineticEnergy();
// proton shoud be stopped - check on kinetic energy
// electrons never have such low energy
if (fPrimaryEnergy <= fAbsorptionEnergy) {
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(fPrimaryEnergy);
return;
}
fSelectedShell = SelectShell();
G4double bindingEnergy = waterStructure.IonisationEnergy(fSelectedShell);
//SI: additional protection if tcs interpolation method is modified
if (fPrimaryEnergy < bindingEnergy) { return; }
// compute max energy
if (isElectron) {
fMaxEnergy = 0.5*(fPrimaryEnergy - bindingEnergy);
} else {
G4double tau = fPrimaryEnergy/fMass;
fMaxEnergy = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
}
// SI: The following protection is necessary to avoid infinite loops :
// e- ionisation cross section has non zero partial xs at 18 eV for shell 2.
// e- has zero cumulated partial xs at 18 eV for shell 2.
// This is due to the fact that the max allowed transfered energy is
// (18+10.79)/2=17.025 eV and only transfered energies strictly above this
// value have non zero partial cross section starting at transition energy 17.12 eV.
if (fasterCode && isElectron && 2 == fSelectedShell && fPrimaryEnergy < feLimitEnergy) {
do {
fSelectedShell = SelectShell();
} while (2 == fSelectedShell);
}
G4double esec = fasterCode ? SampleCumulative() : SampleDifferential();
G4double esum = 0.0;
// sample deexcitation
// here we assume that H2O electronic levels are the same as Oxygen.
// this can be considered true with a rough 10% error in energy on K-shell,
G4int Z = 8;
G4ThreeVector deltaDir =
GetAngularDistribution()->SampleDirectionForShell(dynParticle, esec, Z,
fSelectedShell,
couple->GetMaterial());
// SI: only atomic deexcitation from K shell is considered
if (fAtomDeexcitation != nullptr && fSelectedShell == 4) {
auto as = G4AtomicShellEnumerator(0);
auto ashell = fAtomDeexcitation->GetAtomicShell(Z, as);
fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
// compute energy sum from de-excitation
for (auto const & ptr : *fvect) {
esum += ptr->GetKineticEnergy();
}
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = fPrimaryEnergy - bindingEnergy - esec;
if (scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNABornIonisationModel::SampleSecondaries: "
<< "final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< fPrimaryEnergy/CLHEP::keV << " " << fParticle->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(exc);
} else {
fParticleChangeForGamma->SetProposedKineticEnergy(fPrimaryEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(fPrimaryEnergy - scatteredEnergy);
}
// delta-electron
auto dp = new G4DynamicParticle(G4Electron::Electron(), deltaDir, esec);
fvect->push_back(dp);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, fSelectedShell, fTrack);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int G4DNABornIonisationModel::SelectShell()
{
G4double sum = 0.0;
G4double xs;
G4double e = std::min(fPrimaryEnergy, fHighEnergy);
for (G4int i=0; i<5; ++i) {
auto ptr = xsdata->GetComponent(i);
xs = (e > fLowEnergy) ? ptr->FindValue(e)
: ptr->FindValue(fLowEnergy) * e/fLowEnergy;
sum += xs;
fTemp[i] = sum;
}
sum *= G4UniformRand();
for (G4int i=0; i<5; ++i) {
if (sum <= fTemp[i]) { return i; }
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::SampleCumulative()
{
G4double e = sampling->SampleCumulative(fPrimaryEnergy, fSelectedShell);
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel::SampleCumulative: "
<< fParticle->GetParticleName()
<< " Ekin(keV)=" << fPrimaryEnergy/CLHEP::keV
<< " Ee(keV)=" << e/CLHEP::keV << G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::SampleDifferential()
{
G4double xs = ComputeIntegral(0.0, fMaxEnergy);
G4double e = (xs > 0.0) ? SampleValue() : G4UniformRand()*fMaxEnergy;
if (verbose > 1) {
G4cout << "G4DNABornIonisationModel::SampleDifferential: "
<< fParticle->GetParticleName()
<< " Ekin(keV)=" << fPrimaryEnergy/CLHEP::keV
<< " Ee(keV)=" << e/CLHEP::keV << G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel::ProbabilityDensityFunction(G4double ekin)
{
return sampling->GetValue(fPrimaryEnergy, ekin, fSelectedShell);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -29,6 +29,7 @@
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4EmParameters.hh"
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
@@ -68,17 +69,7 @@ G4VEmModel(nam)
// Define default angular generator
SetAngularDistribution(new G4DNABornAngle());
// Selection of computation method
fasterCode = false;
// Selection of stationary mode
statCode = false;
// Selection of SP scaling
spScaling = true;
fasterCode = G4EmParameters::Instance()->DNAFast();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -123,7 +114,7 @@ void G4DNABornIonisationModel1::Initialise(const G4ParticleDefinition* particle,
G4String proton;
G4double scaleFactor = (1.e-22 / 3.343) * m*m;
const char *path = G4FindDataDir("G4LEDATA");
// *** ELECTRON
@@ -295,25 +286,36 @@ void G4DNABornIonisationModel1::Initialise(const G4ParticleDefinition* particle,
<< G4endl;
}
// Initialize water density pointer
if (isInitialised) { return; }
fParticleChangeForGamma = GetParticleChangeForGamma();
// Initialize water density pointer
fpMolWaterDensity = G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// AD
statCode = G4EmParameters::Instance()->DNAStationary();
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// AD
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
//
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNABornIonisationModel1::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNABornIonisationModel1::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* particleDefinition,
G4double ekin,
@@ -450,20 +452,19 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
G4int ionizationShell = 0;
if (!fasterCode) ionizationShell = RandomSelect(k,particleName);
// SI: The following protection is necessary to avoid infinite loops :
// sigmadiff_ionisation_e_born.dat has non zero partial xs at 18 eV for shell 3 (ionizationShell ==2)
// sigmadiff_cumulated_ionisation_e_born.dat has zero cumulated partial xs at 18 eV for shell 3 (ionizationShell ==2)
// this is due to the fact that the max allowed transfered energy is (18+10.79)/2=17.025 eV and only transfered energies
// strictly above this value have non zero partial xs in sigmadiff_ionisation_e_born.dat (starting at trans = 17.12 eV)
if (fasterCode)
do
{
if (!fasterCode) {
ionizationShell = RandomSelect(k,particleName);
} while (k<19*eV && ionizationShell==2 && particle->GetDefinition()==G4Electron::ElectronDefinition());
} else {
do {
ionizationShell = RandomSelect(k,particleName);
} while (k<19*eV && ionizationShell==2 && particle->GetDefinition()==G4Electron::ElectronDefinition());
}
G4double bindingEnergy = 0;
bindingEnergy = waterStructure.IonisationEnergy(ionizationShell);
@@ -481,8 +482,6 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
{
secondaryKinetic = RandomizeEjectedElectronEnergyFromCumulatedDcs(particle->GetDefinition(),k,ionizationShell);
}
//
G4int Z = 8;
G4ThreeVector deltaDirection =
@@ -587,17 +586,10 @@ void G4DNABornIonisationModel1::SampleSecondaries(std::vector<G4DynamicParticle*
fParticleChangeForGamma->ProposeLocalEnergyDeposit(k-scatteredEnergy);
}
// TEST //////////////////////////
// if (secondaryKinetic<0) abort();
// if (scatteredEnergy<0) abort();
// if (k-scatteredEnergy-secondaryKinetic-deexSecEnergy<0) abort();
// if (k-scatteredEnergy<0) abort();
/////////////////////////////////
const G4Track * theIncomingTrack = fParticleChangeForGamma->GetCurrentTrack();
G4DNAChemistryManager::Instance()->CreateWaterMolecule(eIonizedMolecule,
ionizationShell,
theIncomingTrack);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, ionizationShell, fTrack);
}
}
}
@@ -696,50 +688,6 @@ G4double G4DNABornIonisationModel1::RandomizeEjectedElectronEnergy(G4ParticleDef
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
// The following section is not used anymore but is kept for memory
// GetAngularDistribution()->SampleDirectionForShell is used instead
/*
void G4DNABornIonisationModel1::RandomizeEjectedElectronDirection(G4ParticleDefinition* particleDefinition,
G4double k,
G4double secKinetic,
G4double & cosTheta,
G4double & phi )
{
if (particleDefinition == G4Electron::ElectronDefinition())
{
phi = twopi * G4UniformRand();
if (secKinetic < 50.*eV) cosTheta = (2.*G4UniformRand())-1.;
else if (secKinetic <= 200.*eV)
{
if (G4UniformRand() <= 0.1) cosTheta = (2.*G4UniformRand())-1.;
else cosTheta = G4UniformRand()*(std::sqrt(2.)/2);
}
else
{
G4double sin2O = (1.-secKinetic/k) / (1.+secKinetic/(2.*electron_mass_c2));
cosTheta = std::sqrt(1.-sin2O);
}
}
else if (particleDefinition == G4Proton::ProtonDefinition())
{
G4double maxSecKinetic = 4.* (electron_mass_c2 / proton_mass_c2) * k;
phi = twopi * G4UniformRand();
// cosTheta = std::sqrt(secKinetic / maxSecKinetic);
// Restriction below 100 eV from Emfietzoglou (2000)
if (secKinetic>100*eV) cosTheta = std::sqrt(secKinetic / maxSecKinetic);
else cosTheta = (2.*G4UniformRand())-1.;
}
}
*/
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNABornIonisationModel1::DifferentialCrossSection(G4ParticleDefinition * particleDefinition,
G4double k,
@@ -32,6 +32,7 @@
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4EmParameters.hh"
#include "G4DNABornAngle.hh"
#include "G4DeltaAngle.hh"
#include "G4Exp.hh"
@@ -91,13 +92,7 @@ G4VEmModel(nam)
G4DNABornIonisationModel2::~G4DNABornIonisationModel2()
{
// Cross section
delete fTableData;
// Final state
delete fTableData;
fVecm.clear();
}
@@ -248,13 +243,14 @@ void G4DNABornIonisationModel2::Initialise(const G4ParticleDefinition* particle,
fpMolWaterDensity = G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// AD
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
statCode = G4EmParameters::Instance()->DNAStationary();
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
isInitialised = true;
}
@@ -44,79 +44,58 @@ G4DNAEventScheduler::G4DNAEventScheduler()
, fpUpdateSystem(new G4DNAUpdateSystemModel())
{}
void G4DNAEventScheduler::ClearAndReChargeCounter()
{
fCounterMap.clear();
if(fTimeToRecord.empty())
{
G4String WarMessage = "fTimeToRecord is empty ";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"TimeToRecord is empty", JustWarning, WarMessage);
}
fLastRecoredTime = fTimeToRecord.begin();
if(G4VMoleculeCounter::Instance()->InUse()) // copy from MoleculeCounter
{
G4MoleculeCounter::RecordedMolecules species;
species = G4MoleculeCounter::Instance()->GetRecordedMolecules();
if(species.get() == nullptr)
{
return;
}
if(species->empty())
{
G4MoleculeCounter::Instance()->ResetCounter();
return;
}
for(auto time_mol : fTimeToRecord)
{
if(time_mol > fStartTime)
{
continue;
}
for(auto molecule : *species)
{
G4int n_mol = G4MoleculeCounter::Instance()->GetNMoleculesAtTime(
molecule, time_mol);
if(n_mol < 0)
{
G4cerr << "G4DNAEventScheduler::ClearAndReChargeCounter() ::N "
"molecules not valid < 0 "
<< G4endl;
G4Exception("", "N<0", FatalException, "");
}
fCounterMap[time_mol][molecule] = n_mol;
}
fLastRecoredTime++;
}
G4MoleculeCounter::Instance()->ResetCounter(); // reset
G4MoleculeCounter::Instance()->Use(false); // no more used
}
else
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "G4VMoleculeCounter is not used";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"G4DNAEventScheduler010", JustWarning, exceptionDescription);
}
}
[[maybe_unused]] void G4DNAEventScheduler::AddTimeToRecord(const G4double& time)
{
if(fTimeToRecord.find(time) == fTimeToRecord.end())
{
fTimeToRecord.insert(time);
}
fLastRecoredTime = fTimeToRecord.begin();
}
G4DNAEventScheduler::~G4DNAEventScheduler() = default;
void G4DNAEventScheduler::Voxelizing()
void G4DNAEventScheduler::Voxelizing(const G4DNABoundingBox& boundingBox)
{
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
std::map<G4VDNAMesh::Index, MapList> TrackKeyMap;
if(fpMesh == nullptr){
fpMesh = std::make_unique<G4DNAMesh>(boundingBox, fPixel);
}else
{
auto newMesh = new G4DNAMesh(fpMesh->GetBoundingBox(), fPixel);
auto begin = fpMesh->begin();//old mesh, should be homogeneous
auto end = fpMesh->end();
for(; begin != end; begin++)
{
auto numberOfBoxes = fPixel*fPixel*fPixel;
const auto& mapData = std::get<2>(*begin);
for(auto it : mapData)
{
if(it.second == 0) continue;
G4int base_mol = std::floor((G4double)it.second / numberOfBoxes);
G4int remainder = (G4int)it.second % numberOfBoxes;
for(G4int i = 0; i < remainder; i++)
{
auto oldIndex = std::get<0>(*begin);
auto idx = newMesh->GetRandomIndex(oldIndex, fpMesh->GetResolution());
TrackKeyMap[idx][it.first] += base_mol + 1;
}
}
}
fpMesh.reset(newMesh);
}
if(!CheckingReactionRadius(fpMesh->GetResolution()))
{
G4String WarMessage = "resolution is not good : " +
std::to_string(fpMesh->GetResolution() / nm);
G4Exception("G4DNAEventScheduler::InitializeInMesh()", "WrongResolution",
JustWarning, WarMessage);
}
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
for(auto track : *pMainList)
{
auto molType = GetMolecule(track)->GetMolecularConfiguration();
@@ -146,7 +125,9 @@ void G4DNAEventScheduler::Voxelizing()
{
TrackKeyMap[key][molType] = 1;
}
track->SetTrackStatus(fStopAndKill);//kill the track
}
G4ITReactionSet::Instance()->CleanAllReaction();
for(auto& it : TrackKeyMap)
{
@@ -212,9 +193,12 @@ void G4DNAEventScheduler::Reset()
fRunning = true;
fReactionNumber = 0;
fJumpingNumber = 0;
fpEventSet->RemoveEventSet();
fpMesh->Reset();
if(fpMesh != nullptr) {
fpMesh->Reset();
fpMesh.reset();
//reset for each event
}
fpGillespieReaction->ResetEquilibrium();
}
@@ -224,16 +208,6 @@ void G4DNAEventScheduler::Initialize(const G4DNABoundingBox& boundingBox,
if(!fInitialized)
{
fPixel = pixel;
fpMesh = std::make_unique<G4DNAMesh>(boundingBox, pixel);
if(!CheckingReactionRadius(fpMesh->GetResolution()))
{
G4String WarMessage = "resolution is not good : " +
std::to_string(fpMesh->GetResolution() / nm);
G4Exception("G4DNAEventScheduler::InitializeInMesh()", "WrongResolution",
JustWarning, WarMessage);
}
// Scavenger();
auto pScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
@@ -250,14 +224,17 @@ void G4DNAEventScheduler::Initialize(const G4DNABoundingBox& boundingBox,
}
}
Voxelizing();
Voxelizing(boundingBox);
fEndTime = std::min(G4ITTrackHolder::Instance()->GetNextTime(), G4Scheduler::Instance()->GetEndTime()-1*ps);
//G4cout<<"fEndTime" <<fEndTime<<" G4ITTrackHolder::Instance()->GetNextTime() : "<<G4ITTrackHolder::Instance()->GetNextTime()<<G4endl;
fpGillespieReaction->SetVoxelMesh(*fpMesh);
fpGillespieReaction->SetEventSet(fpEventSet.get());
fpGillespieReaction->SetTimeStep(0);// reset fTimeStep = 0 in fpGillespieReaction
fpGillespieReaction->Initialize();
fpGillespieReaction->CreateEvents();
fpUpdateSystem->SetMesh(fpMesh.get());
ClearAndReChargeCounter();
fInitialized = true;
}
@@ -305,6 +282,8 @@ void G4DNAEventScheduler::ResetInMesh()
G4double G4DNAEventScheduler::GetStartTime() const { return fStartTime; }
G4double G4DNAEventScheduler::GetGlobalTime() const { return fGlobalTime; }
G4double G4DNAEventScheduler::GetEndTime() const { return fEndTime; }
[[maybe_unused]] G4double G4DNAEventScheduler::GetTimeStep() const
@@ -338,6 +317,7 @@ void G4DNAEventScheduler::Run()
{
RunInMesh();
}
fInitialized = false;
if(fVerbose > 2)
{
if(!fRunning)
@@ -361,7 +341,6 @@ void G4DNAEventScheduler::Run()
}
G4cout << " Computing Time : " << localtimer << G4endl;
}
Reset();
}
void G4DNAEventScheduler::RunInMesh()
@@ -377,7 +356,7 @@ void G4DNAEventScheduler::RunInMesh()
<< " the Mesh has " << fPixel << " x " << fPixel << " x " << fPixel
<< " voxels with Resolution " << G4BestUnit(resolution, "Length")
<< " during next "
<< G4BestUnit(resolution * resolution * C / (6 * D), "Time")
<< G4BestUnit(fGlobalTime + resolution * resolution * C / (6 * D), "Time")
<< G4endl;
}
@@ -501,6 +480,8 @@ void G4DNAEventScheduler::Stepping() // this event loop
// get selected time step
fTimeStep = (*selected)->GetTime();
if(fTimeStep + fStartTime >fEndTime){ return;}
// selected data
auto pJumping = (*selected)->GetJumpingData();
auto pReaction = (*selected)->GetReactionData();
@@ -564,9 +545,15 @@ void G4DNAEventScheduler::SetEndTime(const G4double& endTime)
void G4DNAEventScheduler::RecordTime()
{
if(fLastRecoredTime == fTimeToRecord.end())
{
return;
}
auto recordTime = *fLastRecoredTime;
if(fGlobalTime >= recordTime && fCounterMap[recordTime].empty())
{
if(fpMesh == nullptr) return;
//G4cout<<"recordTime for meso: "<<recordTime<<" fGlobalTime : "<<fGlobalTime<<G4endl;
auto begin = fpMesh->begin();
auto end = fpMesh->end();
for(; begin != end; begin++)
@@ -671,4 +658,63 @@ void G4DNAEventScheduler::LastRegisterForCounter()
}
}
}
void G4DNAEventScheduler::ParticleBasedCounter() {
if(fLastRecoredTime == fTimeToRecord.end())
{
return;
}
auto recordTime = *fLastRecoredTime;
if (recordTime < G4Scheduler::Instance()->GetGlobalTime()) {
//check meso if exist
if(fpMesh != nullptr){
//G4cout<<"there is a mesh"<<G4endl;
auto begin = fpMesh->begin();
auto end = fpMesh->end();
for(; begin != end; begin++)
{
const auto& mapData = std::get<2>(*begin);
if(mapData.empty())
{
continue;
}
for(const auto& it : mapData)
{
fCounterMap[recordTime][it.first] += it.second;
}
}
}
//then particle based
auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
for (auto track: *pMainList) {
auto molType = GetMolecule(track)->GetMolecularConfiguration();
auto pScavengerMaterial =
dynamic_cast<G4DNAScavengerMaterial *>(G4Scheduler::Instance()->GetScavengerMaterial());
if (pScavengerMaterial != nullptr
&& pScavengerMaterial->find(molType)) // avoid voxelize the scavenger
{
continue;
}
fCounterMap[recordTime][molType]++;
}
fLastRecoredTime++;
//PrintRecordTime();
}
}
void G4DNAEventScheduler::ResetCounter()
{
fCounterMap.clear();
if(fTimeToRecord.empty())
{
G4String WarMessage = "fTimeToRecord is empty ";
G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
"TimeToRecord is empty", JustWarning, WarMessage);
}
fLastRecoredTime = fTimeToRecord.begin();
}
@@ -44,6 +44,7 @@
#include "G4ITTrackHolder.hh"
#include "G4ITReaction.hh"
#include "G4Scheduler.hh"
#include "G4MoleculeCounterManager.hh"
using namespace std;
@@ -399,7 +400,10 @@ std::unique_ptr<G4ITReactionChange> G4DNAIRT::MakeReaction(const G4Track& trackA
const auto pMoleculeA = GetMolecule(trackA)->GetMolecularConfiguration();
const auto pMoleculeB = GetMolecule(trackB)->GetMolecularConfiguration();
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
G4double globalTime = G4Scheduler::Instance()->GetGlobalTime();
G4double effectiveReactionRadius = pReactionData->GetEffectiveReactionRadius();
@@ -45,10 +45,11 @@ using namespace std;
using namespace CLHEP;
G4DNAIndependentReactionTimeStepper::Utils::Utils(const G4Track& trackA, const G4Track& trackB)
: fTrackA(trackA), fTrackB(trackB)
: fpTrackA(const_cast<G4Track*>(&trackA)), fpTrackB(const_cast<G4Track*>(&trackB))
{
fpMoleculeA = GetMolecule(trackA);
fpMoleculeB = GetMolecule(trackA);
fpMoleculeB = GetMolecule(trackB);
fUserMinTimeStep = 1 * CLHEP::ps;
}
G4DNAIndependentReactionTimeStepper::G4DNAIndependentReactionTimeStepper()
@@ -58,30 +59,31 @@ G4DNAIndependentReactionTimeStepper::G4DNAIndependentReactionTimeStepper()
void G4DNAIndependentReactionTimeStepper::Prepare()
{
G4VITTimeStepComputer::Prepare();
fSampledPositions.clear();
BuildChemicalMoleculeFinder()
//fVerbose = G4Scheduler::Instance()->GetVerbose();
if (G4Scheduler::Instance()->IsInteractionStep()) {
fReactionSet->CleanAllReaction();
fIsInitialized = false;
fSampledPositions.clear();
fSecondaries.clear();
InitializeForNewTrack();
}
}
void G4DNAIndependentReactionTimeStepper::InitializeForNewTrack()
{
if (fReactants != nullptr) {
fReactants.reset();
}
fSampledMinTimeStep = DBL_MAX;
fHasAlreadyReachedNullTime = false;
fCheckedTracks.clear();
BuildChemicalMoleculeFinder()
}
G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& trackA,
const G4double& userMinTimeStep)
const G4double& /*userMinTimeStep*/)
{
auto pMoleculeA = GetMolecule(trackA);
InitializeForNewTrack();
fUserMinTimeStep = userMinTimeStep;
fSampledMinTimeStep = DBL_MAX;
fCheckedTracks.insert(trackA.GetTrackID());
#ifdef G4VERBOSE
if (fVerbose != 0) {
if (fVerbose > 1) {
G4cout << "________________________________________________________________"
"_______"
<< G4endl;
@@ -96,7 +98,7 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
const auto pReactantList = fMolecularReactionTable->CanReactWith(pMolConfA);
if (pReactantList == nullptr) {
if(fVerbose > 1) {
if (fVerbose > 1) {
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will return infinity "
"for the reaction because the molecule "
@@ -111,7 +113,7 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
auto nbReactives = (G4int)pReactantList->size();
if (nbReactives == 0) {
if(fVerbose != 0){
if (fVerbose > 1) {
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will "
"return infinity "
@@ -125,13 +127,10 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
}
return DBL_MAX;
}
fReactants = std::make_shared<vector<G4Track*>>();
fReactionModel->Initialise(pMolConfA, trackA);
for (G4int i = 0; i < nbReactives; ++i) {
auto pMoleculeB = (*pReactantList)[i];
G4int key = pMoleculeB->GetMoleculeID();
// fRCutOff = G4IRTUtils::GetRCutOff(1 * ps);
fRCutOff = G4IRTUtils::GetRCutOff();
//______________________________________________________________
// Retrieve reaction range
@@ -157,115 +156,107 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& track
"::CalculateStep()",
"G4DNAIndependentReactionTimeStepper007", FatalException, exceptionDescription);
}
if (fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end()) {
continue;
}
Utils utils(trackA, *pTrackB);
auto pMolB = GetMolecule(pTrackB);
auto pMolConfB = pMolB->GetMolecularConfiguration();
G4double distance = (trackA.GetPosition() - pTrackB->GetPosition()).mag();
if (distance * distance < Reff * Reff) {
auto reactionData = fMolecularReactionTable->GetReactionData(pMolConfA, pMolConfB);
if (G4Scheduler::Instance()->GetGlobalTime() == G4Scheduler::Instance()->GetStartTime()) {
if (reactionData->GetProbability() > G4UniformRand()) {
fSampledMinTimeStep = 0.;
}
}
}
else {
if (fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end()) {
G4double tempMinET = GetTimeToEncounter(trackA, *pTrackB);
if (tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime()) {
continue;
}
Utils utils(trackA, *pTrackB);
auto pMolB = GetMolecule(pTrackB);
auto pMolConfB = pMolB->GetMolecularConfiguration();
G4double distance = (trackA.GetPosition() - pTrackB->GetPosition()).mag();
if (distance * distance < Reff * Reff) {
auto reactionData = fMolecularReactionTable->GetReactionData(pMolConfA, pMolConfB);
if (G4Scheduler::Instance()->GetGlobalTime() == G4Scheduler::Instance()->GetStartTime()) {
if (reactionData->GetProbability() > G4UniformRand()) {
if (!fHasAlreadyReachedNullTime) {
fReactants->clear();
fHasAlreadyReachedNullTime = true;
}
fSampledMinTimeStep = 0.;
CheckAndRecordResults(utils);
}
}
}
else {
G4double tempMinET = GetTimeToEncounter(trackA, *pTrackB);
if (tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime()) {
continue;
}
if (tempMinET >= fSampledMinTimeStep) {
continue;
}
fSampledMinTimeStep = tempMinET;
fReactants->clear();
CheckAndRecordResults(utils);
fSampledMinTimeStep = tempMinET;
if (tempMinET < fUserMinTimeStep) {
fSampledMinTimeStep = fUserMinTimeStep;
}
}
CheckAndRecordResults(fSampledMinTimeStep, utils);
}
}
#ifdef G4VERBOSE
if (fVerbose != 0) {
G4cout << "G4DNAIndependentReactionTimeStepper::CalculateStep will finally "
"return :"
<< G4BestUnit(fSampledMinTimeStep, "Time") << G4endl;
if (fVerbose > 1) {
G4cout << "Selected reactants for trackA: " << pMoleculeA->GetName() << " ("
<< trackA.GetTrackID() << ") are: ";
vector<G4Track*>::iterator it;
for (it = fReactants->begin(); it != fReactants->end(); it++) {
G4Track* trackB = *it;
G4cout << GetMolecule(trackB)->GetName() << " (" << trackB->GetTrackID() << ") \t ";
}
G4cout << G4endl;
}
}
#endif
return fSampledMinTimeStep;
}
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(const Utils& utils)
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(G4double reactionTime,
const Utils& utils)
{
if (utils.fTrackB.GetTrackStatus() != fAlive) {
if (utils.fpTrackB->GetTrackStatus() != fAlive) {
return;
}
if (&utils.fTrackB == &utils.fTrackA) {
if (&utils.fpTrackB == &utils.fpTrackA) {
G4ExceptionDescription msg;
msg << "A track is reacting with itself"
" (which is impossible) ie fpTrackA == trackB"
<< G4endl;
" (which is impossible) ie fpTrackA == trackB"
<< G4endl;
msg << "Molecule A is of type : " << utils.fpMoleculeA->GetName()
<< " with trackID : " << utils.fTrackA.GetTrackID()
<< " and B : " << utils.fpMoleculeB->GetName()
<< " with trackID : " << utils.fTrackB.GetTrackID() << G4endl;
<< " with trackID : " << utils.fpTrackA->GetTrackID()
<< " and B : " << utils.fpMoleculeB->GetName()
<< " with trackID : " << utils.fpTrackB->GetTrackID() << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper003", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper003", FatalErrorInArgument, msg);
}
if (fabs(utils.fTrackB.GetGlobalTime() - utils.fTrackA.GetGlobalTime())
> utils.fTrackA.GetGlobalTime() * (1. - 1. / 100))
if (fabs(utils.fpTrackB->GetGlobalTime() - utils.fpTrackA->GetGlobalTime())
> utils.fpTrackA->GetGlobalTime() * (1. - 1. / 100))
{
// DEBUG
G4ExceptionDescription msg;
msg << "The interacting tracks are not synchronized in time" << G4endl;
msg << "trackB->GetGlobalTime() != fpTrackA.GetGlobalTime()" << G4endl;
msg << "fpTrackA : trackID : " << utils.fTrackA.GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackA.GetGlobalTime(), "Time") << G4endl;
msg << "fpTrackA : trackID : " << utils.fpTrackA->GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = " << G4BestUnit(utils.fpTrackA->GetGlobalTime(), "Time")
<< G4endl;
msg << "trackB : trackID : " << utils.fTrackB.GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackB.GetGlobalTime(), "Time") << G4endl;
msg << "trackB : trackID : " << utils.fpTrackB->GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = " << G4BestUnit(utils.fpTrackB->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper004", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper004", FatalErrorInArgument, msg);
}
fReactants->push_back(const_cast<G4Track*>(&utils.fTrackB));
if (reactionTime < 0) {
// DEBUG
G4ExceptionDescription msg;
msg << "The interacting tracks are not in good time" << G4endl;
msg << "fpTrackA : trackID : " << utils.fpTrackA->GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = " << G4BestUnit(utils.fpTrackA->GetGlobalTime(), "Time")
<< G4endl;
msg << "trackB : trackID : " << utils.fpTrackB->GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = " << G4BestUnit(utils.fpTrackB->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CheckAndRecordResults",
"G4DNAIndependentReactionTimeStepper1", FatalErrorInArgument, msg);
}
G4double globalTime = G4Scheduler::Instance()->GetGlobalTime();
fReactionSet->AddReaction(reactionTime + globalTime, utils.fpTrackA, utils.fpTrackB);
fSampledPositions[utils.fpTrackA->GetTrackID()] = utils.fpTrackA->GetPosition();
fSampledPositions[utils.fpTrackB->GetTrackID()] = utils.fpTrackB->GetPosition();
}
std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindReaction(
G4ITReactionSet* pReactionSet, const G4double& currentStepTime,
const G4double& /*previousStepTime*/, const G4bool& /*reachedUserStepTimeLimit*/)
G4ITReactionSet* pReactionSet, G4double& currentStepTime, const G4double globalTime)
{
if (pReactionSet == nullptr) {
return nullptr;
@@ -278,16 +269,13 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
for (auto reaction_i = reactionPerTime.begin(); reaction_i != reactionPerTime.end();
reaction_i = reactionPerTime.begin())
{
if ((*reaction_i)->GetTime() > currentStepTime) {
fReactionSet->CleanAllReaction();
return nullptr;
}
G4Track* pTrackA = (*reaction_i)->GetReactants().first;
currentStepTime = DBL_MAX;
if (pTrackA->GetTrackStatus() == fStopAndKill) {
continue;
}
G4Track* pTrackB = (*reaction_i)->GetReactant(pTrackA);
currentStepTime = DBL_MAX;
if (pTrackB->GetTrackStatus() == fStopAndKill) {
continue;
}
@@ -295,24 +283,27 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
if (pTrackB == pTrackA) {
G4ExceptionDescription msg;
msg << "The IT reaction process sent back a reaction "
"between trackA and trackB. ";
"between trackA and trackB. ";
msg << "The problem is trackA == trackB";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper02", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper02", FatalErrorInArgument, msg);
}
G4double reactionTime = (*reaction_i)->GetTime();
currentStepTime = reactionTime - globalTime;
if(fVerbose > 1)
G4cout << " reaction Time : " << reactionTime << " currentStepTime : " << currentStepTime
<< " globalTime : " << globalTime << " " << pTrackA->GetTrackID() << " + "
<< pTrackB->GetTrackID() << G4endl;
pReactionSet->SelectThisReaction(*reaction_i);
if (fpReactionProcess != nullptr
&& fpReactionProcess->TestReactibility(*pTrackA, *pTrackB, currentStepTime, false))
{
if (fpReactionProcess != nullptr) {
if ((fSampledPositions.find(pTrackA->GetTrackID()) == fSampledPositions.end()
&& (fSampledPositions.find(pTrackB->GetTrackID()) == fSampledPositions.end())))
{
G4ExceptionDescription msg;
msg << "The positions of trackA and trackB have no counted ";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper0001", FatalErrorInArgument,
msg);
"G4DNAIndependentReactionTimeStepper0001", FatalErrorInArgument, msg);
}
pTrackA->SetPosition(fSampledPositions[pTrackA->GetTrackID()]);
@@ -321,6 +312,13 @@ std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindRea
if (pReactionChange == nullptr) {
return nullptr;
}
G4int nbSecondaries = pReactionChange->GetNumberOfSecondaries();
if (nbSecondaries > 0) {
const std::vector<G4Track*>* productsVector = pReactionChange->GetfSecondary();
for (const auto& it : *productsVector) {
fSecondaries.push_back(it);
}
}
return pReactionChange;
}
}
@@ -354,19 +352,44 @@ void G4DNAIndependentReactionTimeStepper::SetReactionProcess(G4VITReactionProces
{
fpReactionProcess = pReactionProcess;
}
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double /*currentGlobalTime*/,
G4double definedMinTimeStep)
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double currentGlobalTime,
G4double /*definedMinTimeStep*/)
{
G4double fTSTimeStep = DBL_MAX;
fCheckedTracks.clear();
// fUserMinTimeStep = definedMinTimeStep;
if (!fIsInitialized) {
InitializeReactions(currentGlobalTime);
}
G4int nbPreviousSecondaries = (G4int)fSecondaries.size();
if (nbPreviousSecondaries > 0) {
InitializeForNewTrack();
for (const auto& it : fSecondaries) {
CalculateStep(*it, fUserMinTimeStep);
}
fSecondaries.clear();
}
fTSTimeStep = GetNextReactionTime() - currentGlobalTime;
if (fTSTimeStep < 0) {
G4ExceptionDescription msg;
msg << "fTSTimeStep < 0" << ": fTSTimeStep : " << fTSTimeStep
<< " GetNextReactionTime() : " << GetNextReactionTime()
<< " currentGlobalTime : " << currentGlobalTime << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep",
"G4DNAIndependentReactionTimeStepper002", FatalErrorInArgument, msg);
}
return fTSTimeStep;
}
void G4DNAIndependentReactionTimeStepper::InitializeReactions(G4double /*currentGlobalTime*/)
{
fCheckedTracks.clear();
for (auto pTrack : *fpTrackContainer->GetMainList()) {
if (pTrack == nullptr) {
G4ExceptionDescription msg;
msg << "No track found.";
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep",
"G4DNAIndependentReactionTimeStepper006", FatalErrorInArgument,
msg);
G4Exception("G4DNAIndependentReactionTimeStepper::InitializeReactions",
"G4DNAIndependentReactionTimeStepper030", FatalErrorInArgument, msg);
continue;
}
@@ -374,36 +397,32 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double /*cu
if (trackStatus == fStopAndKill || trackStatus == fStopButAlive) {
continue;
}
G4double sampledMinTimeStep = CalculateStep(*pTrack, definedMinTimeStep);
G4TrackVectorHandle reactants = GetReactants();
if (sampledMinTimeStep < fTSTimeStep) {
fTSTimeStep = sampledMinTimeStep;
if (reactants) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), std::move(reactants));
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for (const auto& it : *fReactants) {
auto pTrackB = it;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
}
else if (fTSTimeStep == sampledMinTimeStep && G4bool(reactants)) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), std::move(reactants));
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for (const auto& it : *fReactants) {
auto pTrackB = it;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
else if (reactants) {
ResetReactants();
}
CalculateStep(*pTrack, fUserMinTimeStep);
}
return fTSTimeStep;
if (fVerbose > 0)
G4cout << "InitializeReactions : reaction events : "
<< fReactionSet->GetReactionsPerTime().size() << ". The previous time step : "
<< G4BestUnit(G4Scheduler::Instance()->GetPreviousTimeStep(), "Time") << G4endl;
fIsInitialized = true;
}
G4double G4DNAIndependentReactionTimeStepper::GetNextReactionTime()
{
G4double output = DBL_MAX;
auto nextReaction = GetNextReaction();
if (nextReaction != nullptr) {
output = GetNextReaction()->GetTime();
}
return output;
}
const G4ITReaction* G4DNAIndependentReactionTimeStepper::GetNextReaction()
{
G4ITReaction* output = nullptr;
G4ITReactionPerTime& reactionPerTime = fReactionSet->GetReactionsPerTime();
auto reaction_i = reactionPerTime.begin();
if (reaction_i != reactionPerTime.end()) {
output = (reaction_i->get());
}
return output;
}
@@ -37,6 +37,8 @@
#include "G4DNAIndependentReactionTimeStepper.hh"
#include "G4Scheduler.hh"
#include "G4UnitsTable.hh"
#include "G4DNAScavengerMaterial.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAMakeReaction::G4DNAMakeReaction()
:
@@ -45,6 +47,8 @@ G4DNAMakeReaction::G4DNAMakeReaction()
, fpTimeStepper(nullptr)
, fTimeStep(0)
{
fpScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
G4Scheduler::Instance()->GetScavengerMaterial());
}
G4DNAMakeReaction::G4DNAMakeReaction(G4VDNAReactionModel* pReactionModel)
@@ -83,6 +87,10 @@ G4DNAMakeReaction::MakeReaction(const G4Track &trackA,
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
const G4int nbProducts = pReactionData->GetNbProducts();
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
if (nbProducts != 0)
{
const G4double D1 = pMoleculeA->GetDiffusionCoefficient();
@@ -98,7 +106,18 @@ G4DNAMakeReaction::MakeReaction(const G4Track &trackA,
for (G4int j = 0; j < nbProducts; ++j)
{
auto pProduct = new G4Molecule(pReactionData->GetProduct(j));
auto product = pReactionData->GetProduct(j);
if(fpScavengerMaterial != nullptr) {
auto isScavenger = fpScavengerMaterial->find(product);
if (isScavenger) {
fpScavengerMaterial->AddNumberMoleculePerVolumeUnitForMaterialConf(
product, trackA.GetGlobalTime());
continue;
}
}
auto pProduct = new G4Molecule(product);
auto pProductTrack = pProduct->BuildTrack(trackA.GetGlobalTime(), (reactionSite + randP)/2);
pProductTrack->SetTrackStatus(fAlive);
G4ITTrackHolder::Instance()->Push(pProductTrack);
@@ -181,27 +200,30 @@ void G4DNAMakeReaction::UpdatePositionForReaction(G4Track& trackA,
}
}
std::vector<std::unique_ptr<G4ITReactionChange>>
G4DNAMakeReaction::FindReaction(G4ITReactionSet* pReactionSet,
const G4double currentStepTime,
const G4double /*globalTime*/,
const G4double globalTime,
const G4bool /*reachedUserStepTimeLimit*/)
{
std::vector<std::unique_ptr<G4ITReactionChange>> ReactionInfo;
ReactionInfo.clear();
auto stepper = dynamic_cast<G4DNAIndependentReactionTimeStepper*>(fpTimeStepper);
if(stepper == nullptr){
return ReactionInfo;
}else
{
do{
auto pReactionChange = stepper->
FindReaction(pReactionSet,currentStepTime);
if (pReactionChange != nullptr)
{
ReactionInfo.push_back(std::move(pReactionChange));
}
}while (!pReactionSet->GetReactionsPerTime().empty());
}
std::vector<std::unique_ptr<G4ITReactionChange>> ReactionInfo;
auto stepper = dynamic_cast<G4DNAIndependentReactionTimeStepper*>(fpTimeStepper);
if (stepper == nullptr) {
return ReactionInfo;
}else {
G4double StepTime = 0;
do {
auto pReactionChange = stepper->FindReaction(pReactionSet, StepTime, globalTime);
if (pReactionChange != nullptr) {
// G4cout<<" time : "<<globalTime<<" "<<pReactionChange->GetTrackA()->GetTrackID()
// <<" + "<<pReactionChange->GetTrackB()->GetTrackID()<<G4endl;
ReactionInfo.push_back(std::move(pReactionChange));
}
else{
break;
}
}while(StepTime == currentStepTime);
}
return ReactionInfo;
}
@@ -45,6 +45,7 @@
#include "G4ITReaction.hh"
#include "G4ITTrackHolder.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAMolecularReaction::G4DNAMolecularReaction()
:
@@ -91,7 +92,10 @@ std::unique_ptr<G4ITReactionChange> G4DNAMolecularReaction::MakeReaction(const G
const auto pMoleculeB = GetMolecule(trackB)->GetMolecularConfiguration();
const auto pReactionData = fMolReactionTable->GetReactionData(pMoleculeA, pMoleculeB);
// Notify molecule (reaction) counter
if (G4MoleculeCounterManager::Instance()->GetIsActive()) {
G4MoleculeCounterManager::Instance()->RecordReaction(pReactionData, trackA.GetGlobalTime());
}
const G4int nbProducts = pReactionData->GetNbProducts();
if (nbProducts != 0)
@@ -0,0 +1,556 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Created 11.02.2025 V.Ivanchenko & M. Vologzhin
// on base of previous Rudd models
//
// Russian Goverment grant No 075-15-2024-667 23.08.2024
//
#include "G4DNARuddIonisationDynamicModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4NistManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4LogLogInterpolation.hh"
#include "G4ProductionCutsTable.hh"
#include "G4DNAGenericIonsManager.hh"
#include "G4DNACrossSectionDataSet.hh"
#include "G4NistManager.hh"
#include "G4IonTable.hh"
#include "G4DNARuddAngle.hh"
#include "G4DeltaAngle.hh"
#include "G4Exp.hh"
#include "G4Log.hh"
#include "G4Pow.hh"
#include "G4Alpha.hh"
#include "G4Proton.hh"
#include "G4Electron.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_hydrogen = nullptr;
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_helium = nullptr;
G4DNACrossSectionDataSet* G4DNARuddIonisationDynamicModel::xsdata_p = nullptr;
const std::vector<G4double>* G4DNARuddIonisationDynamicModel::fpWaterDensity = nullptr;
namespace
{
const G4double scaleFactor = CLHEP::m*CLHEP::m;
const G4double tolerance = 1*CLHEP::eV;
const G4double Ry = 13.6*CLHEP::eV;
// Following values provided by M. Dingfelder (priv. comm)
const G4double Bj[5] = {12.60*CLHEP::eV, 14.70*CLHEP::eV, 18.40*CLHEP::eV,
32.20*CLHEP::eV, 539*CLHEP::eV};
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNARuddIonisationDynamicModel::G4DNARuddIonisationDynamicModel(const G4ParticleDefinition*,
const G4String& nam)
: G4VEmModel(nam)
{
fGpow = G4Pow::GetInstance();
fLowestEnergy = 100*CLHEP::eV;
fAbsorptionEnergy = 50*CLHEP::eV;
// Mark this model as "applicable" for atomic deexcitation
SetDeexcitationFlag(true);
// Define default angular generator
SetAngularDistribution(new G4DNARuddAngle());
if (nullptr == xsdata_p) {
isFirst = true;
LoadData();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNARuddIonisationDynamicModel::~G4DNARuddIonisationDynamicModel()
{
if (isFirst) {
delete xsdata_p;
delete xsdata_hydrogen;
delete xsdata_helium;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::LoadData()
{
// initialisation of static data once
G4String filename = "dna/sigma_ionisation_p_rudd";
xsdata_p = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_p->LoadData(filename);
filename = "dna/sigma_ionisation_h_rudd";
xsdata_hydrogen = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_hydrogen->LoadData(filename);
filename = "dna/sigma_ionisation_he_rudd";
xsdata_helium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata_helium->LoadData(filename);
// to avoid possible threading problem fill this vector only once
auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
fpWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
{
if (p != fParticle) { SetParticle(p); }
// particle change object may be externally set
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
}
const G4String& pname = p->GetParticleName();
// the same definition of generic ion as in G4VEmProcess class
if (p->GetParticleType() == "nucleus" && p->GetParticleSubType() == "generic") {
if (pname != "deuteron" && pname != "triton" &&
pname != "He3" && pname != "alpha" && pname != "alpha+" &&
pname != "helium" && pname != "hydrogen") {
isIon = true;
}
}
// initialisation once in each thread
if (!isInitialised) {
isInitialised = true;
xsdata = xsdata_p;
if (pname == "helium") {
isHelium = true;
xsdata = xsdata_helium;
slaterEffectiveCharge[0]=1.7;
slaterEffectiveCharge[1]=1.15;
slaterEffectiveCharge[2]=1.15;
sCoefficient[0]=0.5;
sCoefficient[1]=0.25;
sCoefficient[2]=0.25;
fLowestEnergy = 1*CLHEP::keV;
} else if (pname == "alpha+") {
isHelium = true;
// The following values are provided by M. Dingfelder (priv. comm)
slaterEffectiveCharge[0]=2.0;
slaterEffectiveCharge[1]=2.0;
slaterEffectiveCharge[2]=2.0;
sCoefficient[0]=0.7;
sCoefficient[1]=0.15;
sCoefficient[2]=0.15;
} else if (pname == "hydrogen") {
xsdata = xsdata_hydrogen;
}
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
// chemistry
auto chem = G4DNAChemistryManager::Instance();
if (chem->IsChemistryActivated()) {
fChemistry = chem;
}
InitialiseIntegrator(0.1, 0.25, 1.05, 1*CLHEP::eV, 0.2*CLHEP::eV, 10*CLHEP::keV);
if (verbose > 0) {
G4cout << "### G4DNARuddIonisationDynamicModel::Initialise(..) "
<< fParticle->GetParticleName() << G4endl;
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::SetParticle(const G4ParticleDefinition* p)
{
fParticle = p;
fMass = p->GetPDGMass();
fMassRate = CLHEP::proton_mass_c2/fMass;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationDynamicModel::StartTracking(G4Track* track)
{
fTrack = track;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double
G4DNARuddIonisationDynamicModel::CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* part,
G4double kinE,
G4double, G4double)
{
// check if model is applicable for given material
G4double density = (material->GetIndex() < fpWaterDensity->size())
? (*fpWaterDensity)[material->GetIndex()] : 0.0;
if (0.0 == density) { return 0.0; }
// check on kinetic energy (not scaled energy) to stop low-energy ion
if (kinE < fAbsorptionEnergy) { return DBL_MAX; }
// ion may be different
if (fParticle != part) { SetParticle(part); }
G4double q = fTrack->GetDynamicParticle()->GetCharge()*inveplus;
// cross section for scaled energy
G4double e = kinE*fMassRate;
auto xs = xsdata;
if (0.0 == q) { xs = isHelium ? xsdata_helium : xsdata_hydrogen; }
G4double sigma = (e > fLowestEnergy) ? xs->FindValue(e)
: xs->FindValue(fLowestEnergy) * e / fLowestEnergy;
sigma *= density;
if (q > 1.5) { sigma *= q * q; }
if (verbose > 1) {
G4cout << "G4DNARuddIonisationDynamicModel for " << part->GetParticleName()
<< " Ekin(keV)=" << kinE/CLHEP::keV
<< " sigma(cm^2)=" << sigma/CLHEP::cm2 << G4endl;
}
return sigma;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void
G4DNARuddIonisationDynamicModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dpart,
G4double, G4double)
{
const G4ParticleDefinition* pd = dpart->GetDefinition();
if (fParticle != pd) { SetParticle(pd); }
// stop ion with energy below low energy limit
G4double kinE = dpart->GetKineticEnergy();
// ion shoud be stopped - check on kinetic energy and not scaled energy
if (kinE <= fAbsorptionEnergy) {
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE);
return;
}
fScaledEnergy = kinE*fMassRate;
fSelectedShell = SelectShell();
G4double bindingEnergy = (useDNAWaterStructure)
? waterStructure.IonisationEnergy(fSelectedShell) : Bj[fSelectedShell];
//Si: additional protection if tcs interpolation method is modified
if (kinE < bindingEnergy) { return; }
G4double esec = SampleElectronEnergy();
G4double esum = 0.0;
// sample deexcitation
// here we assume that H2O electronic levels are the same as Oxygen.
// this can be considered true with a rough 10% error in energy on K-shell,
G4int Z = 8;
G4ThreeVector deltaDir =
GetAngularDistribution()->SampleDirectionForShell(dpart, esec, Z,
fSelectedShell,
couple->GetMaterial());
// SI: only atomic deexcitation from K shell is considered
if (fAtomDeexcitation != nullptr && fSelectedShell == 4) {
auto as = G4AtomicShellEnumerator(0);
auto ashell = fAtomDeexcitation->GetAtomicShell(Z, as);
fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
// compute energy sum from de-excitation
for (auto const & ptr : *fvect) {
esum += ptr->GetKineticEnergy();
}
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = kinE - bindingEnergy - esec;
if(scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNARuddIonisationDynamicModel::SampleSecondaries: "
<< "negative final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< kinE/CLHEP::keV << " " << pd->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
fParticleChangeForGamma->SetProposedKineticEnergy(scatteredEnergy);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(exc);
} else {
fParticleChangeForGamma->SetProposedKineticEnergy(kinE);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(kinE - scatteredEnergy);
}
// delta-electron
auto dp = new G4DynamicParticle(G4Electron::Electron(), deltaDir, esec);
fvect->push_back(dp);
// create radical
if (nullptr != fChemistry) {
fChemistry->CreateWaterMolecule(eIonizedMolecule, fSelectedShell, fTrack);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int G4DNARuddIonisationDynamicModel::SelectShell()
{
G4double sum = 0.0;
G4double xs;
for (G4int i=0; i<5; ++i) {
auto ptr = xsdata->GetComponent(i);
xs = (fScaledEnergy > fLowestEnergy) ? ptr->FindValue(fScaledEnergy)
: ptr->FindValue(fLowestEnergy)*fScaledEnergy/fLowestEnergy;
sum += xs;
fTemp[i] = sum;
}
sum *= G4UniformRand();
for (G4int i=0; i<5; ++i) {
if (sum <= fTemp[i]) { return i; }
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double
G4DNARuddIonisationDynamicModel::MaxEnergy()
{
// kinematic limit
G4double tau = fScaledEnergy/CLHEP::proton_mass_c2;
G4double gam = 1.0 + tau;
G4double emax = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
// Initialisation of sampling
G4double A1, B1, C1, D1, E1, A2, B2, C2, D2;
if (fSelectedShell == 4) {
//Data For Liquid Water K SHELL from Dingfelder (Protons in Water)
A1 = 1.25;
B1 = 0.5;
C1 = 1.00;
D1 = 1.00;
E1 = 3.00;
A2 = 1.10;
B2 = 1.30;
C2 = 1.00;
D2 = 0.00;
alphaConst = 0.66;
} else {
//Data For Liquid Water from Dingfelder (Protons in Water)
A1 = 1.02;
B1 = 82.0;
C1 = 0.45;
D1 = -0.80;
E1 = 0.38;
A2 = 1.07;
// Value provided by M. Dingfelder (priv. comm)
B2 = 11.6;
C2 = 0.60;
D2 = 0.04;
alphaConst = 0.64;
}
bEnergy = Bj[fSelectedShell];
G4double v2 = 0.25*emax/(bEnergy*gam*gam);
v = std::sqrt(v2);
u = Ry/bEnergy;
wc = 4.*v2 - 2.*v - 0.25*u;
G4double L1 = (C1 * fGpow->powA(v, D1)) / (1. + E1 * fGpow->powA(v, (D1 + 4.)));
G4double L2 = C2 * fGpow->powA(v, D2);
G4double H1 = (A1 * G4Log(1. + v2)) / (v2 + (B1 / v2));
G4double H2 = (A2 / v2) + (B2 / (v2 * v2));
F1 = L1 + H1;
F2 = (L2 * H2) / (L2 + H2);
return emax;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double
G4DNARuddIonisationDynamicModel::SampleElectronEnergy()
{
// sampling is performed for proton projectile
G4double emax = MaxEnergy();
ComputeIntegral(0.0, emax);
G4double e = SampleValue();
if (verbose > 1) {
G4cout << "G4DNARuddIonisationDynamicModel::SampleElectronEnergy: "
<< fParticle->GetParticleName()
<< " Escaled(keV)=" << fScaledEnergy/CLHEP::keV << " Ee(keV)=" << e/CLHEP::keV
<< G4endl;
}
return e;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::ProbabilityDensityFunction(G4double e)
{
// Shells ids are 0 1 2 3 4 (4 is k shell)
// !!Attention, "energyTransfer" here is the energy transfered to the electron which means
// that the secondary kinetic energy is w = energyTransfer - bindingEnergy
//
// ds S F1(nu) + w * F2(nu)
// ---- = G(k) * ---- -------------------------------------------
// dw Bj (1+w)^3 * [1 + exp{alpha * (w - wc) / nu}]
//
// w is the secondary electron kinetic Energy in eV
//
// All the other parameters can be found in Rudd's Papers
//
// M.Eugene Rudd, 1988, User-Friendly model for the energy distribution of
// electrons from protons or electron collisions. Nucl. Tracks Rad. Meas.Vol 16 N0 2/3 pp 219-218
//
G4double w = e/bEnergy;
G4double x = alphaConst*(w - wc)/v;
G4double y = (x > -15.) ? 1.0 + G4Exp(x) : 1.0;
G4double res = CorrectionFactor() * (F1 + w*F2) /
(fGpow->powN((1. + w)/u, 3) * y);
if (isHelium) {
G4double energyTransfer = e + bEnergy;
G4double Zeff = 2.0 -
(sCoefficient[0] * S_1s(fScaledEnergy, energyTransfer, slaterEffectiveCharge[0], 1.) +
sCoefficient[1] * S_2s(fScaledEnergy, energyTransfer, slaterEffectiveCharge[1], 2.) +
sCoefficient[2] * S_2p(fScaledEnergy, energyTransfer, slaterEffectiveCharge[2], 2.) );
res *= Zeff * Zeff;
}
return std::max(res, 0.0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_1s(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2r) * ( 1 + 2 r + 2 r^2)
// Dingfelder, in Chattanooga 2005 proceedings, formula (7)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value = 1. - G4Exp(-2 * r) * ( ( 2. * r + 2. ) * r + 1. );
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_2s(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 2 r^4)
// Dingfelder, in Chattanooga 2005 proceedings, formula (8)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value =
1. - G4Exp(-2 * r) * (((2. * r * r + 2.) * r + 2.) * r + 1.);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::S_2p(G4double kine,
G4double energyTransfer,
G4double slaterEffCharge,
G4double shellNumber)
{
// 1 - e^(-2 r) * ( 1 + 2 r + 2 r^2 + 4/3 r^3 + 2/3 r^4)
// Dingfelder, in Chattanooga 2005 proceedings, formula (9)
G4double r = Rh(kine, energyTransfer, slaterEffCharge, shellNumber);
G4double value =
1. - G4Exp(-2 * r) * (((( 2./3. * r + 4./3.) * r + 2.) * r + 2.) * r + 1.);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::Rh(G4double ekin, G4double etrans,
G4double q, G4double shell)
{
// The following values are provided by M. Dingfelder (priv. comm)
// Dingfelder, in Chattanooga 2005 proceedings, p 4
G4double escaled = CLHEP::electron_mass_c2/fMass * ekin;
const G4double H = 13.60569172 * CLHEP::eV;
G4double value = 2.0*std::sqrt(escaled / H)*q*H /(etrans*shell);
return value;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationDynamicModel::CorrectionFactor()
{
// ZF Shortened
G4double res = 1.0;
if (fSelectedShell < 4) {
const G4double ln10 = fGpow->logZ(10);
G4double x = 2.0*((G4Log(fScaledEnergy/CLHEP::eV)/ln10) - 4.2);
// The following values are provided by M. Dingfelder (priv. comm)
res = 0.6/(1.0 + G4Exp(x)) + 0.9;
}
return res;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -91,7 +91,7 @@ G4DNARuddIonisationExtendedModel::G4DNARuddIonisationExtendedModel(const G4Parti
G4DNARuddIonisationExtendedModel::~G4DNARuddIonisationExtendedModel()
{
if(isFirst) {
if (isFirst) {
for(auto & i : xsdata) { delete i; }
}
}
@@ -222,7 +222,8 @@ void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
statCode = G4EmParameters::Instance()->DNAStationary();
// initialise atomic de-excitation
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (verbose > 0) {
G4cout << "### G4DNARuddIonisationExtendedModel::Initialise(..) " << pname
@@ -330,17 +331,18 @@ G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicParticl
}
// check energy balance
// remaining excitation energy of water molecule
G4double exc = bindingEnergy - esum;
G4double exc = std::max(bindingEnergy - esum, 0.0);
// remaining projectile energy
G4double scatteredEnergy = kinE - bindingEnergy - esec;
if(scatteredEnergy < -tolerance || exc < -tolerance) {
if (scatteredEnergy < -tolerance || exc < -tolerance) {
G4cout << "G4DNARuddIonisationExtendedModel::SampleSecondaries: "
<< "negative final E(keV)=" << scatteredEnergy/CLHEP::keV << " Ein(keV)="
<< kinE/CLHEP::keV << " " << pd->GetParticleName()
<< " Edelta(keV)=" << esec/CLHEP::keV << " MeV, Exc(keV)=" << exc/CLHEP::keV
<< G4endl;
}
scatteredEnergy = std::max(scatteredEnergy, 0.0);
// projectile
if (!statCode) {
@@ -258,7 +258,22 @@ void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
SetHighEnergyLimit(highEnergyLimit[alphaPlusPlus]);
}
if( verboseLevel>0 )
if (isInitialised) { return; }
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
// Initialize water density pointer
fpWaterDensity = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
// atomic de-excitation
if (!statCode)
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
if (verboseLevel > 0)
{
G4cout << "Rudd ionisation model is initialized " << G4endl
<< "Energy range: "
@@ -267,19 +282,6 @@ void G4DNARuddIonisationModel::Initialise(const G4ParticleDefinition* particle,
<< particle->GetParticleName()
<< G4endl;
}
// Initialize water density pointer
fpWaterDensity = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
//
fAtomDeexcitation = G4LossTableManager::Instance()->AtomDeexcitation();
if (isInitialised)
{ return;}
fParticleChangeForGamma = GetParticleChangeForGamma();
isInitialised = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -32,6 +32,8 @@
#include "G4DNAScavengerMaterial.hh"
#include "G4Scheduler.hh"
#include "G4MoleculeCounterManager.hh"
G4DNAUpdateSystemModel::G4DNAUpdateSystemModel() = default;
void G4DNAUpdateSystemModel::SetMesh(G4DNAMesh* pMesh) { fpMesh = pMesh; }
@@ -53,9 +55,9 @@ void G4DNAUpdateSystemModel::KillMolecule(const Index& index, MolType type)
FatalErrorInArgument, exceptionDescription);
}
iter->second--;
if(G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->RemoveAMoleculeAtTime(type, fGlobalTime);
G4MoleculeCounterManager::Instance()->RemoveMoleculeWithoutTrack(type, fGlobalTime);
}
}
else
@@ -131,9 +133,9 @@ void G4DNAUpdateSystemModel::CreateMolecule(const Index& index, MolType type)
node[type] = 1;
}
if(G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->AddAMoleculeAtTime(type, fGlobalTime);
G4MoleculeCounterManager::Instance()->AddMoleculeWithoutTrack(type, fGlobalTime);
}
}
@@ -205,7 +205,7 @@ public:
*/
void PrintState() const;
G4Track * BuildTrack(G4double globalTime, const G4ThreeVector& Position);
G4Track* BuildTrack(G4double globalTime, const G4ThreeVector &Position, const G4Track * = nullptr);
G4double GetKineticEnergy() const;
@@ -24,14 +24,15 @@
// ********************************************************************
//
// Author: Mathieu Karamitros
// Modified by Christian Velten (2024)
// The code is developed in the framework of the ESA AO7146
//
// We would be very happy hearing from you, send us your feedback! :)
//
// In order for Geant4-DNA to be maintained and still open-source,
// article citations are crucial.
// If you use Geant4-DNA chemistry and you publish papers about your software,
// article citations are crucial.
// If you use Geant4-DNA chemistry and you publish papers about your software,
// in addition to the general paper on Geant4-DNA:
//
// Int. J. Model. Simul. Sci. Comput. 1 (2010) 157178
@@ -40,111 +41,62 @@
// reference papers on chemistry:
//
// J. Comput. Phys. 274 (2014) 841-882
// Prog. Nucl. Sci. Tec. 2 (2011) 503-508
// Prog. Nucl. Sci. Tec. 2 (2011) 503-508
#pragma once
#include "G4VMoleculeCounter.hh"
#include "G4MolecularConfiguration.hh"
#include "G4VUserMoleculeCounter.hh"
#include <map>
#include <memory>
#include <set>
#include <vector>
//------------------------------------------------------------------------------
namespace G4 {
namespace MoleculeCounter {
struct TimePrecision
struct G4MoleculeCounterIndex : public G4VMoleculeCounter::G4VMoleculeCounterIndex
{
bool operator()(const double& a, const double& b) const;
static G4ThreadLocal double fPrecision;
};
}
}
using NbMoleculeAgainstTime = std::map<G4double, G4int, G4::MoleculeCounter::TimePrecision>;
using RecordedTimes = std::unique_ptr<std::set<G4double>>;
//------------------------------------------------------------------------------
class G4MoleculeCounter : public G4VMoleculeCounter
{
//----------------------------------------------------------------------------
public:
using ReactantList = std::vector<Reactant*>;
using CounterMapType = std::map<Reactant*, NbMoleculeAgainstTime>;
using RecordedMolecules = std::unique_ptr<ReactantList>;
static G4MoleculeCounter* Instance();
void Initialize() override;
void ResetCounter() override;
/* The dynamics of the given molecule won't be saved into memory.*/
void DontRegister(const G4MoleculeDefinition*) override;
bool IsRegistered(const G4MoleculeDefinition*) override;
void RegisterAll() override;
//----------------------------------------------------------------------------
int GetNMoleculesAtTime(Reactant* molecule, double time);
const NbMoleculeAgainstTime& GetNbMoleculeAgainstTime(Reactant* molecule);
RecordedMolecules GetRecordedMolecules();
RecordedTimes GetRecordedTimes();
void SetVerbose(G4int);
G4int GetVerbose();
/* It sets the min time difference in between two time slices. */
static void SetTimeSlice(double);
void Dump();
G4bool IsTimeCheckedForConsistency() const;
void CheckTimeForConsistency(G4bool flag);
#ifdef MOLECULE_COUNTER_TESTING
public:
#else
protected:
#endif
void AddAMoleculeAtTime(Reactant*,
G4double time,
const G4ThreeVector* position = nullptr,
int number = 1) override;
void RemoveAMoleculeAtTime(Reactant*,
G4double time,
const G4ThreeVector* position = nullptr,
int number = 1) override;
//----------------------------------------------------------------------------
protected:
G4bool SearchTimeMap(Reactant* molecule);
int SearchUpperBoundTime(double time, bool sameTypeOfMolecule);
protected:
G4MoleculeCounter();
~G4MoleculeCounter() override;
CounterMapType fCounterMap;
std::map<const G4MoleculeDefinition*, G4bool> fDontRegister;
G4int fVerbose;
G4bool fCheckTimeIsConsistentWithScheduler;
struct Search
const G4MolecularConfiguration* Molecule;
G4MoleculeCounterIndex() : Molecule(nullptr) {}
explicit G4MoleculeCounterIndex(const G4MolecularConfiguration* molecule) : Molecule(molecule)
{}
~G4MoleculeCounterIndex() override = default;
G4bool operator<(G4VMoleculeCounterIndex const& other) const override
{
Search()
{
fLowerBoundSet = false;
}
CounterMapType::iterator fLastMoleculeSearched;
NbMoleculeAgainstTime::iterator fLowerBoundTime;
bool fLowerBoundSet;
};
return std::less{}(Molecule, static_cast<const G4MoleculeCounterIndex&>(other).Molecule);
}
G4bool operator==(G4VMoleculeCounterIndex const& other) const override
{
return std::equal_to{}(Molecule, static_cast<const G4MoleculeCounterIndex&>(other).Molecule);
}
G4String GetInfo() const override
{
G4String null = "null";
if (Molecule == nullptr) {
return null;
}
else {
G4String name = Molecule->GetName();
G4String info = "Molecule: " + name;
return info;
}
}
const G4MolecularConfiguration* GetMolecule() const override { return Molecule; }
};
std::unique_ptr<Search> fpLastSearch;
class G4MoleculeCounter : public G4VUserMoleculeCounter<G4MoleculeCounterIndex>
{
//----------------------------------------------------------------------------
public:
G4MoleculeCounter();
G4MoleculeCounter(G4String);
~G4MoleculeCounter() override = default;
friend class G4Molecule;
friend class G4VMoleculeCounter;
};
void InitializeUser() override;
public:
std::unique_ptr<G4VMoleculeCounterIndex> BuildIndex(const G4Track*) const override;
std::unique_ptr<G4VMoleculeCounterIndex> BuildIndex(const G4Track*,
const G4StepPoint*) const override;
std::unique_ptr<G4VMoleculeCounterIndex>
BuildSimpleIndex(const G4MolecularConfiguration*) const override;
};
@@ -0,0 +1,250 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4MOLECULECOUNTERMANAGER_HH
#define G4MOLECULECOUNTERMANAGER_HH 1
#include "G4Exception.hh"
#include "G4Threading.hh"
#include "G4Types.hh"
#include "G4VMoleculeCounter.hh"
#include "G4VMoleculeReactionCounter.hh"
#include "G4ios.hh"
#include <functional>
#include <map>
#include <vector>
class G4Event;
class G4Run;
class G4Step;
class G4StepPoint;
class G4Track;
class G4MoleculeCounterManagerMessenger;
class G4MoleculeCounterManager final
{
private:
struct Private
{
explicit Private() = default;
};
public:
G4MoleculeCounterManager(Private);
~G4MoleculeCounterManager();
private:
G4bool fInstancesRegistered{false};
void RegisterInstance();
public:
static G4MoleculeCounterManager* Instance();
static G4MoleculeCounterManager* GetInstanceIfExists();
static void DeleteInstance();
void Initialize();
//
// Management
G4int RegisterCounter(std::unique_ptr<G4VMoleculeCounter>);
G4int RegisterCounter(std::unique_ptr<G4VMoleculeReactionCounter>);
void DeregisterAllCounters();
private:
template<typename T>
G4int RegisterCounter(std::map<G4int, T*>&, std::unique_ptr<T>, std::function<G4int()>);
void InitializeMaster();
void InitializeWorker();
public:
// methods to receive forwarding from G4DNAChemistryManager
void BeginOfEventAction(const G4Event*);
void BeginOfRunAction(const G4Run*);
void EndOfEventAction(const G4Event*);
void EndOfRunAction(const G4Run*);
// Dumping counters
void DumpMasterCounters() const;
void DumpWorkerCounters() const;
// Accumulation of counters into master
void AbsorbWorkerManagerCounters(const G4MoleculeCounterManager* = nullptr);
//
// Calls to Molecule Counters
public:
// [[deprecated("This should only be used for IRT and may be replaced as well.")]]
void AddMoleculeWithoutTrack(const G4MolecularConfiguration*, G4double, G4int = 1);
// [[deprecated("This should only be used for IRT and may be replaced as well.")]]
void RemoveMoleculeWithoutTrack(const G4MolecularConfiguration*, G4double, G4int = 1);
void AddMolecule(const G4Track*, G4double, G4int = 1);
void RemoveMolecule(const G4Track*, G4double, G4int = 1);
void AddMolecule(const G4Track*, const G4StepPoint*, G4double, G4int = 1);
void RemoveMolecule(const G4Track*, const G4StepPoint*, G4double, G4int = 1);
void ActivateCounterAtTimes(G4int, G4double, G4double, G4bool = true, G4bool = true);
//
// Calls to Molecule Reaction Counters
// [[deprecated("TBD")]]
void RecordReaction(const G4DNAMolecularReactionData*, G4double, G4int = 1);
// void RecordReaction(const G4Track*, const G4Track*, const G4DNAMolecularReactionData*, G4double,
// G4int = 1);
void ActivateReactionCounterAtTimes(G4int, G4double, G4double, G4bool = true, G4bool = true);
//
// Other Calls to both types or only one (e.g., BroadcastIgnoreMolecule)
void ResetCounters();
void NotifyOfStep(const G4Step*);
void NotifyOfFinalize();
// These will be broadcast to all counters registered at time of call
void BroadcastIgnoreMolecule(const G4MoleculeDefinition*);
void BroadcastIgnoreReactant(const G4MolecularConfiguration*);
void BroadcastRegisterAllMoleculesAndReactants();
private:
static const G4MoleculeCounterManager* fpMasterInstance;
static std::vector<const G4MoleculeCounterManager*> fWorkerInstances;
G4ThreadLocalStatic std::unique_ptr<G4MoleculeCounterManager> fpInstance;
std::unique_ptr<G4MoleculeCounterManagerMessenger> fpMessenger;
G4int fVerbosity;
G4bool fIsInitialized;
G4bool fIsActive;
static std::atomic<G4bool> fResetCountersBeforeEvent;
static std::atomic<G4bool> fResetCountersBeforeRun;
static std::atomic<G4bool> fResetMasterCounterWithWorkers;
static std::atomic<G4bool> fAccumulateCounterIntoMaster;
std::map<G4int, G4VMoleculeCounter*> fCounters{};
std::map<G4int, G4VMoleculeReactionCounter*> fReactionCounters{};
public:
G4bool GetIsActive() const { return fIsActive; }
void SetIsActive(G4bool flag) { fIsActive = flag; }
G4int GetVerbosity() const { return fVerbosity; }
void SetVerbosity(G4int v) { fVerbosity = v; }
G4bool GetResetCountersBeforeEvent() const;
void SetResetCountersBeforeEvent(G4bool = true);
G4bool GetResetCountersBeforeRun() const;
void SetResetCountersBeforeRun(G4bool = true);
G4bool GetResetMasterCounterWithWorkers() const;
void SetResetMasterCounterWithWorkers(G4bool = true);
G4bool GetAccumulateCounterIntoMaster() const;
void SetAccumulateCounterIntoMaster(G4bool = true);
std::vector<const G4VMoleculeCounter*> GetMoleculeCounters() const;
std::vector<const G4VMoleculeCounter*> GetMoleculeCounters(G4String) const;
template<typename T = G4VMoleculeCounter>
const T* GetMoleculeCounter(G4int) const;
G4VMoleculeCounter* GetEditableMoleculeCounter(G4int) const;
std::vector<const G4VMoleculeReactionCounter*> GetMoleculeReactionCounters() const;
std::vector<const G4VMoleculeReactionCounter*> GetMoleculeReactionCounters(G4String) const;
G4VMoleculeReactionCounter* GetEditableMoleculeReactionCounter(G4int) const;
template<typename T = G4VMoleculeReactionCounter>
const T* GetMoleculeReactionCounter(G4int) const;
private:
G4ThreadLocalStatic std::atomic<G4bool> fBeginOfEventTriggered;
static std::atomic<G4bool> fBeginOfRunTriggered;
};
//------------------------------------------------------------------------------
template<typename T>
G4int G4MoleculeCounterManager::RegisterCounter(std::map<G4int, T*>& map,
std::unique_ptr<T> counter,
std::function<G4int()> idProvider)
{
// this template allows for more than one counter type to be registered in the same way without
// duplicating code; see public methods for G4VMoleculeCounter and G4VMoleculeReactionCounter
if (fVerbosity > 0) {
G4cout << "G4MoleculeCounterManager::RegisterCounter ("
<< (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
}
if (counter->GetManagedId() >= 0) {
G4ExceptionDescription description;
description << "Trying to add a counter whose id was already altered to be non-negative!\n";
description << " Id: " << counter->GetManagedId() << "\n";
description << "Name: " << counter->GetName();
G4Exception("G4MoleculeCounterManager::RegisterCounter", "MOLMAN002", FatalErrorInArgument,
description);
}
T* sp = counter.release();
// Set managed Id
sp->SetManagedId(idProvider());
map.emplace(sp->GetManagedId(), sp);
return sp->GetManagedId();
}
//------------------------------------------------------------------------------
template<typename T>
const T* G4MoleculeCounterManager::GetMoleculeCounter(G4int id) const
{
static_assert(std::is_base_of<G4VMoleculeCounter, T>::value,
"T must be derived from G4VMoleculeCounter!");
auto base_ptr = GetEditableMoleculeCounter(id);
if (base_ptr == nullptr) return nullptr;
const T* ptr = dynamic_cast<const T*>(base_ptr);
return ptr;
}
template<typename T>
const T* G4MoleculeCounterManager::GetMoleculeReactionCounter(G4int id) const
{
static_assert(std::is_base_of<G4VMoleculeReactionCounter, T>::value,
"T must be derived from G4VMoleculeReactionCounter!");
auto base_ptr = GetEditableMoleculeReactionCounter(id);
if (base_ptr == nullptr) return nullptr;
const T* ptr = dynamic_cast<const T*>(base_ptr);
return ptr;
}
//------------------------------------------------------------------------------
#endif // G4MOLECULECOUNTERMANAGER_HH
@@ -0,0 +1,61 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// Author: Christian Velten (2025)
#ifndef G4MOLECULECOUNTERMANAGERMESSENGER_HH
#define G4MOLECULECOUNTERMANAGERMESSENGER_HH 1
#include "G4UIcmdWithABool.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIdirectory.hh"
#include "G4UImessenger.hh"
#include <memory>
class G4MoleculeCounterManager;
class G4MoleculeCounterManagerMessenger : public G4UImessenger
{
public:
explicit G4MoleculeCounterManagerMessenger(G4MoleculeCounterManager*);
~G4MoleculeCounterManagerMessenger() override = default;
void SetNewValue(G4UIcommand*, G4String) override;
private:
void InitializeCommands();
private:
G4MoleculeCounterManager* fpManager{nullptr};
std::unique_ptr<G4UIdirectory> fpManagerDir;
std::unique_ptr<G4UIcmdWithABool> fpActiveCmd;
std::unique_ptr<G4UIcmdWithABool> fpResetBeforeEventCmd;
std::unique_ptr<G4UIcmdWithABool> fpResetBeforeRunCmd;
std::unique_ptr<G4UIcmdWithABool> fpAccumulateIntoMasterCmd;
std::unique_ptr<G4UIcmdWithAnInteger> fpVerboseCmd;
};
#endif // G4MOLECULECOUNTERMANAGERMESSENGER_HH
@@ -0,0 +1,157 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4MOLECULECOUNTERTEMPLATES_HH
#define G4MOLECULECOUNTERTEMPLATES_HH 1
#include "G4Types.hh"
#include "G4VMoleculeCounter.hh"
#include <map>
#include <set>
#include <vector>
namespace G4
{
namespace MoleculeCounter
{
//------------------------------------------------------------------------------
template<typename T>
G4String GetTemplateTypeName()
{
return G4String(typeid(T).name());
}
//------------------------------------------------------------------------------
template<typename T>
G4bool Contains(const std::set<T>& _set, const T& _value)
{
return std::binary_search(_set.cbegin(), _set.cend(), _value);
}
template<typename T>
G4bool Contains(const std::vector<T>& _vector, const T& _value)
{
auto p = std::find(_vector.cbegin(), _vector.cend(), _value);
return p != _vector.cend();
}
template<typename T, typename U>
G4bool ContainsKey(const std::map<T, U>& _map, const T& _key)
{
auto keys = GetMapIndices(_map);
return Contains(keys, _key);
}
//------------------------------------------------------------------------------
template<typename T, typename U>
const std::vector<T> GetMapIndices(const std::map<T, U>& _map)
{
std::vector<T> output;
for (auto const& it : _map)
output.push_back(it.first);
return output;
}
//------------------------------------------------------------------------------
template<typename T>
void DumpCounterMapIndices(const std::map<T, InnerCounterMapType>& map, G4bool includeEmpty = false)
{
G4cout << "--- BEGIN COUNTER MAP INDEX DUMP ---" << G4endl;
auto i = 0;
for (auto const& it : map) {
if (!includeEmpty && it.second.size() == 0) continue;
G4cout << i++ << ": " << it.first.GetInfo() << G4endl;
}
G4cout << "--- END COUNTER MAP INDEX DUMP ---" << G4endl;
}
//------------------------------------------------------------------------------
template<typename T>
void DumpCounterMapContents(const std::map<T, InnerCounterMapType>& map,
G4bool includeEmpty = false)
{
G4cout << "--- BEGIN COUNTER MAP DUMP ---" << G4endl;
for (auto const& it : map) {
if (!includeEmpty && it.second.size() == 0) continue;
G4cout << " :: " << it.first.GetInfo() << G4endl;
for (auto const& it2 : it.second) {
G4cout << std::setw(3) << std::setprecision(3) << " " << G4BestUnit(it2.first, "Time")
<< " " << std::setw(5) << it2.second << G4endl;
}
}
G4cout << "--- END COUNTER MAP DUMP ---" << G4endl;
}
//------------------------------------------------------------------------------
template<typename T>
std::set<G4double> GetRecordedTimes(const std::map<T, InnerCounterMapType>& map)
{
std::set<G4double> output{};
for (const auto& it : map) {
G4cerr << it.second.size() << G4endl;
for (const auto& it2 : it.second) {
output.insert(it2.first);
}
}
return output;
}
//------------------------------------------------------------------------------
template<typename TKey, typename TValue, typename TComp>
typename std::map<TKey, TValue, TComp>::iterator
FindClosestEntryForKey(std::map<TKey, TValue, TComp>& map, TKey key)
{
if (map.empty()) return map.end();
auto it_lb = map.lower_bound(key);
if (it_lb == map.begin()) return it_lb;
if (it_lb == map.end()) return --it_lb;
auto prev_it = std::prev(it_lb);
if (std::abs(it_lb->first - key) < std::abs(prev_it->first - key))
return it_lb;
else
return prev_it;
}
//------------------------------------------------------------------------------
} // namespace MoleculeCounter
} // namespace G4
#endif
@@ -0,0 +1,69 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#ifndef G4MOLECULECOUNTERTIMECOMPARER_HH
#define G4MOLECULECOUNTERTIMECOMPARER_HH 1
#include "G4SystemOfUnits.hh"
#include "G4Types.hh"
#include <map>
#include <vector>
class G4MoleculeCounterTimeComparer
{
public:
enum TimeComparerType
{
FixedPrecision,
VariablePrecision
};
public:
G4MoleculeCounterTimeComparer();
virtual ~G4MoleculeCounterTimeComparer() = default;
G4MoleculeCounterTimeComparer(const G4MoleculeCounterTimeComparer&);
G4MoleculeCounterTimeComparer& operator=(const G4MoleculeCounterTimeComparer&);
void SetFixedPrecision(G4double);
void SetVariablePrecision(const std::vector<G4double>&, const std::vector<G4double>&);
void SetVariablePrecision(const std::map<G4double, G4double>&);
G4double GetPrecisionAtTime(G4double) const;
bool operator()(const G4double&, const G4double&) const;
private:
TimeComparerType fType;
G4double fPrecision{1 * picosecond};
std::map<G4double, G4double> fVariablePrecision{};
public: // Factory
static G4MoleculeCounterTimeComparer CreateWithFixedPrecision(G4double);
static G4MoleculeCounterTimeComparer CreateWithVariablePrecision(const std::map<G4double, G4double>&);
};
#endif
@@ -32,7 +32,6 @@
#include <memory>
class G4UIcmdWithAString;
class G4DNAMolecularReactionTable;
class G4UIcmdWithoutParameter;
class G4UIcmdWithADoubleAndUnit;
class G4UIcmdWithAnInteger;
@@ -27,80 +27,133 @@
// Geant4
//
// Created by Mathieu Karamitros on 02/11/2016.
// Modified by Christian Velten on 10/27/2024.
//
//
#ifndef G4VMOLECULECOUNTER_HH
#define G4VMOLECULECOUNTER_HH 1
#pragma once
#include "G4MoleculeCounterTimeComparer.hh"
#include "G4VMoleculeCounterInternalBase.hh"
#include <G4Types.hh>
#include <G4ios.hh>
#include "G4ThreeVector.hh"
#include <map>
#include <memory>
class G4MolecularConfiguration;
class G4MoleculeDefinition;
class G4Track;
class G4StepPoint;
class G4VMoleculeCounter
//------------------------------------------------------------------------------
class G4VMoleculeCounter : public G4VMoleculeCounterInternalBase
{
protected:
static G4ThreadLocal G4VMoleculeCounter* fpInstance;
G4bool fUse = false;
template<typename>
friend class G4VUserMoleculeCounter;
G4VMoleculeCounter() = default;
virtual ~G4VMoleculeCounter() = default;
public:
static void SetInstance(G4VMoleculeCounter*);
static void DeleteInstance();
using Reactant = const G4MolecularConfiguration;
/*
* If no instance of G4VMoleculeCounter is provided
* then use G4MoleculeCounter
*/
static G4VMoleculeCounter* Instance();
static void InitializeInstance();
/*
* If the molecule counter is used, it will be called
* at every creation/deletion of a molecule to
* to increase/decrease the number at a given time.
*/
void Use(G4bool flag = true);
G4bool InUse();
//----------------------------------------------------
virtual void Initialize() = 0;
virtual void ResetCounter() = 0;
virtual void AddAMoleculeAtTime(Reactant*,
G4double time,
const G4ThreeVector* position = nullptr,
int number = 1) = 0;
virtual void RemoveAMoleculeAtTime(Reactant*,
G4double time,
const G4ThreeVector* position = nullptr,
int number = 1) = 0;
/* The dynamics of the given molecule won't be recorded. */
virtual void DontRegister(const G4MoleculeDefinition*)
public:
enum MoleculeCounterType
{
}
virtual bool IsRegistered(const G4MoleculeDefinition*)
Other,
Basic,
Mesoscopic,
};
struct G4VMoleculeCounterIndex : public G4VMoleculeCounterIndexInterface
{
return false;
}
virtual ~G4VMoleculeCounterIndex() = default;
virtual G4bool operator<(G4VMoleculeCounterIndex const&) const = 0;
virtual G4bool operator==(G4VMoleculeCounterIndex const&) const = 0;
virtual G4String GetInfo() const = 0;
virtual const G4MolecularConfiguration* GetMolecule() const = 0;
};
virtual void RegisterAll()
{
}
};
private:
G4VMoleculeCounter();
G4VMoleculeCounter(const G4String&, MoleculeCounterType = MoleculeCounterType::Other);
G4VMoleculeCounter(G4VMoleculeCounter const&) = delete;
void operator=(G4VMoleculeCounter const& x) = delete;
public:
~G4VMoleculeCounter() override = default;
public:
virtual std::unique_ptr<G4VMoleculeCounterIndex> BuildIndex(const G4Track*) const = 0;
virtual std::unique_ptr<G4VMoleculeCounterIndex> BuildIndex(const G4Track*,
const G4StepPoint*) const = 0;
virtual std::unique_ptr<G4VMoleculeCounterIndex> BuildSimpleIndex(const G4MolecularConfiguration*) const = 0;
virtual void AddMolecule(std::unique_ptr<G4VMoleculeCounterIndex>, G4double, G4int = 1) = 0;
virtual void RemoveMolecule(std::unique_ptr<G4VMoleculeCounterIndex>, G4double, G4int = 1) = 0;
virtual std::set<const G4MolecularConfiguration*> GetRecordedMolecules() const = 0;
std::set<G4double> GetRecordedTimes() const override = 0;
virtual void SchedulerFinalizedTracking() = 0;
protected:
MoleculeCounterType fType{MoleculeCounterType::Other};
G4bool fSensitiveToStepping{false};
G4bool fNegativeCountsAreFatal{true};
std::set<const G4MoleculeDefinition*> fIgnoredMolecules{};
std::set<const G4MolecularConfiguration*> fIgnoredReactants{};
public:
MoleculeCounterType GetType() const;
G4bool GetSensitiveToStepping() const;
void SetSensitiveToStepping(G4bool = true);
G4bool GetNegativeCountsAreFatal() const;
// Ignore certain molecules from counting
void IgnoreMolecule(const G4MoleculeDefinition*);
void IgnoreReactant(const G4MolecularConfiguration*);
void RegisterAll();
G4bool IsReactantIgnored(const G4MoleculeDefinition*) const;
G4bool IsReactantIgnored(const G4MolecularConfiguration*) const;
protected:
void SetNegativeCountsAreFatal(G4bool);
};
//------------------------------------------------------------------------------
inline G4VMoleculeCounter::MoleculeCounterType G4VMoleculeCounter::GetType() const
{
return fType;
}
inline G4bool G4VMoleculeCounter::GetSensitiveToStepping() const
{
return fSensitiveToStepping;
}
inline G4bool G4VMoleculeCounter::GetNegativeCountsAreFatal() const
{
return fNegativeCountsAreFatal;
}
inline void G4VMoleculeCounter::SetNegativeCountsAreFatal(G4bool flag)
{
fNegativeCountsAreFatal = flag;
}
inline void G4VMoleculeCounter::IgnoreMolecule(const G4MoleculeDefinition* molecule)
{
fIgnoredMolecules.insert(molecule);
}
inline void G4VMoleculeCounter::IgnoreReactant(const G4MolecularConfiguration* reactant)
{
fIgnoredReactants.insert(reactant);
}
inline void G4VMoleculeCounter::RegisterAll()
{
fIgnoredMolecules.clear();
fIgnoredReactants.clear();
}
#endif
@@ -0,0 +1,264 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4VMoleculeCounterInternalBaseBASE_HH
#define G4VMoleculeCounterInternalBaseBASE_HH 1
#include "G4Exception.hh"
#include "G4MoleculeCounterTimeComparer.hh"
#include "G4String.hh"
#include "G4Types.hh"
#include "G4UnitsTable.hh"
#include "G4ios.hh"
#include <iomanip>
#include <map>
#include <memory>
#include <set>
//------------------------------------------------------------------------------
namespace G4
{
namespace MoleculeCounter
{
struct FixedTimeComparer
{
G4bool operator()(const G4double& a, const G4double& b) const;
static G4ThreadLocal G4double fPrecision;
};
} // namespace MoleculeCounter
} // namespace G4
//------------------------------------------------------------------------------
using InnerCounterMapType = std::map<G4double, G4int, G4MoleculeCounterTimeComparer>;
//------------------------------------------------------------------------------
class G4VMoleculeCounterInternalBase
{
friend class G4VMoleculeCounter;
friend class G4VMoleculeReactionCounter;
// only allow these classes to derive
public:
struct G4VMoleculeCounterIndexInterface
{
virtual ~G4VMoleculeCounterIndexInterface() = default;
virtual G4String GetInfo() const = 0;
};
private:
G4VMoleculeCounterInternalBase();
G4VMoleculeCounterInternalBase(const G4String&);
G4VMoleculeCounterInternalBase(G4VMoleculeCounterInternalBase const&) = delete;
void operator=(G4VMoleculeCounterInternalBase const& x) = delete;
public:
virtual ~G4VMoleculeCounterInternalBase() = default;
public:
virtual void Initialize() = 0;
virtual void InitializeUser() = 0;
virtual void ResetCounter() = 0;
virtual void Dump() const = 0;
virtual void DumpCounterMapIndices() const = 0;
virtual std::set<G4double> GetRecordedTimes() const = 0;
virtual void AbsorbCounter(const G4VMoleculeCounterInternalBase*) = 0;
private:
static G4ThreadLocal G4int _createdCounters;
protected:
G4bool fIsInitialized{false};
G4int fId;
G4int fManagedId{-1};
G4String fName{};
G4int fVerbose{0};
G4double fActiveLowerBound{0}, fActiveUpperBound{std::numeric_limits<G4double>::max()};
G4bool fActiveLowerBoundInclusive{true}, fActiveUpperBoundInclusive{true};
G4bool fCheckTimeIsConsistentWithScheduler{true};
G4bool fCheckRecordedTimesAreConsistent{true};
G4MoleculeCounterTimeComparer fTimeComparer{};
public:
G4int GetId() const;
void SetManagedId(G4int);
G4int GetManagedId() const;
const G4String& GetName() const;
G4int GetVerbose() const;
void SetVerbose(G4int);
// Set counter active w.r.t. time
G4double GetActiveLowerBound() const;
void SetActiveLowerBound(G4double, G4bool = true);
G4double GetActiveUpperBound() const;
void SetActiveUpperBound(G4double, G4bool = true);
G4bool GetActiveLowerBoundInclusive() const;
G4bool GetActiveUpperBoundInclusive() const;
G4bool IsTimeBelowLowerBound(G4double) const;
G4bool IsTimeAboveUpperBound(G4double) const;
G4bool IsActiveAtGlobalTime(G4double) const;
G4bool GetCheckTimeConsistencyWithScheduler() const; // w.r.t. scheduler time
void SetCheckTimeConsistencyWithScheduler(G4bool = true);
G4bool GetCheckRecordedTimeConsistency() const; // w.r.t last recorded time
void SetCheckRecordedTimeConsistency(G4bool = true);
const G4MoleculeCounterTimeComparer& GetTimeComparer() const;
void SetTimeComparer(const G4MoleculeCounterTimeComparer&);
public:
static void SetFixedTimePrecision(G4double);
};
//------------------------------------------------------------------------------
inline G4int G4VMoleculeCounterInternalBase::GetId() const
{
return fId;
}
inline void G4VMoleculeCounterInternalBase::SetManagedId(G4int id)
{
if (fManagedId > -1) {
G4ExceptionDescription description;
description << "Someone is trying to change the managed id of this counter but it was already "
"changed from -1!\n";
description << " Id: " << fManagedId << "\n";
description << "Name: " << fName << "\n";
G4Exception("G4VMoleculeCounterInternalBase::SetManagedId", "MOLCTR000", FatalException, description);
}
fManagedId = id;
}
inline G4int G4VMoleculeCounterInternalBase::GetManagedId() const
{
return fManagedId;
}
inline const G4String& G4VMoleculeCounterInternalBase::GetName() const
{
return fName;
}
inline G4int G4VMoleculeCounterInternalBase::GetVerbose() const
{
return fVerbose;
}
inline void G4VMoleculeCounterInternalBase::SetVerbose(G4int verbose)
{
fVerbose = verbose;
}
inline G4double G4VMoleculeCounterInternalBase::GetActiveLowerBound() const
{
return fActiveLowerBound;
}
inline void G4VMoleculeCounterInternalBase::SetActiveLowerBound(G4double time, G4bool inclusive)
{
fActiveLowerBound = time;
fActiveLowerBoundInclusive = inclusive;
}
inline G4double G4VMoleculeCounterInternalBase::GetActiveUpperBound() const
{
return fActiveUpperBound;
}
inline void G4VMoleculeCounterInternalBase::SetActiveUpperBound(G4double time, G4bool inclusive)
{
fActiveUpperBound = time;
fActiveUpperBoundInclusive = inclusive;
}
inline G4bool G4VMoleculeCounterInternalBase::GetActiveLowerBoundInclusive() const
{
return fActiveLowerBoundInclusive;
}
inline G4bool G4VMoleculeCounterInternalBase::GetActiveUpperBoundInclusive() const
{
return fActiveUpperBoundInclusive;
}
inline G4bool G4VMoleculeCounterInternalBase::IsTimeBelowLowerBound(G4double time) const
{
return (fActiveLowerBoundInclusive && time < fActiveLowerBound)
|| (!fActiveLowerBoundInclusive && time <= fActiveLowerBound);
}
inline G4bool G4VMoleculeCounterInternalBase::IsTimeAboveUpperBound(G4double time) const
{
return (fActiveUpperBoundInclusive && time > fActiveUpperBound)
|| (!fActiveUpperBoundInclusive && time >= fActiveUpperBound);
}
inline G4bool G4VMoleculeCounterInternalBase::IsActiveAtGlobalTime(G4double time) const
{
return !(IsTimeBelowLowerBound(time) || IsTimeAboveUpperBound(time));
}
inline G4bool G4VMoleculeCounterInternalBase::GetCheckTimeConsistencyWithScheduler() const
{
return fCheckTimeIsConsistentWithScheduler;
}
inline void G4VMoleculeCounterInternalBase::SetCheckTimeConsistencyWithScheduler(G4bool flag)
{
fCheckTimeIsConsistentWithScheduler = flag;
}
inline G4bool G4VMoleculeCounterInternalBase::GetCheckRecordedTimeConsistency() const
{
return fCheckRecordedTimesAreConsistent;
}
inline void G4VMoleculeCounterInternalBase::SetCheckRecordedTimeConsistency(G4bool flag)
{
fCheckRecordedTimesAreConsistent = flag;
}
inline const G4MoleculeCounterTimeComparer& G4VMoleculeCounterInternalBase::GetTimeComparer() const
{
return fTimeComparer;
}
inline void G4VMoleculeCounterInternalBase::SetTimeComparer(const G4MoleculeCounterTimeComparer& comparer)
{
if (fIsInitialized) {
G4Exception("G4VMoleculeCounterInternalBase::SetTimeComparer()", "AlreadyInitialized", JustWarning,
"Molecule counter was already initialized, assigning the time comparer now may "
"have no effect!");
}
fTimeComparer = comparer;
}
//------------------------------------------------------------------------------
#endif
@@ -0,0 +1,92 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4VMOLECULEREACTIONCOUNTER_HH
#define G4VMOLECULEREACTIONCOUNTER_HH 1
#include "G4VMoleculeCounterInternalBase.hh"
#include <map>
#include <memory>
class G4Track;
class G4DNAMolecularReactionData;
//------------------------------------------------------------------------------
class G4VMoleculeReactionCounter : public G4VMoleculeCounterInternalBase
{
template<typename>
friend class G4VUserMoleculeReactionCounter;
public:
enum MoleculeReactionCounterType
{
Other,
Basic,
};
struct G4VMoleculeReactionCounterIndex
{
virtual ~G4VMoleculeReactionCounterIndex() = default;
virtual G4bool operator<(G4VMoleculeReactionCounterIndex const&) const = 0;
virtual G4bool operator==(G4VMoleculeReactionCounterIndex const&) const = 0;
virtual G4String GetInfo() const = 0;
virtual const G4DNAMolecularReactionData* GetReactionData() const = 0;
};
private:
G4VMoleculeReactionCounter();
G4VMoleculeReactionCounter(const G4String&, MoleculeReactionCounterType =
MoleculeReactionCounterType::Basic);
G4VMoleculeReactionCounter(G4VMoleculeReactionCounter const&) = delete;
void operator=(G4VMoleculeReactionCounter const& x) = delete;
public:
~G4VMoleculeReactionCounter() override = default;
public:
// virtual std::unique_ptr<G4VMoleculeReactionCounterIndex> BuildIndex(const G4Track*, const G4Track*, const G4DNAMolecularReactionData*) const = 0;
virtual std::unique_ptr<G4VMoleculeReactionCounterIndex> BuildSimpleIndex(const G4DNAMolecularReactionData*) const = 0;
virtual void RecordReaction(std::unique_ptr<G4VMoleculeReactionCounterIndex>, G4double, G4int = 1) = 0;
virtual std::set<const G4DNAMolecularReactionData*> GetRecordedReactions() const = 0;
protected:
MoleculeReactionCounterType fType{MoleculeReactionCounterType::Basic};
public:
MoleculeReactionCounterType GetType() const;
};
//------------------------------------------------------------------------------
inline G4VMoleculeReactionCounter::MoleculeReactionCounterType G4VMoleculeReactionCounter::GetType() const
{
return fType;
}
#endif
@@ -0,0 +1,764 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4VUSERMOLECULECOUNTER_HH
#define G4VUSERMOLECULECOUNTER_HH 1
#include "G4MoleculeCounterManager.hh"
#include "G4MolecularConfiguration.hh"
#include "G4MoleculeCounterTemplates.hh"
#include "G4Scheduler.hh"
#include "G4UnitsTable.hh"
#include "G4VMoleculeCounter.hh"
//------------------------------------------------------------------------------
template<class TIndex>
class G4VUserMoleculeCounter : public G4VMoleculeCounter
{
static_assert(std::is_base_of<G4VMoleculeCounter::G4VMoleculeCounterIndex, TIndex>::value,
"TIndex must be derived from G4VMoleculeCounter::G4VMoleculeCounterIndex! "
"No forward declaration is allowed.");
protected:
struct Search;
public:
G4VUserMoleculeCounter();
G4VUserMoleculeCounter(G4String, MoleculeCounterType = MoleculeCounterType::Other);
~G4VUserMoleculeCounter() override = default;
public:
void Initialize() final;
void InitializeUser() override = 0;
void ResetCounter() override;
void Dump() const override;
void DumpCounterMapIndices() const override;
void AbsorbCounter(const G4VMoleculeCounterInternalBase*) override;
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*) const override = 0;
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*, const G4StepPoint*) const override = 0;
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildSimpleIndex(const G4MolecularConfiguration*) const override = 0;
void AddMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
void RemoveMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
std::set<const G4MolecularConfiguration*> GetRecordedMolecules() const override;
std::set<G4double> GetRecordedTimes() const override;
void SchedulerFinalizedTracking() override;
protected:
std::map<TIndex, InnerCounterMapType> fCounterMap{};
std::map<TIndex, G4int> fShadowCounterMap{};
public:
const std::map<TIndex, InnerCounterMapType>& GetCounterMap() const { return fCounterMap; }
std::vector<TIndex> GetMapIndices() const;
virtual G4int GetNbMoleculesAtTime(const TIndex&, G4double) const;
virtual G4int GetNbMoleculesAtTime(Search&, const TIndex&, G4double) const;
virtual std::vector<G4int> GetNbMoleculesAtTimes(const TIndex&, const std::vector<G4double>&) const;
//-SEARCH-----------------------------------------------------------------------
protected:
struct Search
{
Search() : fLowerBoundSet(false) {}
typename std::map<TIndex, InnerCounterMapType>::const_iterator fLastIndexSearched;
InnerCounterMapType::const_iterator fLowerBoundTime;
G4bool fLowerBoundSet;
};
G4bool SearchIndexUpdated(Search&, const TIndex&) const;
G4int SearchUpperBoundTime(Search&, G4double, G4bool) const;
};
//------------------------------------------------------------------------------
// #include "G4VUserMoleculeCounter.icc"
//------------------------------------------------------------------------------
template<typename T>
G4VUserMoleculeCounter<T>::G4VUserMoleculeCounter() : G4VMoleculeCounter()
{}
//------------------------------------------------------------------------------
template<typename T>
G4VUserMoleculeCounter<T>::G4VUserMoleculeCounter(G4String name, MoleculeCounterType type)
: G4VMoleculeCounter(name, type)
{}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeCounter<TIndex>::Initialize()
{
InitializeUser();
fIsInitialized = true;
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4int G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTime(const TIndex& index, G4double time) const
{
Search search = {};
return GetNbMoleculesAtTime(search, index, time);
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4int G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTime(Search& search, const TIndex& index,
G4double time) const
{
G4bool sameIndex = !SearchIndexUpdated(search, index);
return SearchUpperBoundTime(search, time, sameIndex);
}
//------------------------------------------------------------------------------
template<typename TIndex>
std::vector<G4int>
G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTimes(const TIndex& index,
const std::vector<G4double>& times) const
{
Search search = {};
std::vector<G4int> counts = {};
for (auto time : times)
counts.push_back(GetNbMoleculesAtTime(search, index, time));
return counts;
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeCounter<TIndex>::AddMolecule(
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
{
const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
if(mapIndex == nullptr)
{
G4ExceptionDescription errMsg;
errMsg << "mapIndex is not found "<< G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
"mapIndex == nullptr", FatalException, errMsg);
}else{
if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
|| G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
{
return;
}
if (fCheckTimeIsConsistentWithScheduler && G4Scheduler::Instance()->IsRunning()
&& std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
> G4Scheduler::Instance()->GetTimeTolerance())
{
G4ExceptionDescription errMsg;
errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
<< G4BestUnit(time, "Time") << "while the global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
"TIME_DONT_MATCH", FatalException, errMsg);
}
if (IsTimeAboveUpperBound(time)) {
if (fVerbose > 3) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
<< ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
G4cout << ":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true"
<< G4endl;
}
return;
}
else if (IsTimeBelowLowerBound(time)) {
// put into shadow counter
auto [it, indexIsNew] = fShadowCounterMap.emplace(*mapIndex, number);
if (!indexIsNew) it->second += number;
if (fVerbose > 3) {
G4cout << ":: [IsTimeBelowLowerBound] Adding " << mapIndex->GetInfo()
<< " shadow count: " << it->second - number << " + " << number << G4endl;
}
return;
}
if (fVerbose > 1) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
<< ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
}
// within time bounds && not-ignored molecule
// -> continue
auto it_shadow = fShadowCounterMap.find(*mapIndex);
auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
if (it_shadow != fShadowCounterMap.end()) {
// entry found in shadow counter
if (indexIsNew) {
// mapIndex is new, initialize with shadow counter
it->second[fActiveLowerBound] = it_shadow->second;
}
else {
// mapIndex existed, we need to add the shadow count to it
// this happens if we are in a subsequent event and have just crossed over the lower
// activity bound the counter has then already entries from the previous event
InnerCounterMapType::iterator it_time;
G4bool timeIsNew;
std::tie(it_time, timeIsNew) = it->second.emplace(fActiveLowerBound, 0);
do {
it_time->second += it_shadow->second;
} while (++it_time != it->second.end());
}
// either way, remove the shadow count
fShadowCounterMap.erase(it_shadow);
}
// map for index existed (and was not empty)
if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent())
// can only do consistency check if the counters are cleared for each event (= chem run)
{
auto end = it->second.rbegin();
auto init_n = end == it->second.rend() ? 0 : end->second;
auto [it_time, timeIsNew] = it->second.emplace(time, init_n);
it_time->second += number;
if (fCheckRecordedTimesAreConsistent
&& !(end->first <= time
|| std::fabs(end->first - time) <= fTimeComparer.GetPrecisionAtTime(time)))
// Case 1 = new time comes after last recorded data
// Case 2 = new time is about the same as the last recorded one
{
G4ExceptionDescription errMsg;
errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
<< G4BestUnit(time, "Time") << "while the global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< "(last counter time: " << G4BestUnit(end->first, "Time") << ")" << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::AddMolecule"),
"TIME_DONT_MATCH", FatalException, errMsg);
}
}
else // counters are not (automatically) reset by manager
{
// since counters are not cleared after chemical run (i.e., after event)
// there will already be numbers in the map, so...
// (1) find the closest time
// (2) emplace entry using closest value as init + number
// (3) add number to all "future" entries as well
if (it->second.empty()) {
it->second.emplace(time, number);
}
else { // at least one element exists, so we can try to find the closest key
auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(it->second, time);
auto [it_time, _] = it->second.emplace(time, it_closest->second);
do {
it_time->second += number;
} while (++it_time != it->second.end());
}
}
}
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeCounter<TIndex>::RemoveMolecule(
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
{
const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
if(mapIndex == nullptr)
{
G4ExceptionDescription errMsg;
errMsg << "mapIndex is not found "<< G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
"mapIndex == nullptr", FatalException, errMsg);
}else{
if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
|| G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
{
return;
}
if (fCheckTimeIsConsistentWithScheduler && G4Scheduler::Instance()->IsRunning()
&& std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
> G4Scheduler::Instance()->GetTimeTolerance())
{
G4ExceptionDescription errMsg;
errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
<< G4BestUnit(time, "Time") << "while the global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RemoveMolecule"),
"TIME_DONT_MATCH", FatalException, errMsg);
}
if (IsTimeBelowLowerBound(time)) {
auto it = fShadowCounterMap.find(*mapIndex);
if (it == fShadowCounterMap.end()) {
G4ExceptionDescription errMsg;
errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
<< " recorded at the time or even before the time asked" << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RemoveMolecule"),
"", FatalErrorInArgument, errMsg);
}
else {
if (fVerbose > 3) {
G4cout << ":: [IsTimeBelowLowerBound] Removing " << mapIndex->GetInfo()
<< " shadow count: " << it->second << " - " << number << G4endl;
}
it->second -= number;
return;
}
}
else if (IsTimeAboveUpperBound(time)) {
// if the "active" counter was not filled, add the shadow counter to it at the lower bound
// only needed for remove since remove will always be called at the end when the molecule is
// destroyed
auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
if (indexIsNew || it->second.empty()) {
auto it_shadow = fShadowCounterMap.find(*mapIndex);
if (it_shadow != fShadowCounterMap.end()) {
it->second[fActiveLowerBound] = it_shadow->second;
if (fVerbose > 3) {
G4cout << ":: [IsTimeAboveUpperBound] Set " << mapIndex->GetInfo()
<< " Map[ActiveLowerBound] with shadow count:" << it_shadow->second << G4endl;
}
fShadowCounterMap.erase(it_shadow);
}
else if (fVerbose > 3) {
G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count since"
" no shadow count was found!"
<< G4endl;
}
}
else if (fVerbose > 3) {
G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count"
" since it already exists "
<< G4endl;
}
return;
}
if (fVerbose > 2) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
<< ">(" << GetName() << ")::RemoveMolecule : " << mapIndex->GetMolecule()->GetName()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
}
// within time bounds && not-ignored molecule
// -> continue
auto it_shadow = fShadowCounterMap.find(*mapIndex);
auto it = fCounterMap.find(*mapIndex);
if (it_shadow != fShadowCounterMap.end()) {
// entry found in shadow counter
if (it == fCounterMap.end()) {
// no mapIndex found, initialize with shadow counter
G4bool indexIsNew = false;
std::tie(it, indexIsNew) =
fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
if (!indexIsNew) {
G4ExceptionDescription errMsg;
errMsg << "We tried to emplace the index after it was found to not exist, but now it "
"says it existed!?"
<< G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RemoveMolecule"),
"NONSENSICAL", FatalErrorInArgument, errMsg);
}
it->second[fActiveLowerBound] = it_shadow->second;
}
else { // it != fCounterMap.end()
// mapIndex exists, we need to add the shadow count to it
// this happens if we are in a subsequent event and have just crossed over the lower
// activity bound the counter has then already entries from the previous event
auto [it_time, _] = it->second.emplace(fActiveLowerBound, 0);
do {
it_time->second += it_shadow->second;
} while (++it_time != it->second.end());
}
// either way, remove the shadow count
fShadowCounterMap.erase(it_shadow);
// if (it_shadow != fShadowCounterMap.end()) {
// G4bool indexIsNew = false;
// // auto [it_, indexIsNew] = fCounterMap.emplace(*mapIndex,
// // InnerCounterMapType{fTimeComparer});
// std::tie(it, indexIsNew) = fCounterMap.emplace(*mapIndex,
// InnerCounterMapType{fTimeComparer}); if (!indexIsNew) {
// G4ExceptionDescription errMsg;
// errMsg << "We tried to emplace the index after it was found to not exist, but now it
// "
// "says it existed!?"
// << G4endl;
// G4Exception(G4String("G4VUserMoleculeCounter<"
// + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
// + ">::RemoveMolecule"),
// "NONSENSICAL", FatalErrorInArgument, errMsg);
// }
// it->second[fActiveLowerBound] = it_shadow->second;
// // it = it_;
// if (fVerbose > 3) {
// G4cout << ":: Initialize " << mapIndex->GetInfo()
// << " Map[ActiveLowerBound] with shadow count:" << it_shadow->second <<
// G4endl;
// }
// fShadowCounterMap.erase(it_shadow);
// }
}
InnerCounterMapType& nbMolPerTime = it->second;
InnerCounterMapType::iterator it_time;
G4bool isNewTime = false;
G4double oldTime = 0;
if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent()) {
auto end = nbMolPerTime.rbegin(); // get last entry
oldTime = end->first;
// CHECK: no molecules have been recorded for this index
if (end == nbMolPerTime.rend()) {
if (fVerbose > 2) {
mapIndex->GetMolecule()->PrintState();
Dump();
}
G4ExceptionDescription errMsg;
errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
<< " recorded at the time or even before the time asked" << G4endl;
G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "", FatalErrorInArgument, errMsg);
}
// CHECK: current time is less (by more than counter precision) than the most recently
// recorded index
if (fCheckRecordedTimesAreConsistent
&& time - end->first < -fTimeComparer.GetPrecisionAtTime(time))
{
if (fVerbose > 2) {
mapIndex->GetMolecule()->PrintState();
Dump();
}
G4ExceptionDescription errMsg;
errMsg << "Is time going back?? " << mapIndex->GetMolecule()->GetName()
<< " is being removed at time " << G4BestUnit(time, "Time")
<< "while last recorded time was " << G4BestUnit(end->first, "Time") << ".";
G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "RETURN_TO_THE_FUTUR",
FatalErrorInArgument, errMsg);
}
std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, end->second);
// auto oldNumber = it_time->second;
it_time->second -= number;
// if (time > 0.001)
// G4cout << "(t=" << time << ")=" << number << " | old_it(t=" << it_time->first
// << ") = " << oldNumber << " | timeIsNew=" << isNewTime
// << " | new_it(t=" << it_time->first << ") = " << it_time->second << G4endl;
}
else {
// since counters are not cleared after chemical run (i.e., after event)
// there will already be numbers in the map, so...
// (1) find the closest time
// (2) emplace entry using closest value as init - number
// (3) remove number from all "future" entries as well
auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(nbMolPerTime, time);
std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, it_closest->second);
auto _it = it_time;
do {
_it->second -= number;
} while (++_it != it->second.end());
}
// Check that count at new time is >= 0
// This currently throws tons of errors for non-basic counters.
// auto it_time = nbMolPerTime.find(time);
if (it_time == nbMolPerTime.end() || it_time->second < 0) {
if (fVerbose > 2) Dump();
G4ExceptionDescription errMsg;
errMsg << "After removal of " << number << " species of "
<< mapIndex->GetMolecule()->GetName() << " the final number at time "
<< G4BestUnit(time, "Time") << " is less than zero and so not valid."
<< "\nIndex was :" << mapIndex->GetInfo() << "\nGlobal time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< "\nPrevious selected time is " << G4BestUnit(oldTime, "Time") << G4endl;
if (fNegativeCountsAreFatal) {
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RemoveMolecule"),
"N_INF_0", FatalException, errMsg);
}
else if (fVerbose > 0) {
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RemoveMolecule"),
"N_INF_0", JustWarning, errMsg);
}
}
}
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeCounter<TIndex>::SchedulerFinalizedTracking()
{
// Add record to fCounterMap for each fShadowCounterMap index unless they exist already
for (auto& it_shadow : fShadowCounterMap) {
auto [it, indexIsNew] =
fCounterMap.emplace(it_shadow.first, InnerCounterMapType{fTimeComparer});
if (indexIsNew || it->second.empty()) {
it->second[fActiveLowerBound] = it_shadow.second;
if (fVerbose > 3) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
<< ">(" << GetName() << ")::SchedulerEndedTracking : " << "setting map index '"
<< it_shadow.first.GetInfo() << "' from shadow counter to n = " << it_shadow.second
<< G4endl;
}
}
else if (fVerbose > 2) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
<< ">(" << GetName() << ")::SchedulerEndedTracking : "
<< "encountered dangling shadow counter iterator for index '"
<< it_shadow.first.GetInfo() << "'" << G4endl;
}
}
fShadowCounterMap.clear();
}
//------------------------------------------------------------------------------
template<typename TIndex>
std::vector<TIndex> G4VUserMoleculeCounter<TIndex>::GetMapIndices() const
{
if (fVerbose > 2) {
G4cout << "Entering in G4VUserMoleculeCounter::GetMapIndices" << G4endl;
}
return G4::MoleculeCounter::GetMapIndices(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
std::set<const G4MolecularConfiguration*> G4VUserMoleculeCounter<T>::GetRecordedMolecules() const
{
if (fVerbose > 2) {
G4cout << "Entering in G4MoleculeCounter::RecordMolecules" << G4endl;
}
std::set<const G4MolecularConfiguration*> output{};
for (const auto& it : fCounterMap) {
output.insert(it.first.GetMolecule());
}
return output;
}
//------------------------------------------------------------------------------
template<typename T>
std::set<G4double> G4VUserMoleculeCounter<T>::GetRecordedTimes() const
{
return G4::MoleculeCounter::GetRecordedTimes<T>(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
void G4VUserMoleculeCounter<T>::Dump() const
{
DumpCounterMapIndices();
G4::MoleculeCounter::DumpCounterMapContents<T>(fCounterMap);
}
template<typename T>
void G4VUserMoleculeCounter<T>::DumpCounterMapIndices() const
{
G4::MoleculeCounter::DumpCounterMapIndices<T>(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
void G4VUserMoleculeCounter<T>::ResetCounter()
{
if (fVerbose > 1) {
G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<T>() << ">("
<< GetName() << ")::ResetCounter" << G4endl;
}
fCounterMap.clear();
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4bool G4VUserMoleculeCounter<TIndex>::SearchIndexUpdated(Search& search, const TIndex& index) const
{
if (search.fLowerBoundSet && !(search.fLastIndexSearched->first < index)
&& !(index < search.fLastIndexSearched->first))
{
return true;
}
auto mol_it = fCounterMap.find(index);
search.fLastIndexSearched = mol_it;
if (mol_it != fCounterMap.end()) {
search.fLowerBoundTime = search.fLastIndexSearched->second.end();
search.fLowerBoundSet = true;
}
else {
search.fLowerBoundSet = false;
}
return false;
}
//------------------------------------------------------------------------------
template<typename T>
G4int G4VUserMoleculeCounter<T>::SearchUpperBoundTime(Search& search, G4double time,
G4bool sameIndex) const
{
auto mol_it = search.fLastIndexSearched;
if (mol_it == fCounterMap.end()) {
return 0;
}
InnerCounterMapType const& timeMap = mol_it->second;
if (timeMap.empty()) {
return 0;
}
if (sameIndex) {
if (search.fLowerBoundSet && search.fLowerBoundTime != timeMap.end()) {
if (search.fLowerBoundTime->first < time) {
auto upperToLast = search.fLowerBoundTime;
upperToLast++;
if (upperToLast == timeMap.end()) {
return search.fLowerBoundTime->second;
}
if (upperToLast->first > time) {
return search.fLowerBoundTime->second;
}
}
}
}
auto up_time_it = timeMap.upper_bound(time);
if (up_time_it == timeMap.end()) {
auto last_time = timeMap.rbegin();
return last_time->second;
}
if (up_time_it == timeMap.begin()) {
return 0;
}
up_time_it--;
search.fLowerBoundTime = up_time_it;
search.fLowerBoundSet = true;
return search.fLowerBoundTime->second;
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeCounter<TIndex>::AbsorbCounter(const G4VMoleculeCounterInternalBase* pCounterBase)
{
if (pCounterBase == nullptr) {
G4ExceptionDescription errMsg;
errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
<< "Because the pointer is nullptr!" << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"BAD_REFERENCE", FatalException, errMsg);
}
auto pCounter = dynamic_cast<G4VUserMoleculeCounter<TIndex> const*>(pCounterBase);
if (pCounter == nullptr) {
G4ExceptionDescription errMsg;
errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
<< "Because the objects aren't of the same type!" << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"BAD_REFERENCE", FatalException, errMsg);
}
if (pCounter->GetType() != GetType()) {
G4ExceptionDescription errMsg;
errMsg << "You are trying to absorb a counter with different type!" << G4endl;
G4Exception(G4String("G4VUserMoleculeCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"TYPE_DIFF", JustWarning, errMsg);
}
for (auto const& worker_it : pCounter->GetCounterMap()) {
auto [master_it, indexIsNew] =
fCounterMap.emplace(worker_it.first, InnerCounterMapType{fTimeComparer});
G4int currentNumber = 0, previousNumber = 0;
for (auto const& [time, number] : worker_it.second) {
currentNumber = number - previousNumber;
previousNumber = number;
if (master_it->second.empty()) {
master_it->second.emplace(time, currentNumber);
}
else { // at least one element exists, so we can try to find the closest key
auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(master_it->second, time);
auto [it, _] = master_it->second.emplace(time, it_closest->second);
do {
it->second += currentNumber;
} while (++it != master_it->second.end());
}
}
}
}
//------------------------------------------------------------------------------
#endif
@@ -7,37 +7,49 @@ geant4_add_module(G4emdna-molman
G4MolecularConfiguration.hh
G4MolecularDissociationChannel.hh
G4MolecularDissociationTable.hh
G4MoleculeCounter.hh
G4MoleculeDefinition.hh
G4MoleculeFinder.hh
G4MoleculeHandleManager.hh
G4Molecule.hh
G4MoleculeIterator.hh
G4MoleculeTable.hh
G4MoleculeTableMessenger.hh
G4Serialize.hh
G4VMolecularDissociationDisplacer.hh
G4MoleculeCounterManager.hh
G4MoleculeCounterManagerMessenger.hh
G4MoleculeCounterTemplates.hh
G4VMoleculeCounterInternalBase.hh
G4VMoleculeCounter.hh
G4MoleculeTableMessenger.hh
G4VMoleculeReactionCounter.hh
G4VUserMoleculeCounter.hh
G4MoleculeCounter.hh
G4MoleculeCounterTimeComparer.hh
SOURCES
G4MolecularConfiguration.cc
G4MolecularDissociationChannel.cc
G4MolecularDissociationTable.cc
G4MoleculeCounter.cc
G4Molecule.cc
G4MoleculeDefinition.cc
G4MoleculeHandleManager.cc
G4MoleculeTable.cc
G4MoleculeTableMessenger.cc
G4Serialize.cc
G4VMolecularDissociationDisplacer.cc
G4MoleculeCounterManager.cc
G4MoleculeCounterManagerMessenger.cc
G4VMoleculeCounterInternalBase.cc
G4VMoleculeCounter.cc
G4MoleculeTableMessenger.cc)
G4VMoleculeReactionCounter.cc
G4MoleculeCounter.cc
G4MoleculeCounterTimeComparer.cc)
geant4_module_link_libraries(G4emdna-molman
PUBLIC
G4emdna-man
G4globman
G4partman
G4intercoms
PRIVATE
G4heprandom
G4intercoms
G4track)
@@ -48,12 +48,13 @@
#include "G4Molecule.hh"
#include "G4MolecularConfiguration.hh"
#include "G4MoleculeLocator.hh"
#include "Randomize.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Track.hh"
#include "G4VMoleculeCounter.hh"
//#include "G4DNAChemistryManager.hh"
#include "G4MoleculeCounterManager.hh"
using namespace std;
G4Allocator<G4Molecule>*& aMoleculeAllocator()
@@ -154,12 +155,23 @@ G4Molecule::~G4Molecule()
{
if (fpTrack != nullptr)
{
if (G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->
RemoveAMoleculeAtTime(fpMolecularConfiguration,
fpTrack->GetGlobalTime(),
&(fpTrack->GetPosition()));
switch (fpTrack->GetTrackStatus())
{
case fAlive:
case fPostponeToNextEvent:
case fStopButAlive:
case fSuspend:
// do not remove molecule count if the track is not being killed
break;
case fStopAndKill:
case fKillTrackAndSecondaries:
default:
G4MoleculeCounterManager::Instance()->RemoveMolecule(fpTrack,
fpTrack->GetGlobalTime());
break;
}
}
fpTrack = nullptr;
}
@@ -360,8 +372,9 @@ void G4Molecule::PrintState() const
//______________________________________________________________________________
G4Track* G4Molecule::BuildTrack(G4double globalTime,
const G4ThreeVector& position)
G4Track *G4Molecule::BuildTrack(G4double globalTime,
const G4ThreeVector &position,
const G4Track *parentTrack)
{
if (fpTrack != nullptr)
{
@@ -386,18 +399,35 @@ G4Track* G4Molecule::BuildTrack(G4double globalTime,
fpMolecularConfiguration->GetDefinition(), MomentumDirection,
KineticEnergy);
if (G4VMoleculeCounter::Instance()->InUse())
{
G4VMoleculeCounter::Instance()->
AddAMoleculeAtTime(fpMolecularConfiguration,
globalTime,
&(fpTrack->GetPosition()));
}
//Set the Track
// Set the Track
fpTrack = new G4Track(dynamicParticle, globalTime, position);
fpTrack->SetUserInformation(this);
// Copy over touchable handle (see G4VEmProcess)
if (parentTrack == nullptr || parentTrack->GetTouchable() == nullptr ||
position != parentTrack->GetPosition())
{
// If (1) no track or touchable handle exists, or
// If (2) the new position is inconsistent with the track's position
// create a new touchable from the position:
// this way the subsequent calls *should* properly see its location (i.e. PV)
G4MoleculeLocator::Instance()->LocateMoleculeSetStateAndTouchable(fpTrack);
}
else
{
fpTrack->SetTouchableHandle(parentTrack->GetTouchableHandle());
}
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4MoleculeCounterManager::Instance()->AddMolecule(fpTrack,
fpTrack->GetGlobalTime());
// G4VMoleculeCounter::Instance()->
// AddAMoleculeAtTime(fpMolecularConfiguration,
// globalTime,
// &(fpTrack->GetPosition()));
}
return fpTrack;
}
@@ -23,486 +23,52 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Mathieu Karamitros
// Modified by Christian Velten on 10/27/2024.
//
#include "G4MoleculeCounter.hh"
#include "G4MolecularConfiguration.hh"
#include "G4MoleculeDefinition.hh"
#include "G4Molecule.hh"
#include "G4MoleculeTable.hh"
#include "G4Scheduler.hh" // TODO: remove this dependency
#include "G4SystemOfUnits.hh"
#include "G4UIcommand.hh"
#include "G4UnitsTable.hh"
#include <iomanip>
#include <memory>
using namespace std;
namespace G4{
namespace MoleculeCounter {
bool TimePrecision::operator()(const double& a, const double& b) const
{
if (std::fabs(a - b) < fPrecision)
{
return false;
}
return a < b;
}
G4ThreadLocal double TimePrecision::fPrecision = 0.5 * picosecond;
}
}
//------------------------------------------------------------------------------
G4MoleculeCounter* G4MoleculeCounter::Instance()
G4MoleculeCounter::G4MoleculeCounter() : G4VUserMoleculeCounter() {}
G4MoleculeCounter::G4MoleculeCounter(G4String name)
: G4VUserMoleculeCounter(name, MoleculeCounterType::Basic)
{}
//------------------------------------------------------------------------------
void G4MoleculeCounter::InitializeUser() {}
//------------------------------------------------------------------------------
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>
G4MoleculeCounter::BuildIndex(const G4Track* aTrack) const
{
if (fpInstance == nullptr)
{
fpInstance = new G4MoleculeCounter();
}
return dynamic_cast<G4MoleculeCounter*>(fpInstance);
return std::make_unique<G4MoleculeCounterIndex>(GetMolecule(aTrack)->GetMolecularConfiguration());
}
//------------------------------------------------------------------------------
G4MoleculeCounter::G4MoleculeCounter()
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>
G4MoleculeCounter::BuildIndex(const G4Track* aTrack, const G4StepPoint*) const
{
fVerbose = 0;
fCheckTimeIsConsistentWithScheduler = true;
return BuildIndex(aTrack);
}
//------------------------------------------------------------------------------
G4MoleculeCounter::~G4MoleculeCounter() = default;
//------------------------------------------------------------------------------
void G4MoleculeCounter::Initialize()
std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>
G4MoleculeCounter::BuildSimpleIndex(const G4MolecularConfiguration* configuration) const
{
auto mol_iterator = G4MoleculeTable::Instance()->GetConfigurationIterator();
while ((mol_iterator)())
{
if (!IsRegistered(mol_iterator.value()->GetDefinition()))
{
continue;
}
fCounterMap[mol_iterator.value()]; // initialize the second map
}
return std::make_unique<G4MoleculeCounterIndex>(configuration);
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::SetTimeSlice(double timeSlice)
{
G4::MoleculeCounter::TimePrecision::fPrecision = timeSlice;
}
//------------------------------------------------------------------------------
G4bool G4MoleculeCounter::SearchTimeMap(Reactant* molecule)
{
if (fpLastSearch == nullptr)
{
fpLastSearch = std::make_unique<Search>();
}
else
{
if (fpLastSearch->fLowerBoundSet &&
fpLastSearch->fLastMoleculeSearched->first == molecule)
{
return true;
}
}
auto mol_it = fCounterMap.find(molecule);
fpLastSearch->fLastMoleculeSearched = mol_it;
if (mol_it != fCounterMap.end())
{
fpLastSearch->fLowerBoundTime = fpLastSearch->fLastMoleculeSearched->second
.end();
fpLastSearch->fLowerBoundSet = true;
}
else
{
fpLastSearch->fLowerBoundSet = false;
}
return false;
}
//------------------------------------------------------------------------------
int G4MoleculeCounter::SearchUpperBoundTime(double time,
bool sameTypeOfMolecule)
{
auto mol_it = fpLastSearch->fLastMoleculeSearched;
if (mol_it == fCounterMap.end())
{
return 0;
}
NbMoleculeAgainstTime& timeMap = mol_it->second;
if (timeMap.empty())
{
return 0;
}
if (sameTypeOfMolecule)
{
if (fpLastSearch->fLowerBoundSet && fpLastSearch->fLowerBoundTime != timeMap.end())
{
if (fpLastSearch->fLowerBoundTime->first < time)
{
auto upperToLast = fpLastSearch->fLowerBoundTime;
upperToLast++;
if (upperToLast == timeMap.end())
{
return fpLastSearch->fLowerBoundTime->second;
}
if (upperToLast->first > time)
{
return fpLastSearch->fLowerBoundTime->second;
}
}
}
}
auto up_time_it = timeMap.upper_bound(time);
if (up_time_it == timeMap.end())
{
auto last_time = timeMap.rbegin();
return last_time->second;
}
if (up_time_it == timeMap.begin())
{
return 0;
}
up_time_it--;
fpLastSearch->fLowerBoundTime = up_time_it;
fpLastSearch->fLowerBoundSet = true;
return fpLastSearch->fLowerBoundTime->second;
}
//------------------------------------------------------------------------------
int G4MoleculeCounter::GetNMoleculesAtTime(Reactant* molecule,
double time)
{
G4bool sameTypeOfMolecule = SearchTimeMap(molecule);
return SearchUpperBoundTime(time, sameTypeOfMolecule);
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::AddAMoleculeAtTime(Reactant* molecule,
G4double time,
const G4ThreeVector* /*position*/,
int number)
{
if (fDontRegister[molecule->GetDefinition()])
{
return;
}
if (fVerbose != 0)
{
G4cout << "G4MoleculeCounter::AddAMoleculeAtTime : " << molecule->GetName()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
}
auto counterMap_i = fCounterMap.find(molecule);
if (counterMap_i == fCounterMap.end())
{
fCounterMap[molecule][time] = number;
}
else if (counterMap_i->second.empty())
{
counterMap_i->second[time] = number;
}
else
{
auto end = counterMap_i->second.rbegin();
if (end->first <= time ||
fabs(end->first - time) <= G4::MoleculeCounter::TimePrecision::fPrecision)
// Case 1 = new time comes after last recorded data
// Case 2 = new time is about the same as the last recorded one
{
double newValue = end->second + number;
counterMap_i->second[time] = newValue;
}
else
{
// if(fabs(time - G4Scheduler::Instance()->GetGlobalTime()) >
// G4Scheduler::Instance()->GetTimeTolerance())
{
G4ExceptionDescription errMsg;
errMsg << "Time of species "
<< molecule->GetName() << " is "
<< G4BestUnit(time, "Time") << " while "
<< " global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4MoleculeCounter::AddAMoleculeAtTime",
"TIME_DONT_MATCH",
FatalException, errMsg);
}
}
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::RemoveAMoleculeAtTime(const G4MolecularConfiguration* pMolecule,
G4double time,
const G4ThreeVector* /*position*/,
int number)
{
if (fDontRegister[pMolecule->GetDefinition()])
{
return;
}
if (fVerbose != 0)
{
G4cout << "G4MoleculeCounter::RemoveAMoleculeAtTime : "
<< pMolecule->GetName() << " at time : " << G4BestUnit(time, "Time")
<< G4endl;
}
if (fCheckTimeIsConsistentWithScheduler)
{
if (fabs(time - G4Scheduler::Instance()->GetGlobalTime()) >
G4Scheduler::Instance()->GetTimeTolerance())
{
G4ExceptionDescription errMsg;
errMsg << "Time of species "
<< pMolecule->GetName() << " is "
<< G4BestUnit(time, "Time") << " while "
<< " global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< G4endl;
G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
"TIME_DONT_MATCH",
FatalException, errMsg);
}
}
NbMoleculeAgainstTime& nbMolPerTime = fCounterMap[pMolecule];
if (nbMolPerTime.empty())
{
pMolecule->PrintState();
Dump();
G4String errMsg =
"You are trying to remove molecule " + pMolecule->GetName() +
" from the counter while this kind of molecules has not been registered yet";
G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime", "",
FatalErrorInArgument, errMsg);
return;
}
auto it = nbMolPerTime.rbegin();
if (it == nbMolPerTime.rend())
{
it--;
G4String errMsg =
"There was no " + pMolecule->GetName() + " recorded at the time or even before the time asked";
G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime", "",
FatalErrorInArgument, errMsg);
}
if (time - it->first < -G4::MoleculeCounter::TimePrecision::fPrecision)
{
Dump();
G4ExceptionDescription errMsg;
errMsg << "Is time going back?? " << pMolecule->GetName()
<< " is being removed at time " << G4BestUnit(time, "Time")
<< " while last recorded time was "
<< G4BestUnit(it->first, "Time") << ".";
G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
"RETURN_TO_THE_FUTUR",
FatalErrorInArgument,
errMsg);
}
double finalN = it->second - number;
if (finalN < 0)
{
Dump();
G4ExceptionDescription errMsg;
errMsg << "After removal of " << number << " species of "
<< pMolecule->GetName() << " the final number at time "
<< G4BestUnit(time, "Time") << " is less than zero and so not valid."
<< " Global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< ". Previous selected time is "
<< G4BestUnit(it->first, "Time")
<< G4endl;
G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
"N_INF_0",
FatalException, errMsg);
}
nbMolPerTime[time] = finalN;
}
//------------------------------------------------------------------------------
G4MoleculeCounter::RecordedMolecules G4MoleculeCounter::GetRecordedMolecules()
{
if (fVerbose > 1)
{
G4cout << "Entering in G4MoleculeCounter::RecordMolecules" << G4endl;
}
RecordedMolecules output(new ReactantList());
for (const auto & it : fCounterMap)
{
output->push_back(it.first);
}
return output;
}
//------------------------------------------------------------------------------
RecordedTimes G4MoleculeCounter::GetRecordedTimes()
{
RecordedTimes output(new std::set<G4double>);
for(const auto& it : fCounterMap)
{
for(const auto& it2 : it.second)
{
//time = it2->first;
output->insert(it2.first);
}
}
return output;
}
//------------------------------------------------------------------------------
// >>DEV<<
//void G4MoleculeCounter::SignalReceiver(G4SpeciesInCM* /*speciesInCM*/,
// size_t moleculeID,
// int /*number*/,
// G4SpeciesInCM::SpeciesChange speciesChange,
// int diff)
//{
// switch(speciesChange)
// {
// case G4SpeciesInCM::eAdd:
// AddAMoleculeAtTime(G4MoleculeTable::Instance()->GetConfiguration((int)moleculeID),
// G4Scheduler::Instance()->GetGlobalTime(),
// diff);
// break;
// case G4SpeciesInCM::eRemove:
// RemoveAMoleculeAtTime(G4MoleculeTable::Instance()->GetConfiguration((int)moleculeID),
// G4Scheduler::Instance()->GetGlobalTime(),
// diff);
// break;
// }
//}
//------------------------------------------------------------------------------
void G4MoleculeCounter::Dump()
{
for (const auto& it : fCounterMap)
{
auto pReactant = it.first;
G4cout << " --- > For " << pReactant->GetName() << G4endl;
for (const auto& it2 : it.second)
{
G4cout << " " << G4BestUnit(it2.first, "Time")
<< " " << it2.second << G4endl;
}
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::ResetCounter()
{
if (fVerbose != 0)
{
G4cout << " ---> G4MoleculeCounter::ResetCounter" << G4endl;
}
fCounterMap.clear();
fpLastSearch.reset(nullptr);
}
//------------------------------------------------------------------------------
const NbMoleculeAgainstTime& G4MoleculeCounter::GetNbMoleculeAgainstTime(Reactant* molecule)
{
return fCounterMap[molecule];
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::SetVerbose(G4int level)
{
fVerbose = level;
}
//------------------------------------------------------------------------------
G4int G4MoleculeCounter::GetVerbose()
{
return fVerbose;
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::DontRegister(const G4MoleculeDefinition* molDef)
{
fDontRegister[molDef] = true;
}
//------------------------------------------------------------------------------
bool G4MoleculeCounter::IsRegistered(const G4MoleculeDefinition* molDef)
{
return fDontRegister.find(molDef) == fDontRegister.end();
}
//------------------------------------------------------------------------------
void G4MoleculeCounter::RegisterAll()
{
fDontRegister.clear();
}
G4bool G4MoleculeCounter::IsTimeCheckedForConsistency() const
{
return fCheckTimeIsConsistentWithScheduler;
}
void G4MoleculeCounter::CheckTimeForConsistency(G4bool flag)
{
fCheckTimeIsConsistentWithScheduler = flag;
}
@@ -0,0 +1,711 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4MoleculeCounterManager.hh"
#include "G4AutoLock.hh"
#include "G4MoleculeCounterManagerMessenger.hh"
#include "G4MoleculeCounterTemplates.hh"
#include "G4StateManager.hh"
#include "G4Step.hh"
#include "G4Threading.hh"
//------------------------------------------------------------------------------
static G4Mutex managerInstance;
static G4Mutex masterInstanceMutex;
static G4Mutex workerInstancesMutex;
const G4MoleculeCounterManager* G4MoleculeCounterManager::fpMasterInstance = nullptr;
std::vector<const G4MoleculeCounterManager*> G4MoleculeCounterManager::fWorkerInstances = {};
G4ThreadLocal std::unique_ptr<G4MoleculeCounterManager> G4MoleculeCounterManager::fpInstance = nullptr;
//------------------------------------------------------------------------------
G4ThreadLocal std::atomic<G4bool> G4MoleculeCounterManager::fBeginOfEventTriggered(false);
std::atomic<G4bool> G4MoleculeCounterManager::fBeginOfRunTriggered(false);
//------------------------------------------------------------------------------
//
// CTOR & INSTANCE
//
G4MoleculeCounterManager::G4MoleculeCounterManager(G4MoleculeCounterManager::Private)
: fVerbosity(0), fIsInitialized(false), fIsActive(true)
{
fpMessenger = std::make_unique<G4MoleculeCounterManagerMessenger>(this);
}
G4MoleculeCounterManager::~G4MoleculeCounterManager()
{
// The manager owns all the counters as raw pointers, clean up:
DeregisterAllCounters();
if (fVerbosity > 0) {
if (GetResetCountersBeforeRun() && !fBeginOfRunTriggered.load()) {
G4Exception("G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN000", JustWarning,
"The molecule counter manager was configured to reset counters before each run"
" but the BeginOfRunAction was never triggered!\n"
"Ensure that the user code calls either the G4DNAChemistryManager's or "
"G4MoleculeCounterManager's Run methods!");
}
if (GetResetCountersBeforeEvent() && !fBeginOfEventTriggered.load()
&& (!G4Threading::IsMultithreadedApplication() || G4Threading::IsWorkerThread()))
{
// ignore, if this is the master of a MT application
G4Exception("G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN000", JustWarning,
"The molecule counter manager was configured to reset counters before each event"
" but the BeginOfEventAction was never triggered!\n"
"This can occurr if this thread is never processing an event but:\n"
"Ensure that the user code calls either the G4DNAChemistryManager's or "
"G4MoleculeCounterManager's Event methods!");
}
}
// Handle the recorded master and worker instances
if (G4Threading::IsMasterThread()) {
// This is the master's dtor: set the master const* to nullptr (as it will point to nothing of use)
G4AutoLock lockMaster(&masterInstanceMutex);
fpMasterInstance = nullptr;
}
else {
// This is a worker's dtor: make sure that this worker is still in the list of instances.
// If not, throw a warning (something fishy going on?)
// Either way, set this worker's const* to nullptr in the list of instances.
G4AutoLock lock(&workerInstancesMutex);
auto it = std::find(fWorkerInstances.begin(), fWorkerInstances.end(), this);
if (it == fWorkerInstances.end()) {
G4Exception(
"G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN_DTOR", JustWarning,
"The destroyed instance of G4MoleculeCounterManager has not been registered as a worker!");
}
else {
(*it) = nullptr;
}
}
}
void G4MoleculeCounterManager::RegisterInstance()
{
if (fInstancesRegistered) {
G4Exception("G4MoleculeCounterManager::RegisterInstance", "MOLMAN000", FatalException,
"Instances were already registered once!");
}
else {
if (G4Threading::IsMasterThread()) {
G4AutoLock lock(&masterInstanceMutex);
if (fpMasterInstance != nullptr) {
G4Exception("G4MoleculeCounterManager::RegisterInstance", "MOLMAN000", FatalException,
"Master instance was set already!");
}
fpMasterInstance = Instance();
}
else {
G4AutoLock lock(&workerInstancesMutex);
fWorkerInstances.push_back(Instance());
}
fInstancesRegistered = true;
}
}
G4MoleculeCounterManager* G4MoleculeCounterManager::Instance()
{
if (fpInstance == nullptr) {
G4AutoLock lock(&managerInstance);
fpInstance = std::make_unique<G4MoleculeCounterManager>(G4MoleculeCounterManager::Private());
fpInstance->RegisterInstance();
}
return fpInstance.get();
}
G4MoleculeCounterManager* G4MoleculeCounterManager::GetInstanceIfExists()
{
return fpInstance.get();
}
void G4MoleculeCounterManager::DeleteInstance()
{
G4AutoLock lock(&managerInstance);
if (fpInstance != nullptr) {
fpInstance.reset();
// this should (test!) trigger the dtor, which will delete/deregister the counters
}
}
// ---------------------------------------------------------------------
//
// Initialization
//
void G4MoleculeCounterManager::Initialize()
{
if (fVerbosity > 0) {
G4cout << "G4MoleculeCounterManager::Initialize ("
<< (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
}
if (G4Threading::IsMultithreadedApplication()) {
if (G4Threading::IsWorkerThread())
InitializeWorker();
else
InitializeMaster();
}
else {
InitializeMaster();
}
}
void G4MoleculeCounterManager::InitializeMaster()
{
if (fIsInitialized) return;
for (auto& counter : fCounters)
counter.second->Initialize();
}
void G4MoleculeCounterManager::InitializeWorker()
{
if (fIsInitialized) return;
for (auto& counter : fCounters)
counter.second->Initialize();
}
// ---------------------------------------------------------------------
//
// Add & Remove Molecules
//
void G4MoleculeCounterManager::AddMoleculeWithoutTrack(const G4MolecularConfiguration* molecule,
G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
counter->AddMolecule(counter->BuildSimpleIndex(molecule), time, n);
}
}
void G4MoleculeCounterManager::RemoveMoleculeWithoutTrack(const G4MolecularConfiguration* molecule,
G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
counter->RemoveMolecule(counter->BuildSimpleIndex(molecule), time, n);
}
}
void G4MoleculeCounterManager::AddMolecule(const G4Track* aTrack, G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
counter->AddMolecule(counter->BuildIndex(aTrack), time, n);
}
}
void G4MoleculeCounterManager::RemoveMolecule(const G4Track* aTrack, G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
counter->RemoveMolecule(counter->BuildIndex(aTrack), time, n);
}
}
void G4MoleculeCounterManager::AddMolecule(const G4Track* aTrack, const G4StepPoint* aStepPoint,
G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
if (counter->GetSensitiveToStepping()) {
counter->AddMolecule(counter->BuildIndex(aTrack, aStepPoint), time, n);
}
}
}
void G4MoleculeCounterManager::RemoveMolecule(const G4Track* aTrack, const G4StepPoint* aStepPoint,
G4double time, G4int n)
{
for (auto& [id, counter] : fCounters) {
if (counter->GetSensitiveToStepping()) {
counter->RemoveMolecule(counter->BuildIndex(aTrack, aStepPoint), time, n);
}
}
}
// ---------------------------------------------------------------------
void G4MoleculeCounterManager::RecordReaction(const G4DNAMolecularReactionData* reactionData,
G4double time, G4int n)
{
for (auto& [id, counter] : fReactionCounters) {
counter->RecordReaction(counter->BuildSimpleIndex(reactionData), time, n);
}
}
// ---------------------------------------------------------------------
//
// Notification of Step or Finalization (must be implemented in a custom G4ITTrackingInteractivity!
//
/* Example:
void ChemistrySteppingAction::UserSteppingAction(const G4Step* aStep)
{
if (G4MoleculeCounterManager::Instance()->GetIsActive())
G4MoleculeCounterManager::Instance()->NotifyOfStep(aStep);
}
*/
void G4MoleculeCounterManager::NotifyOfStep(const G4Step* aStep)
{
const G4Track* aTrack = aStep->GetTrack();
for (auto& [id, counter] : fCounters) {
auto preStepIndex = counter->BuildIndex(aTrack, aStep->GetPreStepPoint());
auto postStepIndex = counter->BuildIndex(aTrack, aStep->GetPostStepPoint());
if (!(*preStepIndex == *postStepIndex)) {
#ifdef G4VERBOSE
if (GetVerbosity() > 1) {
G4cout << "G4MoleculeCounterManager::NotifyOfStep for counter " << counter->GetName()
<< ":\n-- Pre = " << preStepIndex->GetInfo() << "\n"
<< "-- Post = " << postStepIndex->GetInfo() << G4endl;
}
#endif
counter->RemoveMolecule(std::move(preStepIndex), aTrack->GetGlobalTime(), 1);
counter->AddMolecule(std::move(postStepIndex), aTrack->GetGlobalTime(), 1);
}
}
}
void G4MoleculeCounterManager::NotifyOfFinalize()
{
for (auto& [id, counter] : fCounters) {
counter->SchedulerFinalizedTracking();
}
}
//
// Broadcast Functions
//
void G4MoleculeCounterManager::BroadcastIgnoreMolecule(const G4MoleculeDefinition* molecule)
{
for (auto& [id, counter] : fCounters) {
counter->IgnoreMolecule(molecule);
}
}
void G4MoleculeCounterManager::BroadcastIgnoreReactant(const G4MolecularConfiguration* molecule)
{
for (auto& [id, counter] : fCounters) {
counter->IgnoreReactant(molecule);
}
}
void G4MoleculeCounterManager::BroadcastRegisterAllMoleculesAndReactants()
{
for (auto& [id, counter] : fCounters) {
counter->RegisterAll();
}
}
//------------------------------------------------------------------------------
//
// Manager Functions
//
G4int G4MoleculeCounterManager::RegisterCounter(std::unique_ptr<G4VMoleculeCounter> counter)
{
auto idProvider = [&]() {
if (fCounters.size() == 0) return 0;
auto indices = G4::MoleculeCounter::GetMapIndices(fCounters);
auto lastIndex = *indices.rbegin();
return ++lastIndex;
};
return RegisterCounter(fCounters, std::move(counter), idProvider);
}
//------------------------------------------------------------------------------
G4int G4MoleculeCounterManager::RegisterCounter(std::unique_ptr<G4VMoleculeReactionCounter> counter)
{
auto idProvider = [&] {
if (fReactionCounters.size() == 0) return 0;
auto indices = G4::MoleculeCounter::GetMapIndices(fReactionCounters);
auto lastIndex = *indices.rbegin();
return ++lastIndex;
};
return RegisterCounter(fReactionCounters, std::move(counter), idProvider);
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::DeregisterAllCounters()
{
for (auto& [id, ctr] : fCounters) {
delete ctr;
}
fCounters.clear();
for (auto& [id, ctr] : fReactionCounters) {
delete ctr;
}
fReactionCounters.clear();
}
//------------------------------------------------------------------------------
//
// Manipulate Counters
//
void G4MoleculeCounterManager::ResetCounters()
{
if (fVerbosity > 0) {
G4cout << "G4MoleculeCounterManager::ResetCounters ("
<< (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
}
for (auto& [id, counter] : fCounters)
counter->ResetCounter();
for (auto& [id, counter] : fReactionCounters)
counter->ResetCounter();
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::ActivateCounterAtTimes(G4int id, G4double aboveTime,
G4double belowTime, G4bool aboveTimeInclusive,
G4bool belowTimeInclusive)
{
if (fVerbosity > 0) {
G4cout << "G4MoleculeCounterManager::ActivateCounterAtTimes ("
<< (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
}
auto counter = GetEditableMoleculeCounter(id);
counter->SetActiveLowerBound(aboveTime, aboveTimeInclusive);
counter->SetActiveUpperBound(belowTime, belowTimeInclusive);
}
void G4MoleculeCounterManager::ActivateReactionCounterAtTimes(G4int id, G4double aboveTime,
G4double belowTime,
G4bool aboveTimeInclusive,
G4bool belowTimeInclusive)
{
if (fVerbosity > 0) {
G4cout << "G4MoleculeCounterManager::ActivateReactionCounterAtTimes ("
<< (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
}
auto counter = GetEditableMoleculeReactionCounter(id);
counter->SetActiveLowerBound(aboveTime, aboveTimeInclusive);
counter->SetActiveUpperBound(belowTime, belowTimeInclusive);
}
//------------------------------------------------------------------------------
G4VMoleculeCounter* G4MoleculeCounterManager::GetEditableMoleculeCounter(G4int id) const
{
auto it = fCounters.find(id);
if (it == fCounters.end()) {
G4ExceptionDescription description;
description << "No molecule counter with Id = " << id << " was found!\n";
G4Exception("G4MoleculeCounterManager::GetMoleculeCounter", "MOLMAN001", FatalErrorInArgument,
description);
return nullptr;
}else{
return it->second;
}
}
std::vector<const G4VMoleculeCounter*> G4MoleculeCounterManager::GetMoleculeCounters() const
{
std::vector<const G4VMoleculeCounter*> output;
output.reserve(fCounters.size());
for (auto& [id, counter] : fCounters)
output.push_back(counter);
return output;
}
std::vector<const G4VMoleculeCounter*> G4MoleculeCounterManager::GetMoleculeCounters(G4String name) const
{
std::vector<const G4VMoleculeCounter*> output;
for (auto& [id, counter] : fCounters) {
if (name == counter->GetName()) output.push_back(counter);
}
return output;
}
//------------------------------------------------------------------------------
G4VMoleculeReactionCounter*
G4MoleculeCounterManager::GetEditableMoleculeReactionCounter(G4int id) const
{
auto it = fReactionCounters.find(id);
if (it == fReactionCounters.end()) {
G4ExceptionDescription description;
description << "No molecule reaction counter with Id = " << id << " was found!\n";
G4Exception("G4MoleculeCounterManager::GetMoleculeReactionCounter", "MOLMAN001",
FatalErrorInArgument, description);
return nullptr;
}else
{
return it->second;
}
}
std::vector<const G4VMoleculeReactionCounter*>
G4MoleculeCounterManager::GetMoleculeReactionCounters() const
{
std::vector<const G4VMoleculeReactionCounter*> output;
output.reserve(fReactionCounters.size());
for (auto& [id, counter] : fReactionCounters)
output.push_back(counter);
return output;
}
std::vector<const G4VMoleculeReactionCounter*>
G4MoleculeCounterManager::GetMoleculeReactionCounters(G4String name) const
{
std::vector<const G4VMoleculeReactionCounter*> output;
for (auto& [id, counter] : fReactionCounters) {
if (name == counter->GetName()) output.push_back(counter);
}
return output;
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::BeginOfEventAction(const G4Event*)
{
fBeginOfEventTriggered = true;
if (GetResetCountersBeforeEvent()) {
// trigger reset if:
// * is not an MT app (master = worker)
// * is an MT app, master, and we want to reset the master
// * is an MT app and worker
if (!G4Threading::IsMultithreadedApplication()
|| (G4Threading::IsMultithreadedApplication() && G4Threading::IsMasterThread()
&& GetResetMasterCounterWithWorkers())
|| (G4Threading::IsMultithreadedApplication() && G4Threading::IsWorkerThread()))
ResetCounters();
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::BeginOfRunAction(const G4Run*)
{
fBeginOfRunTriggered = true;
if (GetResetCountersBeforeRun()) {
// trigger reset if:
// * is not an MT app (master = worker)
// * is an MT app, master, and we want to reset the master
// * is an MT app and worker
if (!G4Threading::IsMultithreadedApplication()
|| (G4Threading::IsMultithreadedApplication() && G4Threading::IsMasterThread()
&& GetResetMasterCounterWithWorkers())
|| (G4Threading::IsMultithreadedApplication() && G4Threading::IsWorkerThread()))
ResetCounters();
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::EndOfEventAction(const G4Event*)
{
// EndOfEvent is never triggered on the master of a G4MT
if (GetAccumulateCounterIntoMaster() && GetResetCountersBeforeEvent()
&& G4Threading::IsMultithreadedApplication() && G4Threading::IsWorkerThread())
{
AbsorbWorkerManagerCounters(this);
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::EndOfRunAction(const G4Run*)
{
if (GetAccumulateCounterIntoMaster() && GetResetCountersBeforeRun()
&& !GetResetCountersBeforeEvent() &&
// if ResetBeforeEvent, AbsorbWorkerManagerCounters will have been triggered already
G4Threading::IsMultithreadedApplication() && G4Threading::IsMasterThread())
AbsorbWorkerManagerCounters();
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::AbsorbWorkerManagerCounters(
const G4MoleculeCounterManager* selectedWorker)
{
if (selectedWorker == nullptr && !G4Threading::IsMasterThread()) {
// Can only call without worker from master thread!
G4ExceptionDescription description;
description << "This method may only be called from the master thread!";
G4Exception("G4MoleculeCounterManager::AbsorbWorkerManagerCounters", "MOLMAN999",
FatalException, description);
}
// prevent changes to any of the instances
G4AutoLock lockMaster(&masterInstanceMutex);
G4AutoLock lockWorker(&workerInstancesMutex);
for (auto const& worker : fWorkerInstances) {
if (selectedWorker == nullptr || worker != selectedWorker) continue;
for (auto& [id, masterCounter] : fpMasterInstance->fCounters) {
// acquire worker counter
auto workerCounter = worker->GetMoleculeCounter(id);
masterCounter->AbsorbCounter(workerCounter);
}
for (auto& [id, masterCounter] : fpMasterInstance->fReactionCounters) {
// acquire worker counter
auto workerCounter = worker->GetMoleculeReactionCounter(id);
masterCounter->AbsorbCounter(workerCounter);
}
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::DumpMasterCounters() const
{
G4AutoLock lock(&masterInstanceMutex);
for (auto const& pCounter : fpMasterInstance->GetMoleculeCounters()) {
G4cout << "=========================================================================== \n"
<< " >> [MASTER] Dumping Molecule Counter `" << pCounter->GetName() << "`\n"
<< G4endl;
pCounter->Dump();
G4cout << "\n=========================================================================== "
<< G4endl;
}
for (auto const& pCounter : fpMasterInstance->GetMoleculeReactionCounters()) {
G4cout << "=========================================================================== \n"
<< " >> [MASTER] Dumping Molecule Reaction Counter `" << pCounter->GetName() << "`\n"
<< G4endl;
pCounter->Dump();
G4cout << "\n=========================================================================== "
<< G4endl;
}
}
//------------------------------------------------------------------------------
void G4MoleculeCounterManager::DumpWorkerCounters() const
{
G4AutoLock lock(&workerInstancesMutex);
for (auto const& worker : G4MoleculeCounterManager::fWorkerInstances) {
for (auto const& pCounter : worker->GetMoleculeCounters()) {
G4cout << "=========================================================================== \n"
<< " >> [WORKER<" << worker << ">] Dumping Molecule Counter `" << pCounter->GetName()
<< "`\n"
<< G4endl;
pCounter->Dump();
G4cout << "\n=========================================================================== "
<< G4endl;
}
for (auto const& pCounter : worker->GetMoleculeReactionCounters()) {
G4cout << "=========================================================================== \n"
<< " >> [WORKER<" << worker << ">] Dumping Molecule Reaction Counter `"
<< pCounter->GetName() << "`\n"
<< G4endl;
pCounter->Dump();
G4cout << "\n=========================================================================== "
<< G4endl;
}
}
}
//------------------------------------------------------------------------------
std::atomic<G4bool> G4MoleculeCounterManager::fResetCountersBeforeEvent(false);
std::atomic<G4bool> G4MoleculeCounterManager::fResetCountersBeforeRun(false);
std::atomic<G4bool> G4MoleculeCounterManager::fAccumulateCounterIntoMaster(true);
std::atomic<G4bool> G4MoleculeCounterManager::fResetMasterCounterWithWorkers(false);
G4bool G4MoleculeCounterManager::GetResetCountersBeforeEvent() const
{
return fResetCountersBeforeEvent.load();
}
void G4MoleculeCounterManager::SetResetCountersBeforeEvent(G4bool flag)
{
if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit) {
fResetCountersBeforeEvent = flag;
}
else
G4Exception("G4DNAChemistryManager::SetResetCountersBeforeEvent", "WRONG_STATE", FatalException,
"This flag may only be set during the PreInit state!");
}
G4bool G4MoleculeCounterManager::GetResetCountersBeforeRun() const
{
return fResetCountersBeforeRun.load();
}
void G4MoleculeCounterManager::SetResetCountersBeforeRun(G4bool flag)
{
if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
fResetCountersBeforeRun = flag;
else
G4Exception("G4DNAChemistryManager::SetResetCountersBeforeRun", "WRONG_STATE", FatalException,
"This flag may only be set during the PreInit state!");
}
G4bool G4MoleculeCounterManager::GetAccumulateCounterIntoMaster() const
{
return fAccumulateCounterIntoMaster.load();
}
void G4MoleculeCounterManager::SetAccumulateCounterIntoMaster(G4bool flag)
{
if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
fAccumulateCounterIntoMaster = flag;
else
G4Exception("G4DNAChemistryManager::SetAccumulateCounterIntoMaster", "WRONG_STATE",
FatalException, "This flag may only be set during the PreInit state!");
}
G4bool G4MoleculeCounterManager::GetResetMasterCounterWithWorkers() const
{
return fResetMasterCounterWithWorkers.load();
}
void G4MoleculeCounterManager::SetResetMasterCounterWithWorkers(G4bool flag)
{
if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
fResetMasterCounterWithWorkers = flag;
else
G4Exception("G4DNAChemistryManager::SetResetMasterCounterWithWorkers", "WRONG_STATE",
FatalException, "This flag may only be set during the PreInit state!");
}
//------------------------------------------------------------------------------
@@ -0,0 +1,88 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4MoleculeCounterManagerMessenger.hh"
#include "G4MoleculeCounterManager.hh"
G4MoleculeCounterManagerMessenger::G4MoleculeCounterManagerMessenger(
G4MoleculeCounterManager* manager)
: G4UImessenger(), fpManager(manager)
{
fpManagerDir = std::make_unique<G4UIdirectory>("/chem/moleculecounters/", false);
fpManagerDir->SetGuidance("Molecule Counter Manager Commands");
fpManagerDir->AvailableForStates(G4State_PreInit);
InitializeCommands();
}
void G4MoleculeCounterManagerMessenger::InitializeCommands()
{
fpActiveCmd = std::make_unique<G4UIcmdWithABool>("/chem/moleculecounters/active", this);
fpActiveCmd->AvailableForStates(G4State_PreInit);
fpResetBeforeEventCmd =
std::make_unique<G4UIcmdWithABool>("/chem/moleculecounters/resetBeforeEvent", this);
fpResetBeforeEventCmd->AvailableForStates(G4State_PreInit);
fpResetBeforeRunCmd =
std::make_unique<G4UIcmdWithABool>("/chem/moleculecounters/resetBeforeRun", this);
fpResetBeforeRunCmd->AvailableForStates(G4State_PreInit);
fpAccumulateIntoMasterCmd =
std::make_unique<G4UIcmdWithABool>("/chem/moleculecounters/accumulateIntoMaster", this);
fpAccumulateIntoMasterCmd->AvailableForStates(G4State_PreInit);
fpVerboseCmd = std::make_unique<G4UIcmdWithAnInteger>("/chem/moleculecounters/verbose", this);
fpVerboseCmd->SetDefaultValue(0);
fpVerboseCmd->AvailableForStates(G4State_Idle, G4State_Init, G4State_PreInit, G4State_EventProc,
G4State_GeomClosed);
}
void G4MoleculeCounterManagerMessenger::SetNewValue(G4UIcommand* command, G4String newValue)
{
if (command == fpActiveCmd.get()) {
auto value = fpActiveCmd->ConvertToBool(newValue);
fpManager->SetIsActive(value);
}
else if (command == fpResetBeforeEventCmd.get()) {
auto value = fpResetBeforeEventCmd->ConvertToBool(newValue);
fpManager->SetResetCountersBeforeEvent(value);
}
else if (command == fpResetBeforeRunCmd.get()) {
auto value = fpResetBeforeRunCmd->ConvertToBool(newValue);
fpManager->SetResetCountersBeforeRun(value);
}
else if (command == fpAccumulateIntoMasterCmd.get()) {
auto value = fpAccumulateIntoMasterCmd->ConvertToBool(newValue);
fpManager->SetAccumulateCounterIntoMaster(value);
}
else if (command == fpVerboseCmd.get()) {
auto value = fpVerboseCmd->ConvertToInt(newValue);
fpManager->SetVerbosity(value);
}
}
@@ -0,0 +1,140 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4MoleculeCounterTimeComparer.hh"
#include "G4Exception.hh"
G4MoleculeCounterTimeComparer::G4MoleculeCounterTimeComparer()
: fType(TimeComparerType::FixedPrecision)
{}
G4MoleculeCounterTimeComparer::G4MoleculeCounterTimeComparer(
const G4MoleculeCounterTimeComparer& other)
{
*this = other;
}
G4MoleculeCounterTimeComparer&
G4MoleculeCounterTimeComparer::operator=(const G4MoleculeCounterTimeComparer& other)
{
switch (other.fType) {
case TimeComparerType::VariablePrecision:
SetVariablePrecision(other.fVariablePrecision);
break;
case TimeComparerType::FixedPrecision:
default:
SetFixedPrecision(other.fPrecision);
break;
}
return *this;
}
void G4MoleculeCounterTimeComparer::SetFixedPrecision(G4double precision)
{
fType = TimeComparerType::FixedPrecision;
fPrecision = precision;
}
void G4MoleculeCounterTimeComparer::SetVariablePrecision(
const std::vector<G4double>& globalTimeHighEdges, const std::vector<G4double>& resolutions)
{
fType = TimeComparerType::VariablePrecision;
fVariablePrecision.clear();
for (auto key = globalTimeHighEdges.cbegin(), val = resolutions.cbegin();
key != globalTimeHighEdges.cend() && val != resolutions.cend(); ++key, ++val)
{
fVariablePrecision.emplace(*key, *val);
}
if (fVariablePrecision.empty()) {
G4Exception("G4MoleculeCounterTimeComparer::SetVariablePrecision()",
"G4MoleculeCounterTimeComparer", FatalException, "Precision map cannot be empty!");
}
}
void G4MoleculeCounterTimeComparer::SetVariablePrecision(
const std::map<G4double, G4double>& resolutionMap)
{
fType = TimeComparerType::VariablePrecision;
fVariablePrecision = resolutionMap;
if (fVariablePrecision.empty()) {
G4Exception("G4MoleculeCounterTimeComparer::SetVariablePrecision()",
"G4MoleculeCounterTimeComparer", FatalException, "Precision map cannot be empty!");
}
}
G4double G4MoleculeCounterTimeComparer::GetPrecisionAtTime(G4double time) const
{
if (fType == G4MoleculeCounterTimeComparer::FixedPrecision)
return fPrecision;
else
return fVariablePrecision.upper_bound(time)->second;
}
G4bool G4MoleculeCounterTimeComparer::operator()(const G4double& a, const G4double& b) const
{
if (fType == G4MoleculeCounterTimeComparer::FixedPrecision) {
if (std::fabs(a - b) < fPrecision) {
return false;
}
}
else if (fType == G4MoleculeCounterTimeComparer::VariablePrecision) {
const auto it_a = fVariablePrecision.upper_bound(a);
const auto it_b = fVariablePrecision.upper_bound(b);
auto precision = fVariablePrecision.crbegin()->second;
if (it_a != fVariablePrecision.cend() && it_b != fVariablePrecision.cend())
precision = std::min(it_a->second, it_b->second);
if (std::fabs(a - b) < precision) {
return false;
}
}
else {
G4Exception("G4MoleculeCounterTimeComparer::operator()", "G4MoleculeCounterTimeComparer",
FatalException, "Unknown comparison type");
}
return a < b;
}
// ---------------------------------------------------------------------
G4MoleculeCounterTimeComparer
G4MoleculeCounterTimeComparer::CreateWithFixedPrecision(G4double precision)
{
auto obj = G4MoleculeCounterTimeComparer();
obj.SetFixedPrecision(precision);
return obj;
}
G4MoleculeCounterTimeComparer
G4MoleculeCounterTimeComparer::CreateWithVariablePrecision(const std::map<G4double, G4double>& map)
{
auto obj = G4MoleculeCounterTimeComparer();
obj.SetVariablePrecision(map);
return obj;
}
@@ -27,82 +27,46 @@
// Geant4
//
// Created by Mathieu Karamitros on 02/11/2016.
// Modified by Christian Velten on 10/27/2024.
//
//
#include "G4VMoleculeCounter.hh"
#include "G4MoleculeCounter.hh"
G4ThreadLocal
G4VMoleculeCounter* G4VMoleculeCounter::fpInstance = nullptr;
#include "G4MoleculeCounterTemplates.hh"
#include "G4ios.hh"
//------------------------------------------------------------------------------
void
G4VMoleculeCounter::SetInstance(G4VMoleculeCounter* pCounterInstance)
G4VMoleculeCounter::G4VMoleculeCounter() : G4VMoleculeCounterInternalBase() {}
G4VMoleculeCounter::G4VMoleculeCounter(const G4String& name, MoleculeCounterType type)
: G4VMoleculeCounterInternalBase(name), fType(type)
{}
//------------------------------------------------------------------------------
void G4VMoleculeCounter::SetSensitiveToStepping(G4bool flag)
{
if (fpInstance != nullptr)
{
G4ExceptionDescription errMsg;
errMsg << "The G4MoleculeCounter was already initialized." << G4endl
<< "The previous instance will be deleted in order to use yours." << G4endl
<< "However this can generate conflicts. Make sure you call G4MoleculeCounter::SetInstance"
"at the beginning of your application."
<< "A good place would be ActionInitialization::Build & BuildForMaster"
<< G4endl;
G4Exception("G4MoleculeCounter::SetInstance",
"SINGLETON_ALREADY_INITIALIZED",
JustWarning, errMsg);
delete fpInstance;
fpInstance = nullptr;
}
fpInstance = pCounterInstance;
if (fType == MoleculeCounterType::Basic && flag) {
G4ExceptionDescription errMsg;
errMsg << "Cannot set a molecule counter of type 'Basic' to be sensitive to stepping!"
<< G4endl;
G4Exception("G4VMoleculeCounter::SetSensitiveToStepping", "NOT_ALLOWED", FatalException, errMsg);
}
fSensitiveToStepping = flag;
}
//------------------------------------------------------------------------------
G4VMoleculeCounter* G4VMoleculeCounter::Instance()
G4bool G4VMoleculeCounter::IsReactantIgnored(const G4MoleculeDefinition* molecule) const
{
if (fpInstance == nullptr)
{
fpInstance = new G4MoleculeCounter();
}
return fpInstance;
return G4::MoleculeCounter::Contains(fIgnoredMolecules, molecule);
}
//------------------------------------------------------------------------------
void G4VMoleculeCounter::DeleteInstance()
G4bool G4VMoleculeCounter::IsReactantIgnored(const G4MolecularConfiguration* reactant) const
{
if (fpInstance != nullptr)
{
delete fpInstance;
fpInstance = nullptr;
}
return G4::MoleculeCounter::Contains(fIgnoredReactants, reactant);
}
//------------------------------------------------------------------------------
void G4VMoleculeCounter::InitializeInstance()
{
if (fpInstance != nullptr)
{
fpInstance->Initialize();
}
}
//------------------------------------------------------------------------------
void G4VMoleculeCounter::Use(G4bool flag)
{
fUse = flag;
}
//------------------------------------------------------------------------------
G4bool G4VMoleculeCounter::InUse()
{
return fUse;
}
@@ -0,0 +1,62 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4VMoleculeCounterInternalBase.hh"
namespace G4
{
namespace MoleculeCounter
{
G4bool FixedTimeComparer::operator()(const G4double& a, const G4double& b) const
{
if (std::fabs(a - b) < fPrecision) {
return false;
}
return a < b;
}
G4ThreadLocal G4double FixedTimeComparer::fPrecision = 0.1 * picosecond;
} // namespace MoleculeCounter
} // namespace G4
G4ThreadLocal G4int G4VMoleculeCounterInternalBase::_createdCounters = 0;
//------------------------------------------------------------------------------
G4VMoleculeCounterInternalBase::G4VMoleculeCounterInternalBase() : fId(_createdCounters++) {}
G4VMoleculeCounterInternalBase::G4VMoleculeCounterInternalBase(const G4String& name)
: fId(_createdCounters++), fName(name)
{}
//------------------------------------------------------------------------------
void G4VMoleculeCounterInternalBase::SetFixedTimePrecision(G4double precision)
{
G4::MoleculeCounter::FixedTimeComparer::fPrecision = precision;
}
@@ -23,29 +23,17 @@
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
/*
# <<BEGIN-copyright>>
# <<END-copyright>>
*/
#ifndef G4GIDI_map_h_included
#define G4GIDI_map_h_included 1
// Author: Christian Velten (2025)
#include <string>
//using namespace std;
#include "G4VMoleculeReactionCounter.hh"
#include <MCGIDI_map.h>
//------------------------------------------------------------------------------
class G4GIDI_map {
G4VMoleculeReactionCounter::G4VMoleculeReactionCounter() : G4VMoleculeCounterInternalBase() {}
public:
GIDI::statusMessageReporting smr;
GIDI::MCGIDI_map *map;
G4VMoleculeReactionCounter::G4VMoleculeReactionCounter(const G4String& name, MoleculeReactionCounterType type)
: G4VMoleculeCounterInternalBase(name), fType(type)
{}
G4GIDI_map( const std::string &dataDirectory );
~G4GIDI_map( );
std::string path( void );
std::string fileName( void );
};
#endif // End of G4GIDI_map_h_included
//------------------------------------------------------------------------------
@@ -0,0 +1,92 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
#ifndef TRANSPORTATION_H
#define TRANSPORTATION_H
#include "G4DNABoundingBox.hh"
#include "G4ITReaction.hh"
#include "G4ITTransportation.hh"
#include "G4MolecularConfiguration.hh"
class G4Molecule;
class G4VUserBrownianAction;
class G4ChemReboundTransportation : public G4ITTransportation
{
using MolConf = const G4MolecularConfiguration*;
public:
explicit G4ChemReboundTransportation(const G4String& aName = "ChemReboundTransportation",
const G4DNABoundingBox* = nullptr, G4int verbosityLevel = 0);
~G4ChemReboundTransportation() override = default;
G4ChemReboundTransportation(const G4ChemReboundTransportation&) = delete;
G4ChemReboundTransportation& operator=(const G4ChemReboundTransportation&) = delete;
void BuildPhysicsTable(const G4ParticleDefinition&) override;
void StartTracking(G4Track* aTrack) override;
void ComputeStep(const G4Track&, const G4Step&, G4double, G4double&) override;
G4double AlongStepGetPhysicalInteractionLength(const G4Track& /*track*/,
G4double /*previousStepSize*/,
G4double /*currentMinimumStep*/,
G4double& /*currentSafety*/,
G4GPILSelection* /*selection*/) override;
G4VParticleChange* PostStepDoIt(const G4Track& track, const G4Step&) override;
G4VParticleChange* AlongStepDoIt(const G4Track& track, const G4Step&) override;
inline void SetBoundary(const G4DNABoundingBox*);
static G4double calculateNextCoordinate(G4double nextPos, G4double high, G4double low);
G4double GetTimeToBoundary(const G4Track& track);
protected:
//________________________________________________________________
// Process information
struct G4ITBrownianState : public G4ITTransportationState
{
public:
G4ITBrownianState();
~G4ITBrownianState() override = default;
G4String GetType() override { return "Rebound"; }
G4bool fTimeStepReachedLimit;
G4double fRandomNumber;
};
G4ITReactionSet* fReactionSet = G4ITReactionSet::Instance();
G4Material* fNistWater = nullptr;
G4double fMaximumTimeStep = 0;
G4double fInternalMinTimeStep;
const G4DNABoundingBox* fpBoundingBox = nullptr;
G4ThreeVector BouncingAction(const G4ThreeVector& nextPosition);
G4double calculateDistanceFromTimeStep(MolConf mol, G4double timeStep);
};
inline void G4ChemReboundTransportation::SetBoundary(const G4DNABoundingBox* pBounding)
{
fpBoundingBox = pBounding;
}
#endif
@@ -28,6 +28,8 @@
#define G4DNASCAVENGERPROCESS_HH
#include "G4VITProcess.hh"
#include "G4MoleculeTable.hh"
class G4DNAMolecularReactionData;
class G4MolecularConfiguration;
class G4DNABoundingBox;
@@ -100,5 +102,8 @@ class G4DNAScavengerProcess : public G4VITProcess
MolType fpMaterialConf;
const G4DNABoundingBox* fpBoundingBox;
G4DNAScavengerMaterial* fpScavengerMaterial{nullptr};
MolType fH3Op = G4MoleculeTable::Instance()->GetConfiguration("H3Op(B)");
MolType fH2O = G4MoleculeTable::Instance()->GetConfiguration("H2O");
MolType fHOm = G4MoleculeTable::Instance()->GetConfiguration("OHm(B)");
};
#endif // FLASH1_G4DNASCAVENGERPROCESS_HH
@@ -26,6 +26,7 @@ geant4_add_module(G4emdna-processes
G4DNADoubleIonisation.hh
G4DNATripleIonisation.hh
G4DNAQuadrupleIonisation.hh
G4ChemReboundTransportation.hh
SOURCES
G4DNAAttachment.cc
G4DNABrownianTransportation.cc
@@ -48,7 +49,8 @@ geant4_add_module(G4emdna-processes
G4DNAPolyNucleotideReactionProcess.cc
G4DNADoubleIonisation.cc
G4DNATripleIonisation.cc
G4DNAQuadrupleIonisation.cc)
G4DNAQuadrupleIonisation.cc
G4ChemReboundTransportation.cc)
geant4_module_link_libraries(G4emdna-processes
PUBLIC
@@ -0,0 +1,404 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4ChemReboundTransportation.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4H3O.hh"
#include "G4ITNavigator.hh"
#include "G4ITSafetyHelper.hh" // Not used yet
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4Molecule.hh"
#include "G4NistManager.hh"
#include "G4ParticleTable.hh"
#include "G4RandomDirection.hh"
#include "G4SafetyHelper.hh"
#include "G4SystemOfUnits.hh"
#include "G4TrackingInformation.hh"
#include "G4UnitsTable.hh"
#include "G4VUserBrownianAction.hh"
#include "Randomize.hh"
#include <CLHEP/Random/Stat.h>
using namespace std;
#ifndef State
# define State(theXInfo) (GetState<G4ITBrownianState>()->theXInfo)
#endif
static G4double InvErfc(G4double x)
{
return CLHEP::HepStat::inverseErf(1. - x);
}
#ifndef State
# define State(theXInfo) (GetState<G4ITTransportationState>()->theXInfo)
#endif
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ChemReboundTransportation::G4ChemReboundTransportation(const G4String& aName,
const G4DNABoundingBox* pB,
G4int verbosity)
: G4ITTransportation(aName, verbosity), fpBoundingBox(pB)
{
fVerboseLevel = 0;
fpState = std::make_shared<G4ITBrownianState>();
SetProcessSubType(fLowEnergyBrownianTransportation);
fNistWater = G4NistManager::Instance()->FindOrBuildMaterial("G4_WATER");
fInternalMinTimeStep = 1 * CLHEP::ps;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ChemReboundTransportation::G4ITBrownianState::G4ITBrownianState()
{
fTimeStepReachedLimit = false;
fRandomNumber = -1;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4ChemReboundTransportation::StartTracking(G4Track* track)
{
fpState = std::make_shared<G4ITBrownianState>();
SetInstantiateProcessState(false);
G4ITTransportation::StartTracking(track);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4ChemReboundTransportation::BuildPhysicsTable(const G4ParticleDefinition& particle)
{
fpSafetyHelper->InitialiseHelper();
G4ITTransportation::BuildPhysicsTable(particle);
if (fpBoundingBox == nullptr) {
G4ExceptionDescription errMsg;
errMsg << "fpBoundingBox is nullptr";
G4Exception(
"ChemReboundTransportation::BuildPhysicsTable"
"ChemReboundTransportation",
"ChemReboundTransportation", FatalErrorInArgument, errMsg);
}
G4double halfSize =
std::min({fpBoundingBox->halfSideLengthInX(), fpBoundingBox->halfSideLengthInY(),
fpBoundingBox->halfSideLengthInZ()});
fMaximumTimeStep = (halfSize * halfSize) / (60 * G4H3O::Definition()->GetDiffusionCoefficient());
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4ChemReboundTransportation::ComputeStep(const G4Track& track, const G4Step& step,
const G4double timeStep, G4double& spaceStep)
{
if (GetIT(track)->GetTrackingInfo()->IsLeadingStep()) {
G4ExceptionDescription exceptionDescription;
exceptionDescription << "ComputeStep is called while the track has"
"the minimum interaction time";
exceptionDescription << " so it should not recompute a timeStep ";
G4Exception("ChemReboundTransportation::ComputeStep", "ChemReboundTransportation0001",
FatalErrorInArgument, exceptionDescription);
}
State(fGeometryLimitedStep) = false;
if (timeStep == 0) {
State(fTransportEndPosition) = track.GetPosition();
spaceStep = 0.;
}
else {
auto molConf = GetMolecule(track)->GetMolecularConfiguration();
spaceStep = calculateDistanceFromTimeStep(molConf, timeStep);
}
State(fTransportEndPosition) =
BouncingAction(track.GetPosition() + spaceStep * G4RandomDirection());
State(fEndPointDistance) = (track.GetPosition() - State(fTransportEndPosition)).mag();
if (fVerboseLevel > 1)
// if(GetMolecule(track)->GetName() == "e_aq^-1")
{
G4cout << G4endl;
G4cout << "ComputeStep: timeStep : " << G4BestUnit(timeStep, "Time")
<< " State(theInteractionTimeLeft) : " << State(theInteractionTimeLeft)
<< " State(fEndPointDistance) : " << G4BestUnit(State(fEndPointDistance), "Length")
<< " trackID : " << track.GetTrackID()
<< " Molecule name: " << "track.GetPosition() : " << track.GetPosition()
<< " State(fTransportEndPosition) : " << State(fTransportEndPosition) << " "
<< GetMolecule(track)->GetName() << " Diffusion length : " << G4endl;
}
State(fCandidateEndGlobalTime) = step.GetPreStepPoint()->GetGlobalTime() + timeStep;
State(fEndGlobalTimeComputed) = true;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VParticleChange* G4ChemReboundTransportation::PostStepDoIt(const G4Track& track,
const G4Step& step)
{
G4ITTransportation::PostStepDoIt(track, step);
#ifdef G4VERBOSE
// DEBUG
if (fVerboseLevel > 1)
// if(GetMolecule(track)->GetName() == "e_aq^-1")
if (GetIT(track)->GetTrackingInfo()->IsLeadingStep()) {
G4cout << "ChemReboundTransportation::PostStepDoIt() :" << " trackID : " << track.GetTrackID()
<< " Molecule name: " << "prePosition : " << step.GetPreStepPoint()->GetPosition()
<< " postPostion : " << step.GetPostStepPoint()->GetPosition() << " "
<< GetMolecule(track)->GetName()
<< " Diffusion length : " << G4BestUnit(step.GetStepLength(), "Length")
<< " within time step : " << G4BestUnit(step.GetDeltaTime(), "Time")
<< "\t Current global time : " << G4BestUnit(track.GetGlobalTime(), "Time")
<< " track.GetMomentumDirection() : " << track.GetMomentumDirection() << G4endl;
}
#endif
return &fParticleChange;
}
G4double G4ChemReboundTransportation::AlongStepGetPhysicalInteractionLength(
const G4Track& track, G4double /*previousStepSize*/, G4double /*currentMinimumStep*/,
G4double& /*currentSafety*/, G4GPILSelection* /*selection*/)
{
if (!fpBoundingBox->contains(track.GetPosition())) {
G4ExceptionDescription errMsg;
errMsg << "Point is out of box : " << *fpBoundingBox
<< " of particle : " << GetIT(track)->GetName() << "(" << track.GetTrackID()
<< ") : " << track.GetPosition();
G4Exception(
"ChemReboundTransportation::AlongStepGetPhysicalInteractionLength"
"ChemReboundTransportation",
"ChemReboundTransportation", FatalErrorInArgument, errMsg);
}
if (fNistWater != track.GetMaterial()) {
G4ExceptionDescription errMsg;
errMsg << "This is not water";
G4Exception(
"ChemReboundTransportation::AlongStepGetPhysicalInteractionLength"
"ChemReboundTransportation",
"ChemReboundTransportation", FatalErrorInArgument, errMsg);
}
G4double geometryStepLength = DBL_MAX;
State(theInteractionTimeLeft) = DBL_MAX;
auto molConf = GetMolecule(track)->GetMolecularConfiguration();
G4ITReactionPerTime& reactionPerTime = fReactionSet->GetReactionsPerTime();
auto reaction_i = reactionPerTime.begin();
if (reaction_i == reactionPerTime.end()) {
State(fGeometryLimitedStep) = false;
State(theInteractionTimeLeft) = fMaximumTimeStep;
if (fVerboseLevel > 1) {
G4cout << "out of reaction " << G4BestUnit(State(theInteractionTimeLeft), "Time") << G4endl;
}
}
else {
G4Track* pTrackA = (*reaction_i)->GetReactants().first;
G4Track* pTrackB = (*reaction_i)->GetReactant(pTrackA);
if (&track == pTrackA || &track == pTrackB) {
State(theInteractionTimeLeft) = GetTimeToBoundary(track);
State(fTimeStepReachedLimit) = false;
State(fGeometryLimitedStep) = false;
if (fVerboseLevel > 1)
G4cout << "Molecule A is of type : " << GetMolecule(track)->GetName()
<< " with trackID : " << track.GetTrackID()
<< " fMaximumTimeStep : " << G4BestUnit(fMaximumTimeStep, "Time")
<< " State(theInteractionTimeLeft) : "
<< G4BestUnit(State(theInteractionTimeLeft), "Time") << G4endl;
if (State(theInteractionTimeLeft) < fInternalMinTimeStep) {
State(fTimeStepReachedLimit) = true;
State(theInteractionTimeLeft) = fInternalMinTimeStep;
}
else if (State(theInteractionTimeLeft) > fMaximumTimeStep) {
State(fTimeStepReachedLimit) = true;
State(theInteractionTimeLeft) = fMaximumTimeStep;
}
}
else {
State(fGeometryLimitedStep) = false;
State(theInteractionTimeLeft) = DBL_MAX;
}
}
geometryStepLength = calculateDistanceFromTimeStep(molConf, State(theInteractionTimeLeft));
State(fTransportEndPosition) =
geometryStepLength * track.GetMomentumDirection() + track.GetPosition();
State(fTimeStepReachedLimit) = true;
State(fCandidateEndGlobalTime) = track.GetGlobalTime() + State(theInteractionTimeLeft);
State(fEndGlobalTimeComputed) = true;
#ifdef G4VERBOSE
if (fVerboseLevel > 1) {
G4cout << "ChemReboundTransportation::AlongStepGetPhysicalInteractionLength = "
<< G4BestUnit(geometryStepLength, "Length") << " "
<< G4BestUnit(State(theInteractionTimeLeft), "Time")
<< " | trackID = " << track.GetTrackID() << G4endl;
}
#endif
return geometryStepLength;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VParticleChange* G4ChemReboundTransportation::AlongStepDoIt(const G4Track& track,
const G4Step& step)
{
if (GetIT(track)->GetTrackingInfo()->IsLeadingStep()) {
G4double spaceStep = DBL_MAX;
auto molConf = GetMolecule(track)->GetMolecularConfiguration();
spaceStep = calculateDistanceFromTimeStep(molConf, State(theInteractionTimeLeft));
State(fGeometryLimitedStep) = false;
State(fTransportEndPosition) =
BouncingAction(track.GetPosition() + spaceStep * G4RandomDirection());
State(fEndPointDistance) = spaceStep;
if (fVerboseLevel > 1)
// if(GetMolecule(track)->GetName() == "e_aq^-1")
{
G4cout << "ChemReboundTransportation::AlongStepDoIt() :" << " trackID : "
<< track.GetTrackID()
<< " Molecule name: " << "prePosition : " << step.GetPreStepPoint()->GetPosition()
<< " postPostion : " << step.GetPostStepPoint()->GetPosition() << " "
<< GetMolecule(track)->GetName() << " State(theInteractionTimeLeft) : "
<< G4BestUnit(State(theInteractionTimeLeft), "Time")
<< " Diffusion length : " << G4BestUnit(step.GetStepLength(), "Length")
<< " within time step : " << G4BestUnit(step.GetDeltaTime(), "Time")
<< "\t Current global time : " << G4BestUnit(track.GetGlobalTime(), "Time")
<< " track.GetMomentumDirection() : " << track.GetMomentumDirection() << G4endl;
}
}
G4ITTransportation::AlongStepDoIt(track, step);
return &fParticleChange;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ThreeVector G4ChemReboundTransportation::BouncingAction(const G4ThreeVector& nextPosition)
{
// from Karamitros, Mathieu et al.2020,arXiv:2006.14225 (2020)
// https://doi.org/10.48550/arXiv.2006.14225
G4ThreeVector output;
G4double RxM = fpBoundingBox->Getxhi();
G4double RyM = fpBoundingBox->Getyhi();
G4double RzM = fpBoundingBox->Getzhi();
G4double Rxm = fpBoundingBox->Getxlo();
G4double Rym = fpBoundingBox->Getylo();
G4double Rzm = fpBoundingBox->Getzlo();
G4double x = calculateNextCoordinate(nextPosition.getX(), RxM, Rxm);
G4double y = calculateNextCoordinate(nextPosition.getY(), RyM, Rym);
G4double z = calculateNextCoordinate(nextPosition.getZ(), RzM, Rzm);
output.set(x, y, z);
return output;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4ChemReboundTransportation::calculateNextCoordinate(G4double nextPos, G4double high,
G4double low)
{
// from Karamitros, Mathieu et al.2020,arXiv:2006.14225 (2020)
G4double length = high - low;
if (std::abs(length) < 1e-10) {
return low;
}
G4double relativePos = std::abs(nextPos - low);
if (!std::isfinite(relativePos)) {
return low; // no crash
}
G4double n = relativePos / length;
if (!std::isfinite(n)) {
return low;
}
G4double truncVal = std::floor(n);//n is already positive
G4double h = truncVal;
if(truncVal > 2.0){
h = std::fmod(truncVal, 2.0);
}
G4double mod = relativePos;
if(relativePos > length) {
mod = std::fmod(relativePos, length);
}
return low + h * length + (1 - 2 * h) * std::abs(mod);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4ChemReboundTransportation::calculateDistanceFromTimeStep(MolConf mol, G4double timeStep)
{
G4double diffuCoeff = mol->GetDiffusionCoefficient();
if (mol->GetDiffusionCoefficient() <= 0) {
G4ExceptionDescription exceptionDescription;
exceptionDescription << "GetDiffusionCoefficient is negative";
G4Exception("ChemReboundTransportation::calculateDistanceFromTimeStep",
"ChemReboundTransportation030", FatalErrorInArgument, exceptionDescription);
}
G4double sqrt_2Dt = sqrt(2 * diffuCoeff * timeStep);
G4double x = G4RandGauss::shoot(0, sqrt_2Dt);
G4double y = G4RandGauss::shoot(0, sqrt_2Dt);
G4double z = G4RandGauss::shoot(0, sqrt_2Dt);
return sqrt(x * x + y * y + z * z);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4ChemReboundTransportation::GetTimeToBoundary(const G4Track& track)
{
if (!fpBoundingBox->contains(track.GetPosition())) {
G4ExceptionDescription errMsg;
errMsg << "Point is out of box : " << *fpBoundingBox
<< " of particle : " << GetIT(track)->GetName() << "(" << track.GetTrackID()
<< ") : " << track.GetPosition();
G4Exception(
"BoundedBrownianAction::GetTimeToBoundary"
"BoundedBrownianAction",
"BoundedBrownianAction", FatalErrorInArgument, errMsg);
}
auto diffusionCoefficient = GetMolecule(track)->GetDiffusionCoefficient();
auto dx = std::min(track.GetPosition().getX() - fpBoundingBox->Getxlo(),
fpBoundingBox->Getxhi() - track.GetPosition().getX());
auto dy = std::min(track.GetPosition().getY() - fpBoundingBox->Getylo(),
fpBoundingBox->Getyhi() - track.GetPosition().getY());
auto dz = std::min(track.GetPosition().getZ() - fpBoundingBox->Getzlo(),
fpBoundingBox->Getzhi() - track.GetPosition().getZ());
std::vector<G4double> distanceVector{dx, dy, dz};
G4double MinTime = DBL_MAX;
for (const auto& it : distanceVector) {
G4double distance = it;
auto random = G4UniformRand();
auto minTime = 1 / (4 * diffusionCoefficient) * pow(distance / InvErfc(random), 2);
if (MinTime > minTime) {
MinTime = minTime;
}
}
return MinTime;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -44,7 +44,7 @@
#include "G4MoleculeFinder.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VMoleculeCounter.hh"
#include "G4MoleculeCounterManager.hh"
#include <memory>
@@ -182,21 +182,17 @@ void G4DNAElectronHoleRecombination::MakeReaction(const G4Track& track)
if (pSelectedReactant != nullptr)
{
if (G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->
RemoveAMoleculeAtTime(GetMolecule(track)->GetMolecularConfiguration(),
track.GetGlobalTime(),
&(track.GetPosition()));
G4MoleculeCounterManager::Instance()->
RemoveMolecule(&track, track.GetGlobalTime());
}
GetMolecule(track)->ChangeConfigurationToLabel("H2Ovib");
if (G4VMoleculeCounter::Instance()->InUse())
if (G4MoleculeCounterManager::Instance()->GetIsActive())
{
G4VMoleculeCounter::Instance()->
AddAMoleculeAtTime(GetMolecule(track)->GetMolecularConfiguration(),
track.GetGlobalTime(),
&(track.GetPosition()));
G4MoleculeCounterManager::Instance()->
AddMolecule(&track, track.GetGlobalTime());
}
// fParticleChange.ProposeTrackStatus(fStopAndKill);
@@ -28,7 +28,6 @@
#include <G4VScheduler.hh>
#include <memory>
#include "G4Molecule.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4MolecularConfiguration.hh"
#include "G4UnitsTable.hh"
#include "G4TrackingInformation.hh"
@@ -38,6 +37,7 @@
#include "G4DNAScavengerMaterial.hh"
#include "G4MoleculeFinder.hh"
#include "G4Scheduler.hh"
#include "G4ChemicalMoleculeFinder.hh"
#ifndef State
# define State(theXInfo) (GetState<G4DNAScavengerProcessState>()->theXInfo)
@@ -124,10 +124,6 @@ G4double G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength(
{
G4Molecule* molecule = GetMolecule(track);
auto molConf = molecule->GetMolecularConfiguration();
// reset
fpMolecularConfiguration = nullptr;
fpMaterialConf = nullptr;
// this because process for moleculeDifinition not for configuration
// TODO: need change this
auto it = fConfMap.find(molConf);
@@ -135,6 +131,8 @@ G4double G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength(
{
return DBL_MAX;
}
fpMolecularConfiguration = nullptr;
fpMaterialConf = nullptr;
fpMolecularConfiguration = molConf;
auto MaterialMap = it->second;
@@ -150,20 +148,24 @@ G4double G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength(
G4double numMol =
fpScavengerMaterial->GetNumberMoleculePerVolumeUnitForMaterialConf(
matConf);
if(numMol == 0.0) // ie : not found
{
continue;
}
if(verboseLevel > 1)
{
G4cout << " Material of " << matConf->GetName() << " : " << numMol
<< G4endl;
}
// auto data = fReactionMap[mat_it];
if(numMol == 0 && matConf != fH2O){
continue;}
auto data = mat_it.second;
auto reactionRate = data->GetObservedReactionRateConstant(); //_const
G4double propensity =
numMol * reactionRate / (fpBoundingBox->Volume() * Avogadro);
if(fH2O == matConf){
auto factor = reactionRate;
propensity = factor;
}
if(verboseLevel > 1)
{
G4cout << " Material of " << matConf->GetName() << " : " << propensity
<< G4endl;
}
auto reactionData = std::make_pair(mat_it.first, propensity);
if(propensity == 0)
{
@@ -185,6 +187,13 @@ G4double G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength(
fpMaterialConf = rSelectedIter->second.first;
auto type = fConfMap[fpMolecularConfiguration][fpMaterialConf]->GetReactionType();
if(!fpScavengerMaterial->IsEquilibrium(type))
{
return DBL_MAX;
}
State(fIsInGoodMaterial) = true;
G4double previousTimeStep(-1.);
@@ -219,12 +228,6 @@ G4double G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength(
#ifdef G4VERBOSE
if(verboseLevel > 2)
{
G4cout << "G4DNAScavengerProcess::PostStepGetPhysicalInteractionLength:: "
<< molConf->GetName() << G4endl;
G4cout << "theNumberOfInteractionLengthLeft : "
<< fpState->theNumberOfInteractionLengthLeft << G4endl;
G4cout << "currentInteractionLength : " << fpState->currentInteractionLength
<< G4endl;
G4cout << "Material : " << fpMaterialConf->GetName()
<< " ID: " << track.GetTrackID()
<< " Track Time : " << track.GetGlobalTime()
@@ -249,50 +252,51 @@ G4VParticleChange* G4DNAScavengerProcess::PostStepDoIt(const G4Track& track,
{
G4Molecule* molecule = GetMolecule(track);
auto molConf = molecule->GetMolecularConfiguration();
if(fpMolecularConfiguration != molConf)
{
fReturnedValue = DBL_MAX;
fParticleChange.Initialize(track);
State(fPreviousTimeAtPreStepPoint) = -1;
return &fParticleChange;
}
std::vector<G4Track*> products;
#ifdef G4VERBOSE
if(verboseLevel > 1)
{
G4cout << "___________" << G4endl;
G4cout << ">>> Beginning of G4DNAScavengerProcess verbose" << G4endl;
G4cout << ">>> Returned value : " << G4BestUnit(fReturnedValue, "Time")
<< G4endl;
G4cout << ">>> Time Step : "
<< G4BestUnit(G4VScheduler::Instance()->GetTimeStep(), "Time")
<< G4endl;
G4cout << ">>> Global Time : "
<< G4BestUnit(G4VScheduler::Instance()->GetGlobalTime(), "Time")
<< G4endl;
G4cout << ">>> Global Time Track : "
<< G4BestUnit(track.GetGlobalTime(), "Time") << G4endl;
G4cout << ">>> Track Position : " << track.GetPosition() << G4endl;
G4cout << ">>> Reaction : " << molecule->GetName() << "("
<< track.GetTrackID() << ") + " << fpMaterialConf->GetName()
<< G4endl;
G4cout << ">>> End of G4DNAScavengerProcess verbose <<<" << G4endl;
G4cout << ">>> Beginning of G4DNAScavengerProcess verbose>>> Returned value : " << G4BestUnit(fReturnedValue, "Time")
<<"molecule: "<<molConf->GetName()<<G4endl;
G4cout<<" selected Mat : "<<fpMaterialConf->GetName()<< G4endl;
}
#endif
G4double reactionTime = track.GetGlobalTime();
auto data = fConfMap[fpMolecularConfiguration][fpMaterialConf];
auto data = fConfMap[molConf][fpMaterialConf];
if(data == nullptr)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription
<< "No reaction data for scavenger reaction between : "<<fpMaterialConf->GetName()
<<" + "<<molConf->GetName()<<G4endl;
G4Exception("G4DNAScavengerProcess::PostStepDoIt",
"G4DNAScavengerProcess0001111", FatalErrorInArgument,
exceptionDescription);
}
fpScavengerMaterial->SetEquilibrium(data, track.GetGlobalTime());
auto nbSecondaries = data->GetNbProducts();
for(G4int j = 0; j < nbSecondaries; ++j)
{
auto product = data->GetProduct(j);
auto isScavenger = fpScavengerMaterial->find(product);
if(isScavenger){
fpScavengerMaterial->
AddNumberMoleculePerVolumeUnitForMaterialConf(product,track.GetGlobalTime());
continue;
}
auto pProduct = new G4Molecule(data->GetProduct(j));
auto pProductTrack =
pProduct->BuildTrack(reactionTime, track.GetPosition());
pProductTrack->SetTrackStatus(fAlive);
G4ITTrackHolder::Instance()->Push(pProductTrack);
G4MoleculeFinder::Instance()->Push(pProductTrack);
if(!G4ChemicalMoleculeFinder::Instance()->IsOctreeUsed()){
G4MoleculeFinder::Instance()->Push(pProductTrack);
}
products.push_back(pProductTrack);
}
@@ -318,8 +322,28 @@ G4VParticleChange* G4DNAScavengerProcess::PostStepDoIt(const G4Track& track,
if(verboseLevel != 0)
{
G4cout << GetIT(products.at(i))->GetName() << " ("
<< products.at(i)->GetTrackID() << ")";
auto product = data->GetProduct(i);
auto isScavenger = fpScavengerMaterial->find(product);
if(isScavenger)
{
G4cout<<product->GetName()<<" (B)";
}
else
{
auto trackSize = products.size();
if(trackSize > 0)
{
for(G4int it = 0; it < (G4int)trackSize; ++it)
{
if((verboseLevel != 0) && it != 0)
{
G4cout << " + ";
}
G4cout << GetIT(products.at(it))->GetName() << " ("
<< products.at(it)->GetTrackID() << ")";
}
}
}
}
#endif
}
@@ -346,5 +370,12 @@ G4VParticleChange* G4DNAScavengerProcess::PostStepDoIt(const G4Track& track,
fpScavengerMaterial->ReduceNumberMoleculePerVolumeUnitForMaterialConf(
fpMaterialConf, reactionTime);
State(fPreviousTimeAtPreStepPoint) = -1;
if(fpMaterialConf == fH3Op
|| fpMaterialConf == fH2O
|| fpMaterialConf == fHOm) { // these scavengers are not changed
G4Scheduler::Instance()->SetInteractionStep(false);
}
return &fParticleChange;
}
@@ -53,7 +53,10 @@
#include "G4UImessenger.hh"
#include "G4VStateDependent.hh"
#include "G4MoleculeCounterManager.hh"
class G4Track;
class G4Run;
class G4DNAWaterExcitationStructure;
class G4DNAWaterIonisationStructure;
class G4Molecule;
@@ -150,9 +153,6 @@ public:
* in standalone.
*/
void UseAsStandalone(G4bool flag);
G4bool IsCounterResetWhenRunEnds() const;
void ResetCounterWhenRunEnds(G4bool resetCounterWhenRunEnds);
void ForceMasterReinitialization();
void TagThreadForReinitialization();
@@ -199,8 +199,17 @@ public:
void PushMolecule(std::unique_ptr<G4Molecule> pMolecule,
G4double time,
const G4ThreeVector& position,
G4int parentID);
const G4ThreeVector &position,
G4int parentID,
const G4Track *parentTrack = nullptr);
//============================================================================
// Methods called by RunManagers to notify of Runs & Events
//============================================================================
void BeginOfEventAction(const G4Event*);
void BeginOfRunAction(const G4Run*);
void EndOfEventAction(const G4Event*);
void EndOfRunAction(const G4Run*);
protected:
void HandleStandaloneInitialization();
@@ -251,5 +260,4 @@ private:
G4bool fGeometryClosed{false};
G4int fVerbose{0};
G4bool fResetCounterWhenRunEnds{true};
};
@@ -53,6 +53,7 @@ class G4DNAMesh : public G4VDNAMesh
Voxel& GetVoxel(const Index& index); // GetorCreateVoxel
size_t size() { return fVoxelVector.size(); };
Index ConvertIndex(const Index& index, const G4int&) const;
Index GetRandomIndex(const Index&, const G4double& resolution) const;
std::vector<Index> FindNeighboringVoxels(const Index& index) const;
void Reset();
Data& GetVoxelMapList(const Index& index);
@@ -0,0 +1,70 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Created 25.03.2025 V.Ivanchenko
// on base of codes of S.Incerti & M.Karamitros
//
// Double differential cross section data structure
//
#ifndef G4DNASamplingTable_HH
#define G4DNASamplingTable_HH 1
#include "globals.hh"
#include <vector>
class G4DNASamplingTable
{
public:
explicit G4DNASamplingTable(std::size_t npoint);
~G4DNASamplingTable();
void LoadData(const G4String& filename, G4double factorE, G4double scaleFactor,
G4bool verbose);
G4double GetValue(G4double ekinPrimary, G4double ekinSecondary, G4int shell) const;
G4double SampleCumulative(G4double ekinPrimary, G4int shell) const;
G4DNASamplingTable(const G4DNASamplingTable & copy) = delete;
G4DNASamplingTable& operator=(const G4DNASamplingTable& right) = delete;
private:
G4int GetIndex(const std::vector<G4double>&, G4double x) const;
G4double VecInterpolation(const std::vector<G4double>* ener,
const std::vector<G4double>* val, G4double energy) const;
G4double Interpolate(G4double e1, G4double e2, G4double e,
G4double xs1, G4double xs2) const;
G4int fNpoints{0};
std::vector<G4double> fPrimaryEnergy;
std::vector<std::vector<G4double>* > fSecEnergy;
std::vector<std::vector<G4double>* > fPDF[5];
};
#endif
@@ -30,9 +30,10 @@
#include "G4ios.hh"
#include <map>
#include <vector>
#include "G4MoleculeCounter.hh"
#include "G4VMoleculeCounterInternalBase.hh"
#include "G4VScavengerMaterial.hh"
#include "G4MoleculeTable.hh"
#include "G4ChemEquilibrium.hh"
class G4Material;
class G4MolecularConfiguration;
@@ -42,7 +43,7 @@ class G4DNAScavengerMaterial : public G4VScavengerMaterial
{
public:
using NbMoleculeInTime =
std::map<G4double, int64_t, G4::MoleculeCounter::TimePrecision>;
std::map<G4double, int64_t, G4::MoleculeCounter::FixedTimeComparer>;
using MolType = const G4MolecularConfiguration*;
using MaterialMap = std::map<MolType, int64_t>;
using ReactantList = std::vector<MolType>;
@@ -80,9 +81,7 @@ class G4DNAScavengerMaterial : public G4VScavengerMaterial
{
return it->second > 0;
}
return false;
}
void SetCounterAgainstTime() { fCounterAgainstTime = true; }
@@ -103,9 +102,13 @@ class G4DNAScavengerMaterial : public G4VScavengerMaterial
int64_t GetNMoleculesAtTime(MolType molecule, G4double time);
G4bool SearchTimeMap(MolType molecule);
int64_t SearchUpperBoundTime(G4double time, G4bool sameTypeOfMolecule);
void ResetEquilibrium();
G4bool SetEquilibrium(const G4DNAMolecularReactionData* pReaction,
G4double time);
G4bool IsEquilibrium(const G4int& reactionType) const;
private:
G4VChemistryWorld* fpChemistryInfo;
private:
G4VChemistryWorld* fpChemistryInfo = nullptr;
G4bool fIsInitialized;
MaterialMap fScavengerTable;
CounterMapType fCounterMap;
@@ -125,5 +128,6 @@ class G4DNAScavengerMaterial : public G4VScavengerMaterial
std::unique_ptr<Search> fpLastSearch;
void WaterEquilibrium();
std::map<G4int,std::unique_ptr<G4ChemEquilibrium>> fEquilibriumProcesses;
};
#endif // G4DNASCAVENGERMATERIAL_HH
@@ -0,0 +1,80 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
// Author: Christian Velten (2025)
#ifndef G4MoleculeReactionCounter_hh
#define G4MoleculeReactionCounter_hh 1
#include "G4DNAMolecularReactionTable.hh"
#include "G4VUserMoleculeReactionCounter.hh"
//------------------------------------------------------------------------------
struct G4MoleculeReactionCounterIndex : public G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex
{
const G4DNAMolecularReactionData* ReactionData;
G4MoleculeReactionCounterIndex() : ReactionData(nullptr) {}
explicit G4MoleculeReactionCounterIndex(const G4DNAMolecularReactionData* reaction) : ReactionData(reaction) {}
~G4MoleculeReactionCounterIndex() override = default;
G4bool operator<(G4VMoleculeReactionCounterIndex const& other) const override
{
return std::less{}(ReactionData, static_cast<const G4MoleculeReactionCounterIndex&>(other).ReactionData);
}
G4bool operator==(G4VMoleculeReactionCounterIndex const& other) const override
{
return std::equal_to{}(ReactionData, static_cast<const G4MoleculeReactionCounterIndex&>(other).ReactionData);
}
G4String FormattedReactionString(const G4DNAMolecularReactionData* reactionData) const;
G4String GetInfo() const override
{
G4String null = "This reaction data is null";
if (ReactionData == nullptr)
return null;
else
return FormattedReactionString(ReactionData);
}
const G4DNAMolecularReactionData* GetReactionData() const override { return ReactionData; }
};
class G4MoleculeReactionCounter : public G4VUserMoleculeReactionCounter<G4MoleculeReactionCounterIndex>
{
//----------------------------------------------------------------------------
public:
G4MoleculeReactionCounter();
G4MoleculeReactionCounter(G4String);
~G4MoleculeReactionCounter() override = default;
void InitializeUser() override;
public:
std::unique_ptr<G4VMoleculeReactionCounterIndex> BuildSimpleIndex(const G4DNAMolecularReactionData*) const override;
};
#endif // G4MoleculeReactionCounter_hh
@@ -97,64 +97,6 @@ protected:
};
//------------------------------------------------------------------------------
class G4Analysis: public G4VPhysChemIO
{
public:
G4Analysis(G4VAnalysisManager*);
~G4Analysis() override;
void InitializeMaster() override{}
void InitializeThread() override{}
void InitializeFile() override;
void NewRun() override{}
void NewEvent() override{}
/**
* Method used by DNA physics model to create a water molecule.
* The ElectronicModification is a flag telling wheter the molecule
* is ionized or excited, the electronic level is calculated by the
* model and the IncomingTrack is the track responsible for the creation
* of this molecule, for instance an electron.
*/
void CreateWaterMolecule(G4int electronicModif,
G4int /*electronicLevel*/,
G4double energy,
const G4Track* /*theIncomingTrack*/) override;
/**
* Same idea as the previous method but for solvated electron.
* This method should be used by the physics model of the ElectronSolvatation
* process.
*/
void CreateSolvatedElectron(const G4Track* /*theIncomingTrack*/,
G4ThreeVector* finalPosition = nullptr) override;
//============================================================================
// FILE OPERATIONS
//============================================================================
/**
* Tells the chemMan to write into a file
* the position and electronic state of the water molecule
* and the position thermalized or not of the solvated electron
*/
void WriteInto(const G4String&, std::ios_base::openmode mode =
std::ios_base::out) override;
void AddEmptyLineInOutputFile() override{}
/**
* Close the file specified with WriteInto
*/
void CloseFile() override;
protected:
G4VAnalysisManager* fpAnalysisManager;
int fNtupleID;
G4bool fFileInitialized;
};
}
#endif // G4PHYSCHEMIO_HH_
@@ -30,6 +30,7 @@
#include <memory>
#include <map>
#include "globals.hh"
class G4DNABoundingBox;
class G4Material;
class G4MolecularConfiguration;
@@ -72,9 +73,14 @@ class G4VChemistryWorld
{
return fpChemistryBoundary.get();
}
std::map<MolType,G4double> GetChemicalComponent() const
{
return fpChemicalComponent;
}
protected:
std::unique_ptr<G4DNABoundingBox> fpChemistryBoundary;
std::map<MolType,double> fpChemicalComponent;
std::map<MolType,G4double> fpChemicalComponent;
};
#endif
@@ -0,0 +1,437 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#ifndef G4VUSERMOLECULEREACTIONCOUNTER_HH
#define G4VUSERMOLECULEREACTIONCOUNTER_HH 1
#include "G4DNAChemistryManager.hh"
#include "G4MoleculeCounterTemplates.hh"
#include "G4Scheduler.hh"
#include "G4UnitsTable.hh"
#include "G4VMoleculeReactionCounter.hh"
//------------------------------------------------------------------------------
template<class TIndex>
class G4VUserMoleculeReactionCounter : public G4VMoleculeReactionCounter
{
static_assert(std::is_base_of<G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex, TIndex>::value,
"TIndex must be derived from G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex! "
"No forward declaration is allowed.");
protected:
struct Search;
public:
G4VUserMoleculeReactionCounter();
G4VUserMoleculeReactionCounter(const G4String&,
MoleculeReactionCounterType = MoleculeReactionCounterType::Basic);
~G4VUserMoleculeReactionCounter() override = default;
public:
void Initialize() final;
void InitializeUser() override = 0;
void ResetCounter() override;
void Dump() const override;
void DumpCounterMapIndices() const override;
void AbsorbCounter(const G4VMoleculeCounterInternalBase*) override;
std::unique_ptr<G4VMoleculeReactionCounterIndex> BuildSimpleIndex(const G4DNAMolecularReactionData*) const override = 0;
void RecordReaction(std::unique_ptr<G4VMoleculeReactionCounterIndex>, G4double, G4int = 1) override;
std::set<const G4DNAMolecularReactionData*> GetRecordedReactions() const override;
std::set<G4double> GetRecordedTimes() const override;
protected:
std::map<TIndex, InnerCounterMapType> fCounterMap{};
public:
const std::map<TIndex, InnerCounterMapType>& GetCounterMap() const { return fCounterMap; }
std::vector<TIndex> GetMapIndices() const;
virtual G4int GetNbReactionsAtTime(const TIndex&, G4double) const;
virtual G4int GetNbReactionsAtTime(Search&, const TIndex&, G4double) const;
virtual std::vector<G4int> GetNbReactionsAtTimes(const TIndex&,
const std::vector<G4double>&) const;
//-SEARCH-----------------------------------------------------------------------
protected:
struct Search
{
Search() : fLowerBoundSet(false) {}
typename std::map<TIndex, InnerCounterMapType>::const_iterator fLastIndexSearched;
InnerCounterMapType::const_iterator fLowerBoundTime;
G4bool fLowerBoundSet;
};
G4bool SearchIndexUpdated(Search&, const TIndex&) const;
G4int SearchUpperBoundTime(Search&, G4double, G4bool) const;
};
//------------------------------------------------------------------------------
// #include "G4VUserMoleculeReactionCounter.icc"
//------------------------------------------------------------------------------
template<typename T>
G4VUserMoleculeReactionCounter<T>::G4VUserMoleculeReactionCounter() : G4VMoleculeReactionCounter()
{}
//------------------------------------------------------------------------------
template<typename T>
G4VUserMoleculeReactionCounter<T>::G4VUserMoleculeReactionCounter(const G4String& name,
MoleculeReactionCounterType type)
: G4VMoleculeReactionCounter(name, type)
{}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeReactionCounter<TIndex>::Initialize()
{
InitializeUser();
fIsInitialized = true;
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4int G4VUserMoleculeReactionCounter<TIndex>::GetNbReactionsAtTime(const TIndex& index, G4double time) const
{
Search search = {};
return GetNbReactionsAtTime(search, index, time);
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4int G4VUserMoleculeReactionCounter<TIndex>::GetNbReactionsAtTime(Search& search,
const TIndex& index,
G4double time) const
{
G4bool sameIndex = !SearchIndexUpdated(search, index);
return SearchUpperBoundTime(search, time, sameIndex);
}
//------------------------------------------------------------------------------
template<typename TIndex>
std::vector<G4int> G4VUserMoleculeReactionCounter<TIndex>::GetNbReactionsAtTimes(
const TIndex& index, const std::vector<G4double>& times) const
{
Search search = {};
std::vector<G4int> counts = {};
for (auto time : times)
counts.push_back(GetNbReactionsAtTime(search, index, time));
return counts;
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeReactionCounter<TIndex>::RecordReaction(
std::unique_ptr<G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex> pIndex,
G4double time, G4int number)
{
const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
if (IsTimeAboveUpperBound(time)) {
if (fVerbose > 3) {
G4cout << "G4VUserMoleculeReactionCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">(" << GetName()
<< ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
G4cout << ":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true" << G4endl;
}
return;
}
else if (IsTimeBelowLowerBound(time)) {
if (fVerbose > 3) {
G4cout << "G4VUserMoleculeReactionCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">(" << GetName()
<< ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
G4cout << ":: [IsTimeBelowLowerBound] Skipping since IsTimeBelowLowerBound == true" << G4endl;
}
return;
}
if (fVerbose > 2) {
G4cout << "G4VUserMoleculeReactionCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">(" << GetName()
<< ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
<< " at time : " << G4BestUnit(time, "Time") << G4endl;
}
auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
if (indexIsNew || it->second.empty()) {
it->second.emplace(time, number);
// it->second[time] = number;
}
else {
if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent())
// can only do consistency check if the counters are cleared before each event
{
auto end = it->second.rbegin();
if ((end->first <= time || std::fabs(end->first - time) <= fTimeComparer.GetPrecisionAtTime(time)))
// Case 1 = new time comes after last recorded data
// Case 2 = new time is about the same as the last recorded one
{
// it->second[time] = end->second + number;
auto [it_time, _] = it->second.emplace(time, end->second);
it_time->second += number;
}
else {
G4ExceptionDescription errMsg;
errMsg << "Time of reaction " << mapIndex->GetReactionData()->GetReactionID() << " is "
<< G4BestUnit(time, "Time") << "while the global time is "
<< G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
<< "(last counter time: " << G4BestUnit(end->first, "Time") << ")" << G4endl;
G4Exception(G4String("G4VUserMoleculeReactionCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
+ ">::RecordReaction"),
"TIME_DONT_MATCH", FatalException, errMsg);
}
}
else {
// since counters are not cleared after chemical run (i.e., after event)
// there will already be numbers in the map, so...
// (1) find the closest time
// (2) emplace entry using closest value as init + number
// (3) add number to all "future" entries as well
auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(it->second, time);
auto [it_new, _] = it->second.emplace(time, it_closest->second);
do {
it_new->second += number;
} while (++it_new != it->second.end());
}
}
}
//------------------------------------------------------------------------------
template<typename TIndex>
std::vector<TIndex> G4VUserMoleculeReactionCounter<TIndex>::GetMapIndices() const
{
if (fVerbose > 2) {
G4cout << "Entering in G4VUserMoleculeReactionCounter::GetMapIndices" << G4endl;
}
return G4::MoleculeCounter::GetMapIndices(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
std::set<const G4DNAMolecularReactionData*> G4VUserMoleculeReactionCounter<T>::GetRecordedReactions() const
{
if (fVerbose > 2) {
G4cout << "Entering in G4VUserMoleculeReactionCounter::GetRecordedReactions" << G4endl;
}
std::set<const G4DNAMolecularReactionData*> output{};
for (const auto& it : fCounterMap) {
output.insert(it.first.GetReactionData());
}
return output;
}
//------------------------------------------------------------------------------
template<typename T>
std::set<G4double> G4VUserMoleculeReactionCounter<T>::GetRecordedTimes() const
{
return G4::MoleculeCounter::GetRecordedTimes<T>(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
void G4VUserMoleculeReactionCounter<T>::Dump() const
{
DumpCounterMapIndices();
G4::MoleculeCounter::DumpCounterMapContents<T>(fCounterMap);
}
template<typename T>
void G4VUserMoleculeReactionCounter<T>::DumpCounterMapIndices() const
{
G4::MoleculeCounter::DumpCounterMapIndices<T>(fCounterMap);
}
//------------------------------------------------------------------------------
template<typename T>
void G4VUserMoleculeReactionCounter<T>::ResetCounter()
{
if (fVerbose > 1) {
G4cout << "G4VUserMoleculeReactionCounter<" << G4::MoleculeCounter::GetTemplateTypeName<T>()
<< ">(" << GetName() << ")::ResetCounter" << G4endl;
}
fCounterMap.clear();
}
//------------------------------------------------------------------------------
template<typename TIndex>
G4bool G4VUserMoleculeReactionCounter<TIndex>::SearchIndexUpdated(Search& search, const TIndex& index) const
{
if (search.fLowerBoundSet && !(search.fLastIndexSearched->first < index)
&& !(index < search.fLastIndexSearched->first))
{
return true;
}
auto mol_it = fCounterMap.find(index);
search.fLastIndexSearched = mol_it;
if (mol_it != fCounterMap.end()) {
search.fLowerBoundTime = search.fLastIndexSearched->second.end();
search.fLowerBoundSet = true;
}
else {
search.fLowerBoundSet = false;
}
return false;
}
//------------------------------------------------------------------------------
template<typename T>
G4int G4VUserMoleculeReactionCounter<T>::SearchUpperBoundTime(Search& search, G4double time, G4bool sameIndex) const
{
auto mol_it = search.fLastIndexSearched;
if (mol_it == fCounterMap.end()) {
return 0;
}
InnerCounterMapType const& timeMap = mol_it->second;
if (timeMap.empty()) {
return 0;
}
if (sameIndex) {
if (search.fLowerBoundSet && search.fLowerBoundTime != timeMap.end()) {
if (search.fLowerBoundTime->first < time) {
auto upperToLast = search.fLowerBoundTime;
upperToLast++;
if (upperToLast == timeMap.end()) {
return search.fLowerBoundTime->second;
}
if (upperToLast->first > time) {
return search.fLowerBoundTime->second;
}
}
}
}
auto up_time_it = timeMap.upper_bound(time);
if (up_time_it == timeMap.end()) {
auto last_time = timeMap.rbegin();
return last_time->second;
}
if (up_time_it == timeMap.begin()) {
return 0;
}
up_time_it--;
search.fLowerBoundTime = up_time_it;
search.fLowerBoundSet = true;
return search.fLowerBoundTime->second;
}
//------------------------------------------------------------------------------
template<typename TIndex>
void G4VUserMoleculeReactionCounter<TIndex>::AbsorbCounter(
const G4VMoleculeCounterInternalBase* pCounterBase)
{
if (pCounterBase == nullptr) {
G4ExceptionDescription errMsg;
errMsg << "Could not cast the pointer to type G4VUserMoleculeReactionCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
<< "Because the pointer is nullptr!" << G4endl;
G4Exception(G4String("G4VUserMoleculeReactionCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"BAD_REFERENCE", FatalException, errMsg);
}
auto pCounter = dynamic_cast<G4VUserMoleculeReactionCounter<TIndex> const*>(pCounterBase);
if (pCounter == nullptr) {
G4ExceptionDescription errMsg;
errMsg << "Could not cast the pointer to type G4VUserMoleculeReactionCounter<"
<< G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
<< "Because the objects aren't of the same type!" << G4endl;
G4Exception(G4String("G4VUserMoleculeReactionCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"BAD_REFERENCE", FatalException, errMsg);
}
if (pCounter->GetType() != GetType()) {
G4ExceptionDescription errMsg;
errMsg << "You are trying to absorb a counter with different type!" << G4endl;
G4Exception(G4String("G4VUserMoleculeReactionCounter<"
+ G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
"TYPE_DIFF", JustWarning, errMsg);
}
for (auto const& worker_it : pCounter->GetCounterMap()) {
auto [master_it, indexIsNew] =
fCounterMap.emplace(worker_it.first, InnerCounterMapType{fTimeComparer});
G4int currentNumber = 0, previousNumber = 0;
for (auto const& [time, number] : worker_it.second) {
currentNumber = number - previousNumber;
previousNumber = number;
if (master_it->second.empty()) {
master_it->second.emplace(time, currentNumber);
}
else { // at least one element exists, so we can try to find the closest key
auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(master_it->second, time);
auto [it, _] = master_it->second.emplace(time, it_closest->second);
do {
it->second += currentNumber;
} while (++it != master_it->second.end());
}
}
}
}
//------------------------------------------------------------------------------
#endif
@@ -18,6 +18,7 @@ geant4_add_module(G4emdna-utils
G4DNAPTBExcitationStructure.hh
G4DNAPTBIonisationStructure.hh
G4DNARevertProbability.hh
G4DNASamplingTable.hh
G4DNAWaterExcitationStructure.hh
G4DNAWaterIonisationStructure.hh
G4ErrorFunction.hh
@@ -36,6 +37,9 @@ geant4_add_module(G4emdna-utils
G4DNAEventSet.hh
G4ChemicalMoleculeFinder.hh
G4DNAMaterialManager.hh
G4MoleculeReactionCounter.hh
G4VUserMoleculeReactionCounter.hh
G4ChemEquilibrium.hh
SOURCES
G4DNAChemistryManager.cc
G4DNACPA100LogLogInterpolation.cc
@@ -51,6 +55,7 @@ geant4_add_module(G4emdna-utils
G4DNAEmfietzoglouWaterIonisationStructure.cc
G4DNAPTBExcitationStructure.cc
G4DNAPTBIonisationStructure.cc
G4DNASamplingTable.cc
G4DNAWaterExcitationStructure.cc
G4DNAWaterIonisationStructure.cc
G4ErrorFunction.cc
@@ -59,14 +64,15 @@ geant4_add_module(G4emdna-utils
G4ReactionTableMessenger.cc
G4VDNAReactionModel.cc
G4VUserChemistryList.cc
# physchemIO
G4VPhysChemIO.cc
G4PhysChemIO.cc
G4IRTUtils.cc
G4DNAScavengerMaterial.cc
G4DNAMesh.cc
G4DNAEventSet.cc
G4DNAMaterialManager.cc)
G4DNAMaterialManager.cc
G4ChemEquilibrium.cc
G4MoleculeReactionCounter.cc)
geant4_module_link_libraries(G4emdna-utils
PUBLIC
@@ -77,8 +83,8 @@ geant4_module_link_libraries(G4emdna-utils
G4intercoms
G4partman
PRIVATE
G4analysismng
G4emdna-moltypes
G4emutils
G4geometrymng
G4heprandom
G4ions
@@ -36,6 +36,7 @@ G4ChemEquilibrium::G4ChemEquilibrium(const G4int& type, const G4double& time)
void G4ChemEquilibrium::Initialize()
{
Reset();
MolType H2O =
G4MoleculeTable::Instance()->GetConfiguration("H2O");
MolType H3OpB =
@@ -95,6 +96,9 @@ void G4ChemEquilibrium::PrintInfo() const
void G4ChemEquilibrium::SetEquilibrium(Reaction pReaction)
{
if(pReaction == nullptr){
return;
}
if(pReaction->GetReactionType() != fRectionType)
{
std::vector<MolType> molVector;
@@ -113,7 +117,8 @@ void G4ChemEquilibrium::SetEquilibrium(Reaction pReaction)
{
fAddEquilibrium = true;
fEquilibriumTime = fGlobalTime;
if(fVerbose >1) {
if(fVerbose >1)
{
G4cout << "Reaction type : " << pReaction->GetReactionType() << " : "
<< pReaction->GetReactant1()->GetName() << " + "
<< pReaction->GetReactant2()->GetName() << G4endl;
@@ -46,6 +46,7 @@
#include "G4H2O.hh"
#include "G4MolecularConfiguration.hh"
#include "G4Molecule.hh"
#include "G4MoleculeCounterManager.hh"
#include "G4MoleculeFinder.hh"
#include "G4MoleculeTable.hh"
#include "G4PhysChemIO.hh"
@@ -186,7 +187,8 @@ void G4DNAChemistryManager::Clear()
G4DNAMolecularReactionTable::DeleteInstance();
G4MolecularConfiguration::DeleteManager();
G4VMoleculeCounter::DeleteInstance();
if (G4MoleculeCounterManager::GetInstanceIfExists() != nullptr)
G4MoleculeCounterManager::DeleteInstance();
}
//------------------------------------------------------------------------------
@@ -325,11 +327,9 @@ void G4DNAChemistryManager::Run()
}
G4MoleculeTable::Instance()->Finalize();
G4Scheduler::Instance()->Process();
if (fResetCounterWhenRunEnds)
{
G4VMoleculeCounter::Instance()->ResetCounter();
}
CloseFile();
}
@@ -418,6 +418,10 @@ void G4DNAChemistryManager::InitializeMaster()
G4Scheduler::Instance();
// creates a concrete object of the scheduler
if (G4MoleculeCounterManager::GetInstanceIfExists() != nullptr)
G4MoleculeCounterManager::Instance()->Initialize();
fMasterInitialized = true;
}
@@ -484,9 +488,10 @@ void G4DNAChemistryManager::InitializeThread()
G4Scheduler::Instance()->Initialize();
fpThreadData->fThreadInitialized = true;
if (G4MoleculeCounterManager::GetInstanceIfExists() != nullptr)
G4MoleculeCounterManager::Instance()->Initialize();
G4VMoleculeCounter::InitializeInstance();
fpThreadData->fThreadInitialized = true;
InitializeFile();
}
@@ -647,8 +652,9 @@ void G4DNAChemistryManager::CreateWaterMolecule(ElectronicModification modificat
}
}
G4Track* pH2OTrack = pH2OMolecule->BuildTrack(picosecond + delayedTime,
pIncomingTrack->GetPosition());
G4Track *pH2OTrack = pH2OMolecule->BuildTrack(picosecond + delayedTime,
pIncomingTrack->GetPosition(),
pIncomingTrack);
pH2OTrack->SetParentID(pIncomingTrack->GetTrackID());
pH2OTrack->SetTrackStatus(fStopButAlive);
@@ -683,8 +689,9 @@ void G4DNAChemistryManager::CreateSolvatedElectron(const G4Track* pIncomingTrack
PushMolecule(std::make_unique<G4Molecule>(G4Electron_aq::Definition()),
picosecond + delayedTime,
pFinalPosition != nullptr ? *pFinalPosition : pIncomingTrack->GetPosition(),
pIncomingTrack->GetTrackID());
pFinalPosition ? *pFinalPosition : pIncomingTrack->GetPosition(),
pIncomingTrack->GetTrackID(),
pIncomingTrack);
}
}
@@ -692,13 +699,14 @@ void G4DNAChemistryManager::CreateSolvatedElectron(const G4Track* pIncomingTrack
void G4DNAChemistryManager::PushMolecule(std::unique_ptr<G4Molecule> pMolecule,
double time,
const G4ThreeVector& position,
int parentID)
const G4ThreeVector &position,
int parentID,
const G4Track *parentTrack)
{
assert(fActiveChemistry
&& "To inject chemical species, the chemistry must be activated. "
"Check chemistry activation before injecting species.");
G4Track* pTrack = pMolecule->BuildTrack(time, position);
G4Track* pTrack = pMolecule->BuildTrack(time, position, parentTrack);
pTrack->SetTrackStatus(fAlive);
pTrack->SetParentID(parentID);
pMolecule.release();
@@ -767,16 +775,30 @@ void G4DNAChemistryManager::SetVerbose(G4int verbose)
//------------------------------------------------------------------------------
G4bool G4DNAChemistryManager::IsCounterResetWhenRunEnds() const
void G4DNAChemistryManager::BeginOfEventAction(const G4Event* pEvent)
{
return fResetCounterWhenRunEnds;
G4MoleculeCounterManager::Instance()->BeginOfEventAction(pEvent);
}
//------------------------------------------------------------------------------
void G4DNAChemistryManager::ResetCounterWhenRunEnds(G4bool resetCounterWhenRunEnds)
void G4DNAChemistryManager::BeginOfRunAction(const G4Run* pRun)
{
fResetCounterWhenRunEnds = resetCounterWhenRunEnds;
G4MoleculeCounterManager::Instance()->BeginOfRunAction(pRun);
}
//------------------------------------------------------------------------------
void G4DNAChemistryManager::EndOfEventAction(const G4Event* pEvent)
{
G4MoleculeCounterManager::Instance()->EndOfEventAction(pEvent);
}
//------------------------------------------------------------------------------
void G4DNAChemistryManager::EndOfRunAction(const G4Run* pRun) // for potential future use
{
G4MoleculeCounterManager::Instance()->EndOfRunAction(pRun);
}
//------------------------------------------------------------------------------
@@ -65,6 +65,10 @@ void Event::PrintEvent() const
G4bool comparatorEventSet::operator()(std::unique_ptr<Event> const& rhs,
std::unique_ptr<Event> const& lhs) const
{
if(rhs->GetTime() == lhs->GetTime())
{
return rhs->GetIndex() < lhs->GetIndex();
}
return rhs->GetTime() < lhs->GetTime();
}
@@ -26,6 +26,7 @@
#include <algorithm>
#include <ostream>
#include "G4ITTrackHolder.hh"
#include "Randomize.hh"
std::ostream& operator<<(std::ostream& stream, const G4VDNAMesh::Index& rhs)
{
@@ -232,3 +233,32 @@ G4VDNAMesh::Index G4DNAMesh::ConvertIndex(const Index& index,
}
return Index{ dx, dy, dz };
}
G4VDNAMesh::Index G4DNAMesh:: GetRandomIndex(const Index& oldIndex, const G4double& OldReso) const
{
G4double x_min = oldIndex.x * OldReso;
G4double x_max = (oldIndex.x + 1) * OldReso;
G4double y_min = oldIndex.y * OldReso;
G4double y_max = (oldIndex.y + 1) * OldReso;
G4double z_min = oldIndex.z * OldReso;
G4double z_max = (oldIndex.z + 1) * OldReso;
G4int i_max = std::floor(x_max / fResolution);
G4int j_max = std::floor(y_max / fResolution);
G4int k_max = std::floor(z_max / fResolution);
G4int i_min = std::floor(x_min / fResolution);
G4int j_min = std::floor(y_min / fResolution);
G4int k_min = std::floor(z_min / fResolution);
G4double r1 = G4UniformRand();
G4double r2 = G4UniformRand();
G4double r3 = G4UniformRand();
G4int i_n = i_min + (G4int)std::floor(r1 * (i_max - i_min + 1));
G4int j_n = j_min + (G4int)std::floor(r2 * (j_max - j_min + 1));
G4int k_n = k_min + (G4int)std::floor(r3 * (k_max - k_min + 1));
return Index{ i_n, j_n, k_n };
}
@@ -292,15 +292,20 @@ void G4DNAMolecularReactionData::SetReactionType(G4int type)
fDiffusionRate = 4 * pi * sumDiffCoeff * fReactionRadius * Avogadro;
if (fpReactant1 == fpReactant2) fDiffusionRate/=2;
fActivationRate = fDiffusionRate * fObservedReactionRate / (fDiffusionRate - fObservedReactionRate);
fProbability = Rs / (Rs + (fDiffusionRate / fActivationRate) * (fReactionRadius + Rs));
if(fActivationRate > 0) {
fProbability =
Rs / (Rs + (fDiffusionRate / fActivationRate) * (fReactionRadius + Rs));
}
}else{ // Type IV
fEffectiveReactionRadius = -fOnsagerRadius/(1-exp(fOnsagerRadius/fReactionRadius));
fDiffusionRate = 4 * pi * sumDiffCoeff * fEffectiveReactionRadius * Avogadro;
if (fpReactant1 == fpReactant2) fDiffusionRate/=2;
fActivationRate = fDiffusionRate * fObservedReactionRate / (fDiffusionRate - fObservedReactionRate);
fProbability = Rs / (Rs + (fDiffusionRate / fActivationRate) * (fEffectiveReactionRadius + Rs));
if(fActivationRate > 0) {
fProbability =
Rs / (Rs + (fDiffusionRate / fActivationRate) * (fEffectiveReactionRadius + Rs));
}
}
}
@@ -0,0 +1,221 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
#include "G4DNASamplingTable.hh"
#include "G4EmParameters.hh"
#include "Randomize.hh"
#include "G4Log.hh"
#include "G4Exp.hh"
#include <vector>
#include <fstream>
#include <sstream>
G4DNASamplingTable::G4DNASamplingTable(std::size_t npoints)
{
fPrimaryEnergy.reserve(npoints);
fSecEnergy.reserve(npoints);
for (G4int i=0; i<5; ++i) { (fPDF[i]).reserve(npoints); }
}
G4DNASamplingTable::~G4DNASamplingTable()
{
for (auto & p : fSecEnergy) { delete p; }
for (G4int i=0; i<5; ++i) {
for (auto & p : fPDF[i]) { delete p; }
}
}
void G4DNASamplingTable::LoadData(const G4String& fname, G4double factE,
G4double fact, G4bool verbose)
{
std::ostringstream ost;
ost << G4EmParameters::Instance()->GetDirLEDATA() << "/" << fname;
std::ifstream fin(ost.str().c_str());
if (!fin.is_open()) {
G4ExceptionDescription ed;
ed << "File <" << ost.str().c_str() << "> is not opened!";
G4Exception("G4DNASamplingTable::LoadDifferential ", "em0003",
FatalException, ed, "");
return;
}
G4double t, e, sig;
G4double e0{0.0};
G4int ntmax{0};
G4int nt{0};
std::vector<G4double>* v = nullptr;
std::vector<G4double>* vPDF[5];
for (;;) {
fin >> e;
if (fin.eof()) { break; }
if (e != e0 || nullptr == v) {
fPrimaryEnergy.push_back(e*factE);
e0 = e;
++fNpoints;
v = new std::vector<G4double>;
fSecEnergy.push_back(v);
for (G4int i=0; i<5; ++i) {
vPDF[i] = new std::vector<G4double>;
(fPDF[i]).push_back(vPDF[i]);
}
ntmax = std::max(ntmax, nt);
nt = 0;
}
fin >> t;
v->push_back(t*factE);
++nt;
for (G4int i=0; i<5; ++i) {
fin >> sig;
sig *= fact;
(vPDF[i])->push_back(sig);
}
if (fin.eof()) { break; }
}
if (verbose) {
G4cout << "G4DNASamplingTable::LoadData from file:" << G4endl;
G4cout << fname << G4endl;
G4cout << " Nenergy= " << fNpoints << " NmaxT= " << ntmax << G4endl;
}
if (fNpoints > 0) { --fNpoints; }
}
G4double G4DNASamplingTable::GetValue(G4double ekinPrimary,
G4double ekinSec, G4int shell) const
{
std::vector<G4double>* e1{nullptr};
std::vector<G4double>* e2{nullptr};
std::vector<G4double>* s1{nullptr};
std::vector<G4double>* s2{nullptr};
G4int idx = GetIndex(fPrimaryEnergy, ekinPrimary);
if (idx == -1) {
e1 = fSecEnergy[0];
s1 = (fPDF[shell])[0];
} else if (idx > fNpoints) {
e1 = fSecEnergy[fNpoints];
s1 = (fPDF[shell])[fNpoints];
} else {
e1 = fSecEnergy[idx];
s1 = (fPDF[shell])[idx];
e2 = fSecEnergy[idx + 1];
s2 = (fPDF[shell])[idx + 1];
}
// edge cases
G4double res1 = VecInterpolation(e1, s1, ekinSec);
if (nullptr == e2) { return res1; }
// ordinary case
G4double res2 = VecInterpolation(e2, s2, ekinSec);
G4double res = Interpolate(fPrimaryEnergy[idx], fPrimaryEnergy[idx + 1],
ekinPrimary, res1, res2);
return res;
}
G4int G4DNASamplingTable::GetIndex(const std::vector<G4double>& v, G4double x) const
{
G4int idx;
if (x <= v[0]) { idx = -1; }
else if (x >= v.back()) { idx = (G4int)v.size(); }
else {
std::size_t i = std::upper_bound(v.cbegin(), v.cend(), x) - v.cbegin() - 1;
idx = (G4int)i;
}
return idx;
}
G4double G4DNASamplingTable::VecInterpolation(const std::vector<G4double>* ener,
const std::vector<G4double>* val,
G4double e) const
{
G4int idx = GetIndex(*ener, e);
G4double res;
if (idx == -1) { res = (*val)[0]; }
else if (e >= ener->back()) { res = val->back(); }
else {
res = Interpolate((*ener)[idx], (*ener)[idx + 1], e, (*val)[idx], (*val)[idx + 1]);
}
return res;
}
G4double G4DNASamplingTable::Interpolate(G4double e1, G4double e2, G4double e,
G4double xs1, G4double xs2) const
{
G4double res;
// special case
if (e1 == e2) {
res = 0.5 * (xs1 + xs2);
// Log-log interpolation by default
} else if (e1 > 0.0 && e2 > 0.0 && xs1 > 0.0 && xs2 > 0.0) {
G4double y = G4Log(xs1) + G4Log(e/e1) * G4Log(xs2/xs1)/G4Log(e2/e1);
res = G4Exp(y);
// Lin-Log interpolation
} else if (xs1 > 0.0 && xs2 > 0.0) {
G4double y = G4Log(xs1) + (e - e1) * G4Log(xs2/xs1)/(e2 - e1);
res = G4Exp(y);
// Lin-Lin interpolation
} else {
res = xs1 + (e - e1) * (xs2 - xs1)/(e2 - e1);
}
return res;
}
G4double
G4DNASamplingTable::SampleCumulative(G4double ekinPrimary, G4int shell) const
{
std::vector<G4double>* e1{nullptr};
std::vector<G4double>* e2{nullptr};
std::vector<G4double>* s1{nullptr};
std::vector<G4double>* s2{nullptr};
G4int idx = GetIndex(fPrimaryEnergy, ekinPrimary);
if (idx == -1) {
e1 = fSecEnergy[0];
s1 = (fPDF[shell])[0];
} else if (idx > fNpoints) {
e1 = fSecEnergy[fNpoints];
s1 = (fPDF[shell])[fNpoints];
} else {
e1 = fSecEnergy[idx];
s1 = (fPDF[shell])[idx];
e2 = fSecEnergy[idx + 1];
s2 = (fPDF[shell])[idx + 1];
}
G4double q = G4UniformRand();
// edge cases
G4double res1 = VecInterpolation(s1, e1, q);
if (nullptr == e2) { return res1; }
// ordinary case
G4double res2 = VecInterpolation(s2, e2, q);
G4double res = Interpolate(fPrimaryEnergy[idx], fPrimaryEnergy[idx + 1],
ekinPrimary, res1, res2);
return res;
}
@@ -60,6 +60,19 @@ void G4DNAScavengerMaterial::Initialize()
G4cout << "G4DNAScavengerMaterial existed but empty" << G4endl;
}
Reset();
fEquilibriumProcesses.emplace(
std::make_pair(6, std::make_unique<G4ChemEquilibrium>(6, 10 * CLHEP::us)));//reactionType6 and 10 * us
fEquilibriumProcesses.emplace(
std::make_pair(7, std::make_unique<G4ChemEquilibrium>(7, 10 * CLHEP::us)));//reactionType6 and 10 * us
fEquilibriumProcesses.emplace(
std::make_pair(8, std::make_unique<G4ChemEquilibrium>(8, 10 * CLHEP::us)));//reactionType6 and 10 * us
for(auto& it : fEquilibriumProcesses)
{
it.second->Initialize();
it.second->SetVerbose(fVerbose);
}
fIsInitialized = true;
}
@@ -68,10 +81,7 @@ G4DNAScavengerMaterial::GetNumberMoleculePerVolumeUnitForMaterialConf(MolType ma
{
// no change these molecules
if (fH2O == matConf) {
G4ExceptionDescription exceptionDescription;
exceptionDescription << "matConf : " << matConf->GetName();
G4Exception("G4DNAScavengerMaterial::GetNumberMoleculePerVolumeUnitForMaterialConf",
"G4DNAScavengerMaterial001", FatalErrorInArgument, exceptionDescription);
return 0;
}
auto iter = fScavengerTable.find(matConf);
@@ -118,7 +128,7 @@ void G4DNAScavengerMaterial::AddNumberMoleculePerVolumeUnitForMaterialConf(MolTy
// no change these molecules
if (fH2O == matConf || fH3Op == matConf || // pH has no change
G4MoleculeTable::Instance()->GetConfiguration("OHm(B)") == matConf)
fHOm == matConf)
{
// G4cout<<"moletype : "<<matConf->GetName()<<G4endl;
// kobs is already counted these molecule concentrations
@@ -173,6 +183,8 @@ void G4DNAScavengerMaterial::Reset()
return;
}
ResetEquilibrium();
fScavengerTable.clear();
fCounterMap.clear();
fpLastSearch.reset(nullptr);
@@ -213,12 +225,17 @@ void G4DNAScavengerMaterial::AddAMoleculeAtTime(MolType molecule, G4double time,
auto end = counterMap_i->second.rbegin();
if (end->first <= time
|| fabs(end->first - time) <= G4::MoleculeCounter::TimePrecision::fPrecision) {
|| fabs(end->first - time) <= G4::MoleculeCounter::FixedTimeComparer::fPrecision) {
G4double newValue = end->second + number;
counterMap_i->second[time] = newValue;
if (newValue != (floor)(fScavengerTable[molecule])) // protection
{
G4String errMsg = "You are trying to add wrong molecule ";
G4String errMsg = "You are trying to add wrong molecule : ";
G4cout<< " newValue : "<<newValue<<" " << molecule->GetName()
<< " at time : " << G4BestUnit(time, "Time")
<< " with number : " << number
<<" (floor)(fScavengerTable[molecule]) : "<<(floor)(fScavengerTable[molecule])
<< " and the final number is not valid." << G4endl;
G4Exception("AddAMoleculeAtTime", "", FatalErrorInArgument, errMsg);
}
}
@@ -427,4 +444,37 @@ G4double G4DNAScavengerMaterial::GetpH()
fScavengerTable[fHOm] = 0;
}
return -pH;
}
G4bool G4DNAScavengerMaterial::SetEquilibrium(const G4DNAMolecularReactionData* pReaction,
G4double time)
{
for(auto& it : fEquilibriumProcesses)
{
it.second->SetGlobalTime(time);
it.second->SetEquilibrium(pReaction);
if(it.second->IsStatusChanged()) return true;
}
return false;
}
void G4DNAScavengerMaterial::ResetEquilibrium()
{
for(auto& it : fEquilibriumProcesses)
{
it.second->Reset();
}
}
G4bool G4DNAScavengerMaterial::IsEquilibrium(const G4int& reactionType) const
{
auto reaction = fEquilibriumProcesses.find(reactionType);
if(reaction == fEquilibriumProcesses.end())
{
return true;
}else
{
return (reaction->second->GetEquilibriumStatus());
}
}
@@ -0,0 +1,79 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Author: Christian Velten (2025)
#include "G4MoleculeReactionCounter.hh"
//------------------------------------------------------------------------------
G4String G4MoleculeReactionCounterIndex::FormattedReactionString(const G4DNAMolecularReactionData* reactionData) const
{
const G4MolecularConfiguration* reactant1 = reactionData->GetReactant1();
const G4MolecularConfiguration* reactant2 = reactionData->GetReactant2();
const std::vector<const G4MolecularConfiguration*>* products = reactionData->GetProducts();
G4String reactionLhs = "";
if (reactant1 != nullptr) {
reactionLhs += reactant1->GetUserID();
if (reactant2 != nullptr) reactionLhs += " + ";
}
if (reactant2 != nullptr) reactionLhs += reactant2->GetUserID();
G4String reactionRhs = "";
for (auto it = products->cbegin(); it != products->cend(); ++it) {
if (*it != nullptr) {
if (it != products->cbegin() && reactionRhs.size() > 0) reactionRhs += " + ";
reactionRhs += (*it)->GetUserID();
}
}
G4String reactionString = reactionLhs + " -> " + reactionRhs;
return reactionString;
}
//------------------------------------------------------------------------------
G4MoleculeReactionCounter::G4MoleculeReactionCounter() : G4VUserMoleculeReactionCounter() {}
G4MoleculeReactionCounter::G4MoleculeReactionCounter(G4String name)
: G4VUserMoleculeReactionCounter(std::move(name), MoleculeReactionCounterType::Basic)
{}
//------------------------------------------------------------------------------
void G4MoleculeReactionCounter::InitializeUser() {}
//------------------------------------------------------------------------------
std::unique_ptr<G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex>
G4MoleculeReactionCounter::BuildSimpleIndex(const G4DNAMolecularReactionData* reactionData) const
{
return std::make_unique<G4MoleculeReactionCounterIndex>(reactionData);
}
//------------------------------------------------------------------------------
@@ -33,7 +33,6 @@
#include "G4PhysChemIO.hh"
#include "G4SystemOfUnits.hh"
#include "G4Track.hh"
#include "G4VAnalysisManager.hh"
using namespace std;
@@ -42,7 +41,6 @@ using namespace std;
namespace G4PhysChemIO{
FormattedText::FormattedText(){
fRunID = -1;
fEventID = -1;
fFileInitialized = false;
}
@@ -154,155 +152,4 @@ void FormattedText::CreateSolvatedElectron(const G4Track* theIncomingTrack,
fOfstream << G4endl;
}
//------------------------------------------------------------------------------
//
// Using G4analysis
//
G4Analysis::G4Analysis(G4VAnalysisManager* analysisManager):
fpAnalysisManager(analysisManager)
{
fFileInitialized = false;
fNtupleID = -1;
}
//------------------------------------------------------------------------------
G4Analysis::~G4Analysis()
{
fpAnalysisManager = nullptr;
}
//------------------------------------------------------------------------------
void G4Analysis::InitializeFile()
{
if (fFileInitialized) return;
fNtupleID = fpAnalysisManager->CreateNtuple("PhysChem","PhysChem");
fpAnalysisManager->CreateNtupleIColumn(fNtupleID, "ParentID");
fpAnalysisManager->CreateNtupleSColumn(fNtupleID, "Molecule");
//----------------------------------------------------------------------------
// valid for H2O only
fpAnalysisManager->CreateNtupleIColumn(fNtupleID, "ElectronicModif");
// ionization = 0 / excitation = 1 / diss att = 2
fpAnalysisManager->CreateNtupleIColumn(fNtupleID, "level");
// valid for ion and exc only
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "Energy_eV");
// valid for ion and exc only
//----------------------------------------------------------------------------
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "x_parent_nm");
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "y_parent_nm");
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "z_parent_nm");
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "x_nm");
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "y_nm");
fpAnalysisManager->CreateNtupleDColumn(fNtupleID, "z_nm");
fpAnalysisManager->FinishNtuple(fNtupleID);
fFileInitialized = true;
}
//------------------------------------------------------------------------------
void G4Analysis::WriteInto(const G4String& output,
ios_base::openmode)
{
fpAnalysisManager->OpenFile(output);
fFileInitialized = false;
}
//------------------------------------------------------------------------------
void G4Analysis::CloseFile()
{
// fpAnalysisManager->Write();
// fpAnalysisManager->CloseFile();
}
//------------------------------------------------------------------------------
void G4Analysis::CreateWaterMolecule(G4int modification,
G4int electronicLevel,
G4double energy,
const G4Track* theIncomingTrack)
{
if(!fFileInitialized) InitializeFile();
// parent ID
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 0,
theIncomingTrack->GetTrackID());
// molecule type
fpAnalysisManager->FillNtupleSColumn(fNtupleID, 1, "H2O");
//----------------------------------------------------------------------------
// valid for H2O only
// electronic modif
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 2, modification);
// ionization = 0 / excitation = 1 / diss att = 2
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 3, electronicLevel);
fpAnalysisManager->FillNtupleDColumn(fNtupleID, 4, energy / eV);
//----------------------------------------------------------------------------
const G4ThreeVector& parentPos = theIncomingTrack->GetPosition();
fpAnalysisManager->FillNtupleDColumn(fNtupleID,5,(parentPos.x())/nanometer);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,6,(parentPos.y())/nanometer);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,7,(parentPos.z())/nanometer);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,8,(parentPos.x())/nanometer);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,9,(parentPos.y())/nanometer);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,10,(parentPos.z())/nanometer);
fpAnalysisManager->AddNtupleRow(fNtupleID);
}
//------------------------------------------------------------------------------
void G4Analysis::CreateSolvatedElectron(const G4Track* electronTrack,
G4ThreeVector* finalPosition)
{
if(!fFileInitialized) InitializeFile();
// parent ID
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 0,
electronTrack->GetTrackID());
// molecule type
fpAnalysisManager->FillNtupleSColumn(fNtupleID, 1, "e_aq");
//----------------------------------------------------------------------------
// valid for H2O only
// electronic modif
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 2, -1); // electronic modif
fpAnalysisManager->FillNtupleIColumn(fNtupleID, 3, -1); // electronic level
fpAnalysisManager->FillNtupleDColumn(fNtupleID, 4,
electronTrack->GetKineticEnergy() / eV);
//----------------------------------------------------------------------------
const G4ThreeVector& parentPos = electronTrack->GetPosition();
const double i_nm = 1./nanometer;
fpAnalysisManager->FillNtupleDColumn(fNtupleID,5, parentPos.x() *i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,6, parentPos.y() *i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,7, parentPos.z() *i_nm);
if (finalPosition != nullptr)
{
fpAnalysisManager->FillNtupleDColumn(fNtupleID,8, finalPosition->x()*i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,9, finalPosition->y()*i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,10, finalPosition->z()*i_nm);
}
else
{
fpAnalysisManager->FillNtupleDColumn(fNtupleID,8, parentPos.x() *i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,9, parentPos.y() *i_nm);
fpAnalysisManager->FillNtupleDColumn(fNtupleID,10, parentPos.z() *i_nm);
}
fpAnalysisManager->AddNtupleRow(fNtupleID);
}
}
@@ -6,11 +6,20 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-02-07 L. Pandola (emlowen-V11-02-08)
- Fix residual Coverity defect on G4ShellData
## 2025-05-25 V. Ivanchenko (emlowen-V11-03-03)
- G4LivermorePhotoElectricModel - reorganisation of initialisation and data
destruction.
- G4AtomicTransitionManager, G4UAtomicDeexcitation - use std::size_t and few
other cosmetic changes.
## 2025-01-09 L. Pandola
- Fix Coverity warnings in Penenelope models, G4ShellData, G4FluoData and
## 2025-04-01 V. Ivanchenko (emlowen-V11-03-02)
- G4hIonEffChargeSquare - fixed Coverity warning.
## 2025-02-07 L. Pandola (emlowen-V11-03-01)
- Fix residual Coverity defect on G4ShellData.
## 2025-01-09 L. Pandola (emlowen-V11-03-00)
- Fix Coverity warnings in Penenelope models, G4ShellData, G4FluoData and
G4AugerTransition
## 2024-12-02 A. Ribon (emlowen-V11-02-07)
@@ -49,7 +49,7 @@
class G4AtomicDeexcitation {
public:
///constructor
explicit G4AtomicDeexcitation();
G4AtomicDeexcitation();
~G4AtomicDeexcitation();
/// Returns a vector contains the photons generated by radiative transitions
@@ -61,19 +61,21 @@ public:
/// function Instance()
static G4AtomicTransitionManager* Instance();
~G4AtomicTransitionManager();
/// needs to be called once from other code before start of run
void Initialise();
/// Z is the atomic number of the element, shellIndex is the
/// index (in EADL) of the shell
G4AtomicShell* Shell(G4int Z, size_t shellIndex) const;
G4AtomicShell* Shell(G4int Z, std::size_t shellIndex) const;
/// Z is the atomic number of the element, shellIndex is the
/// index (in EADL) of the final shell for the transition
/// This function gives, upon Z and the Index of the initial shell where
/// the vacancy is, the radiative transition that can happen (originating
/// shell, energy, probability)
const G4FluoTransition* ReachableShell(G4int Z, size_t shellIndex) const;
const G4FluoTransition* ReachableShell(G4int Z, std::size_t shellIndex) const;
/// This function gives, upon Z and the Index of the initial shell where
/// the vacancy is, the NON-radiative transition that can happen with
@@ -98,26 +100,25 @@ public:
/// Gives the sum of the probabilities of radiative transition towards the
/// shell whose index is shellIndex
G4double
TotalRadiativeTransitionProbability(G4int Z, size_t shellIndex) const;
TotalRadiativeTransitionProbability(G4int Z, std::size_t shellIndex) const;
/// Gives the sum of the probabilities of non radiative transition from the
/// shell whose index is shellIndex
G4double
TotalNonRadiativeTransitionProbability(G4int Z, size_t shellIndex) const;
TotalNonRadiativeTransitionProbability(G4int Z, std::size_t shellIndex) const;
/// Verbosity control
void SetVerboseLevel(G4int vl) {verboseLevel = vl;};
G4int GetVerboseLevel(){return verboseLevel;};
private:
explicit G4AtomicTransitionManager();
~G4AtomicTransitionManager();
// Hide copy constructor and assignment operator
G4AtomicTransitionManager& operator=(const G4AtomicTransitionManager& right);
G4AtomicTransitionManager(const G4AtomicTransitionManager&);
G4AtomicTransitionManager& operator=
(const G4AtomicTransitionManager& right) = delete;
G4AtomicTransitionManager(const G4AtomicTransitionManager&) = delete;
private:
G4AtomicTransitionManager();
static G4AtomicTransitionManager* instance;
// since Augereffect data r stored as a table in G4AugerData, we have
// here a pointer to an element of that class itself.
@@ -67,8 +67,6 @@ public:
const G4MaterialCutsCouple*, const G4DynamicParticle*,
G4double tmin, G4double maxEnergy) override;
void InitialiseForElement(const G4ParticleDefinition*, G4int Z) override;
[[maybe_unused]] inline void SetLimitNumberOfShells(G4int n) { nShellLimit = n; };
G4double GetBindingEnergy(G4int Z, G4int shell);
@@ -82,7 +80,7 @@ protected:
private:
void ReadData(const G4int Z);
const G4String& FindDirectoryPath();
void FindDirectoryPath();
void InitialiseOnFly(G4int Z);
@@ -60,8 +60,8 @@ class G4Material;
class G4UAtomicDeexcitation : public G4VAtomDeexcitation
{
public:
explicit G4UAtomicDeexcitation();
virtual ~G4UAtomicDeexcitation();
G4UAtomicDeexcitation();
~G4UAtomicDeexcitation() override;
//=================================================================
// methods that are requested to be implemented by the interface
@@ -39,6 +39,7 @@
#include "G4FluoData.hh"
#include "G4AugerData.hh"
#include "G4AutoLock.hh"
namespace { G4Mutex AtomicTransitionManagerMutex = G4MUTEX_INITIALIZER; }
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -48,7 +49,8 @@ G4AtomicTransitionManager* G4AtomicTransitionManager::instance = nullptr;
G4AtomicTransitionManager* G4AtomicTransitionManager::Instance()
{
if (instance == nullptr) {
instance = new G4AtomicTransitionManager();
static G4AtomicTransitionManager man;
instance = &man;
}
return instance;
}
@@ -65,29 +67,20 @@ G4AtomicTransitionManager::~G4AtomicTransitionManager()
{
delete augerData;
for (auto& pos : shellTable){
std::vector<G4AtomicShell*>vec = pos.second;
std::size_t vecSize = vec.size();
for (std::size_t i=0; i< vecSize; ++i){
G4AtomicShell* shell = vec[i];
delete shell;
}
for (auto const & pos : shellTable) {
std::vector<G4AtomicShell*> vec = pos.second;
for (auto const & p : vec) { delete p; }
}
for (auto& ppos : transitionTable)
{
std::vector<G4FluoTransition*>vec = ppos.second;
std::size_t vecSize=vec.size();
for (std::size_t i=0; i< vecSize; ++i){
G4FluoTransition* transition = vec[i];
delete transition;
}
}
for (auto const & ppos : transitionTable) {
std::vector<G4FluoTransition*> vec = ppos.second;
for (auto const & p : vec) { delete p; }
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4AtomicShell*
G4AtomicTransitionManager::Shell(G4int Z, size_t shellIndex) const
G4AtomicTransitionManager::Shell(G4int Z, std::size_t shellIndex) const
{
auto pos = shellTable.find(Z);
@@ -98,7 +91,7 @@ G4AtomicTransitionManager::Shell(G4int Z, size_t shellIndex) const
else
{
size_t lastShell = v.size();
std::size_t lastShell = v.size();
G4ExceptionDescription ed;
ed << "No de-excitation for Z= " << Z
<< " shellIndex= " << shellIndex
@@ -118,7 +111,7 @@ G4AtomicTransitionManager::Shell(G4int Z, size_t shellIndex) const
G4Exception("G4AtomicTransitionManager::Shell()","de0001",
FatalException,ed,"");
}
return 0;
return nullptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -127,7 +120,7 @@ G4AtomicTransitionManager::Shell(G4int Z, size_t shellIndex) const
// the vacancy is, the radiative transition that can happen (originating
// shell, energy, probability)
const G4FluoTransition*
G4AtomicTransitionManager::ReachableShell(G4int Z,size_t shellIndex) const
G4AtomicTransitionManager::ReachableShell(G4int Z, std::size_t shellIndex) const
{
auto pos = transitionTable.find(Z);
if (pos!= transitionTable.end())
@@ -215,7 +208,7 @@ G4int G4AtomicTransitionManager::NumberOfReachableAugerShells(G4int Z)const
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4AtomicTransitionManager::TotalRadiativeTransitionProbability(
G4int Z, size_t shellIndex) const
G4int Z, std::size_t shellIndex) const
{
auto pos = transitionTable.find(Z);
G4double totalRadTransProb = 0.0;
@@ -229,7 +222,7 @@ G4double G4AtomicTransitionManager::TotalRadiativeTransitionProbability(
G4FluoTransition* transition = v[shellIndex];
G4DataVector transProb = transition->TransitionProbabilities();
for (size_t j=0; j<transProb.size(); ++j)
for (std::size_t j=0; j<transProb.size(); ++j)
{
totalRadTransProb += transProb[j];
}
@@ -258,7 +251,7 @@ G4double G4AtomicTransitionManager::TotalRadiativeTransitionProbability(
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4AtomicTransitionManager::TotalNonRadiativeTransitionProbability(
G4int Z, size_t shellIndex) const
G4int Z, std::size_t shellIndex) const
{
G4double prob = 1.0 - TotalRadiativeTransitionProbability(Z, shellIndex);
if(prob > 1.0 || prob < 0.0) {
@@ -160,7 +160,7 @@ G4double G4FluoData::StartShellEnergy(G4int initIndex, G4int vacancyIndex) const
if (pos != energyMap.end())
{
G4DataVector dataSet = *((*pos).second);
G4int nData = (G4int)dataSet.size();
if (initIndex >= 0 && initIndex < nData)
{
@@ -189,7 +189,7 @@ G4double G4FluoData::StartShellProb(G4int initIndex, G4int vacancyIndex) const
if (pos != probabilityMap.end())
{
G4DataVector dataSet = *((*pos).second);
G4int nData = (G4int)dataSet.size();
if (initIndex >= 0 && initIndex < nData)
{
@@ -46,7 +46,6 @@
#include "G4SystemOfUnits.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4EmParameters.hh"
#include <thread>
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -69,7 +68,8 @@ namespace
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4LivermorePhotoElectricModel::G4LivermorePhotoElectricModel(const G4String& nam) : G4VEmModel(nam)
G4LivermorePhotoElectricModel::G4LivermorePhotoElectricModel(const G4String& nam)
: G4VEmModel(nam)
{
verboseLevel = 0;
// Verbosity scale:
@@ -95,6 +95,21 @@ G4LivermorePhotoElectricModel::G4LivermorePhotoElectricModel(const G4String& nam
// For water
fSandiaCof.resize(4, 0.0);
FindDirectoryPath();
if (fCrossSection == nullptr) {
fCrossSection = new G4ElementData(ZMAXPE);
fCrossSection->SetName("PhotoEffXS");
fCrossSectionLE = new G4ElementData(ZMAXPE);
fCrossSectionLE->SetName("PhotoEffLowXS");
for (G4int i = 0; i < ZMAXPE; ++i) {
fParamHigh[i] = nullptr;
fParamLow[i] = nullptr;
fNShells[i] = 0;
fNShellsUsed[i] = 0;
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -103,14 +118,10 @@ G4LivermorePhotoElectricModel::~G4LivermorePhotoElectricModel()
{
if (isInitializer) {
for (G4int i = 0; i < ZMAXPE; ++i) {
if (fParamHigh[i]) {
delete fParamHigh[i];
fParamHigh[i] = nullptr;
}
if (fParamLow[i]) {
delete fParamLow[i];
fParamLow[i] = nullptr;
}
delete fParamHigh[i];
fParamHigh[i] = nullptr;
delete fParamLow[i];
fParamLow[i] = nullptr;
}
}
}
@@ -129,7 +140,6 @@ void G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*,
if (isInitializer) {
G4AutoLock l(&livPhotoeffMutex);
FindDirectoryPath();
if (fWater == nullptr) {
fWater = G4Material::GetMaterial("G4_WATER", false);
if (fWater == nullptr) {
@@ -140,13 +150,6 @@ void G4LivermorePhotoElectricModel::Initialise(const G4ParticleDefinition*,
}
}
if (fCrossSection == nullptr) {
fCrossSection = new G4ElementData(ZMAXPE);
fCrossSection->SetName("PhotoEffXS");
fCrossSectionLE = new G4ElementData(ZMAXPE);
fCrossSectionLE->SetName("PhotoEffLowXS");
}
const G4ElementTable* elemTable = G4Element::GetElementTable();
std::size_t numElems = (*elemTable).size();
for (std::size_t ie = 0; ie < numElems; ++ie) {
@@ -188,7 +191,8 @@ G4LivermorePhotoElectricModel::CrossSectionPerVolume(const G4Material* material,
G4double, G4double)
{
fCurrSection = 0.0;
if (fWater && (material == fWater || material->GetBaseMaterial() == fWater)) {
if (nullptr != fWater &&
(material == fWater || material->GetBaseMaterial() == fWater)) {
if (energy <= fWaterEnergyLimit) {
fWater->GetSandiaTable()->GetSandiaCofWater(energy, fSandiaCof);
@@ -475,7 +479,7 @@ void G4LivermorePhotoElectricModel::SampleSecondaries(std::vector<G4DynamicParti
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
const G4String& G4LivermorePhotoElectricModel::FindDirectoryPath()
void G4LivermorePhotoElectricModel::FindDirectoryPath()
{
// no check in this method - environment variable is check by utility
if (fDataDirectory.empty()) {
@@ -489,7 +493,6 @@ const G4String& G4LivermorePhotoElectricModel::FindDirectoryPath()
}
fDataDirectory = ost.str();
}
return fDataDirectory;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -512,13 +515,13 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
// spline for photoeffect total x-section above K-shell when using EPDL97
// but below the parameterized ones
G4bool spline = (G4EmParameters::Instance()->LivermoreDataDir() == "livermore");
G4int number = G4EmParameters::Instance()->NumberForFreeVector();
auto pv = new G4PhysicsFreeVector(spline);
auto param = G4EmParameters::Instance();
G4bool spline = (param->LivermoreDataDir() == "livermore");
G4int number = param->NumberForFreeVector();
// fDataDirectory will be defined after these lines
std::ostringstream ost;
ost << FindDirectoryPath() << "pe-cs-" << Z << ".dat";
ost << fDataDirectory << "pe-cs-" << Z << ".dat";
std::ifstream fin(ost.str().c_str());
if (!fin.is_open()) {
G4ExceptionDescription ed;
@@ -532,6 +535,7 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
G4cout << "File " << ost.str().c_str() << " is opened by G4LivermorePhotoElectricModel"
<< G4endl;
}
auto pv = new G4PhysicsFreeVector(spline);
pv->Retrieve(fin, true);
pv->ScaleVector(MeV, barn);
pv->FillSecondDerivatives();
@@ -540,7 +544,6 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
fin.close();
// read high-energy fit parameters
fParamHigh[Z] = new std::vector<G4double>;
G4int n1 = 0;
G4int n2 = 0;
G4double x;
@@ -581,6 +584,7 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
}
fNShells[Z] = n1;
fParamHigh[Z] = new std::vector<G4double>;
fParamHigh[Z]->reserve(7 * n1 + 1);
fParamHigh[Z]->push_back(x * MeV);
for (G4int i = 0; i < n1; ++i) {
@@ -598,7 +602,6 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
fin1.close();
// read low-energy fit parameters
fParamLow[Z] = new std::vector<G4double>;
G4int n1_low = 0;
G4int n2_low = 0;
G4double x_low;
@@ -639,6 +642,7 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
}
fNShells[Z] = n1_low;
fParamLow[Z] = new std::vector<G4double>;
fParamLow[Z]->reserve(7 * n1_low + 1);
fParamLow[Z]->push_back(x_low * MeV);
for (G4int i = 0; i < n1_low; ++i) {
@@ -706,6 +710,7 @@ void G4LivermorePhotoElectricModel::ReadData(G4int Z)
<< G4endl;
G4Exception("G4LivermorePhotoElectricModel::ReadData()", "em0003", FatalException, ed,
"G4LEDATA version should be G4EMLOW8.0 or later.");
delete pv1;
return;
}
if (verboseLevel > 3) {
@@ -744,20 +749,6 @@ G4double G4LivermorePhotoElectricModel::GetBindingEnergy(G4int Z, G4int shell)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void
G4LivermorePhotoElectricModel::InitialiseForElement(const G4ParticleDefinition*, G4int Z)
{
if (fCrossSection == nullptr) {
fCrossSection = new G4ElementData(ZMAXPE);
fCrossSection->SetName("PhotoEffXS");
fCrossSectionLE = new G4ElementData(ZMAXPE);
fCrossSectionLE->SetName("PhotoEffLowXS");
}
ReadData(Z);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4LivermorePhotoElectricModel::InitialiseOnFly(G4int Z)
{
if (fCrossSection->GetElementData(Z) == nullptr && Z > 0 && Z < ZMAXPE) {
@@ -605,7 +605,7 @@ G4double G4PenelopeBremsstrahlungFS::SampleGammaEnergy(G4double energy,const G4M
const G4double cut) const
{
std::pair<const G4Material*,G4double> theKey = std::make_pair(mat,cut);
if (!(fSamplingTable->count(theKey)) || !(fPBcut->count(theKey)) ||
if (!(fSamplingTable->count(theKey)) || !(fPBcut->count(theKey)) ||
!(fReducedXSTable->count(theKey)))
{
G4ExceptionDescription ed;
@@ -257,7 +257,7 @@ G4double G4PenelopeBremsstrahlungModel::CrossSectionPerVolume(const G4Material*
{
G4cout << "G4PenelopeBremsstrahlungModel " << G4endl;
G4cout << "Mean free path for gamma emission > " << cutEnergy/keV << " keV at " <<
energy/keV << " keV = " <<
energy/keV << " keV = " <<
(crossPerVolume? (1./crossPerVolume)/mm : DBL_MAX) << " mm" << G4endl;
}
@@ -236,7 +236,7 @@ G4double G4PenelopeComptonModel::CrossSectionPerVolume(const G4Material* materia
if (fVerboseLevel > 2)
G4cout << "Compton mean free path at " << energy/keV << " keV for material " <<
material->GetName() << " = " <<
material->GetName() << " = " <<
(csvolume ? (1./csvolume)/mm : DBL_MAX) << " mm" << G4endl;
return csvolume;
}
@@ -323,12 +323,12 @@ G4double G4PenelopeIonisationModel::CrossSectionPerVolume(const G4Material* mate
{
G4cout << "G4PenelopeIonisationModel " << G4endl;
G4cout << "Mean free path for delta emission > " << cutEnergy/keV << " keV at " <<
energy/keV << " keV = " <<
energy/keV << " keV = " <<
(crossPerVolume ? (1./crossPerVolume)/mm : DBL_MAX) << " mm" << G4endl;
if (theXS)
totalCross = (theXS->GetTotalCrossSection(energy))*moleculeDensity;
G4cout << "Total free path for ionisation (no threshold) at " <<
energy/keV << " keV = " <<
energy/keV << " keV = " <<
(totalCross ? (1./totalCross)/mm : DBL_MAX) << " mm" << G4endl;
}
return crossPerVolume;
@@ -108,7 +108,7 @@ const std::vector<G4double>& G4ShellData::ShellVector(G4int Z) const
{
if (Z < zMin || Z > zMax)
G4Exception("G4ShellData::ShellVector()","de0001",JustWarning,"Z outside boundaries");
auto pos = occupancyPdfMap.find(Z);
auto pos = occupancyPdfMap.find(Z);
std::vector<G4double>* dataSet = (*pos).second;
return *dataSet;
}
@@ -200,12 +200,12 @@ void G4ShellData::PrintData() const
G4int id = (G4int) (*ids)[i];
G4double e = (*energies)[i] / keV;
G4cout << i << ") ";
if (occupancyData)
if (occupancyData)
{
G4cout << " Occupancy: ";
}
else
else
{
G4cout << " Shell id: ";
}
@@ -213,7 +213,7 @@ void G4ShellData::PrintData() const
<< e << " keV ";
if (occupancyData)
{
auto posOcc = occupancyPdfMap.find(Z);
auto posOcc = occupancyPdfMap.find(Z);
G4double prob = 0.;
if (posOcc != occupancyPdfMap.end())
{
@@ -241,7 +241,7 @@ G4double G4hIonEffChargeSquare::IonEffChargeSquare(
} else {
// v1 is ion velocity in vF unit
G4double v1{0.0}, v2{0.0};
G4double v1{0.01}, v2{0.0};
if (vF > 0.0) {
v1 = std::sqrt( reducedEnergy / (25.0 * keV) )/ vF;
v2 = 1.0/ (vF*vF);
@@ -6,9 +6,14 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-05-12 V.Ivanchenko (emmuons-V11-03-00)
- G4RiGeMuPairProductionModel, G4RiGeAngularGenerator - G.Depaola & R.Pacheco
provided fixes to the angular distribution of electrons and positrons.
- G4MuPairProduction - enable RiGe model via G4EmParameters
## 2023-10-31 V.Ivanchenko (emmuons-V11-01-04)
- G4RiGeMuPairProductionModel, G4RiGeAngularGenerator - a new 5D model for e+e-
pair production by muons
pair production by muons (authors G.Depaola & R.Pacheco)
- fixed declaration of virtual destructors in several header files
- G4MuPairProductionModel - minor clean-up for better code readability
@@ -31,7 +31,7 @@
//
// File name: G4RiGeAngularGenerator
//
// Authors: Girardo Depaola & Ricardo Pacheco
// Authors: Gerardo Depaola & Ricardo Pacheco
//
// Creation date: 29 October 2024
//
@@ -59,15 +59,15 @@ public:
G4double gEnergy, G4int Z,
const G4Material* mat = nullptr) override;
G4LorentzVector Sample5DPairDirections(const G4DynamicParticle* dp,
G4ThreeVector& dirElectron,
G4ThreeVector& dirPositron,
const G4double gEnergy, const G4double q2,
const G4double gMomentum,
G4double muFinalMomentum,
G4double muFinalEnergy,
const G4double* randNumbs,
const G4double* W);
void Sample5DPairDirections(const G4DynamicParticle* dp,
G4ThreeVector& dirElectron,
G4ThreeVector& dirPositron,
const G4double gEnergy, const G4double q2,
const G4double gMomentum,
G4double muFinalMomentum,
G4double muFinalEnergy,
const G4double* randNumbs,
const G4double* W);
void PhiRotation(G4ThreeVector& dir, G4double phi);
@@ -73,6 +73,7 @@
#include "G4Positron.hh"
#include "G4VEmModel.hh"
#include "G4MuPairProductionModel.hh"
#include "G4RiGeMuPairProductionModel.hh"
#include "G4ElementData.hh"
#include "G4EmParameters.hh"
@@ -113,18 +114,22 @@ void G4MuPairProduction::InitialiseEnergyLossProcess(
isInitialised = true;
theParticle = part;
G4EmParameters* param = G4EmParameters::Instance();
G4VEmModel* mod = EmModel(0);
if(nullptr == mod) {
if (nullptr == mod) {
lowestKinEnergy = std::max(lowestKinEnergy, part->GetPDGMass()*8.0);
auto ptr = new G4MuPairProductionModel(part);
ptr->SetLowestKineticEnergy(lowestKinEnergy);
mod = ptr;
if (param->UseRiGePairProductionModel()) {
mod = new G4MuPairProductionModel(part);
} else {
auto ptr = new G4MuPairProductionModel(part);
ptr->SetLowestKineticEnergy(lowestKinEnergy);
mod = ptr;
}
SetEmModel(mod);
}
G4VEmFluctuationModel* fm = nullptr;
G4EmParameters* param = G4EmParameters::Instance();
mod->SetLowEnergyLimit(param->MinKinEnergy());
mod->SetHighEnergyLimit(param->MaxKinEnergy());
mod->SetSecondaryThreshold(param->MuHadBremsstrahlungTh());
@@ -31,7 +31,7 @@
//
// File name: G4RiGeAngularGenerator
//
// Authors: Girardo Depaola & Ricardo Pacheco
// Authors: Gerardo Depaola & Ricardo Pacheco
//
// Creation date: 27 October 2024
//
@@ -85,8 +85,7 @@ G4double G4RiGeAngularGenerator::SampleCosTheta(G4double primKinEnergy,
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4LorentzVector
G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
void G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
G4ThreeVector& dirElectron,
G4ThreeVector& dirPositron,
const G4double gEnergy, const G4double q2,
@@ -96,10 +95,9 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
const G4double* randNumbs,
const G4double* W)
{
G4double muEnergy = dp->GetKineticEnergy();
G4double muKinEnergy = dp->GetKineticEnergy();
G4ThreeVector muMomentumVector = dp->GetMomentum();
G4double muMomentum = muMomentumVector.mag();
G4LorentzVector muFinalFourMomentum(muEnergy, muMomentumVector);
// Electron mass
G4double eMass = CLHEP::electron_mass_c2;
@@ -108,6 +106,9 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
// Muon mass
G4double muMass = dp->GetDefinition()->GetPDGMass();
G4double muEnergy = muKinEnergy + muMass;
G4LorentzVector muFinalFourMomentum(muMomentumVector, muEnergy);
G4double mint3 = 0.;
G4double maxt3 = CLHEP::pi;
G4double Cmin = std::cos(maxt3);
@@ -126,20 +127,7 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
G4ThreeVector dirGamma;
dirGamma.set(sintg*cospg, sintg*sinpg, costg);
G4LorentzVector gFourMomentum(gEnergy, dirGamma*gMomentum);
G4double Ap = muMomentum*muMomentum + muFinalMomentum*muFinalMomentum + gMomentum*gMomentum;
G4double A = Ap - 2.*muMomentum*gMomentum*costg;
G4double B = 2.*muFinalMomentum*gMomentum*sintg*cospg;
G4double C = 2.*muFinalMomentum*gMomentum*costg - 2.*muMomentum*muFinalMomentum;
G4double absB = std::abs(B);
G4double t1interval = (1./(A + C + absB*mint3) - 1./(A + C + absB*maxt3))/absB;
G4double t1 = (-(A + C) + 1./(1./(A + C + absB*mint3) - absB*t1interval*randNumbs[0]))/absB;
G4double sint1 = std::sin(t1);
G4double cost1 = std::cos(t1);
G4ThreeVector dirMuon;
dirMuon.set(sint1, 0., cost1);
G4LorentzVector gFourMomentum(dirGamma*gMomentum, gEnergy);
G4double cost5 = -1. + 2.*randNumbs[6];
G4double phi5 = CLHEP::twopi*randNumbs[8];
@@ -187,10 +175,7 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
G4ThreeVector dirGamma;
dirGamma.set(sint*cosp, sint*sinp, cost);
G4LorentzVector gFourMomentum(gEnergy, dirGamma*gMomentum);
G4ThreeVector dirMuon;
dirMuon.set(sint3, 0., cost3);
G4LorentzVector gFourMomentum(dirGamma*gMomentum, gEnergy);
G4double cost5 = -1. + 2.*randNumbs[6];
G4double phi5 = CLHEP::twopi*randNumbs[8];
@@ -233,17 +218,18 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
G4double pEnergy = muEnergy - muFEnergy - eEnergy;
G4double pMomentum = std::sqrt(pEnergy*pEnergy - eMass*eMass);
G4double A3 = -2.*muMass*muMass + 2.*muEnergy*muFinalEnergy;
G4double B3 = -2.*muMomentum*muFinalMomentum;
G4double A3 = -2.*muMass*muMass + 2.*muEnergy*muFEnergy;
G4double B3 = -2.*std::sqrt(muEnergy*muEnergy - muMass*muMass)*muFMomentum;
G4double cost3interval = G4Log((A3 + B3*Cmax)/(A3 + B3*Cmin))/B3;
G4double expanCost3r6 = G4Exp(B3*cost3interval*randNumbs[5]);
G4double cost3 = A3*(expanCost3r6 - 1.)/B3 + Cmin*expanCost3r6;
G4double sint3 = std::sqrt((1. - cost3)*(1. + cost3));
G4ThreeVector muFinalMomentumVector(muFMomentum*sint3, 0., muFMomentum*cost3);
G4LorentzVector muFourMomentum(muMomentum, muMomentumVector);
muFinalFourMomentum.set(muFEnergy, muFinalMomentumVector);
G4LorentzVector muFourMomentum(muMomentumVector, muEnergy);
muFinalFourMomentum.set(muFinalMomentumVector, muFEnergy);
G4LorentzVector auxVec1 = muFourMomentum - muFinalFourMomentum;
G4double A5 = auxVec1.mag2() - 2.*eEnergy*(muEnergy - muFEnergy) +
2.*muMomentumVector[2]*eMomentum - 2.*muFMomentum*eMomentum*cost3;
@@ -308,9 +294,10 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
G4double eEnergy = muEnergy - muFEnergy - pEnergy;
G4double eMomentum = std::sqrt(eEnergy*eEnergy - eMass*eMass);
G4double A3 = -2.*muMass*muMass + 2.*muEnergy*muFinalEnergy;
G4double B3 = -2.*muMomentum*muFMomentum;
G4double A3 = -2.*muMass*muMass + 2.*muEnergy*muFEnergy;
G4double B3 = -2.*std::sqrt(muEnergy*muEnergy - muMass*muMass)*muFMomentum;
G4double cost3interval = G4Log((A3 + B3*Cmax)/(A3 + B3*Cmin))/B3;
G4double expanCost3r6 = G4Exp(B3*cost3interval*randNumbs[5]);
G4double cost3 = A3*(expanCost3r6 - 1.)/B3 + Cmin*expanCost3r6;
G4double sint3 = std::sqrt((1. - cost3)*(1. + cost3));
@@ -319,8 +306,8 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
muFinalMomentumVector.set(muFMomentum*sint3*cosp3, muFMomentum*sint3*sinp3,
muFMomentum*cost3);
G4LorentzVector muFourMomentum(muMomentum, muMomentumVector);
muFinalFourMomentum.set(muFEnergy, muFinalMomentumVector);
G4LorentzVector muFourMomentum(muMomentumVector, muEnergy);
muFinalFourMomentum.set(muFinalMomentumVector, muFEnergy);
G4LorentzVector auxVec1 = muFourMomentum - muFinalFourMomentum;
G4double A6 = auxVec1.mag2() - 2.*pEnergy*(muEnergy - muFEnergy) +
2.*muMomentumVector[2]*pMomentum - 2.*muFMomentum*pMomentum*cost3;
@@ -360,7 +347,6 @@ G4RiGeAngularGenerator::Sample5DPairDirections(const G4DynamicParticle* dp,
PhiRotation(dirElectron, phi3);
PhiRotation(dirPositron, phi3);
}
return muFinalFourMomentum;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -395,7 +381,8 @@ G4LorentzVector G4RiGeAngularGenerator::eDP2(G4double x1, G4double x2,
}
G4double QJM = std::sqrt(QJM2);
G4LorentzVector x6(std::sqrt(x2 + QJM2), QJM*sint*cosp, QJM*sint*sinp, QJM*x4);
G4LorentzVector x6(QJM*sint*cosp, QJM*sint*sinp, QJM*x4, std::sqrt(x2 + QJM2));
return x6;
}
@@ -404,7 +391,7 @@ G4LorentzVector G4RiGeAngularGenerator::eDP2(G4double x1, G4double x2,
G4LorentzVector G4RiGeAngularGenerator::pDP2(G4double x3, const G4LorentzVector& x6)
{
G4LorentzVector x7(x3 + x6.vect().dot(x6.vect()), -x6.vect());
G4LorentzVector x7(-x6.vect(), std::sqrt(x3 + x6.vect().dot(x6.vect())));
return x7;
}
@@ -534,6 +534,7 @@ void G4RiGeMuPairProductionModel::SampleSecondaries(std::vector<G4DynamicParticl
// Energy and momentum of the pramary particle
G4double kinEnergy = aDynamicParticle->GetKineticEnergy();
G4double totEnergy = aDynamicParticle->GetTotalEnergy();
G4double particleMomentum = aDynamicParticle->GetTotalMomentum();
G4ThreeVector particleMomentumVector = aDynamicParticle->GetMomentum();
G4ThreeVector partDirection = aDynamicParticle->GetMomentumDirection();
@@ -660,7 +661,7 @@ void G4RiGeMuPairProductionModel::SampleSecondaries(std::vector<G4DynamicParticl
G4ThreeVector dirGamma;
dirGamma.set(sintg*cospg, sintg*sinpg, costg);
G4LorentzVector gFourMomentum(gEnergy, dirGamma*gMomentum);
G4LorentzVector gFourMomentum(dirGamma*gMomentum, gEnergy);
G4double Ap = particleMomentum*particleMomentum +
particleFinalMomentum*particleFinalMomentum + gMomentum*gMomentum;
@@ -723,7 +724,7 @@ void G4RiGeMuPairProductionModel::SampleSecondaries(std::vector<G4DynamicParticl
G4ThreeVector dirGamma;
dirGamma.set(sint*cosp, sint*sinp, cost);
G4LorentzVector gFourMomentum(gEnergy, dirGamma*gMomentum);
G4LorentzVector gFourMomentum(dirGamma*gMomentum, gEnergy);
// Ingoing parent particle change
G4double Phi = CLHEP::twopi*randNumbs[3];
@@ -779,8 +780,8 @@ void G4RiGeMuPairProductionModel::SampleSecondaries(std::vector<G4DynamicParticl
G4ThreeVector muFinalMomentumVector;
muFinalMomentumVector.set(particleFinalMomentum*sint3, 0., particleFinalMomentum*cost3);
G4LorentzVector muFourMomentum(particleMomentum, particleMomentumVector);
G4LorentzVector muFinalFourMomentum(particleFinalEnergy, muFinalMomentumVector);
G4LorentzVector muFourMomentum(particleMomentumVector, totEnergy);
G4LorentzVector muFinalFourMomentum(muFinalMomentumVector, particleFinalEnergy);
G4LorentzVector auxVec1 = muFourMomentum - muFinalFourMomentum;
G4double A5 = auxVec1.mag2() - 2.*eEnergy*(kinEnergy - particleFinalEnergy) +
2.*particleMomentumVector[2]*eMomentum - 2.*particleFinalMomentum*eMomentum*cost3;
@@ -893,13 +894,14 @@ void G4RiGeMuPairProductionModel::SampleSecondaries(std::vector<G4DynamicParticl
eDirection.set(sint5*cosp5, sint5*sinp5, cost5);
}
// these lines are closed temporary, will be enabled or removed after testing
/*
fAngularGenerator->Sample5DPairDirections(aDynamicParticle, eDirection, pDirection,
gEnergy, Q2, gMomentum,
particleFinalMomentum,
particleFinalEnergy,
randNumbs, W);
*/
// create G4DynamicParticle object for e+e-
auto aParticle1 = new G4DynamicParticle(theElectron, eDirection, eEnergy);
auto aParticle2 = new G4DynamicParticle(thePositron, pDirection, pEnergy);
@@ -6,6 +6,10 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-02-13 Gabriele Cosmo (empii-V11-03-00)
- Use "const G4String&" in G4hImpactIonisation::InitializeMe() to avoid
unnecessary copy.
## 2023-08-29 Ben Morgan (empii-V11-01-00)
- Fix Coverity warnings
@@ -121,7 +121,7 @@ void G4hImpactIonisation::InitializeMe()
eMinPixe = 1.* keV;
eMaxPixe = 200. * MeV;
G4String defaultPixeModel("ecpssr");
const G4String& defaultPixeModel("ecpssr");
modelK = defaultPixeModel;
modelL = defaultPixeModel;
modelM = defaultPixeModel;
@@ -6,10 +6,33 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2025-02-07 Igor Semeniouk (emstand-V11-02-22)
## 2025-04-25 V.Ivanchenko (emstand-V11-03-06)
- G4LowPAIH2O - fixed Coverity warnings
## 2025-04-23 V.Ivanchenko (emstand-V11-03-05)
- G4UrbanMscModel - L.Urban propose a small change for Opt3 case, which may
improve performance. Should not affect any result.
## 2025-03-12 V.Ivanchenko (emstand-V11-03-04)
- G4LowPAIH2O - removed compilation warnings due to explicit types conversion
problems reported by J.Allison
## 2025-03-11 V.Grichine (emstand-V11-03-03)
- G4LowPAIH2O class with G4LowDataH2O.hh data file for dE/dx in water for p and e-.
## 2025-02-26 V.Ivanchenko (emstand-V11-03-02)
- G4UrbanMscModel - L.Urban propose cosmetic change for Opt3 case and updated
comments to the code. Should not affect any result.
## 2025-02-07 Igor Semeniouk (emstand-V11-03-01)
- G4OrePowellAtRestModel - Add missing decay plane rotation
( random x axis phi )
## 2025-01-19 V.Ivanchenko (emstand-V11-03-00)
- G4eBremsstrahlungRelModel - This is a reversion of !4755 (merged just before the
release 11.3). This implementation needed for EM design toward parallel
initialisation of EM physics.
## 2024-11-08 V.Ivanchenko (emstand-V11-02-21)
- G4BraggModel - fixed problem of 4.12 MeV mu+ range reported in
the Forum #12312.
@@ -0,0 +1,554 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4LowDataH2O.hh -- header file
//
// GEANT 4 class header file --- Copyright CERN 1995
// CERB Geneva Switzerland
//
// for information related to this code, please, contact
// CERN, CN Division, ASD Group
//
// Preparation of ionizing collision cross section according to Photo Absorption
// Ionization (PAI) model for simulation of ionization energy losses in very thin
// layers of water for low energy protons and electrons.
//
// Author: Vladimir.Grichine@cern.ch
//
// History:
//
// 2.12.24, V. Grichine: 1st version
#ifndef G4LOWDATAH2O_HH
#define G4LOWDATAH2O_HH
#include "G4LowPAIH2O.hh"
// The data array size
const G4int G4LowPAIH2O:: theBin = 1007;
/////////////////////////////////////////
//
// Transfer energies in Geant4 units (MeV)
const G4double G4LowPAIH2O::theEsum[1007] = {
1.00084e-07, 1.00315e-07, 1.00778e-07, 1.01243e-07, 1.01711e-07, 1.01945e-07,
1.02416e-07, 1.02888e-07, 1.03363e-07, 1.0384e-07, 1.0408e-07, 1.0456e-07,
1.05043e-07, 1.05528e-07, 1.06015e-07, 1.06504e-07, 1.06996e-07, 1.07242e-07,
1.07737e-07, 1.08235e-07, 1.08734e-07, 1.09348e-07, 1.0974e-07, 1.10247e-07,
1.10756e-07, 1.11267e-07, 1.11781e-07, 1.12296e-07, 1.12815e-07, 1.13336e-07,
1.13859e-07, 1.14384e-07, 1.14912e-07, 1.15443e-07, 1.15975e-07, 1.16511e-07,
1.17049e-07, 1.17589e-07, 1.18132e-07, 1.18677e-07, 1.19225e-07, 1.19775e-07,
1.20328e-07, 1.20883e-07, 1.21441e-07, 1.22283e-07, 1.22786e-07, 1.23414e-07,
1.23984e-07, 1.24557e-07, 1.25131e-07, 1.25999e-07, 1.2658e-07, 1.27165e-07,
1.27752e-07, 1.28341e-07, 1.29231e-07, 1.29827e-07, 1.30427e-07, 1.31331e-07,
1.31937e-07, 1.32546e-07, 1.33465e-07, 1.34081e-07, 1.347e-07, 1.35633e-07,
1.36259e-07, 1.36888e-07, 1.37837e-07, 1.38473e-07, 1.39433e-07, 1.40077e-07,
1.41048e-07, 1.41699e-07, 1.42353e-07, 1.4334e-07, 1.44333e-07, 1.44999e-07,
1.46005e-07, 1.46678e-07, 1.47695e-07, 1.48377e-07, 1.49405e-07, 1.5044e-07,
1.51135e-07, 1.52183e-07, 1.53238e-07, 1.53945e-07, 1.55012e-07, 1.56087e-07,
1.56807e-07, 1.57894e-07, 1.58989e-07, 1.60091e-07, 1.61201e-07, 1.61945e-07,
1.63067e-07, 1.64197e-07, 1.65336e-07, 1.66482e-07, 1.67636e-07, 1.68798e-07,
1.69968e-07, 1.71146e-07, 1.72332e-07, 1.73527e-07, 1.74729e-07, 1.75941e-07,
1.7716e-07, 1.78388e-07, 1.79625e-07, 1.8087e-07, 1.82124e-07, 1.83809e-07,
1.85083e-07, 1.86366e-07, 1.87658e-07, 1.89394e-07, 1.90707e-07, 1.92029e-07,
1.93806e-07, 1.95149e-07, 1.96955e-07, 1.9832e-07, 2.00155e-07, 2.01542e-07,
2.03407e-07, 2.04817e-07, 2.06712e-07, 2.08145e-07, 2.10071e-07, 2.12015e-07,
2.13977e-07, 2.1546e-07, 2.17453e-07, 2.19466e-07, 2.21496e-07, 2.23546e-07,
2.25614e-07, 2.27702e-07, 2.29809e-07, 2.31935e-07, 2.34081e-07, 2.36248e-07,
2.38433e-07, 2.40639e-07, 2.42866e-07, 2.45678e-07, 2.47951e-07, 2.50245e-07,
2.53143e-07, 2.55485e-07, 2.58444e-07, 2.60835e-07, 2.63856e-07, 2.66911e-07,
2.69381e-07, 2.725e-07, 2.75655e-07, 2.78847e-07, 2.82076e-07, 2.85342e-07,
2.88646e-07, 2.91989e-07, 2.9537e-07, 2.9879e-07, 3.0225e-07, 3.06455e-07,
3.10003e-07, 3.13593e-07, 3.17956e-07, 3.22379e-07, 3.26112e-07, 3.30648e-07,
3.35248e-07, 3.39912e-07, 3.44641e-07, 3.49435e-07, 3.54296e-07, 3.59225e-07,
3.65062e-07, 3.7014e-07, 3.75289e-07, 3.81387e-07, 3.87584e-07, 3.93882e-07,
4.00282e-07, 4.06786e-07, 4.13396e-07, 4.15304e-07, 4.16262e-07, 4.18183e-07,
4.19147e-07, 4.20113e-07, 4.22052e-07, 4.23025e-07, 4.24e-07, 4.24978e-07,
4.2694e-07, 4.27924e-07, 4.2891e-07, 4.29899e-07, 4.31883e-07, 4.32879e-07,
4.33877e-07, 4.34877e-07, 4.36884e-07, 4.37891e-07, 4.38901e-07, 4.39912e-07,
4.40927e-07, 4.42962e-07, 4.43983e-07, 4.45006e-07, 4.46032e-07, 4.48091e-07,
4.49124e-07, 4.50159e-07, 4.51197e-07, 4.52237e-07, 4.54325e-07, 4.55372e-07,
4.56422e-07, 4.57474e-07, 4.58528e-07, 4.59585e-07, 4.61707e-07, 4.62771e-07,
4.63838e-07, 4.64907e-07, 4.65979e-07, 4.67053e-07, 4.6813e-07, 4.70291e-07,
4.71375e-07, 4.72461e-07, 4.7355e-07, 4.74642e-07, 4.75736e-07, 4.77932e-07,
4.79034e-07, 4.80138e-07, 4.81245e-07, 4.82355e-07, 4.83467e-07, 4.85698e-07,
4.8794e-07, 4.90192e-07, 4.92455e-07, 4.9359e-07, 4.95868e-07, 4.98157e-07,
5.00456e-07, 5.0161e-07, 5.03926e-07, 5.06251e-07, 5.08588e-07, 5.09761e-07,
5.12114e-07, 5.14477e-07, 5.16852e-07, 5.19238e-07, 5.20435e-07, 5.22837e-07,
5.2525e-07, 5.27675e-07, 5.3011e-07, 5.32557e-07, 5.35015e-07, 5.36249e-07,
5.38724e-07, 5.41211e-07, 5.43709e-07, 5.46218e-07, 5.4874e-07, 5.51273e-07,
5.53817e-07, 5.53894e-07, 5.58941e-07, 5.61521e-07, 5.64113e-07, 5.66717e-07,
5.69333e-07, 5.71961e-07, 5.74601e-07, 5.77253e-07, 5.79918e-07, 5.82594e-07,
5.85284e-07, 5.87985e-07, 5.90699e-07, 5.93426e-07, 5.96165e-07, 5.98917e-07,
6.01681e-07, 6.04458e-07, 6.07248e-07, 6.11458e-07, 6.1428e-07, 6.17115e-07,
6.19964e-07, 6.22825e-07, 6.257e-07, 6.30037e-07, 6.32945e-07, 6.35867e-07,
6.38802e-07, 6.41751e-07, 6.46199e-07, 6.49182e-07, 6.52178e-07, 6.56699e-07,
6.5973e-07, 6.62775e-07, 6.65835e-07, 6.7045e-07, 6.73545e-07, 6.78213e-07,
6.81344e-07, 6.84489e-07, 6.89233e-07, 6.92415e-07, 6.97214e-07, 7.00433e-07,
7.03666e-07, 7.08543e-07, 7.11814e-07, 7.16748e-07, 7.20056e-07, 7.25047e-07,
7.30073e-07, 7.33443e-07, 7.38527e-07, 7.41936e-07, 7.47079e-07, 7.52257e-07,
7.55729e-07, 7.60968e-07, 7.6448e-07, 7.69779e-07, 7.75115e-07, 7.80488e-07,
7.84091e-07, 7.89526e-07, 7.94999e-07, 8.00509e-07, 8.04204e-07, 8.09779e-07,
8.15392e-07, 8.21044e-07, 8.26735e-07, 8.32465e-07, 8.38236e-07, 8.44046e-07,
8.49897e-07, 8.55788e-07, 8.6172e-07, 8.67694e-07, 8.73708e-07, 8.79764e-07,
8.85862e-07, 8.92003e-07, 8.98186e-07, 9.04412e-07, 9.10681e-07, 9.19108e-07,
9.25478e-07, 9.31894e-07, 9.38353e-07, 9.47036e-07, 9.536e-07, 9.6021e-07,
9.69095e-07, 9.75812e-07, 9.84842e-07, 9.91668e-07, 1.00084e-06, 1.00778e-06,
1.01711e-06, 1.02416e-06, 1.03363e-06, 1.0408e-06, 1.05043e-06, 1.06015e-06,
1.06996e-06, 1.07737e-06, 1.08734e-06, 1.0974e-06, 1.10756e-06, 1.11781e-06,
1.12815e-06, 1.13859e-06, 1.14912e-06, 1.15976e-06, 1.17049e-06, 1.18132e-06,
1.19225e-06, 1.20328e-06, 1.21441e-06, 1.22847e-06, 1.23984e-06, 1.24557e-06,
1.25131e-06, 1.25999e-06, 1.2658e-06, 1.27165e-06, 1.27752e-06, 1.28341e-06,
1.29231e-06, 1.29827e-06, 1.30427e-06, 1.31331e-06, 1.31937e-06, 1.32546e-06,
1.33465e-06, 1.34081e-06, 1.347e-06, 1.35633e-06, 1.36259e-06, 1.36888e-06,
1.37837e-06, 1.38473e-06, 1.39433e-06, 1.40077e-06, 1.41048e-06, 1.41699e-06,
1.42353e-06, 1.4334e-06, 1.44333e-06, 1.44999e-06, 1.46004e-06, 1.46678e-06,
1.47695e-06, 1.48377e-06, 1.49405e-06, 1.50441e-06, 1.51129e-06, 1.52183e-06,
1.53238e-06, 1.53945e-06, 1.55012e-06, 1.56087e-06, 1.56807e-06, 1.57894e-06,
1.58989e-06, 1.60091e-06, 1.612e-06, 1.61945e-06, 1.63067e-06, 1.64197e-06,
1.65336e-06, 1.66482e-06, 1.67636e-06, 1.68798e-06, 1.69968e-06, 1.71146e-06,
1.72332e-06, 1.73527e-06, 1.7473e-06, 1.75941e-06, 1.7716e-06, 1.78388e-06,
1.79625e-06, 1.8087e-06, 1.82124e-06, 1.83809e-06, 1.85083e-06, 1.86366e-06,
1.87658e-06, 1.89394e-06, 1.90707e-06, 1.92029e-06, 1.93806e-06, 1.95149e-06,
1.96955e-06, 1.9832e-06, 2.00155e-06, 2.01542e-06, 2.03407e-06, 2.04817e-06,
2.06712e-06, 2.08145e-06, 2.10071e-06, 2.12015e-06, 2.13977e-06, 2.1546e-06,
2.17447e-06, 2.19465e-06, 2.21496e-06, 2.23546e-06, 2.25614e-06, 2.27702e-06,
2.29809e-06, 2.31935e-06, 2.34081e-06, 2.36247e-06, 2.38433e-06, 2.40639e-06,
2.42866e-06, 2.45678e-06, 2.47951e-06, 2.50245e-06, 2.53143e-06, 2.55485e-06,
2.58444e-06, 2.60835e-06, 2.63856e-06, 2.66911e-06, 2.69381e-06, 2.725e-06,
2.75655e-06, 2.78847e-06, 2.82076e-06, 2.85342e-06, 2.88646e-06, 2.91989e-06,
2.9537e-06, 2.9879e-06, 3.0225e-06, 3.06455e-06, 3.10003e-06, 3.13593e-06,
3.17955e-06, 3.22379e-06, 3.26112e-06, 3.30648e-06, 3.35248e-06, 3.39912e-06,
3.4464e-06, 3.49435e-06, 3.54296e-06, 3.59225e-06, 3.65062e-06, 3.7014e-06,
3.75289e-06, 3.81387e-06, 3.87584e-06, 3.93882e-06, 4.00282e-06, 4.06786e-06,
4.13396e-06, 4.20113e-06, 4.27924e-06, 4.34877e-06, 4.42962e-06, 4.51197e-06,
4.59585e-06, 4.6813e-06, 4.76833e-06, 4.85698e-06, 4.95868e-06, 5.06252e-06,
5.16852e-06, 5.27669e-06, 5.38724e-06, 5.51272e-06, 5.64113e-06, 5.77253e-06,
5.90699e-06, 6.04458e-06, 6.19964e-06, 6.35867e-06, 6.52178e-06, 6.7045e-06,
6.89233e-06, 7.08543e-06, 7.11814e-06, 7.20056e-06, 7.30073e-06, 7.38527e-06,
7.47079e-06, 7.55729e-06, 7.6448e-06, 7.75115e-06, 7.84091e-06, 7.94999e-06,
8.04204e-06, 8.15392e-06, 8.26735e-06, 8.38236e-06, 8.49897e-06, 8.6172e-06,
8.73708e-06, 8.85863e-06, 8.98186e-06, 9.10681e-06, 9.25478e-06, 9.38353e-06,
9.536e-06, 9.69095e-06, 9.84841e-06, 1.00084e-05, 1.01711e-05, 1.03363e-05,
1.05043e-05, 1.06996e-05, 1.08734e-05, 1.10756e-05, 1.12815e-05, 1.14912e-05,
1.17049e-05, 1.19225e-05, 1.21441e-05, 1.23984e-05, 1.2658e-05, 1.29231e-05,
1.31937e-05, 1.347e-05, 1.37837e-05, 1.41048e-05, 1.44333e-05, 1.47695e-05,
1.51135e-05, 1.55012e-05, 1.58989e-05, 1.63067e-05, 1.67636e-05, 1.72332e-05,
1.7654e-05, 1.82124e-05, 1.87658e-05, 1.93806e-05, 2.00155e-05, 2.06712e-05,
2.13977e-05, 2.18265e-05, 2.24077e-05, 2.30044e-05, 2.3617e-05, 2.42459e-05,
2.48915e-05, 2.55543e-05, 2.62348e-05, 2.69334e-05, 2.76507e-05, 2.8387e-05,
2.91429e-05, 2.99189e-05, 3.07157e-05, 3.15336e-05, 3.23733e-05, 3.32354e-05,
3.41204e-05, 3.5029e-05, 3.59618e-05, 3.69194e-05, 3.79025e-05, 3.89119e-05,
3.99481e-05, 4.10118e-05, 4.21039e-05, 4.32251e-05, 4.43762e-05, 4.55579e-05,
4.6771e-05, 4.80165e-05, 4.92951e-05, 5.06078e-05, 5.19555e-05, 5.3339e-05,
5.47594e-05, 5.62176e-05, 5.77146e-05, 5.92515e-05, 6.08293e-05, 6.24491e-05,
6.41121e-05, 6.58193e-05, 6.75721e-05, 6.93714e-05, 7.12187e-05, 7.31152e-05,
7.50622e-05, 7.70611e-05, 7.91131e-05, 8.12198e-05, 8.33827e-05, 8.56031e-05,
8.78826e-05, 9.02228e-05, 9.26254e-05, 9.50919e-05, 9.76241e-05, 0.000100224,
0.000102893, 0.000105633, 0.000108445, 0.000111333, 0.000114298, 0.000117342,
0.000120466, 0.000123674, 0.000126968, 0.000130349, 0.00013382, 0.000137383,
0.000141042, 0.000144797, 0.000148653, 0.000152612, 0.000156676, 0.000160848,
0.000165131, 0.000169528, 0.000174043, 0.000178677, 0.000183435, 0.00018832,
0.000193335, 0.000198483, 0.000203769, 0.000209195, 0.000214765, 0.000220484,
0.000226356, 0.000232383, 0.000238572, 0.000244925, 0.000251447, 0.000258143,
0.000265017, 0.000272074, 0.000279319, 0.000286757, 0.000294393, 0.000302232,
0.000310281, 0.000318543, 0.000327026, 0.000335734, 0.000344674, 0.000353853,
0.000363275, 0.000372949, 0.00038288, 0.000393076, 0.000403544, 0.00041429,
0.000425322, 0.000436648, 0.000448275, 0.000460212, 0.000472467, 0.000485049,
0.000497965, 0.000511226, 0.000524839, 0.000538815, 0.000553163, 0.000567894,
0.000583016, 0.000598541, 0.00061448, 0.000630843, 0.000647642, 0.000664888,
0.000682593, 0.00070077, 0.000719431, 0.000738589, 0.000758257, 0.000778448,
0.000799178, 0.000820459, 0.000842307, 0.000864737, 0.000887764, 0.000911405,
0.000935675, 0.000960591, 0.000986171, 0.00101243, 0.00103939, 0.00106707,
0.00109548, 0.00112466, 0.0011546, 0.00118535, 0.00121692, 0.00124932,
0.00128259, 0.00131674, 0.00135181, 0.0013878, 0.00142476, 0.0014627, 0.00150165,
0.00154164, 0.00158269, 0.00162484, 0.00166811, 0.00171253, 0.00175813,
0.00180495, 0.00185301, 0.00190235, 0.00195301, 0.00200502, 0.00205841,
0.00211322, 0.0021695, 0.00222727, 0.00228658, 0.00234747, 0.00240998,
0.00247416, 0.00254004, 0.00260768, 0.00267712, 0.00274841, 0.0028216,
0.00289674, 0.00297387, 0.00305306, 0.00313436, 0.00321783, 0.00330352,
0.00339149, 0.0034818, 0.00357452, 0.0036697, 0.00376742, 0.00386775, 0.00397074,
0.00407648, 0.00418503, 0.00429648, 0.00441089, 0.00452835, 0.00464893,
0.00477273, 0.00489982, 0.0050303, 0.00516425, 0.00530177, 0.00544295,
0.00558789, 0.00573669, 0.00588946, 0.00604629, 0.0062073, 0.00637259,
0.00654229, 0.0067165, 0.00689536, 0.00707898, 0.00726748, 0.00746101,
0.00765969, 0.00786366, 0.00807306, 0.00828804, 0.00850874, 0.00873532,
0.00896794, 0.00920675, 0.00945191, 0.00970361, 0.00996201, 0.0102273,
0.0104996, 0.0107792, 0.0110663, 0.0113609, 0.0116635, 0.0119741, 0.0122929,
0.0126203, 0.0129564, 0.0133014, 0.0136556, 0.0140192, 0.0143925, 0.0147758,
0.0151692, 0.0155732, 0.0159879, 0.0164136, 0.0168507, 0.0172994, 0.0177601,
0.018233, 0.0187186, 0.019217, 0.0197288, 0.0202541, 0.0207935, 0.0213472,
0.0219156, 0.0224992, 0.0230984, 0.0237135, 0.0243449, 0.0249932, 0.0256588,
0.026342, 0.0270435, 0.0277636, 0.028503, 0.029262, 0.0300412, 0.0308412,
0.0316624, 0.0325056, 0.0333712, 0.0342598, 0.0351721, 0.0361087, 0.0370703,
0.0380574, 0.0390709, 0.0401113, 0.0411794, 0.042276, 0.0434017, 0.0445575,
0.045744, 0.0469622, 0.0482127, 0.0494966, 0.0508146, 0.0521678, 0.053557,
0.0549831, 0.0564473, 0.0579504, 0.0594936, 0.0610779, 0.0627043, 0.0643741,
0.0660883, 0.0678482, 0.0696549, 0.0715097, 0.073414, 0.0753689, 0.0773759,
0.0794364, 0.0815517, 0.0837234, 0.0859528, 0.0882417, 0.0905915, 0.0930039,
0.0954805, 0.098023, 0.100633, 0.103313, 0.106064, 0.108889, 0.111788, 0.114765,
0.117821, 0.120959, 0.12418, 0.127486, 0.130881, 0.134366, 0.137945, 0.141618,
0.145389, 0.149261, 0.153235, 0.157316, 0.161505, 0.165806, 0.170221, 0.174754,
0.179407, 0.184185, 0.18909, 0.194125, 0.199294, 0.204601, 0.21005, 0.215643,
0.221385, 0.227281, 0.233333, 0.239546, 0.245925, 0.252474, 0.259197, 0.266099,
0.273185, 0.28046, 0.287929, 0.295596, 0.303467, 0.311549, 0.319845, 0.328362,
0.337106, 0.346083, 0.355299, 0.36476, 0.374473, 0.384445, 0.394682, 0.405192,
0.415982, 0.42706, 0.438432, 0.450107, 0.462093, 0.474398, 0.487031
};
////////////////////////////////////////////////////
//
// Energy Loss Fuction (ELF) for water
const G4double G4LowPAIH2O::theELFsum[1007] = {
0.343701, 0.338322, 0.331699, 0.32522, 0.32051, 0.313544, 0.304649, 0.297559,
0.289704, 0.282644, 0.274489, 0.264361, 0.255236, 0.245748, 0.236871, 0.228919,
0.221906, 0.214845, 0.206271, 0.198028, 0.190106, 0.182071, 0.173805, 0.166123,
0.159188, 0.151848, 0.14468, 0.138038, 0.132675, 0.127068, 0.121363, 0.116174,
0.110695, 0.10539, 0.100535, 0.0958877, 0.0916441, 0.0878014, 0.0841337,
0.0806099, 0.0774056, 0.0731865, 0.0718562, 0.0685493, 0.065072, 0.0645778,
0.0627131, 0.0611187, 0.0595864, 0.0582351, 0.0570597, 0.0556476, 0.0545836,
0.0535382, 0.0526438, 0.051649, 0.0505599, 0.0496273, 0.0489336, 0.0479354,
0.0472902, 0.0466596, 0.0457391, 0.0451427, 0.0444471, 0.0437851, 0.0432295,
0.0426777, 0.0419665, 0.0414367, 0.0408504, 0.0403443, 0.0397835, 0.0392967,
0.0389018, 0.0383693, 0.0378514, 0.0374829, 0.0369796, 0.0367081, 0.0362265,
0.0358779, 0.0355725, 0.035119, 0.0348648, 0.0344976, 0.0341371, 0.0338999,
0.0335476, 0.0332797, 0.0330546, 0.0327189, 0.0323864, 0.032056, 0.0318024,
0.0316622, 0.0313428, 0.031206, 0.0309285, 0.0307598, 0.0305957, 0.0303611,
0.0301941, 0.0301014, 0.0298693, 0.0297723, 0.0296079, 0.0294363, 0.029396,
0.0294251, 0.0293818, 0.0294662, 0.0296168, 0.0297788, 0.0301786, 0.0307169,
0.0315479, 0.0327722, 0.0342432, 0.036205, 0.0384716, 0.0420536, 0.0476498,
0.0574523, 0.0721343, 0.106124, 0.117998, 0.120116, 0.109687, 0.0915872,
0.066625, 0.0458, 0.0343237, 0.0254945, 0.0204653, 0.0164614, 0.0138845,
0.0121716, 0.0110882, 0.0102305, 0.0153323, 0.00922561, 0.00907538, 0.00912068,
0.0092554, 0.00966081, 0.0100684, 0.0106331, 0.0111436, 0.0117403, 0.0122232,
0.0128286, 0.0133119, 0.013764, 0.0139136, 0.0137185, 0.0130353, 0.012035,
0.0109236, 0.0100244, 0.00902829, 0.00812679, 0.00734715, 0.00657945, 0.00593111,
0.00533323, 0.0047942, 0.00429417, 0.00387625, 0.00348138, 0.0031574, 0.00290842,
0.00278184, 0.00275416, 0.00287829, 0.00334779, 0.00401539, 0.00521023,
0.00708225, 0.0097644, 0.0140521, 0.0183347, 0.0250544, 0.0399675, 0.0587405,
0.0840311, 0.121028, 0.160966, 0.203027, 0.211079, 0.217312, 0.227821, 0.235095,
0.24169, 0.252298, 0.258592, 0.262752, 0.265536, 0.276661, 0.275552, 0.274533,
0.269661, 0.270219, 0.265797, 0.257128, 0.245891, 0.23504, 0.223146, 0.208363,
0.193196, 0.17773, 0.164163, 0.153071, 0.141107, 0.126677, 0.113678, 0.101827,
0.0886036, 0.0743801, 0.0618476, 0.0499254, 0.0367243, 0.0261855, 0.0232968,
0.0202302, 0.0176638, 0.0151418, 0.0124048, 0.0100069, 0.00849212, 0.00721195,
0.00611224, 0.00488681, 0.00485658, 0.00444412, 0.00363214, 0.00325423,
0.00293729, 0.0027827, 0.00264948, 0.00258351, 0.00253143, 0.00246953,
0.00243187, 0.00237879, 0.00223043, 0.00214095, 0.00207511, 0.00203558,
0.00199335, 0.00192966, 0.00183032, 0.00172071, 0.00158785, 0.00147243,
0.0013439, 0.00124105, 0.00114029, 0.001058, 0.000975114, 0.000892649,
0.000830566, 0.000773989, 0.000723575, 0.000665725, 0.000616754, 0.000579494,
0.000523586, 0.00049199, 0.000472557, 0.000449239, 0.000431062, 0.000409861,
0.000388832, 0.000370606, 0.000354888, 0.000338291, 0.000326973, 0.000321925,
0.000319208, 0.000317914, 0.000318873, 0.000322065, 0.000328313, 0.000335467,
0.000345962, 0.000356796, 0.000369682, 0.000388372, 0.000408962, 0.00043066,
0.000452471, 0.000489845, 0.000529109, 0.000572854, 0.000621666, 0.000680914,
0.000740288, 0.000816467, 0.000908885, 0.00100946, 0.00114474, 0.00128348,
0.00141561, 0.00156923, 0.00168858, 0.00174342, 0.00175514, 0.00166801,
0.0015318, 0.00105924, 0.000840322, 0.000657855, 0.000473997, 0.00029131,
0.000168926, 0.000140695, 0.000128445, 0.000124845, 0.000123977, 0.000122763,
0.00012008, 0.00010938, 0.000100936, 9.46588e-05, 8.99595e-05, 8.5502e-05,
7.99431e-05, 7.54954e-05, 7.22003e-05, 6.93847e-05, 6.79397e-05, 6.70749e-05,
6.62253e-05, 6.61113e-05, 6.77887e-05, 7.05426e-05, 7.2218e-05, 7.40878e-05,
7.84424e-05, 8.32266e-05, 8.84459e-05, 9.52342e-05, 0.00010135, 0.000110116,
0.000119698, 0.000127913, 0.000142122, 0.000154316, 0.000173446, 0.000199033,
0.000235344, 0.000266991, 0.000299439, 0.00031852, 0.000321345, 0.000320485,
0.00031236, 0.000282171, 0.000224058, 0.000134947, 9.34181e-05, 6.87239e-05,
5.10966e-05, 3.96443e-05, 3.55887e-05, 2.50008e-05, 1.97753e-05, 1.67933e-05,
1.43874e-05, 1.22857e-05, 1.07103e-05, 9.9882e-06, 9.55529e-06, 9.45036e-06,
9.63188e-06, 9.96535e-06, 1.01485e-05, 1.03076e-05, 1.0405e-05, 1.04779e-05,
1.03146e-05, 1.01275e-05, 9.76685e-06, 9.32094e-06, 8.1128e-06, 5.18542e-06,
3.36972e-06, 2.28825e-06, 1.77385e-06, 1.48604e-06, 1.30301e-06, 1.1547e-06,
1.09367e-06, 1.128e-06, 1.23206e-06, 1.46642e-06, 1.73534e-06, 2.03945e-06,
2.32915e-06, 2.59852e-06, 2.71171e-06, 2.81681e-06, 2.88823e-06, 2.95867e-06,
3.01136e-06, 3.02957e-06, 2.99639e-06, 2.90383e-06, 2.75796e-06, 2.53457e-06,
2.20994e-06, 1.87411e-06, 1.52972e-06, 1.18165e-06, 9.14966e-07, 7.1684e-07,
5.77823e-07, 4.91715e-07, 4.44251e-07, 4.19278e-07, 3.98474e-07, 3.79573e-07,
3.6493e-07, 3.49207e-07, 3.36684e-07, 3.22787e-07, 3.05344e-07, 2.88179e-07,
2.71379e-07, 2.52029e-07, 2.31401e-07, 2.11463e-07, 1.92818e-07, 1.75395e-07,
1.56274e-07, 1.39251e-07, 1.24357e-07, 1.14166e-07, 1.09005e-07, 1.07229e-07,
1.07939e-07, 1.09923e-07, 1.14802e-07, 1.20729e-07, 1.2667e-07, 1.30778e-07,
1.34412e-07, 1.353e-07, 1.35255e-07, 1.33352e-07, 1.30877e-07, 1.24656e-07,
1.1523e-07, 9.82685e-08, 7.80301e-08, 6.22455e-08, 5.11626e-08, 4.26378e-08,
3.49651e-08, 2.85412e-08, 2.52526e-08, 2.26017e-08, 2.10365e-08, 2.03456e-08,
1.85169e-08, 1.784e-08, 1.72669e-08, 1.64828e-08, 1.50933e-08, 1.42117e-08,
1.36272e-08, 1.3309e-08, 1.31507e-08, 1.34033e-08, 1.24588e-08, 1.1836e-08,
1.1246e-08, 1.04646e-08, 9.5612e-09, 8.13265e-09, 6.5166e-09, 5.36704e-09,
4.39996e-09, 3.7338e-09, 3.23547e-09, 2.88829e-09, 2.63234e-09, 2.41013e-09,
2.23222e-09, 2.04846e-09, 1.90159e-09, 1.75712e-09, 1.57936e-09, 1.46947e-09,
1.37036e-09, 1.31071e-09, 1.21947e-09, 1.05641e-09, 8.98271e-10, 7.69237e-10,
6.52693e-10, 6.09908e-10, 5.94159e-10, 5.8809e-10, 5.80861e-10, 6.03393e-10,
6.19614e-10, 6.27668e-10, 6.43036e-10, 6.66392e-10, 7.14854e-10, 7.68705e-10,
8.35919e-10, 8.92526e-10, 9.57347e-10, 1.02921e-09, 1.09379e-09, 1.1597e-09,
1.21236e-09, 1.28534e-09, 1.35021e-09, 1.42768e-09, 1.48883e-09, 1.56739e-09,
1.63815e-09, 1.70417e-09, 1.78093e-09, 1.85677e-09, 1.93572e-09, 2.01793e-09,
2.1132e-09, 2.19675e-09, 2.28431e-09, 2.35885e-09, 2.42877e-09, 2.50647e-09,
2.60432e-09, 2.76878e-09, 2.97722e-09, 3.21569e-09, 3.40185e-09, 3.68834e-09,
4.14105e-09, 4.40767e-09, 4.77438e-09, 5.17213e-09, 5.58864e-09, 5.96795e-09,
6.38569e-09, 6.85652e-09, 7.24103e-09, 7.60813e-09, 7.70074e-09, 7.84358e-09,
8.16024e-09, 8.84067e-09, 1.37338e-08, 2.60346e-08, 4.4736e-08, 7.19727e-08,
1.18248e-07, 2.25675e-07, 7.52606e-07, 3.45946e-05, 0.000184565, 0.000635798,
0.00103903, 0.0019317, 0.0182683, 0.0322752, 0.0456558, 0.0590582, 0.0728399,
0.0887233, 0.105449, 0.120398, 0.137241, 0.147511, 0.150233, 0.144037, 0.133044,
0.119254, 0.102717, 0.0833649, 0.0724089, 0.073295, 0.085751, 0.105138, 0.125623,
0.143651, 0.15568, 0.163681, 0.170532, 0.176964, 0.183206, 0.190715, 0.199072,
0.206747, 0.214796, 0.224665, 0.235198, 0.247949, 0.261726, 0.278921, 0.299982,
0.324028, 0.349266, 0.377322, 0.406436, 0.438649, 0.470931, 0.498468, 0.524826,
0.548057, 0.567545, 0.58861, 0.623154, 0.745122, 0.731576, 0.795212, 0.864073,
0.916613, 0.925369, 0.899703, 0.244356, 0.252615, 0.261018, 0.269569, 0.27827,
0.28712, 0.296119, 0.305263, 0.31455, 0.323972, 0.333522, 0.343189, 0.35296,
0.362819, 0.372747, 0.382722, 0.392719, 0.402707, 0.412654, 0.422523, 0.43227,
0.44185, 0.451211, 0.460298, 0.46905, 0.477403, 0.48529, 0.492639, 0.499376,
0.504367, 0.509777, 0.514929, 0.518523, 0.521151, 0.522737, 0.523212, 0.522524,
0.520632, 0.517512, 0.513156, 0.507572, 0.500784, 0.492833, 0.483774, 0.473678,
0.462625, 0.450709, 0.438027, 0.424686, 0.410794, 0.39646, 0.381793, 0.366898,
0.351875, 0.336819, 0.321818, 0.306951, 0.292288, 0.272404, 0.258131, 0.244245,
0.230786, 0.217783, 0.205262, 0.193237, 0.18172, 0.170717, 0.160228, 0.15025,
0.140775, 0.131796, 0.123299, 0.11527, 0.107696, 0.100558, 0.0938403, 0.0875248,
0.0815935, 0.0760284, 0.0708116, 0.0659252, 0.0613519, 0.0570747, 0.0530771,
0.0493433, 0.0458578, 0.0426059, 0.0395735, 0.0367473, 0.0341144, 0.0316626,
0.0293804, 0.0272569, 0.0252818, 0.0234452, 0.0217382, 0.0201519, 0.0186783,
0.0173098, 0.0160392, 0.0148597, 0.0137651, 0.0127495, 0.0118075, 0.0109337,
0.0101236, 0.00937242, 0.00867615, 0.00803086, 0.00743288, 0.00687884,
0.00636558, 0.00589016, 0.00544984, 0.00504208, 0.00466452, 0.00431495,
0.00399133, 0.00369177, 0.0034145, 0.00315789, 0.00292042, 0.00336515,
0.00310903, 0.00287178, 0.0026521, 0.00244876, 0.00226062, 0.00208661,
0.00192571, 0.00177698, 0.00163954, 0.00151256, 0.00139527, 0.00128696,
0.00118696, 0.00109464, 0.00100944, 0.000930809, 0.000858257, 0.000791323,
0.000729578, 0.000672625, 0.000620099, 0.000571659, 0.000526992, 0.000485805,
0.000447831, 0.000412821, 0.000380545, 0.000350791, 0.000323363, 0.000298079,
0.000274774, 0.000253293, 0.000233492, 0.000215242, 0.000198421, 0.000182917,
0.000168626, 0.000155455, 0.000143316, 0.000132126, 0.000121813, 0.000112308,
0.000103546, 9.547e-05, 8.8026e-05, 8.11643e-05, 7.48394e-05, 6.90091e-05,
6.36347e-05, 5.86803e-05, 5.4113e-05, 4.99025e-05, 4.60209e-05, 4.24422e-05,
3.91429e-05, 3.6101e-05, 3.32964e-05, 3.07105e-05, 2.83261e-05, 2.61275e-05,
2.41002e-05, 2.22307e-05, 2.05068e-05, 1.8917e-05, 1.74509e-05, 1.60987e-05,
1.48518e-05, 1.37016e-05, 1.26409e-05, 1.16625e-05, 1.07601e-05, 9.92771e-06,
9.1599e-06, 8.45163e-06, 7.79829e-06, 7.19558e-06, 6.63956e-06, 6.12673e-06,
5.65369e-06, 5.21733e-06, 4.81479e-06, 4.44345e-06, 4.10087e-06, 3.78481e-06,
3.49321e-06, 3.22417e-06, 2.97593e-06, 2.74688e-06, 2.53553e-06, 2.34051e-06,
2.16054e-06, 1.99446e-06, 1.8412e-06, 1.69976e-06, 1.56922e-06, 1.44874e-06,
1.33754e-06, 1.23491e-06, 1.14018e-06, 1.05274e-06, 9.72031e-07, 8.97527e-07,
8.28751e-07, 7.65262e-07, 7.06652e-07, 6.52544e-07, 6.02591e-07, 5.56473e-07,
5.13895e-07, 4.74583e-07, 4.38287e-07, 4.04775e-07, 3.73831e-07, 3.45259e-07,
3.18877e-07, 2.94515e-07, 2.7202e-07, 2.51246e-07, 2.32063e-07, 2.14348e-07,
1.97988e-07, 1.8288e-07, 1.68927e-07, 1.56041e-07, 1.4414e-07, 1.33148e-07,
1.22997e-07, 1.13621e-07, 1.04961e-07, 9.69623e-08, 8.95744e-08, 8.27505e-08,
7.64473e-08, 7.06252e-08, 6.52472e-08, 6.02795e-08, 5.56907e-08, 5.14518e-08,
4.75361e-08, 4.39188e-08, 4.05772e-08, 3.74902e-08, 3.46383e-08, 3.20037e-08,
2.95698e-08, 2.73212e-08, 2.52438e-08, 2.33245e-08, 2.15513e-08, 1.99131e-08,
1.83995e-08, 1.70011e-08, 1.5709e-08, 1.45153e-08, 1.34123e-08, 1.23933e-08,
1.14517e-08, 1.05817e-08, 9.77786e-09, 9.03513e-09, 8.34886e-09, 7.71475e-09,
7.12884e-09, 6.58746e-09, 6.08722e-09, 5.62498e-09, 5.19787e-09, 4.80321e-09,
4.43853e-09, 4.10156e-09, 3.79018e-09, 3.50245e-09, 3.23657e-09, 2.99089e-09,
2.76387e-09, 2.55408e-09, 2.36023e-09, 2.18109e-09, 2.01556e-09, 1.8626e-09,
1.72125e-09, 1.59062e-09, 1.46992e-09, 1.35838e-09, 1.2553e-09, 1.16005e-09,
1.07203e-09, 9.90691e-10, 9.15525e-10, 8.46063e-10, 7.81873e-10, 7.22554e-10,
6.67737e-10, 6.1708e-10, 5.70266e-10, 5.27005e-10, 4.87027e-10, 4.50082e-10,
4.15937e-10, 3.84386e-10, 3.55229e-10, 3.28284e-10, 3.03384e-10, 2.80373e-10,
2.59107e-10, 2.39455e-10, 2.21293e-10, 2.04509e-10, 1.88999e-10, 1.74665e-10,
1.61418e-10, 1.49176e-10, 1.37863e-10, 1.27408e-10, 1.17745e-10, 1.08816e-10,
1.00564e-10, 9.29376e-11, 8.58897e-11, 7.93764e-11, 7.33571e-11, 6.77943e-11,
6.26534e-11, 5.79023e-11, 5.35116e-11, 4.94538e-11, 4.57038e-11, 4.22381e-11,
3.90353e-11, 3.60753e-11, 3.33399e-11, 3.08118e-11, 2.84755e-11, 2.63163e-11,
2.43209e-11, 2.24767e-11, 2.07724e-11, 1.91974e-11, 1.77418e-11, 1.63965e-11,
1.51533e-11, 1.40043e-11, 1.29425e-11, 1.19612e-11, 1.10542e-11, 1.02161e-11,
9.44151e-12, 8.72564e-12, 8.06406e-12, 7.45264e-12, 6.88758e-12, 6.36536e-12,
5.88274e-12, 5.43672e-12, 5.02451e-12, 4.64356e-12, 4.29149e-12, 3.96612e-12,
3.66541e-12
};
//////////////////////////////
//
// Rutherford term (\int of ELF*omega) of the PAI model for water
const G4double G4LowPAIH2O::theRuthSum[1007] = {
0, 0.000783401, 0.00231191, 0.00379636, 0.00524157, 0.00594579, 0.00730817,
0.00862143, 0.00988839, 0.0111095, 0.0116985, 0.0128262, 0.0138996, 0.0149204,
0.0158897, 0.0168116, 0.0176908, 0.0181112, 0.0189103, 0.0196636, 0.0203729,
0.021186, 0.0216702, 0.0222506, 0.0227922, 0.0232961, 0.0237622, 0.0241923,
0.024591, 0.0249609, 0.0253014, 0.0256139, 0.025899, 0.0261568, 0.026389,
0.0265973, 0.0267833, 0.026949, 0.027096, 0.0272252, 0.0273377, 0.0274322,
0.0275132, 0.0275827, 0.0276361, 0.0277017, 0.0277353, 0.0277681, 0.0277901,
0.0278054, 0.0278147, 0.0278197, 0.0278173, 0.0278101, 0.0277985, 0.0277827,
0.0277521, 0.0277273, 0.027699, 0.0276512, 0.0276159, 0.0275781, 0.0275166,
0.0274727, 0.0274261, 0.0273525, 0.0273011, 0.0272477, 0.0271642, 0.0271063,
0.0270167, 0.0269551, 0.0268601, 0.0267951, 0.0267287, 0.026627, 0.0265231,
0.0264526, 0.0263451, 0.0262724, 0.0261621, 0.0260875, 0.0259747, 0.0258608,
0.0257841, 0.0256682, 0.0255515, 0.0254732, 0.025355, 0.0252364, 0.025157,
0.0250375, 0.0249173, 0.0247964, 0.0246752, 0.0245945, 0.0244731, 0.0243519,
0.0242309, 0.0241101, 0.0239897, 0.0238696, 0.0237499, 0.0236308, 0.0235123,
0.0233943, 0.023277, 0.0231601, 0.0230442, 0.0229297, 0.0228169, 0.0227057,
0.0225968, 0.0224554, 0.0223529, 0.0222551, 0.0221633, 0.0220523, 0.0219796,
0.0219197, 0.0218604, 0.0218367, 0.0218475, 0.0219083, 0.0220998, 0.0224082,
0.0230219, 0.0235228, 0.024142, 0.0245011, 0.0247757, 0.0248363, 0.0247485,
0.0246141, 0.0243745, 0.0240981, 0.0237967, 0.0234813, 0.0231588, 0.0228334,
0.0225333, 0.022234, 0.0219117, 0.0215947, 0.0212845, 0.0209824, 0.0206894,
0.0203363, 0.0200645, 0.0198027, 0.0194883, 0.0192469, 0.0189576, 0.0187351,
0.0184661, 0.018203, 0.0179929, 0.017726, 0.0174531, 0.017175, 0.0168925,
0.0166056, 0.0163156, 0.0160235, 0.0157299, 0.015436, 0.0151422, 0.0147915,
0.0145013, 0.014213, 0.0138709, 0.0135342, 0.0132585, 0.0129349, 0.0126208,
0.0123193, 0.0120337, 0.0117686, 0.0115317, 0.0113322, 0.0111617, 0.0110782,
0.0110721, 0.0112368, 0.0116636, 0.0124264, 0.0136592, 0.0154631, 0.0178602,
0.0186456, 0.019052, 0.0198976, 0.0203379, 0.0207921, 0.0217337, 0.0222207,
0.0227174, 0.0232199, 0.0242497, 0.0247726, 0.0252907, 0.0257995, 0.0268004,
0.027293, 0.0277682, 0.0282184, 0.029062, 0.0294548, 0.0298151, 0.0301393,
0.0304269, 0.0309315, 0.0311538, 0.0313486, 0.0315121, 0.0317741, 0.0318756,
0.0319479, 0.0319883, 0.0319978, 0.0319606, 0.0319133, 0.0318389, 0.0317495,
0.0316536, 0.0315517, 0.0313376, 0.0312253, 0.0311076, 0.0309859, 0.0308616,
0.0307351, 0.0306065, 0.0303482, 0.0302194, 0.0300899, 0.0299595, 0.029829,
0.0296985, 0.0294387, 0.0293095, 0.0291807, 0.0290523, 0.0289245, 0.0287971,
0.0285437, 0.028292, 0.0280423, 0.0277946, 0.0276715, 0.0274268, 0.027184,
0.0269429, 0.0268229, 0.026584, 0.0263467, 0.0261111, 0.0259939, 0.0257606,
0.0255291, 0.0252993, 0.0250713, 0.024958, 0.0247326, 0.024509, 0.0242873,
0.0240673, 0.0238492, 0.0236329, 0.0235254, 0.0233118, 0.0231001, 0.0228903,
0.0226823, 0.022476, 0.0222716, 0.022069, 0.022063, 0.0216692, 0.021472,
0.0212766, 0.021083, 0.0208912, 0.0207011, 0.0205129, 0.0203264, 0.0201416,
0.0199586, 0.0197774, 0.0195979, 0.0194202, 0.0192441, 0.0190699, 0.0188974,
0.0187266, 0.0185577, 0.0183905, 0.0181431, 0.0179803, 0.0178194, 0.0176605,
0.0175035, 0.0173486, 0.0171198, 0.0169697, 0.0168216, 0.0166752, 0.0165303,
0.0163153, 0.016173, 0.0160307, 0.0158173, 0.0156757, 0.0155346, 0.0153939,
0.0151843, 0.0150458, 0.0148403, 0.0147048, 0.0145705, 0.0143715, 0.0142403,
0.0140457, 0.0139174, 0.0137902, 0.0136017, 0.0134774, 0.013293, 0.0131715,
0.0129913, 0.0128135, 0.0126964, 0.0125226, 0.0124081, 0.0122383, 0.0120709,
0.0119605, 0.0117969, 0.0116891, 0.0115292, 0.0113716, 0.0112162, 0.0111138,
0.0109619, 0.0108123, 0.0106647, 0.0105675, 0.0104234, 0.0102814, 0.0101415,
0.0100036, 0.00986787, 0.00973419, 0.00960257, 0.00947294, 0.00934516,
0.00921914, 0.00909482, 0.00897207, 0.00885071, 0.0087305, 0.0086115, 0.0084939,
0.00837777, 0.00826314, 0.00811266, 0.00800156, 0.00789193, 0.00778377,
0.00764184, 0.00753708, 0.00743375, 0.00729816, 0.0071981, 0.0070668, 0.00696991,
0.00684278, 0.00674896, 0.00662588, 0.00653504, 0.00641585, 0.0063279,
0.00621249, 0.00609919, 0.00598796, 0.00590586, 0.00579813, 0.00569234,
0.00558847, 0.00548648, 0.00538636, 0.00528806, 0.00519155, 0.00509681,
0.00500379, 0.00491247, 0.00482282, 0.00473481, 0.00464841, 0.00454262,
0.00445973, 0.00441886, 0.00437835, 0.0043183, 0.00427872, 0.00423951,
0.00420066, 0.00416216, 0.00410507, 0.00406745, 0.00403017, 0.00397489,
0.00393846, 0.00390236, 0.00384883, 0.00381354, 0.00377859, 0.00372675,
0.00369258, 0.00365873, 0.00360853, 0.00357545, 0.0035264, 0.00349407,
0.00344613, 0.00341454, 0.00338323, 0.00333682, 0.00329104, 0.00326086,
0.00321613, 0.00318664, 0.00314292, 0.00311411, 0.00307138, 0.00302924,
0.00300172, 0.00296029, 0.00291967, 0.00289291, 0.00285321, 0.00281407,
0.00278827, 0.00275001, 0.00271228, 0.00267507, 0.00263837, 0.00261418,
0.00257831, 0.00254294, 0.00250805, 0.00247364, 0.0024397, 0.00240622,
0.00237321, 0.00234065, 0.00230854, 0.00227686, 0.00224562, 0.00221481,
0.00218442, 0.00215445, 0.00212489, 0.00209574, 0.00206698, 0.00202926,
0.00200141, 0.00197395, 0.00194687, 0.00191134, 0.00188511, 0.00185925,
0.00182531, 0.00180027, 0.00176741, 0.00174316, 0.00171134, 0.00168786,
0.00165706, 0.00163432, 0.00160449, 0.00158248, 0.00155359, 0.00152524,
0.0014974, 0.00147685, 0.00144998, 0.00142343, 0.00139745, 0.00137195,
0.00134691, 0.00132232, 0.00129819, 0.00127449, 0.00125123, 0.00122839,
0.00120597, 0.00118396, 0.00116235, 0.00113589, 0.00111516, 0.00109481,
0.00106989, 0.00105036, 0.00102645, 0.00100771, 0.000984776, 0.00096236,
0.000944795, 0.000923289, 0.000902272, 0.000881734, 0.000861663, 0.000842049,
0.000822882, 0.000804151, 0.000785846, 0.000767958, 0.000750477, 0.000730025,
0.000713407, 0.000697168, 0.000678168, 0.000659686, 0.00064467, 0.000627101,
0.000610011, 0.000593386, 0.000577215, 0.000561484, 0.000546182, 0.000531297,
0.000514444, 0.000500424, 0.000486786, 0.000471344, 0.000456392, 0.000441914,
0.000427896, 0.000414322, 0.000401179, 0.000388453, 0.000374402, 0.000362525,
0.000349412, 0.000336774, 0.000324593, 0.000312852, 0.000301536, 0.000290629,
0.00027883, 0.00026751, 0.000256649, 0.000246235, 0.000236233, 0.000225601,
0.000215447, 0.000205751, 0.000196491, 0.000187648, 0.000178381, 0.000169572,
0.0001612, 0.000152547, 0.000144823, 0.000139991, 0.000140589, 0.000146924,
0.000163174, 0.00027459, 0.000556121, 0.000987089, 0.00156066, 0.00241699,
0.00328156, 0.00451532, 0.00569793, 0.00729826, 0.0090396, 0.0108219, 0.0125318,
0.0140779, 0.015413, 0.016505, 0.0173227, 0.0179117, 0.0184991, 0.0190787,
0.0199878, 0.0211842, 0.0226481, 0.0243037, 0.0260656, 0.0278894, 0.0297607,
0.0319413, 0.0338936, 0.0361926, 0.0385534, 0.040971, 0.0434633, 0.0460499,
0.0487535, 0.0519478, 0.0553268, 0.0589571, 0.0628979, 0.067179, 0.0723321,
0.0778967, 0.0839009, 0.0903606, 0.0972024, 0.105039, 0.113101, 0.121291,
0.130311, 0.139594, 0.149138, 0.162421, 0.175168, 0.190137, 0.206066, 0.221952,
0.237589, 0.239452, 0.233554, 0.22817, 0.223279, 0.21886, 0.214892, 0.211355,
0.208231, 0.205504, 0.203155, 0.20117, 0.199533, 0.198228, 0.197241, 0.196558,
0.196165, 0.196047, 0.196192, 0.196584, 0.19721, 0.198054, 0.199103, 0.200341,
0.201752, 0.203318, 0.205023, 0.206849, 0.208777, 0.210786, 0.212842, 0.214926,
0.217038, 0.219155, 0.221242, 0.223276, 0.225233, 0.227086, 0.228812, 0.230385,
0.231782, 0.23298, 0.233958, 0.234697, 0.235181, 0.235394, 0.235326, 0.234967,
0.234312, 0.233357, 0.232103, 0.230551, 0.228707, 0.22658, 0.224178, 0.221515,
0.218602, 0.215457, 0.212095, 0.208462, 0.204579, 0.200534, 0.196346, 0.192033,
0.187615, 0.183109, 0.178532, 0.173902, 0.169233, 0.164542, 0.159841, 0.155145,
0.150466, 0.145815, 0.141203, 0.136638, 0.13213, 0.127686, 0.123312, 0.119015,
0.114801, 0.110672, 0.106635, 0.10269, 0.098842, 0.0950917, 0.0914411, 0.0878912,
0.0844426, 0.0810957, 0.0778502, 0.0747058, 0.0716619, 0.0687174, 0.0658712,
0.063122, 0.0604682, 0.0579081, 0.05544, 0.0530619, 0.0507717, 0.0485675,
0.046447, 0.0444081, 0.0424485, 0.040566, 0.0387584, 0.0370233, 0.0353586,
0.0337619, 0.0322311, 0.0307639, 0.0293582, 0.0280118, 0.0267226, 0.0254886,
0.0243077, 0.023178, 0.0220975, 0.0210643, 0.0200767, 0.0191328, 0.0182309,
0.0173779, 0.016571, 0.015799, 0.0150607, 0.0143549, 0.0136801, 0.0130353,
0.0124192, 0.0118306, 0.0112686, 0.0107319, 0.0102196, 0.00973068, 0.00926409,
0.00881894, 0.0083943, 0.00798931, 0.00760313, 0.00723493, 0.00688394, 0.0065494,
0.00623059, 0.00592681, 0.00563739, 0.0053617, 0.00509911, 0.00484903,
0.00461089, 0.00438416, 0.0041683, 0.00396282, 0.00376724, 0.0035811, 0.00340396,
0.00323541, 0.00307504, 0.00292246, 0.00277732, 0.00263926, 0.00250794,
0.00238305, 0.00226428, 0.00215134, 0.00204394, 0.00194183, 0.00184475,
0.00175246, 0.00166472, 0.00158132, 0.00150205, 0.0014267, 0.00135509,
0.00128704, 0.00122237, 0.00116091, 0.00110251, 0.00104702, 0.000994296,
0.000944203, 0.000896612, 0.000851398, 0.000808446, 0.000767644, 0.000728884,
0.000692067, 0.000657096, 0.000623879, 0.00059233, 0.000562366, 0.000533908,
0.000506881, 0.000481213, 0.000456838, 0.00043369, 0.000411709, 0.000390836,
0.000371015, 0.000352195, 0.000334325, 0.000317357, 0.000301246, 0.000285949,
0.000271426, 0.000257637, 0.000244546, 0.000232118, 0.000220318, 0.000209116,
0.000198482, 0.000188387, 0.000178803, 0.000169705, 0.000161069, 0.00015287,
0.000145088, 0.000137701, 0.000130689, 0.000124033, 0.000117714, 0.000111717,
0.000106025, 0.000100622, 9.54938e-05, 9.06262e-05, 8.60062e-05, 8.16212e-05,
7.74592e-05, 7.35091e-05, 6.976e-05, 6.62017e-05, 6.28245e-05, 5.96193e-05,
5.65774e-05, 5.36904e-05, 5.09504e-05, 4.835e-05, 4.58822e-05, 4.35401e-05,
4.13173e-05, 3.92079e-05, 3.7206e-05, 3.53062e-05, 3.35033e-05, 3.17923e-05,
3.01685e-05, 2.86276e-05, 2.71653e-05, 2.57776e-05, 2.44607e-05, 2.3211e-05,
2.20251e-05, 2.08997e-05, 1.98318e-05, 1.88184e-05, 1.78567e-05, 1.69441e-05,
1.60781e-05, 1.52563e-05, 1.44765e-05, 1.37365e-05, 1.30343e-05, 1.2368e-05,
1.17357e-05, 1.11357e-05, 1.05664e-05, 1.00261e-05, 9.51346e-06, 9.02701e-06,
8.56541e-06, 8.1274e-06, 7.71178e-06, 7.31739e-06, 6.94317e-06, 6.58807e-06,
6.25112e-06, 5.9314e-06, 5.62801e-06, 5.34014e-06, 5.06699e-06, 4.8078e-06,
4.56186e-06, 4.3285e-06, 4.10707e-06, 3.89696e-06, 3.69759e-06, 3.50843e-06,
3.32893e-06, 3.15861e-06, 2.99701e-06, 2.84367e-06, 2.69817e-06, 2.56011e-06,
2.42912e-06, 2.30482e-06, 2.18689e-06, 2.07498e-06, 1.9688e-06, 1.86806e-06,
1.77246e-06, 1.68176e-06, 1.5957e-06, 1.51404e-06, 1.43655e-06, 1.36304e-06,
1.29328e-06, 1.22709e-06, 1.16429e-06, 1.1047e-06, 1.04816e-06, 9.94518e-07,
9.43617e-07, 8.95321e-07, 8.49496e-07, 8.06016e-07, 7.64762e-07, 7.25618e-07,
6.88477e-07, 6.53238e-07, 6.19801e-07, 5.88076e-07, 5.57974e-07, 5.29413e-07,
5.02314e-07, 4.76602e-07, 4.52205e-07, 4.29057e-07, 4.07094e-07, 3.86255e-07,
3.66483e-07, 3.47723e-07, 3.29922e-07, 3.13033e-07, 2.97009e-07, 2.81805e-07,
2.67378e-07, 2.53691e-07, 2.40704e-07, 2.28381e-07, 2.1669e-07, 2.05597e-07,
1.95071e-07, 1.85085e-07, 1.7561e-07, 1.66619e-07, 1.58089e-07, 1.49996e-07,
1.42317e-07, 1.35031e-07, 1.28118e-07, 1.21559e-07, 1.15335e-07, 1.09431e-07,
1.03828e-07, 9.85126e-08, 9.3469e-08, 8.86837e-08, 8.41433e-08, 7.98354e-08,
7.5748e-08, 7.18699e-08, 6.81903e-08, 6.46991e-08, 6.13866e-08, 5.82437e-08,
5.52617e-08, 5.24324e-08, 4.97479e-08, 4.72009e-08, 4.47842e-08, 4.24913e-08,
4.03158e-08, 3.82516e-08, 3.62932e-08, 3.4435e-08, 3.26719e-08, 3.09991e-08,
2.9412e-08, 2.79061e-08, 2.64773e-08, 2.51216e-08
};
#endif
////////////////////// end of G4LowDataH2O header file ////////////////
@@ -0,0 +1,267 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4LowPAIxs.hh -- header file
//
// GEANT 4 class header file --- Copyright CERN 1995
// CERB Geneva Switzerland
//
// for information related to this code, please, contact
// CERN, CN Division, ASD Group
//
// Preparation of ionizing collision cross section according to Photo Absorption
// Ionization (PAI) model for simulation of ionization energy losses in very thin
// layers of water for low energy protons and electrons.
//
// Author: Vladimir.Grichine@cern.ch
//
// History:
//
// 2.12.24, V. Grichine: 1st version
#ifndef G4LOWPAIH2O_HH
#define G4LOWPAIH2O_HH
#include "G4ios.hh"
#include "globals.hh"
#include "Randomize.hh"
#include "G4PhysicsLogVector.hh"
#include "G4DataVector.hh"
#include "G4PhysicsTable.hh"
#include "G4VEmModel.hh"
#include "G4VEmFluctuationModel.hh"
class G4MaterialCutsCouple;
class G4Material;
class G4SandiaTable;
class G4PhysicsLogVector;
class G4PhysicsTable;
class G4ParticleDefinition;
class G4ParticleChangeForLoss;
class G4LowPAIH2O :
public G4VEmModel , public G4VEmFluctuationModel
{
public:
// Constructors
explicit G4LowPAIH2O( const G4ParticleDefinition* p = nullptr,
const G4String& nam = "lowpaih2o");
~G4LowPAIH2O() override;
G4LowPAIH2O & operator=(const G4LowPAIH2O &right) = delete;
G4LowPAIH2O(const G4LowPAIH2O&) = delete;
// methods
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
void InitialiseLocal(const G4ParticleDefinition*,
G4VEmModel* masterModel) override;
G4double CrossSectionPerVolume(const G4Material*,
const G4ParticleDefinition*,
G4double kineticEnergy,
G4double cutEnergy,
G4double maxEnergy) override;
G4double CrossSectionPerAtom(
const G4ParticleDefinition*,
G4double kineticEnergy, G4double Z,
G4double A,
G4double cutEnergy,
G4double maxEnergy);
virtual G4double ComputeCrossSectionPerElectron(
const G4ParticleDefinition*,
G4double kineticEnergy,
G4double cutEnergy,
G4double maxEnergy);
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double tmin,
G4double maxEnergy) override;
G4double SampleFluctuations(const G4MaterialCutsCouple*,
const G4DynamicParticle*,
const G4double tcut,
const G4double tmax,
const G4double length,
const G4double meanLoss) override;
void CorrectionsAlongStep(const G4MaterialCutsCouple*,
const G4DynamicParticle*,
const G4double& length,
G4double& eloss) override;
G4double Dispersion(const G4Material*, const G4DynamicParticle*,
const G4double, const G4double, const G4double) override {return 0.;};
inline G4double ComputeMeanFreePath( const G4ParticleDefinition*,
G4double kineticEnergy,
const G4Material*,
G4double cutEnergy = 0.0,
G4double maxEnergy = DBL_MAX);
void Initialize();
void InitRuthELF();
void BuildPhysicsTable(const G4ParticleDefinition* pd);
void BuildPrEnergyTable();
void BuildElEnergyTable();
G4double GetPrTransfer( G4double Tkin);
G4double CorrectPrTransfer( G4double Tkin);
G4double CorrectElTransfer( G4double Tkin);
G4double GetElTransfer( G4double Tkin);
G4double GetPrMFP( G4double Tkin);
G4double GetPrdNdx( G4double Tkin);
G4double GetElMFP( G4double Tkin);
G4double GetEldNdx( G4double Tkin);
G4double PrPAId2Ndxdw( G4double omega );
G4double ElPAId2Ndxdw( G4double omega );
void SetBe2( G4double be2 ){ fBe2 = be2; };
G4double GetBe2(){ return fBe2; };
void SetOmega( G4double ww ){ fOmega = ww; };
G4double GetOmega(){ return fOmega;};
void SetBias( G4double bb ){ fBias = bb; };
G4double GetBias(){ return fBias;};
G4double GetElectronTmax( G4double Tkin );
G4double GetProtonTmax( G4double Tkin );
inline G4double GetSumELF( G4double energy );
inline G4double GetSumRuth( G4double energy );
private:
// Local class members
G4int fTotBin{0};
G4int fBinTr{0};
G4int fBias{0};
G4double fCof{0.0};
G4double fBeta{0.0};
G4double fBe2{0.0};
G4double fTkin{0.0};
G4double fBmin{0.0};
G4double fBmax{0.0};
G4double fWmin{0.0};
G4double fWmax{0.0};
G4double fOmega{0.0};
G4double fElectronDensity{0.0};
G4double fNat{0.0};
G4double fNel{0.0};
G4double fMass{0.0};
static const G4int theBin;
static const G4double theEsum[1007], theELFsum[1007], theRuthSum[1007];
G4DataVector fEsum;
G4DataVector fELFsum, fRuthSum;
G4DataVector fPrWmaxVector;
G4Material* fMat{nullptr};
G4PhysicsLogVector* fBetaVector{nullptr};
G4PhysicsTable* fPrEnergyTable{nullptr};
G4PhysicsTable* fElEnergyTable{nullptr};
G4PhysicsLogVector* fTransferVector{nullptr};
G4ParticleDefinition* theElectron{nullptr};
G4ParticleDefinition* theProton{nullptr};
G4ParticleChangeForLoss* fParticleChange{nullptr};
};
///////////////////////////////////////////////////////////////////
//////////////// Inline methods //////////////////////////////////
////////////////////////////////////////////////////////////////////
/////////////////// fast (STL) get ELF /////////////////
G4double G4LowPAIH2O::GetSumELF( G4double energy )
{
G4double ee = energy; // /CLHEP::eV;
G4double elf(0.), y1(0.), y2(0.), x1(0.), x2(0.), aa(0.);
std::size_t nlow = std::lower_bound( fEsum.begin(), fEsum.end(), ee ) - fEsum.begin();
x1 = fEsum[nlow-1];
x2 = fEsum[nlow];
y1 = fELFsum[nlow-1];
y2 = fELFsum[nlow];
aa = (y2-y1)/(x2-x1);
elf = y1 + aa*(ee-x1);
return elf;
}
/////////////////////// fast (STL) get Rutherford /////////////////////
G4double G4LowPAIH2O::GetSumRuth( G4double energy )
{
G4double ee = energy; // /CLHEP::eV;
G4double ruth(0.), y1(0.), y2(0.), x1(0.), x2(0.), aa(0.);
std::size_t nlow = std::lower_bound( fEsum.begin(), fEsum.end(), ee ) - fEsum.begin();
x1 = fEsum[nlow-1];
x2 = fEsum[nlow];
y1 = fRuthSum[nlow-1];
y2 = fRuthSum[nlow];
aa = (y2-y1)/(x2-x1);
ruth = y1 + aa*(ee-x1);
return ruth;
}
///////////////////////////////////////////////
G4double G4LowPAIH2O::ComputeMeanFreePath( const G4ParticleDefinition* pd,
G4double Tkin,
const G4Material*,
G4double, // cutEnergy, // = 0.0,
G4double ) //maxEnergy ) // = DBL_MAX)
{
G4double dndx(0.), mfp(DBL_MAX);
if ( pd == theProton ) dndx = GetPrdNdx(Tkin);
else if( pd == theElectron ) dndx = GetEldNdx(Tkin);
else return DBL_MAX;
if( dndx > 0.) mfp = 1./dndx;
else mfp = DBL_MAX;
mfp *= fBias;
return mfp;
}
#endif
///////////////// end of G4LowPAIH2O header file //////////////////

Some files were not shown because too many files have changed in this diff Show More