Import Geant4 11.3.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2024-06-28 13:08:51 +02:00
parent f7b23877ed
commit e58e650b32
5232 changed files with 239416 additions and 244360 deletions
+79 -12
View File
@@ -6,15 +6,82 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-05-11 Gabriele Cosmo (emdna-V11-01-26)
## 2024-05-23 Hoang Tran (emdna-V11-02-12)
- Delete enum unused due to te use of EmParameters
to control chemistry models in G4EmDNAChemistry_option3.
## 2024-05-11 Gabriele Cosmo (emdna-V11-02-11)
- Fixed compilation error on macOS/clang with C++23 enabled, for the use
of std::function in G4OctreeFinder.
## 2024-04-19 Gabriele Cosmo
## 2024-05-06 Gabriele Cosmo (emdna-V11-02-10)
- Fixed compilation warning on macOS/XCode for implicit type conversion
in G4DNADoubleIonisationModel and G4DNAMultipleIonisationManager.
## 2024-04-25 Hoang Tran (emdna-V11-02-09)
- Delete DelayLists at the end of chemistry stage
- clean the G4Scheduler
## 2024-04-24 W.G.Shin (emdna-V11-02-08)
- G4DNAELSEPAElasticModel
- Modified to be compatible with density scaling
## 2024-04-19 Gabriele Cosmo (emdna-V11-02-07)
- Fixed compilation error on Windows VC++ with C++20 Standard enabled.
Added missing declarations for TG4MoleculeShoot specialisations on G4Track.
Based on [GitHub PR#69](https://github.com/Geant4/geant4/pull/69).
## 2024-04-18 Hoang Tran (emdna-V11-02-06)
- debug invalid KDTree node.
## 2024-04-15 Vladimir Ivanchenko (emdna-V11-02-05)
- G4GeneralIonIonisationModel, G4DNAIonChargeIncreaseModel,
G4DNAIonChargeDecreaseModel - new classes implementing general models for
ions heavier than Helium
- G4DNAChargeDecrease, G4DNAChargeIncrease - removed obsolete definition of
min/max model energy inside processes class, code clean-up
- G4DNARuddIonisationExtendedModel - updated initialisation to allow be called
from the general model
- source.cmake in models sub-directory become using alphabetical order for
both .hh and .cc files
## 2024-04-10 Shogo Okada (emdna-V11-02-04)
- G4DNAElectronHoleRecombination
- Changed the branch condition in FindReactant() to select only H2O+ ions
involved in electron-hole recombination
- G4DNAWaterDissociationDisplacer
- Added dissociative decay channels for multiple-ionized water ions
- G4DNAMultipleIonisationManager
- New class focusing on generation of multiple-ionized water ions and
calculation of scale parameter to compute cross-section of each
multiple-ionization process
- G4DNADoubleIonisation
- G4DNATripleIonisation
- G4DNAQuadrupleIonisation
- New process classes for multiple-ionization
- G4DNADoubleIonisationModel
- G4DNATripleIonisationModel
- G4DNAQuadrupleIonisationModel
- New model classes related to multiple-ionization
## 2024-04-05 Vladimir Ivanchenko (emdna-V11-02-03)
- G4DNARuddIonisationExtendedModel - updated model: do not use autolock but
uppload data in the class constructor once in all threads, use
effective charge approach for all ions with Z > 2 (in order to have more
correct computation of stopping power and ranges), precompute internal
variables before sampling, optimized algorithm of sampling (at 10 MeV it
becomes ~10 times faster), removed unused parameters.
## 2024-02-29 Hoang Tran (emdna-V11-02-02)
- correct verbose conditions for warning in IRT-syn model
## 2024-02-24 Hoang Tran (emdna-V11-02-01)
- Optimize IRT-syn at 1 ps for high LET applications
## 2023-12-15 Vladimir Ivanchenko (emdna-V11-02-00)
- G4DNABornAngle - fixed numerical problem: added protection for cosTheta;
use relativistic formula for max energy transfer to delta-electron
## 2023-11-14 Ben Morgan (emdna-V11-01-25)
- Use G4FindDataDir to access data libraries in place of raw `getenv`.
@@ -115,10 +182,10 @@ G4DNAPTBExcitationStructure) - PTB models
## 2022-11-24 Vladimir Ivanchenko (emdna-V11-00-39)
- G4DNARuddIonisationExtendedModel - fixed common work between DNA physics and
radioactive decay module - before this update test2.in macro crash, because
radioactive decay module - before this update test2.in macro crash, because
only 5 ions have data needed for this model; with this modification of the
model scaling relation to the carbon ion is used for any ion, which has
no data; low-energy limit is used now more correctly - all ions are stopped
no data; low-energy limit is used now more correctly - all ions are stopped
but not killed, because they may have radioactive decay at rest; all commented
lines are removed from the class
@@ -132,7 +199,7 @@ G4DNAPTBExcitationStructure) - PTB models
- Fixed compilation warnings for implicit type conversions on macOS/XCode 14.1.
## 2022-11-08 Vladimir Ivanchenko (emdna-V11-00-35)
- G4DNAUeharaScreenedRutherfordElasticModel - code cleanup; introduced
- G4DNAUeharaScreenedRutherfordElasticModel - code cleanup; introduced
low and high energy limit for the model; removed missleading G4Exception
## 2022-11-01 Hoang Tran (emdna-V11-00-34)
@@ -180,9 +247,9 @@ G4DNARPWBAExcitationModel
errors on NVHPC compiler.
## 2022-08-30 Vladimir Ivanchenko (emdna-V11-00-24)
- G4DNAExcitation, G4DNAVibExcitation, G4DNARotExcitation - class
- G4DNAExcitation, G4DNAVibExcitation, G4DNARotExcitation - class
cleanup according to the recent G4VEmProcess base class; model
headers are moved to source; C++11 keywards are introduced.
headers are moved to source; C++11 keywards are introduced.
## 2022-06-21 Igor Semeniouk (emdna-V11-00-23)
- G4DNABornIonisationModel1.cc, G4DNACPA100ElasticModel.cc,
@@ -225,7 +292,7 @@ G4DNARPWBAExcitationModel
- add fResetScavenger in G4SchedulerMessenger
## 2022-04-14 Paolo Dondero (emdna-V11-00-13)
- save local instances for recurrent access to particle definition in
- save local instances for recurrent access to particle definition in
G4DNAMillerGreenExcitationModel, G4DNARuddIonisationExtendedModel and
G4DNARuddIonisationModel
- use G4Pow and G4Log instead of std::pow and std::log
@@ -238,7 +305,7 @@ G4DNARPWBAExcitationModel
- Delete G4ITFinder.cc
## 2022-04-04 Paolo Dondero (emdna-V11-00-11)
- save local instances for recurrent access to particle definition in
- save local instances for recurrent access to particle definition in
G4DNADingfelderChargeDecreaseModel and G4DNADingfelderChargeIncreaseModel
- use G4Pow and G4Log instead of std::pow and std::log
@@ -309,18 +376,18 @@ warning in G4DNAMolecularDissociation::DecayIt()
23-09-2021, A. Ribon, emdna-V10-07-12
- G4ITTransportation, G4DNAElastic, G4DNAExcitation, G4DNAIonisation,
G4DNAVibExcitation, G4DNAAttachment, G4DNAChargeDecrease,
G4DNAVibExcitation, G4DNAAttachment, G4DNAChargeDecrease,
G4DNAChargeIncrease, G4DNAElectronSolvation, G4DNAMolecularDissociation,
G4DNASecondOrderReaction, G4DNAElectronHoleRecombination,
G4DNABrownianTransportation : replaced hardwired process-sub-types
with enum values introduced in the new class G4LowEnergyEmProcessSubType
18-07-2021, V. Ivanchenko, emdna-V10-07-11
- G4DNABohrExcitationModel2, G4DNABohrIonisationModel2,
- G4DNABohrExcitationModel2, G4DNABohrIonisationModel2,
G4VLEPSModel - updated interfaces to G4PhysicsVector
16-07-2021, D. Sakata, emdna-V10-07-10
- Fixed initialization error in G4DNAELSEPAElasticModel
- Fixed initialization error in G4DNAELSEPAElasticModel
28-06-2021, G. Cosmo, emdna-V10-07-09
- Fixed compilation error in G4ITMultiNavigator when compiling with c++20
@@ -76,7 +76,7 @@ template<typename Position>
G4KDNode_Base* aParent = nullptr;
G4KDNode_Base* next = this;
G4int split = -1;
while(next)
while(next != nullptr && next->IsValid())
{
split = (G4int)next->fAxis;
aParent = next;
@@ -31,8 +31,8 @@
// 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
@@ -41,26 +41,24 @@
// 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
#ifndef G4Scheduler_h
#define G4Scheduler_h
#include <G4VScheduler.hh>
#include <vector>
#include <map>
#include <memory>
#include "globals.hh"
#include "G4ITModelHandler.hh"
#include "G4ITReaction.hh"
#include "G4ITStepStatus.hh"
#include "G4ITTrackHolder.hh"
#include "G4VStateDependent.hh"
#include "G4ITReaction.hh"
#include "G4VScavengerMaterial.hh"
#include "G4VStateDependent.hh"
#include "globals.hh"
#include <G4VScheduler.hh>
#include <map>
#include <memory>
#include <vector>
class G4ITTrackingManager;
class G4ITModelProcessor;
@@ -72,226 +70,211 @@ class G4ITTrackingInteractivity;
class G4ITGun;
#ifndef compTrackPerID__
#define compTrackPerID__
struct compTrackPerID
{
# define compTrackPerID__
struct compTrackPerID
{
G4bool operator()(G4Track* rhs, G4Track* lhs) const
{
return rhs->GetTrackID() < lhs->GetTrackID();
}
};
};
#endif
/**
* G4Scheduler synchronizes (in time) track stepping
*/
class G4Scheduler :
public G4VScheduler,
public G4VStateDependent
class G4Scheduler : public G4VScheduler, public G4VStateDependent
{
protected:
~G4Scheduler() override;
protected:
~G4Scheduler() override;
public:
G4Scheduler(const G4Scheduler&) = delete;
G4Scheduler& operator=(const G4Scheduler&) = delete;
public:
G4Scheduler(const G4Scheduler&) = delete;
G4Scheduler& operator=(const G4Scheduler&) = delete;
static G4Scheduler* Instance();
/** DeleteInstance should be used instead
* of the destructor
*/
static void DeleteInstance();
G4bool Notify(G4ApplicationState requestedState) override;
static G4Scheduler* Instance();
/** DeleteInstance should be used instead
* of the destructor
*/
static void DeleteInstance();
G4bool Notify(G4ApplicationState requestedState) override;
void RegisterModel(G4VITStepModel*, G4double) override;
void RegisterModel(G4VITStepModel*, G4double) override;
void Initialize() override;
void ForceReinitialization();
inline G4bool IsInitialized();
inline G4bool IsRunning() override{return fRunning;}
void Reset() override;
void Process() override;
void ClearList();
void Initialize() override;
void ForceReinitialization();
inline G4bool IsInitialized();
inline G4bool IsRunning() override { return fRunning; }
void Reset() override;
void Process() override;
void ClearList();
inline void SetGun(G4ITGun*) override;
inline G4ITGun* GetGun();
inline void SetGun(G4ITGun*) override;
inline G4ITGun* GetGun();
inline void Stop();
void Clear();
inline void Stop();
void Clear();
// To be called only in UserReactionAction::EndProcessing()
// after fRunning flag has been turned off.
// This is not done automatically before UserReactionAction::EndProcessing()
// is called in case one would like to access some track information
void EndTracking();
// To be called only in UserReactionAction::EndProcessing()
// after fRunning flag has been turned off.
// This is not done automatically before UserReactionAction::EndProcessing()
// is called in case one would like to access some track information
void EndTracking();
void SetEndTime(const G4double) override;
void SetEndTime(const G4double) override;
/* Two tracks below the time tolerance are supposed to be
* in the same time slice
*/
inline void SetTimeTolerance(G4double) override;
inline G4double GetTimeTolerance() const override;
/* Two tracks below the time tolerance are supposed to be
* in the same time slice
*/
inline void SetTimeTolerance(G4double) override;
inline G4double GetTimeTolerance() const override;
inline void SetMaxZeroTimeAllowed(G4int) override;
inline G4int GetMaxZeroTimeAllowed() const override;
inline void SetMaxZeroTimeAllowed(G4int) override;
inline G4int GetMaxZeroTimeAllowed() const override;
inline G4ITModelHandler* GetModelHandler() override;
inline G4ITModelHandler* GetModelHandler() override;
inline void SetTimeSteps(std::map<G4double, G4double>*) override;
inline void AddTimeStep(G4double, G4double) override;
inline void SetDefaultTimeStep(G4double) override;
G4double GetLimitingTimeStep() const override;
inline G4int GetNbSteps() const override;
inline void SetMaxNbSteps(G4int) override;
inline G4int GetMaxNbSteps() const override;
inline G4double GetStartTime() const override;
inline G4double GetEndTime() const override;
inline G4double GetTimeStep() const override;
inline G4double GetPreviousTimeStep() const override;
inline G4double GetGlobalTime() const override;
inline void SetUserAction(G4UserTimeStepAction*) override;
inline G4UserTimeStepAction* GetUserTimeStepAction() const override;
inline void SetTimeSteps(std::map<G4double, G4double>*) override;
inline void AddTimeStep(G4double, G4double) override;
inline void SetDefaultTimeStep(G4double) override;
G4double GetLimitingTimeStep() const override;
inline G4int GetNbSteps() const override;
inline void SetMaxNbSteps(G4int) override;
inline G4int GetMaxNbSteps() const override;
inline G4double GetStartTime() const override;
inline G4double GetEndTime() const override;
inline G4double GetTimeStep() const override;
inline G4double GetPreviousTimeStep() const override;
inline G4double GetGlobalTime() const override;
inline void SetUserAction(G4UserTimeStepAction*) override;
inline G4UserTimeStepAction* GetUserTimeStepAction() const override;
// To use with transportation only, no reactions
inline void UseDefaultTimeSteps(G4bool);
inline G4bool AreDefaultTimeStepsUsed();
// To use with transportation only, no reactions
inline void UseDefaultTimeSteps(G4bool);
inline G4bool AreDefaultTimeStepsUsed();
inline G4ITStepStatus GetStatus() const;
inline G4ITStepStatus GetStatus() const;
/* 1 : Reaction information
* 2 : (1) + time step information
* 3 : (2) + step info for individual tracks
* 4 : (2) + trackList processing info + pushed and killed track info
*/
inline void SetVerbose(G4int) override;
inline G4int GetVerbose() const;
/* 1 : Reaction information
* 2 : (1) + time step information
* 3 : (2) + step info for individual tracks
* 4 : (2) + trackList processing info + pushed and killed track info
*/
inline void SetVerbose(G4int) override;
inline void WhyDoYouStop();
inline G4int GetVerbose() const;
void SetInteractivity(G4ITTrackingInteractivity*) override;
inline G4ITTrackingInteractivity* GetInteractivity() override;
inline void WhyDoYouStop();
virtual size_t GetNTracks();
void SetInteractivity(G4ITTrackingInteractivity*) override;
inline G4ITTrackingInteractivity* GetInteractivity() override;
void GetCollisionType(G4String& interactionType);
virtual size_t GetNTracks();
void AddWatchedTime(G4double time)
{
fWatchedTimes.insert(time);
}
void GetCollisionType(G4String& interactionType);
G4double GetNextWatchedTime() const;
void AddWatchedTime(G4double time) { fWatchedTimes.insert(time); }
inline void SetMaxTimeStep(G4double maxTimeStep)
{
fMaxTimeStep = maxTimeStep;
}
G4double GetNextWatchedTime() const;
inline G4double GetMaxTimeStep() const
{
return fMaxTimeStep;
}
inline void SetMaxTimeStep(G4double maxTimeStep) { fMaxTimeStep = maxTimeStep; }
inline G4VScavengerMaterial* GetScavengerMaterial() const
{
return fpUserScavenger.get();
}
inline void SetScavengerMaterial(std::unique_ptr<G4VScavengerMaterial> scavengerMaterial)
{
inline G4double GetMaxTimeStep() const { return fMaxTimeStep; }
inline G4VScavengerMaterial* GetScavengerMaterial() const { return fpUserScavenger.get(); }
inline void SetScavengerMaterial(std::unique_ptr<G4VScavengerMaterial> scavengerMaterial)
{
fpUserScavenger = std::move(scavengerMaterial);
}
}
protected:
protected:
void DoProcess();
void SynchronizeTracks();
void Stepping();
void DoProcess();
void SynchronizeTracks();
void Stepping();
void FindUserPreDefinedTimeStep();
void FindUserPreDefinedTimeStep();
G4bool CanICarryOn();
G4bool CanICarryOn();
void PrintWhyDoYouStop();
void PrintWhyDoYouStop();
private:
G4Scheduler();
void Create();
private:
G4Scheduler();
void Create();
G4SchedulerMessenger* fpMessenger = nullptr;
G4SchedulerMessenger* fpMessenger;
static G4ThreadLocal G4Scheduler* fgScheduler;
G4int fVerbose;
G4bool fWhyDoYouStop;
G4bool fInitialized;
G4bool fRunning;
G4bool fContinue;
static G4ThreadLocal G4Scheduler* fgScheduler;
G4int fVerbose;
G4bool fWhyDoYouStop;
G4bool fInitialized;
G4bool fRunning;
G4bool fContinue;
G4int fNbSteps;
G4int fMaxSteps;
G4int fNbSteps;
G4int fMaxSteps;
G4ITStepStatus fITStepStatus;
G4ITStepStatus fITStepStatus;
// Time members
G4bool fUseDefaultTimeSteps;
G4double fTimeTolerance;
G4double fGlobalTime;
G4double fStartTime;
G4double fStopTime;
G4double fEndTime;
G4double fPreviousTimeStep;
G4int fZeroTimeCount;
G4int fMaxNZeroTimeStepsAllowed;
// Time members
G4bool fUseDefaultTimeSteps;
G4double fTimeTolerance;
G4double fGlobalTime;
G4double fTmpGlobalTime;
G4double fStartTime;
G4double fStopTime;
G4double fEndTime;
G4double fPreviousTimeStep;
G4int fZeroTimeCount;
G4int fMaxNZeroTimeStepsAllowed;
G4double fTimeStep; // The selected minimum time step
G4double fMaxTimeStep;
G4double fTimeStep; // The selected minimum time step
G4double fMaxTimeStep;
// User steps
G4bool fUsePreDefinedTimeSteps;
G4double fDefaultMinTimeStep;
std::map<G4double, G4double>* fpUserTimeSteps = nullptr;
// One can give time steps in respect to the global time
mutable G4double fUserUpperTimeLimit;
G4double fDefinedMinTimeStep;
// selected user time step in respect to the global time
G4bool fReachedUserTimeLimit; // if fMinTimeStep == the user time step
// User steps
G4bool fUsePreDefinedTimeSteps;
G4double fDefaultMinTimeStep;
std::map<G4double, G4double>* fpUserTimeSteps;
// One can give time steps in respect to the global time
mutable G4double fUserUpperTimeLimit;
G4double fDefinedMinTimeStep;
// selected user time step in respect to the global time
G4bool fReachedUserTimeLimit; // if fMinTimeStep == the user time step
std::set<G4double> fWatchedTimes;
std::set<G4double> fWatchedTimes;
G4UserTimeStepAction* fpUserTimeStepAction;
G4UserTimeStepAction* fpUserTimeStepAction;
std::unique_ptr<G4VScavengerMaterial> fpUserScavenger;
std::unique_ptr<G4VScavengerMaterial> fpUserScavenger;
// ==========================================
// TO BE REMOVED
G4ITStepProcessor* fpStepProcessor = nullptr;
G4ITModelProcessor* fpModelProcessor = nullptr;
G4ITTrackingManager* fpTrackingManager = nullptr;
G4ITTrackingInteractivity* fpTrackingInteractivity = nullptr;
G4ITReactionSet* fReactionSet = nullptr;
G4ITTrackHolder& fTrackContainer;
G4ITModelHandler* fpModelHandler = nullptr;
// ==========================================
// ==========================================
// TO BE REMOVED
G4ITStepProcessor* fpStepProcessor;
G4ITModelProcessor* fpModelProcessor;
G4ITTrackingManager* fpTrackingManager;
G4ITTrackingInteractivity* fpTrackingInteractivity;
G4ITReactionSet* fReactionSet;
G4ITTrackHolder& fTrackContainer;
G4ITModelHandler* fpModelHandler;
// ==========================================
G4double fTSTimeStep;
// Time calculated by the time stepper in CalculateMinTimeStep()
G4double fILTimeStep;
// Time calculated by the interaction length methods
// in ComputeInteractionLength()
G4double fTSTimeStep;
// Time calculated by the time stepper in CalculateMinTimeStep()
G4double fILTimeStep;
// Time calculated by the interaction length methods
// in ComputeInteractionLength()
G4bool fInteractionStep;
// Flag : if the step is driven by the interaction with the matter and
// NOT by the reaction between tracks
G4bool fInteractionStep;
// Flag : if the step is driven by the interaction with the matter and
// NOT by the reaction between tracks
G4ITGun* fpGun;
G4ITGun* fpGun;
// ==========================================
// Hoang
G4bool fResetScavenger;
// ==========================================
//Hoang
bool fResetScavenger;
public:
void ResetScavenger(bool);
public:
void ResetScavenger(bool);
};
inline G4bool G4Scheduler::IsInitialized()
@@ -309,8 +292,7 @@ inline void G4Scheduler::SetEndTime(const G4double __endtime)
fEndTime = __endtime;
}
inline
void G4Scheduler::SetTimeSteps(std::map<G4double, G4double>* steps)
inline void G4Scheduler::SetTimeSteps(std::map<G4double, G4double>* steps)
{
fUsePreDefinedTimeSteps = true;
fpUserTimeSteps = steps;
@@ -318,8 +300,7 @@ void G4Scheduler::SetTimeSteps(std::map<G4double, G4double>* steps)
inline void G4Scheduler::AddTimeStep(G4double startingTime, G4double timeStep)
{
if (fpUserTimeSteps == nullptr)
{
if (fpUserTimeSteps == nullptr) {
fpUserTimeSteps = new std::map<G4double, G4double>();
fUsePreDefinedTimeSteps = true;
}
@@ -367,8 +348,7 @@ inline G4double G4Scheduler::GetGlobalTime() const
return fGlobalTime;
}
inline
void G4Scheduler::SetUserAction(G4UserTimeStepAction* userITAction)
inline void G4Scheduler::SetUserAction(G4UserTimeStepAction* userITAction)
{
fpUserTimeStepAction = userITAction;
}
@@ -388,8 +368,7 @@ inline G4int G4Scheduler::GetVerbose() const
return fVerbose;
}
inline
void G4Scheduler::SetMaxZeroTimeAllowed(G4int maxTimeStepAllowed)
inline void G4Scheduler::SetMaxZeroTimeAllowed(G4int maxTimeStepAllowed)
{
fMaxNZeroTimeStepsAllowed = maxTimeStepAllowed;
}
@@ -456,7 +435,7 @@ inline G4bool G4Scheduler::AreDefaultTimeStepsUsed()
inline void G4Scheduler::ResetScavenger(bool value)
{
fResetScavenger = value;
fResetScavenger = value;
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,165 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNADoubleIonisationModel.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#ifndef G4DNA_DOUBLE_IONISATION_MODEL_HH_
#define G4DNA_DOUBLE_IONISATION_MODEL_HH_
#include "G4VEmModel.hh"
#include "G4ParticleChangeForGamma.hh"
#include "G4ProductionCutsTable.hh"
#include "G4DNAGenericIonsManager.hh"
#include "G4DNACrossSectionDataSet.hh"
#include "G4Electron.hh"
#include "G4Proton.hh"
#include "G4LogLogInterpolation.hh"
#include "G4DNAWaterIonisationStructure.hh"
#include "G4VAtomDeexcitation.hh"
#include "G4NistManager.hh"
#include "G4DNAMultipleIonisationManager.hh"
using EnergyLimitTable = std::map<G4String, G4double, std::less<G4String>>;
using CrossSectionDataTable = std::map<G4String, G4DNACrossSectionDataSet*,
std::less<G4String>>;
//==============================================================================
class G4DNADoubleIonisationModel : public G4VEmModel {
public:
// constructor
G4DNADoubleIonisationModel(
const G4ParticleDefinition* p = nullptr,
const G4String& model_name = "G4DNADoubleIonisationModel");
// destructor
~G4DNADoubleIonisationModel() override;
G4DNADoubleIonisationModel& operator=(
const G4DNADoubleIonisationModel&) = delete;
G4DNADoubleIonisationModel(const G4DNADoubleIonisationModel&) = delete;
void Initialise(
const G4ParticleDefinition* particle, const G4DataVector&) override;
G4double CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double) override;
void SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double) override;
void SelectStationary(G4bool in);
void SelectVerboseLevel(G4int in);
void UseChampionAlphaParameter(G4bool in);
void SetMultipleIonisationEnergy(G4double in);
protected:
G4double RandomizeEjectedElectronEnergy(
G4ParticleDefinition* pdef, G4double ekin, G4int shell);
G4ParticleChangeForGamma* particle_change_ = nullptr;
G4int RandomSelect(G4double energy, G4double scale_param,
const G4String& pname);
G4double GenerateSecondaries(std::vector<G4DynamicParticle*>* vsec,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle,
G4int ioni_shell,
G4double& theta, G4double& phi,
G4double& shell_energy);
G4double GetLowEnergyLimit(const G4String& pname);
G4double GetUppEnergyLimit(const G4String& pname);
G4bool stat_code_;
G4VAtomDeexcitation* atom_deex_;
EnergyLimitTable elow_tab_;
EnergyLimitTable eupp_tab_;
CrossSectionDataTable xs_tab_;
G4ParticleDefinition* proton_def_;
G4ParticleDefinition* alpha_def_;
G4ParticleDefinition* carbon_def_;
const std::vector<G4double>* water_density_;
G4bool is_initialized_;
G4int verbose_level_;
std::map<G4double, G4double> model_elow_tab_;
G4DNAMultipleIonisationManager* mioni_manager_;
G4bool use_champion_param_;
G4double energy_threshold_;
};
//==============================================================================
inline void G4DNADoubleIonisationModel::SelectStationary(G4bool in)
{
stat_code_ = in;
}
//------------------------------------------------------------------------------
inline void G4DNADoubleIonisationModel::SelectVerboseLevel(G4int in)
{
verbose_level_ = in;
}
//------------------------------------------------------------------------------
inline void G4DNADoubleIonisationModel::UseChampionAlphaParameter(G4bool in)
{
use_champion_param_ = in;
}
//------------------------------------------------------------------------------
inline void G4DNADoubleIonisationModel::SetMultipleIonisationEnergy(G4double in)
{
energy_threshold_ = in;
}
#endif // G4DNA_DOUBLE_IONISATION_MODEL_HH_
@@ -159,6 +159,8 @@ private:
std::vector<G4double> eEdummyVec_Au;
std::vector<G4double> eEdummyVec_H2O;
G4Material* fpBaseWater;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -0,0 +1,83 @@
//
// ********************************************************************
// * 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 V.Ivanchenko 15.04.2024
//
// General ion ionisation model applicable for G4GenericIons.
// Concrete model of ion ionisation is selected on fly.
// Lowest energy limit - tracking cut and stationary mode are taken
// from EM parameters.
//
#ifndef G4DNAGeneralIonIonisationModel_h
#define G4DNAGeneralIonIonisationModel_h 1
#include "G4VEmModel.hh"
#include "G4ParticleChangeForGamma.hh"
class G4DNAGeneralIonIonisationModel : public G4VEmModel
{
public:
G4DNAGeneralIonIonisationModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "DNAIonIonisationModel");
~G4DNAGeneralIonIonisationModel() override = default;
G4DNAGeneralIonIonisationModel & operator=
(const G4DNAGeneralIonIonisationModel &right) = delete;
G4DNAGeneralIonIonisationModel(const G4DNAGeneralIonIonisationModel&) = delete;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) 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, G4double) override;
void StartTracking(G4Track*) override;
protected:
G4ParticleChangeForGamma* fParticleChangeForGamma{nullptr};
private:
G4double fLowestEnergy{0.0};
const G4DynamicParticle* fDynParticle{nullptr};
G4VEmModel* fCurrentModel{nullptr};
// list of concrete ion ionisation models, put extra here
G4VEmModel* fRuddIonisation;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#endif
@@ -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 V.Ivanchenko 15.04.2024
//
// General ion model for simulation of charge decrease.
// Concrete model of ion ionisation is selected on fly.
//
#ifndef G4DNAIonChargeDecreaseModel_h
#define G4DNAIonChargeDecreaseModel_h 1
#include "G4VEmModel.hh"
#include "G4ParticleChangeForGamma.hh"
class G4DNAIonChargeDecreaseModel : public G4VEmModel
{
public:
G4DNAIonChargeDecreaseModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "DNAIonChargeDecrease");
~G4DNAIonChargeDecreaseModel() override = default;
G4DNAIonChargeDecreaseModel & operator=
(const G4DNAIonChargeDecreaseModel &right) = delete;
G4DNAIonChargeDecreaseModel(const G4DNAIonChargeDecreaseModel&) = delete;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
G4double CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin, G4double,
G4double) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double, G4double) override;
void StartTracking(G4Track*) override;
protected:
G4ParticleChangeForGamma* fParticleChangeForGamma{nullptr};
private:
const G4DynamicParticle* fDynParticle{nullptr};
G4VEmModel* fCurrentModel{nullptr};
// list of concrete ion ionisation models, put extra here
G4VEmModel* fDummy;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#endif
@@ -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 V.Ivanchenko 15.04.2024
//
// General ion model for simulation of charge increase.
// Concrete model of ion ionisation is selected on fly.
//
#ifndef G4DNAIonChargeIncreaseModel_h
#define G4DNAIonChargeIncreaseModel_h 1
#include "G4VEmModel.hh"
#include "G4ParticleChangeForGamma.hh"
class G4DNAIonChargeIncreaseModel : public G4VEmModel
{
public:
G4DNAIonChargeIncreaseModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "DNAIonChargeIncrease");
~G4DNAIonChargeIncreaseModel() override = default;
G4DNAIonChargeIncreaseModel & operator=
(const G4DNAIonChargeIncreaseModel &right) = delete;
G4DNAIonChargeIncreaseModel(const G4DNAIonChargeIncreaseModel&) = delete;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
G4double CrossSectionPerVolume(const G4Material* material,
const G4ParticleDefinition* p,
G4double ekin, G4double,
G4double) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double, G4double) override;
void StartTracking(G4Track*) override;
protected:
G4ParticleChangeForGamma* fParticleChangeForGamma{nullptr};
private:
const G4DynamicParticle* fDynParticle{nullptr};
G4VEmModel* fCurrentModel{nullptr};
// list of concrete ion ionisation models, put extra here
G4VEmModel* fDummy;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
#endif
@@ -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. *
// ********************************************************************
//
// G4DNAMultipleIonisationManager.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#ifndef G4DNA_MULTIPLE_IONISATION_MANAGER_HH_
#define G4DNA_MULTIPLE_IONISATION_MANAGER_HH_
#include "globals.hh"
#include <vector>
class G4Track;
enum MultipleIonisedModification {
eDoubleIonisedMolecule = 3,
eTripleIonisedMolecule = 4,
eQuadrupleIonisedMolecule = 5
};
class G4DNAMultipleIonisationManager {
public:
G4DNAMultipleIonisationManager() = default;
~G4DNAMultipleIonisationManager() = default;
void CreateMultipleIonisedWaterMolecule(
MultipleIonisedModification mod, G4int* shell_level,
const G4Track* incoming_track);
G4bool CheckShellEnergy(
MultipleIonisedModification mod, G4double* shell_energy);
void LoadAlphaParam(const G4String& filepath, G4double Z, G4double A);
G4double GetAlphaParam(G4double energy);
private:
G4int num_node_;
std::vector<G4double> Eion_;
std::vector<G4double> alpha_;
};
#endif // G4DNA_MULTIPLE_IONISATION_MANAGER_HH_
@@ -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. *
// ********************************************************************
//
// G4DNAQuadrupleIonisationModel.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#ifndef G4DNA_QUADRUPLE_IONISATION_MODEL_HH_
#define G4DNA_QUADRUPLE_IONISATION_MODEL_HH_
#include "G4DNADoubleIonisationModel.hh"
#include "G4VEmModel.hh"
class G4DNAQuadrupleIonisationModel : public G4DNADoubleIonisationModel {
public:
// constructor
G4DNAQuadrupleIonisationModel(
const G4ParticleDefinition* p = nullptr,
const G4String& model_name = "G4DNAQuadrupleIonisationModel");
// destructor
~G4DNAQuadrupleIonisationModel() override = default;
void Initialise(const G4ParticleDefinition* particle,
const G4DataVector&) override;
G4double CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double) override;
void SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double) override;
};
#endif // G4DNA_QUADRUPLE_IONISATION_MODEL_HH_
@@ -83,14 +83,17 @@ public:
private:
void LoadData();
void SetParticle(const G4ParticleDefinition*);
G4int SelectShell(G4double energy);
G4double SampleElectronEnergy(G4double kine, G4double bindingEnergy, G4int shell);
G4double MaxEnergy(G4double kine, G4int shell);
G4double ProbabilityFunction(G4double kine, G4double deltae,
G4double bindingEnergy, G4int shell);
G4double SampleElectronEnergy(G4double kine, G4int shell);
G4double ProbabilityFunction(G4double kine, G4double deltae, G4int shell);
G4double S_1s(G4double t,
G4double energyTransferred,
@@ -148,10 +151,17 @@ private:
G4double fLimitEnergy;
G4double fMass{0.0};
G4double fAmass{0.0};
G4double fMassRate{1.0};
G4double fElow{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};
G4double slaterEffectiveCharge[3] = {0.0};
G4double sCoefficient[3] = {0.0};
G4double fTemp[5] = {0.0};
@@ -159,6 +169,7 @@ private:
G4int idx{-1};
G4int verbose{0};
G4bool isInitialised{false};
G4bool isIon{false};
G4bool isFirst{false};
G4bool isHelium{false};
@@ -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. *
// ********************************************************************
//
// G4DNATripleIonisationModel.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#ifndef G4DNA_TRIPLE_IONISATION_MODEL_HH_
#define G4DNA_TRIPLE_IONISATION_MODEL_HH_
#include "G4DNADoubleIonisationModel.hh"
#include "G4VEmModel.hh"
class G4DNATripleIonisationModel : public G4DNADoubleIonisationModel {
public:
// constructor
G4DNATripleIonisationModel(
const G4ParticleDefinition* p = nullptr,
const G4String& model_name = "G4DNATripleIonisationModel");
// destructor
~G4DNATripleIonisationModel() override = default;
void Initialise(const G4ParticleDefinition* particle,
const G4DataVector&) override;
G4double CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double) override;
void SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double) override;
};
#endif // G4DNA_TRIPLE_IONISATION_MODEL_HH_
@@ -3,6 +3,7 @@
# Define the Geant4 Module.
geant4_add_module(G4emdna-models
PUBLIC_HEADERS
G4ChemEquilibrium.hh
G4DNABornAngle.hh
G4DNABornExcitationModel.hh
G4DNABornExcitationModel1.hh
@@ -10,40 +11,60 @@ geant4_add_module(G4emdna-models
G4DNABornIonisationModel.hh
G4DNABornIonisationModel1.hh
G4DNABornIonisationModel2.hh
G4DNAChampionElasticModel.hh
G4DNACPA100ElasticModel.hh
G4DNACPA100ExcitationModel.hh
G4DNACPA100IonisationModel.hh
G4DNASmoluchowskiDiffusion.hh
G4DNASmoluchowskiReactionModel.hh
G4DNAChampionElasticModel.hh
G4DNADingfelderChargeDecreaseModel.hh
G4DNADingfelderChargeIncreaseModel.hh
G4DNADiracRMatrixExcitationModel.hh
G4DNADoubleIonisationModel.hh
G4DNAELSEPAElasticModel.hh
G4DNAEmfietzoglouExcitationModel.hh
G4DNAEmfietzoglouIonisationModel.hh
G4DNAELSEPAElasticModel.hh
G4DNAIonElasticModel.hh
G4DNAEventScheduler.hh
G4DNAGeneralIonIonisationModel.hh
G4DNAGillespieDirectMethod.hh
G4DNAIRT.hh
G4DNAIndependentReactionTimeModel.hh
G4DNAIndependentReactionTimeStepper.hh
G4DNAIonChargeDecreaseModel.hh
G4DNAIonChargeIncreaseModel.hh
G4DNAIonElasticModel.hh
G4DNAIRTMoleculeEncounterStepper.hh
G4DNAMakeReaction.hh
G4DNAMeltonAttachmentModel.hh
G4DNAMillerGreenExcitationModel.hh
G4DNAModelInterface.hh
G4DNAMolecularIRTModel.hh
G4DNAMolecularReaction.hh
G4DNAMolecularStepByStepModel.hh
G4DNAMoleculeEncounterStepper.hh
G4DNAMultipleIonisationManager.hh
G4DNAOneStepThermalizationModel.hh
G4DNAOneStepThermalizationModel.hpp
G4DNAPTBAugerModel.hh
G4DNAPTBElasticModel.hh
G4DNAPTBExcitationModel.hh
G4DNAPTBIonisationModel.hh
G4DNAQuadrupleIonisationModel.hh
G4DNAQuinnPlasmonExcitationModel.hh
G4DNARPWBAExcitationModel.hh
G4DNARPWBAIonisationModel.hh
G4DNARelativisticIonisationModel.hh
G4DNARuddAngle.hh
G4DNARuddIonisationExtendedModel.hh
G4DNARuddIonisationModel.hh
G4DNASancheExcitationModel.hh
G4DNAOneStepThermalizationModel.hh
G4DNAOneStepThermalizationModel.hpp
G4DNAPTBIonisationModel.hh
G4DNAPTBElasticModel.hh
G4DNAPTBExcitationModel.hh
G4DNAPTBAugerModel.hh
G4DNAScreenedRutherfordElasticModel.hh
G4DNASmoluchowskiDiffusion.hh
G4DNASmoluchowskiReactionModel.hh
G4DNATransformElectronModel.hh
G4DNATripleIonisationModel.hh
G4DNAUeharaScreenedRutherfordElasticModel.hh
G4DNAUpdateSystemModel.hh
G4DNAVacuumModel.hh
G4DiffusionControlledReactionModel.hh
G4LEPTSAttachmentModel.hh
G4LEPTSDissociationModel.hh
G4LEPTSElasticModel.hh
@@ -51,97 +72,88 @@ geant4_add_module(G4emdna-models
G4LEPTSPositroniumModel.hh
G4LEPTSRotExcitationModel.hh
G4LEPTSVibExcitationModel.hh
G4VLEPTSModel.hh
G4LEPTSDiffXS.hh
G4LEPTSDistribution.hh
G4LEPTSElossDistr.hh
G4LEPTSExcitationModel.hh
G4VDNAModel.hh
G4DNAModelInterface.hh
G4DNADiracRMatrixExcitationModel.hh
G4DNAQuinnPlasmonExcitationModel.hh
G4DNARelativisticIonisationModel.hh
G4DiffusionControlledReactionModel.hh
G4DNAIndependentReactionTimeModel.hh
G4DNAIndependentReactionTimeStepper.hh
G4DNAMakeReaction.hh
G4DNAUpdateSystemModel.hh
G4DNAGillespieDirectMethod.hh
G4VUpdateSystemModel.hh
G4DNAUpdateSystemModel.hh
G4DNAEventScheduler.hh
G4DNARPWBAExcitationModel.hh
G4DNARPWBAIonisationModel.hh
G4VDNAHitModel.hh
G4ChemEquilibrium.hh
G4VLEPTSModel.hh
G4VUpdateSystemModel.hh
SOURCES
G4ChemEquilibrium.cc
G4DNABornAngle.cc
G4DNABornExcitationModel1.cc
G4DNABornExcitationModel2.cc
G4DNABornIonisationModel1.cc
G4DNABornIonisationModel2.cc
G4DNAChampionElasticModel.cc
G4DNACPA100ElasticModel.cc
G4DNACPA100ExcitationModel.cc
G4DNACPA100IonisationModel.cc
G4DNASmoluchowskiDiffusion.cc
G4DNASmoluchowskiReactionModel.cc
G4DNAChampionElasticModel.cc
G4DNADingfelderChargeDecreaseModel.cc
G4DNADingfelderChargeIncreaseModel.cc
G4DNADiracRMatrixExcitationModel.cc
G4DNADoubleIonisationModel.cc
G4DNAELSEPAElasticModel.cc
G4DNAEmfietzoglouExcitationModel.cc
G4DNAEmfietzoglouIonisationModel.cc
G4DNAIonElasticModel.cc
G4DNAEventScheduler.cc
G4DNAGeneralIonIonisationModel.cc
G4DNAGillespieDirectMethod.cc
G4DNAIRT.cc
G4DNAIndependentReactionTimeModel.cc
G4DNAIndependentReactionTimeStepper.cc
G4DNAIonChargeDecreaseModel.cc
G4DNAIonChargeIncreaseModel.cc
G4DNAIonElasticModel.cc
G4DNAIRTMoleculeEncounterStepper.cc
G4DNAMakeReaction.cc
G4DNAMeltonAttachmentModel.cc
G4DNAMillerGreenExcitationModel.cc
G4DNAModelInterface.cc
G4DNAMolecularIRTModel.cc
G4DNAMolecularReaction.cc
G4DNAMolecularStepByStepModel.cc
G4DNAMoleculeEncounterStepper.cc
G4DNAMultipleIonisationManager.cc
G4DNAOneStepThermalizationModel.cc
G4DNAPTBAugerModel.cc
G4DNAPTBElasticModel.cc
G4DNAPTBExcitationModel.cc
G4DNAPTBIonisationModel.cc
G4DNAQuadrupleIonisationModel.cc
G4DNAQuinnPlasmonExcitationModel.cc
G4DNARPWBAExcitationModel.cc
G4DNARPWBAIonisationModel.cc
G4DNARelativisticIonisationModel.cc
G4DNARuddAngle.cc
G4DNARuddIonisationExtendedModel.cc
G4DNARuddIonisationModel.cc
G4DNASancheExcitationModel.cc
G4DNAOneStepThermalizationModel.cc
G4DNAPTBIonisationModel.cc
G4DNAPTBElasticModel.cc
G4DNAPTBExcitationModel.cc
G4DNAPTBAugerModel.cc
G4DNAScreenedRutherfordElasticModel.cc
G4DNASmoluchowskiDiffusion.cc
G4DNASmoluchowskiReactionModel.cc
G4DNATransformElectronModel.cc
G4DNATripleIonisationModel.cc
G4DNAUeharaScreenedRutherfordElasticModel.cc
G4DNAUpdateSystemModel.cc
G4DNAVacuumModel.cc
G4LEPTSElossDistr.cc
G4DiffusionControlledReactionModel.cc
G4LEPTSAttachmentModel.cc
G4LEPTSDissociationModel.cc
G4LEPTSElasticModel.cc
G4LEPTSDistribution.cc
G4LEPTSIonisationModel.cc
G4LEPTSPositroniumModel.cc
G4LEPTSRotExcitationModel.cc
G4LEPTSVibExcitationModel.cc
G4VLEPTSModel.cc
G4LEPTSExcitationModel.cc
G4LEPTSDiffXS.cc
G4LEPTSDistribution.cc
G4LEPTSElossDistr.cc
G4LEPTSExcitationModel.cc
G4VDNAModel.cc
G4DNAModelInterface.cc
G4DNADiracRMatrixExcitationModel.cc
G4DNAQuinnPlasmonExcitationModel.cc
G4DNARelativisticIonisationModel.cc
G4DiffusionControlledReactionModel.cc
G4DNAIndependentReactionTimeModel.cc
G4DNAIndependentReactionTimeStepper.cc
G4DNAMakeReaction.cc
G4DNAUpdateSystemModel.cc
G4DNAGillespieDirectMethod.cc
G4DNAUpdateSystemModel.cc
G4DNAEventScheduler.cc
G4DNARPWBAExcitationModel.cc
G4DNARPWBAIonisationModel.cc
G4VDNAHitModel.cc
G4ChemEquilibrium.cc)
G4VLEPTSModel.cc)
geant4_module_link_libraries(G4emdna-models
PUBLIC
@@ -72,6 +72,7 @@ G4DNABornAngle::SampleDirectionForShell(const G4DynamicParticle* dp,
{
G4double k = dp->GetKineticEnergy();
G4double cosTheta = 1.0;
if (dp->GetDefinition() == fElectron)
{
if (secKinetic < 50.*eV) cosTheta = (2.*G4UniformRand())-1.;
@@ -89,14 +90,12 @@ G4DNABornAngle::SampleDirectionForShell(const G4DynamicParticle* dp,
}
else
{
G4double mass = dp->GetDefinition()->GetPDGMass();
G4double maxSecKinetic = 4.* (electron_mass_c2 / mass) * k;
// cosTheta = std::sqrt(secKinetic / maxSecKinetic);
G4double tau = k/dp->GetDefinition()->GetPDGMass();
G4double maxSecKinetic = 2.* electron_mass_c2*tau*(tau + 2.0);
// Restriction below 100 eV from Emfietzoglou (2000)
if (secKinetic>100*eV) cosTheta = std::sqrt(secKinetic / maxSecKinetic);
if (secKinetic>100*eV) cosTheta = std::min(std::sqrt(secKinetic / maxSecKinetic), 1.0);
else cosTheta = (2.*G4UniformRand())-1.;
}
@@ -0,0 +1,736 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNADoubleIonisationModel.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#include "G4DNADoubleIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4IonTable.hh"
#include "G4GenericIon.hh"
#include "G4DNARuddAngle.hh"
#include "G4DeltaAngle.hh"
#include "G4Exp.hh"
#include <sstream>
namespace {
G4DNAWaterIonisationStructure water_structure;
// parameters for rejection function
struct FuncParams {
G4double Bj_energy;
G4double alpha_const;
G4double beta_squared;
G4double velocity;
G4double correction_factor;
G4double wc;
G4double F1;
G4double F2;
G4double c;
};
//------------------------------------------------------------------------------
void setup_rejection_function(G4ParticleDefinition* pdef, const G4double ekin,
const G4int shell, FuncParams& par)
{
// Following values provided by M. Dingfelder (priv. comm)
const G4double Bj[5]
= { 12.60 * eV, 14.70 * eV, 18.40 * eV, 32.20 * eV, 540.0 * eV };
// Data For Liquid Water from Dingfelder (Protons in Water)
G4double A1{1.02}, B1{82.0}, C1{0.45}, D1{-0.80}, E1{0.38}, A2{1.07},
B2{11.6}, // Value provided by M. Dingfelder (priv. comm)
C2{0.60}, D2{0.04}, alpha_const{0.64};
auto Bj_energy = Bj[shell];
if (shell == 4) {
alpha_const = 0.66;
//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;
// The following cases are provided by M. Dingfelder (priv. comm)
Bj_energy = water_structure.IonisationEnergy(shell);
}
const auto mass = pdef->GetPDGMass();
const auto tau = ekin * electron_mass_c2 / mass;
const auto A_ion = pdef->GetAtomicMass();
G4double v2;
G4double beta2;
constexpr G4double Ry = 13.6 * eV;
constexpr G4double xxx = 5.447761194E-02 * MeV;
if (tau < xxx) {
v2 = tau / Bj_energy;
beta2 = 2.0 * tau / electron_mass_c2;
} else {
// Relativistic
v2 = (0.5 * electron_mass_c2 / Bj_energy)
* (1.0 - (1.0 / std::pow((1.0 + (tau / electron_mass_c2)), 2.0)));
beta2 = 1.0 - 1.0 / std::pow((1.0 + (tau / electron_mass_c2 / A_ion)), 2.0);
}
const auto v = std::sqrt(v2);
const auto wc = 4.0 * v2 - 2.0 * v - (Ry / (4.0 * Bj_energy));
const auto L1 = (C1 * std::pow(v, D1)) / (1.0 + E1 * std::pow(v, (D1 + 4.0)));
const auto L2 = C2 * std::pow(v, D2);
const auto H1 = (A1 * G4Log(1.0 + v2)) / (v2 + (B1 / v2));
const auto H2 = (A2 / v2) + (B2 /(v2 * v2));
const auto F1 = L1 + H1;
const auto F2 = (L2 * H2) / (L2 + H2);
// ZF. generalized & relativistic version
G4double max_energy;
if (ekin <= 0.1 * mass) {
// maximum kinetic energy , non relativistic
max_energy = 4.0 * (electron_mass_c2 / mass) * ekin;
} else {
// relativistic
auto gamma = 1.0 / std::sqrt(1.0 - beta2);
max_energy = 2.0 * electron_mass_c2 * (gamma * gamma - 1.0)
/ (1.0 + 2.0 * gamma * (electron_mass_c2 / mass)
+ std::pow(electron_mass_c2 / mass, 2.0));
}
const auto wmax = max_energy / Bj_energy;
auto c = wmax * (F2 * wmax+ F1 * (2.0 + wmax))
/ (2.0 * (1.0 + wmax) * (1.0 + wmax));
c = 1.0 / c; // manual calculus leads to c = 1 / c
par.Bj_energy = Bj_energy;
par.alpha_const = alpha_const;
par.beta_squared = beta2;
par.velocity = v;
par.correction_factor = 1.0;
par.wc = wc;
par.F1 = F1;
par.F2 = F2;
par.c = c;
}
//------------------------------------------------------------------------------
G4double rejection_function(G4ParticleDefinition* pdef, const G4int shell,
const FuncParams& par, G4double proposed_ws)
{
const G4double Gj[5] = { 0.99, 1.11, 1.11, 0.52, 1.0 };
proposed_ws /= par.Bj_energy;
auto rejection_term = 1.0 + G4Exp(par.alpha_const * (proposed_ws - par.wc)
/ par.velocity);
rejection_term = (1.0 / rejection_term) * par.correction_factor * Gj[shell];
if (pdef == G4Proton::ProtonDefinition()) {
// for protons
return rejection_term;
} else if (pdef->GetAtomicMass() > 4) {
// for carbon ions
auto Z = pdef->GetAtomicNumber();
auto x = 100.0 * std::sqrt(par.beta_squared) / std::pow(Z, 0.6666667);
auto zeff = Z * (1.0 - G4Exp(x * (-1.316 + x * (0.112 - 0.0650 * x))));
rejection_term *= (zeff * zeff);
return rejection_term;
}
// for alpha particles
auto zeff = pdef->GetPDGCharge() / eplus + pdef->GetLeptonNumber();
rejection_term *= (zeff * zeff);
return rejection_term;
}
//------------------------------------------------------------------------------
G4double proposed_sampled_energy(const FuncParams& par)
{
const auto rval = G4UniformRand();
auto proposed_ws = par.c * (par.F1 * par.F1 * par.c
+ 2.0 * rval * (par.F2 - par.F1));
proposed_ws = -par.F1 * par.c + 2.0 * rval + std::sqrt(proposed_ws);
proposed_ws /= (par.c * (par.F1 + par.F2) - 2.0 * rval);
proposed_ws *= par.Bj_energy;
return proposed_ws;
}
} // end of anonymous namespace
//==============================================================================
// constructor
G4DNADoubleIonisationModel::G4DNADoubleIonisationModel(
const G4ParticleDefinition*, const G4String& model_name)
: G4VEmModel(model_name),
is_initialized_(false)
{
water_density_ = nullptr;
model_elow_tab_[1] = 100 * eV;
model_elow_tab_[4] = 1.0 * keV;
model_elow_tab_[5] = 0.5 * MeV; // For A = 3 or above, limit is MeV/uma
verbose_level_ = 0;
// Define default angular generator
SetAngularDistribution(new G4DNARuddAngle());
// Mark this model as "applicable" for atomic deexcitation
SetDeexcitationFlag(true);
atom_deex_ = nullptr;
particle_change_ = nullptr;
// Selection of stationary mode
stat_code_ = false;
// True if use champion alpha parameter
use_champion_param_ = false;
// Double-ionization energy
energy_threshold_ = 40.0 * eV;
}
//------------------------------------------------------------------------------
G4DNADoubleIonisationModel::~G4DNADoubleIonisationModel()
{
for (auto x : xs_tab_) {
G4DNACrossSectionDataSet* table = x.second;
if (table) { delete table; }
}
}
//------------------------------------------------------------------------------
void G4DNADoubleIonisationModel::Initialise(
const G4ParticleDefinition* particle, const G4DataVector&)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNADoubleIonisationModel::Initialise()" << G4endl;
}
proton_def_ = G4Proton::ProtonDefinition();
alpha_def_ = G4DNAGenericIonsManager::Instance()->GetIon("alpha++");
carbon_def_ = G4IonTable::GetIonTable()->GetIon(6, 12);
constexpr G4double kScaleFactor = 1.0 * m * m;
mioni_manager_ = new G4DNAMultipleIonisationManager();
G4double Z{0.0}, A{0.0};
G4String alpha_param_file{"dna/multipleionisation_alphaparam_champion.dat"};
if (particle == proton_def_) {
// *************************************************************************
// for protons
auto proton = proton_def_->GetParticleName();
elow_tab_[proton] = model_elow_tab_[1];
eupp_tab_[proton] = 3.0 * MeV;
// load cross-section data for single ionization process
auto xs_proton = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_proton->LoadData("dna/sigma_ionisation_p_rudd");
xs_tab_[proton] = xs_proton;
// set energy limits
SetLowEnergyLimit(elow_tab_[proton]);
SetHighEnergyLimit(eupp_tab_[proton]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_p.dat";
}
Z = static_cast<G4double>(proton_def_->GetAtomicNumber());
A = static_cast<G4double>(proton_def_->GetAtomicMass());
} else if (particle == alpha_def_) {
//**************************************************************************
// for alpha particles
auto alpha = alpha_def_->GetParticleName();
elow_tab_[alpha] = model_elow_tab_[4];
eupp_tab_[alpha] = 23.0 * MeV;
// load cross-section data for single ionization process
auto xs_alpha = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_alpha->LoadData("dna/sigma_ionisation_alphaplusplus_rudd");
xs_tab_[alpha] = xs_alpha;
// set energy limits
SetLowEnergyLimit(elow_tab_[alpha]);
SetHighEnergyLimit(eupp_tab_[alpha]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_alphaplusplus.dat";
}
Z = static_cast<G4double>(alpha_def_->GetAtomicNumber());
A = static_cast<G4double>(alpha_def_->GetAtomicMass());
} else if (particle == G4GenericIon::GenericIonDefinition()) {
// *************************************************************************
// for carbon ions
auto carbon = carbon_def_->GetParticleName();
elow_tab_[carbon] = model_elow_tab_[5] * carbon_def_->GetAtomicMass();
eupp_tab_[carbon] = 120.0 * MeV;
// load cross-section data for single ionization process
auto xs_carbon = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_carbon->LoadData("dna/sigma_ionisation_c_rudd");
xs_tab_[carbon] = xs_carbon;
// set energy limits
SetLowEnergyLimit(elow_tab_[carbon]);
SetHighEnergyLimit(eupp_tab_[carbon]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_c.dat";
}
Z = static_cast<G4double>(carbon_def_->GetAtomicNumber());
A = static_cast<G4double>(carbon_def_->GetAtomicMass());
}
// load alpha parameter
mioni_manager_->LoadAlphaParam(alpha_param_file, Z, A);
if (verbose_level_ > 0) {
G4cout << "G4DNADoubleIonisationModel is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV for "
<< particle->GetParticleName()
<< G4endl;
}
water_density_ = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(
G4Material::GetMaterial("G4_WATER"));
atom_deex_ = G4LossTableManager::Instance()->AtomDeexcitation();
if (is_initialized_) { return; }
particle_change_ = GetParticleChangeForGamma();
is_initialized_ = true;
}
//------------------------------------------------------------------------------
G4double G4DNADoubleIonisationModel::GetLowEnergyLimit(const G4String& pname)
{
G4double elim{0.0};
EnergyLimitTable::iterator itr = elow_tab_.find(pname);
if (itr != elow_tab_.end()) { elim = itr->second; }
return elim;
}
//------------------------------------------------------------------------------
G4double G4DNADoubleIonisationModel::GetUppEnergyLimit(const G4String& pname)
{
G4double elim{0.0};
EnergyLimitTable::iterator itr = eupp_tab_.find(pname);
if (itr != eupp_tab_.end()) { elim = itr->second; }
return elim;
}
//------------------------------------------------------------------------------
G4double G4DNADoubleIonisationModel::CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNADoubleIonisationModel::CrossSectionPerVolume()"
<< G4endl;
}
// Calculate total cross section for model
if (pdef != proton_def_ && pdef != alpha_def_ && pdef != carbon_def_) {
return 0.0;
}
static G4double water_dens = (*water_density_)[material->GetIndex()];
const auto& pname = pdef->GetParticleName();
const auto low_energy_lim = GetLowEnergyLimit(pname);
const auto upp_energy_lim = GetUppEnergyLimit(pname);
G4double sigma{0.0};
if (ekin <= upp_energy_lim) {
if (ekin < low_energy_lim) { ekin = low_energy_lim; }
CrossSectionDataTable::iterator pos = xs_tab_.find(pname);
if (pos == xs_tab_.end()) {
G4Exception("G4DNADoubleIonisationModel::CrossSectionPerVolume",
"em0002", FatalException,
"Model not applicable to particle type.");
}
G4DNACrossSectionDataSet* table = pos->second;
if (table != nullptr) {
const auto a = mioni_manager_->GetAlphaParam(ekin);
sigma = table->FindValue(ekin) * a;
}
}
if (verbose_level_ > 2) {
std::stringstream msg;
msg << "----------------------------------------------------------------\n";
msg << " G4DNADoubleIonisationModel - XS INFO START\n";
msg << " - Kinetic energy(eV): " << ekin/eV << ", Particle : "
<< pdef->GetParticleName() << "\n";
msg << " - Cross section per water molecule (cm^2): "
<< sigma / cm / cm << "\n";
msg << " - Cross section per water molecule (cm^-1): "
<< sigma * water_dens / (1.0 / cm) << "\n";
msg << " G4DNADoubleIonisationModel - XS INFO END\n";
msg << "----------------------------------------------------------------\n";
G4cout << msg.str() << G4endl;
}
return (sigma * water_dens);
}
//------------------------------------------------------------------------------
G4double G4DNADoubleIonisationModel::GenerateSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4int ioni_shell,
G4double& theta, G4double& phi, G4double& shell_energy)
{
auto pdef = particle->GetDefinition();
// get kinetic energy for a parent particle
auto ekin1 = particle->GetKineticEnergy();
// sample kinetic energy for a secondary electron
auto ekin2 = RandomizeEjectedElectronEnergy(pdef, ekin1, ioni_shell);
// sample momentum direction for a secondary electron
auto sample_electron_direction = [this](
const G4DynamicParticle* dp, G4double _ekin2, G4int _Z, G4int _ioni_shell,
const G4MaterialCutsCouple* mcc, G4double& _theta, G4double& _phi) {
G4ThreeVector locdir;
if (_theta > 0.0) {
auto costh = std::cos(_theta);
auto sinth = std::sqrt((1.0 - costh) * (1.0 + costh));
locdir.set(sinth * std::cos(_phi), sinth * std::sin(_phi), costh);
locdir.rotateUz(dp->GetMomentumDirection());
} else {
locdir = GetAngularDistribution()->SampleDirectionForShell(
dp, _ekin2, _Z, _ioni_shell, mcc->GetMaterial());
_theta = locdir.theta();
_phi = locdir.phi();
}
return locdir;
};
constexpr G4int Z = 8;
auto delta_dir = sample_electron_direction(
particle, ekin2, Z, ioni_shell, couple, theta, phi);
// generate a secondary electron and put it into the stack
auto dp = new G4DynamicParticle(G4Electron::Electron(), delta_dir, ekin2);
vsec->push_back(dp);
if (!atom_deex_ || ioni_shell != 4) { return ekin2; }
// ***************************************************************************
// Only atomic deexcitation from K shell is considered
constexpr auto k_shell = G4AtomicShellEnumerator(0);
const auto shell = atom_deex_->GetAtomicShell(Z, k_shell);
// get number of secondary electrons in the stack
// before processing atomic deescitation
const auto num_sec_init = vsec->size();
// perform atomic deexcitation process
atom_deex_->GenerateParticles(vsec, shell, Z, 0, 0);
// get number of secondary electrons in the stack
// after processing atomic deescitation
const auto num_sec_final = vsec->size();
if (num_sec_final == num_sec_init) { return ekin2; }
for (auto i = num_sec_init; i < num_sec_final; i++) {
auto e = ((*vsec)[i])->GetKineticEnergy();
// Check if there is enough residual energy
if (shell_energy < e) {
// Invalid secondary: not enough energy to create it!
// Keep its energy in the local deposit
delete (*vsec)[i];
(*vsec)[i] = 0;
continue;
}
// Ok, this is a valid secondary: keep it
shell_energy -= e;
}
// ***************************************************************************
return ekin2;
}
//------------------------------------------------------------------------------
void G4DNADoubleIonisationModel::SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling SampleSecondaries() of G4DNADoubleIonisationModel"
<< G4endl;
}
// get the definition for this parent particle
auto pdef = particle->GetDefinition();
// get kinetic energy
auto ekin = particle->GetKineticEnergy();
// get particle name
const auto& pname = pdef->GetParticleName();
// get energy limits
const auto low_energy_lim = GetLowEnergyLimit(pname);
// ***************************************************************************
// stop the transportation process of this parent particle
// if its kinetic energy is below the lower limit
if (ekin < low_energy_lim) {
particle_change_->SetProposedKineticEnergy(0.0);
particle_change_->ProposeTrackStatus(fStopAndKill);
particle_change_->ProposeLocalEnergyDeposit(ekin);
return;
}
// ***************************************************************************
constexpr G4int kNumSecondaries = 2;
constexpr G4double kDeltaTheta = pi;
G4int ioni_shell[kNumSecondaries];
G4double shell_energy[kNumSecondaries];
const auto scale_param = mioni_manager_->GetAlphaParam(ekin);
G4double tot_ioni_energy{0.0};
for (G4int i = 0; i < kNumSecondaries; i++) {
ioni_shell[i] = RandomSelect(ekin, scale_param, pname);
shell_energy[i] = ::water_structure.IonisationEnergy(ioni_shell[i]);
tot_ioni_energy += shell_energy[i];
}
if (ekin < tot_ioni_energy || tot_ioni_energy < energy_threshold_) {
return;
}
// generate secondary electrons
G4double theta{0.0}, phi{0.0}, tot_ekin2{0.0};
for (G4int i = 0; i < kNumSecondaries; i++) {
tot_ekin2 += GenerateSecondaries(vsec, couple, particle, ioni_shell[i],
theta, phi, shell_energy[i]);
theta += kDeltaTheta;
}
// This should never happen
if (mioni_manager_->CheckShellEnergy(eDoubleIonisedMolecule, shell_energy)) {
G4Exception("G4DNADoubleIonisatioModel::SampleSecondaries()",
"em2050", FatalException, "Negative local energy deposit");
}
// ***************************************************************************
// update kinematics for this parent particle
const auto primary_dir = particle->GetMomentumDirection();
particle_change_->ProposeMomentumDirection(primary_dir);
const auto scattered_energy = ekin - tot_ioni_energy - tot_ekin2;
// update total amount of shell energy
tot_ioni_energy = shell_energy[0] + shell_energy[1];
if (stat_code_) {
particle_change_->SetProposedKineticEnergy(ekin);
particle_change_->ProposeLocalEnergyDeposit(ekin - scattered_energy);
} else {
particle_change_->SetProposedKineticEnergy(scattered_energy);
particle_change_->ProposeLocalEnergyDeposit(tot_ioni_energy);
}
// ***************************************************************************
// generate double-ionized water molecules (H2O^2+)
const auto the_track = particle_change_->GetCurrentTrack();
mioni_manager_->CreateMultipleIonisedWaterMolecule(
eDoubleIonisedMolecule, ioni_shell, the_track);
// ***************************************************************************
}
//------------------------------------------------------------------------------
G4double G4DNADoubleIonisationModel::RandomizeEjectedElectronEnergy(
G4ParticleDefinition* pdef, G4double ekin, G4int shell)
{
//
// based on RandomizeEjectedElectronEnergy()
// of G4DNARuddIonisationExtendedModel
//
::FuncParams par;
::setup_rejection_function(pdef, ekin, shell, par);
// calculate maximum value
G4double emax{0.0}, val;
for (G4double en = 0.0; en < 20.0; en += 1.0) {
val = ::rejection_function(pdef, shell, par, en);
if (val <= emax) { continue; }
emax = val;
}
G4double proposed_energy, rand;
do {
// Proposed energy by inverse function sampling
proposed_energy = ::proposed_sampled_energy(par);
rand = G4UniformRand() * emax;
val = ::rejection_function(pdef, shell, par, proposed_energy);
} while (rand > val);
return proposed_energy;
}
//------------------------------------------------------------------------------
G4int G4DNADoubleIonisationModel::RandomSelect(
G4double ekin, G4double scale_param, const G4String& pname)
{
//
// based on RandomSelect() of G4DNARuddIonisationExtendedModel
//
// Retrieve data table corresponding to the current particle type
CrossSectionDataTable::iterator pos = xs_tab_.find(pname);
if (pos == xs_tab_.end()) {
G4Exception("G4DNADoubleIonisationModel::RandomSelect", "em0002",
FatalException, "Model not applicable to particle type.");
}
G4DNACrossSectionDataSet* table = pos->second;
if (table != nullptr) {
// get total number of energy level
const auto num_component = table->NumberOfComponents();
auto* valuesBuffer = new G4double[num_component];
auto shell = num_component;
G4double value = 0.0;
while (shell > 0) {
shell--;
valuesBuffer[shell] = table->GetComponent((G4int)shell)->FindValue(ekin)
* scale_param;
value += valuesBuffer[shell];
}
value *= G4UniformRand();
shell = num_component;
while (shell > 0) {
shell--;
if (valuesBuffer[shell] > value) {
if (valuesBuffer) { delete [] valuesBuffer; }
return (G4int)shell;
}
value -= valuesBuffer[shell];
}
if (valuesBuffer) { delete [] valuesBuffer; }
}
return 0;
}
@@ -38,6 +38,7 @@
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4EmParameters.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -54,18 +55,23 @@ G4VEmModel(nam)
G4ProductionCutsTable* theCoupleTable =
G4ProductionCutsTable::GetProductionCutsTable();
auto numOfCouples = (G4int)theCoupleTable->GetTableSize();
fpBaseWater = G4Material::GetMaterial("G4_WATER");
for(G4int i=0; i<numOfCouples; ++i)
{
const G4MaterialCutsCouple* couple =
theCoupleTable->GetMaterialCutsCouple(i);
const G4Material* material = couple->GetMaterial();
const G4Material* material = couple->GetMaterial()->GetBaseMaterial();
if(!material) material = couple->GetMaterial();
auto nelm = (G4int)material->GetNumberOfElements();
const G4ElementVector* theElementVector = material->GetElementVector();
if(nelm==1)
{// Protection: only for single element
G4int Z = 79;
const G4ElementVector* theElementVector = material->GetElementVector();
Z = G4lrint((*theElementVector)[0]->GetZ());
// Protection: only for GOLD
if (Z==79){
@@ -78,8 +84,8 @@ G4VEmModel(nam)
//continue;
}
}else{// Protection: H2O only is available
if(material->GetName()=="G4_WATER"){
flowEnergyLimit = 10. * eV;
if(material==fpBaseWater){
flowEnergyLimit = 10. * eV;
fhighEnergyLimit = 1 * MeV;
SetLowEnergyLimit (flowEnergyLimit);
SetHighEnergyLimit(fhighEnergyLimit);
@@ -99,7 +105,6 @@ G4VEmModel(nam)
}
}
fParticleChangeForGamma = nullptr;
fpMolDensity = nullptr;
@@ -111,31 +116,9 @@ G4VEmModel(nam)
G4DNAELSEPAElasticModel::~G4DNAELSEPAElasticModel()
{
//std::map<G4int,G4DNACrossSectionDataSet*,
// std::less<G4String>>::iterator posZ;
//for (posZ = tableZData.begin(); posZ != tableZData.end(); ++posZ)
//{
// G4DNACrossSectionDataSet* table = posZ->second;
// delete table;
//}
//for (posZ = tableZData_Au.begin(); posZ != tableZData_Au.end(); ++posZ)
//{
// G4DNACrossSectionDataSet* table = posZ->second;
// delete table;
//}
//for (posZ = tableZData_H2O.begin(); posZ != tableZData_H2O.end(); ++posZ)
//{
// G4DNACrossSectionDataSet* table = posZ->second;
// delete table;
//}
delete fpData_Au;
delete fpData_H2O;
//eEdummyVecZ.clear();
//eCumZ.clear();
//fAngleDataZ.clear();
eEdummyVec_Au.clear();
eEdummyVec_H2O.clear();
eCum_Au.clear();
@@ -168,22 +151,20 @@ const G4DataVector& )
// UNIT OF TCS
G4double scaleFactor = 1.*cm*cm;
//tableZData.clear();
//tableZData_Au.clear();
//tableZData_H2O.clear();
fpData_Au=nullptr;
fpData_H2O=nullptr;
fpBaseWater = G4Material::GetMaterial("G4_WATER");
for(G4int i=0; i<numOfCouples; ++i)
{
const G4MaterialCutsCouple* couple =
theCoupleTable->GetMaterialCutsCouple(i);
const G4Material* material = couple->GetMaterial();
const G4ElementVector* theElementVector = material->GetElementVector();
const G4Material* material = couple->GetMaterial()->GetBaseMaterial();
if(!material) material = couple->GetMaterial();
auto nelm = (G4int)material->GetNumberOfElements();
if (nelm==1){// Protection: only for single element
const G4ElementVector* theElementVector = material->GetElementVector();
G4int Z = G4lrint((*theElementVector)[0]->GetZ());
if (Z!=79)// Protection: only for GOLD
{
@@ -198,13 +179,6 @@ const G4DataVector& )
oss.clear(stringstream::goodbit);
oss << Z;
fileZElectron += oss.str()+"_muffintin";
//G4DNACrossSectionDataSet* tableZE =
// new G4DNACrossSectionDataSet
// (new G4LogLogInterpolation, eV,scaleFactor );
//tableZE->LoadData(fileZElectron);
////tableZData_Au[0] = tableZE;
//tableZData[Z] = tableZE;
fpData_Au = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
eV,
@@ -212,7 +186,8 @@ const G4DataVector& )
fpData_Au->LoadData(fileZElectron);
std::ostringstream eFullFileNameZ;
const char *path = G4FindDataDir("G4LEDATA");
const char *path = G4EmParameters::Instance()->GetDirLEDATA();
if (path == nullptr)
{
G4Exception("G4DNAELSEPAElasticModel::Initialise","em0002",
@@ -236,44 +211,32 @@ const G4DataVector& )
FatalException,"Missing data file for cumulated DCS");
return;
}
//eEdummyVecZ.clear();
//eCumZ.clear();
//fAngleDataZ.clear();
eEdummyVec_Au.clear();
eCum_Au.clear();
fAngleData_Au.clear();
//eEdummyVecZ[Z].push_back(0.);
eEdummyVec_Au.push_back(0.);
do
{
G4double eDummy;
G4double cumDummy;
eDiffCrossSectionZ>>eDummy>>cumDummy;
//if (eDummy != eEdummyVecZ[Z].back())
if (eDummy != eEdummyVec_Au.back())
{
//eEdummyVecZ[Z].push_back(eDummy);
eEdummyVec_Au.push_back(eDummy);
//eCumZ[Z][eDummy].push_back(0.);
eCum_Au[eDummy].push_back(0.);
}
//eDiffCrossSectionZ>>fAngleDataZ[Z][eDummy][cumDummy];
eDiffCrossSectionZ>>fAngleData_Au[eDummy][cumDummy];
//if (cumDummy != eCumZ[Z][eDummy].back())
if (cumDummy != eCum_Au[eDummy].back())
{
//eCumZ[Z][eDummy].push_back(cumDummy);
eCum_Au[eDummy].push_back(cumDummy);
}
}while(!eDiffCrossSectionZ.eof());
}
}else{// Protection: H2O only is available
if(material->GetName()=="G4_WATER"){
if(material == fpBaseWater && !fpData_H2O){
if (LowEnergyLimit() < 10*eV)
{
G4cout<<"G4DNAELSEPAElasticModel: low energy limit increased from "
@@ -292,13 +255,6 @@ const G4DataVector& )
G4String fileZElectron("dna/sigma_elastic_e_elsepa_muffin");
//G4DNACrossSectionDataSet* tableZE =
// new G4DNACrossSectionDataSet(
// new G4LogLogInterpolation, eV,scaleFactor );
//tableZE->LoadData(fileZElectron);
////tableZData_H2O[0] = tableZE;
//tableZData[0] = tableZE;
fpData_H2O = new G4DNACrossSectionDataSet(new G4LogLogInterpolation,
eV,
scaleFactor );
@@ -306,7 +262,7 @@ const G4DataVector& )
std::ostringstream eFullFileNameZ;
const char *path = G4FindDataDir("G4LEDATA");
const char *path = G4EmParameters::Instance()->GetDirLEDATA();
if (path == nullptr)
{
G4Exception("G4DNAELSEPAElasticModel::Initialise","em0004",
@@ -328,15 +284,10 @@ const G4DataVector& )
FatalException,
"Missing data file for cumulated DCS");
//eEdummyVecZ.clear();
//eCumZ.clear();
//fAngleDataZ.clear();
eEdummyVec_H2O.clear();
eCum_H2O.clear();
fAngleData_H2O.clear();
//eEdummyVecZ[0].push_back(0.);
eEdummyVec_H2O.push_back(0.);
do
@@ -344,19 +295,13 @@ const G4DataVector& )
G4double eDummy;
G4double cumDummy;
eDiffCrossSectionZ>>eDummy>>cumDummy;
//if (eDummy != eEdummyVecZ[0].back())
if (eDummy != eEdummyVec_H2O.back())
{
//eEdummyVecZ[0].push_back(eDummy);
eEdummyVec_H2O.push_back(eDummy);
//eCumZ[0][eDummy].push_back(0.);
eCum_H2O[eDummy].push_back(0.);
}
//eDiffCrossSectionZ>>fAngleDataZ[0][eDummy][cumDummy];
eDiffCrossSectionZ>>fAngleData_H2O[eDummy][cumDummy];
//if (cumDummy != eCumZ[0][eDummy].back()){
if (cumDummy != eCum_H2O[eDummy].back()){
//eCumZ[0][eDummy].push_back(cumDummy);
eCum_H2O[eDummy].push_back(cumDummy);
}
}while(!eDiffCrossSectionZ.eof());
@@ -378,7 +323,10 @@ const G4DataVector& )
fParticleChangeForGamma = GetParticleChangeForGamma();
fpMolDensity = nullptr;
fpMolDensity =
G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
isInitialised = true;
}
@@ -403,13 +351,13 @@ G4double G4DNAELSEPAElasticModel::CrossSectionPerVolume
G4double atomicNDensity=0.0;
G4double sigma=0;
const G4ElementVector* theElementVector = material->GetElementVector();
std::size_t nelm = material->GetNumberOfElements();
if (nelm==1) // Protection: only for single element
{
// Protection: only for GOLD
if (material->GetZ()!=79) return 0.0;
const G4ElementVector* theElementVector = material->GetElementVector();
G4int Z = G4lrint((*theElementVector)[0]->GetZ());
const G4String& particleName = particle->GetParticleName();
@@ -420,28 +368,6 @@ G4double G4DNAELSEPAElasticModel::CrossSectionPerVolume
{
if (ekin < fkillBelowEnergy_Au) return DBL_MAX;
//std::map< G4int,G4DNACrossSectionDataSet*,
// std::less<G4String> >::iterator pos;
////pos = tableZData_Au.find(0);
//pos = tableZData.find(Z);
//
////if (pos != tableZData_Au.end())
//if (pos != tableZData.end())
//{
// G4DNACrossSectionDataSet* table = pos->second;
// if (table != 0)
// {
// // XS takes its 10 eV value below 10 eV for GOLD
// if (ekin < 10*eV) sigma = table->FindValue(10*eV);
// else sigma = table->FindValue(ekin);
// }
//}
//else
//{
// G4Exception("G4DNAELSEPAElasticModel::ComputeCrossSectionPerVolume",
// "em0006",FatalException,"Model not applicable to particle type.");
//}
if (ekin < 10*eV) sigma = fpData_Au->FindValue(10*eV);
else sigma = fpData_Au->FindValue(ekin);
}
@@ -462,30 +388,11 @@ G4double G4DNAELSEPAElasticModel::CrossSectionPerVolume
}
else
{
fpMolDensity =
G4DNAMolecularMaterial::Instance()->
GetNumMolPerVolTableFor(G4Material::GetMaterial("G4_WATER"));
atomicNDensity = (*fpMolDensity)[material->GetIndex()];
if(atomicNDensity!= 0.0)
{
if (ekin < HighEnergyLimit() && ekin >= LowEnergyLimit())
{
//std::map< G4int,G4DNACrossSectionDataSet*,
//std::less<G4String> >::iterator pos;
////pos = tableZData_H2O.find(0); // the data is stored as Z=0
//pos = tableZData.find(0); // the data is stored as Z=0
////SI : XS must not be zero
//// otherwise sampling of secondaries method ignored
////if (pos != tableZData_H2O.end())
//if (pos != tableZData.end())
//{
// G4DNACrossSectionDataSet* table = pos->second;
// if (table != 0)
// {
// sigma = table->FindValue(ekin);
// }
//}
sigma = fpData_H2O->FindValue(ekin);
}
}
@@ -524,11 +431,13 @@ void G4DNAELSEPAElasticModel::SampleSecondaries(
G4double electronEnergy0 = aDynamicElectron->GetKineticEnergy();
const G4Material* material = couple->GetMaterial();
const G4ElementVector* theElementVector = material->GetElementVector();
const G4Material* material = couple->GetMaterial()->GetBaseMaterial();
if(!material) material = couple->GetMaterial();
std::size_t nelm = material->GetNumberOfElements();
if (nelm==1) // Protection: only for single element
{
const G4ElementVector* theElementVector = material->GetElementVector();
G4int Z = G4lrint((*theElementVector)[0]->GetZ());
if (Z!=79) return;
if (electronEnergy0 < fkillBelowEnergy_Au)
@@ -571,7 +480,7 @@ void G4DNAELSEPAElasticModel::SampleSecondaries(
}
else
{
if(material->GetName()=="G4_WATER")
if(material == fpBaseWater)
{
//The data for water is stored as Z=0
G4double cosTheta = RandomizeCosTheta(0,electronEnergy0);
@@ -616,9 +525,7 @@ G4double G4DNAELSEPAElasticModel::Theta(G4int Z,
if (particleDefinition == G4Electron::ElectronDefinition())
{
//std::vector<G4double>::iterator e2
// = std::upper_bound(eEdummyVecZ[Z].begin(),
// eEdummyVecZ[Z].end(), k);
std::vector<G4double>::iterator e2;
if(Z==0){
e2 = std::upper_bound(eEdummyVec_H2O.begin(),
@@ -630,9 +537,6 @@ G4double G4DNAELSEPAElasticModel::Theta(G4int Z,
auto e1 = e2 - 1;
//std::vector<G4double>::iterator cum12
// = std::upper_bound(eCumZ[Z][(*e1)].begin(),
// eCumZ[Z][(*e1)].end(),integrDiff);
std::vector<G4double>::iterator cum12;
if(Z==0){
cum12 = std::upper_bound(eCum_H2O[(*e1)].begin(),
@@ -665,11 +569,6 @@ G4double G4DNAELSEPAElasticModel::Theta(G4int Z,
valuecum21 = *cum21;
valuecum22 = *cum22;
//a11 = fAngleDataZ[Z][valueE1][valuecum11];
//a12 = fAngleDataZ[Z][valueE1][valuecum12];
//a21 = fAngleDataZ[Z][valueE2][valuecum21];
//a22 = fAngleDataZ[Z][valueE2][valuecum22];
if(Z==0){
a11 = fAngleData_H2O[valueE1][valuecum11];
a12 = fAngleData_H2O[valueE1][valuecum12];
@@ -0,0 +1,122 @@
//
// ********************************************************************
// * 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 "G4DNAGeneralIonIonisationModel.hh"
#include "G4DNARuddIonisationExtendedModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4EmParameters.hh"
#include "G4GenericIon.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAGeneralIonIonisationModel::G4DNAGeneralIonIonisationModel(
const G4ParticleDefinition*, const G4String& nam)
: G4VEmModel(nam)
{
fRuddIonisation = new G4DNARuddIonisationExtendedModel();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAGeneralIonIonisationModel::Initialise(const G4ParticleDefinition* part,
const G4DataVector& v)
{
if (part != G4GenericIon::GenericIon()) {
G4ExceptionDescription ed;
ed << "Wrong particle type <" << part->GetParticleName()
<< "> - only G4GenericIon is allowed";
G4Exception("G4DNAGeneralIonIonisationModel::Initialise(...)",
"em2001", FatalException, ed);
}
// stationary model and tracking cut may be defined between runs
auto param = G4EmParameters::Instance();
fLowestEnergy = param->LowestMuHadEnergy();
// this pointer should be defined once before initialisation of
// concrete models
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
// should be set once for each model
fRuddIonisation->SetParticleChange(fParticleChangeForGamma);
}
// initialisation of concrete models - put extra model here
fRuddIonisation->Initialise(part, v);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAGeneralIonIonisationModel::StartTracking(G4Track* track)
{
fDynParticle = track->GetDynamicParticle();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAGeneralIonIonisationModel::CrossSectionPerVolume(const G4Material* mat,
const G4ParticleDefinition* p,
G4double ekin,
G4double, G4double)
{
// apply tracking cut
if (ekin <= fLowestEnergy) { return DBL_MAX; }
// select model
fCurrentModel = fRuddIonisation;
// G4int Z = GetAtomicNumber();
// G4int Q = G4lrint(fDynParticle->GetCharge()/CLHEP::eplus);
// compute concrete cross section
return fCurrentModel->CrossSectionPerVolume(mat, p, ekin);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAGeneralIonIonisationModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dp,
G4double, G4double)
{
G4double ekin = dp->GetKineticEnergy();
// tracking cut
if (ekin <= fLowestEnergy) {
fParticleChangeForGamma->SetProposedKineticEnergy(0.);
fParticleChangeForGamma->ProposeTrackStatus(fStopButAlive);
fParticleChangeForGamma->ProposeLocalEnergyDeposit(ekin);
return;
}
// sample secondaries by the selected model
fCurrentModel->SampleSecondaries(fvect, couple, dp);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -25,27 +25,27 @@
// 20/2/2019
// Author: HoangTRAN
#include <memory>
#include "G4DNAIndependentReactionTimeStepper.hh"
#include "G4VDNAReactionModel.hh"
#include "G4DNAMolecularReactionTable.hh"
#include "G4UnitsTable.hh"
#include "G4Molecule.hh"
#include "G4ChemicalMoleculeFinder.hh"
#include "G4DNAChemistryManager.hh"
#include "G4DNAMakeReaction.hh"
#include "G4ITReactionChange.hh"
#include "G4Scheduler.hh"
#include "G4IRTUtils.hh"
#include "Randomize.hh"
#include "G4DNAMolecularReactionTable.hh"
#include "G4DiffusionControlledReactionModel.hh"
#include "G4IRTUtils.hh"
#include "G4ITReactionChange.hh"
#include "G4Molecule.hh"
#include "G4Scheduler.hh"
#include "G4UnitsTable.hh"
#include "G4VDNAReactionModel.hh"
#include "Randomize.hh"
#include <memory>
using namespace std;
using namespace CLHEP;
G4DNAIndependentReactionTimeStepper::Utils::Utils(const G4Track& trackA,
const G4Track& trackB)
: fTrackA(trackA)
, fTrackB(trackB)
G4DNAIndependentReactionTimeStepper::Utils::Utils(const G4Track& trackA, const G4Track& trackB)
: fTrackA(trackA), fTrackB(trackB)
{
fpMoleculeA = GetMolecule(trackA);
fpMoleculeB = GetMolecule(trackA);
@@ -65,16 +65,15 @@ void G4DNAIndependentReactionTimeStepper::Prepare()
void G4DNAIndependentReactionTimeStepper::InitializeForNewTrack()
{
if(fReactants != nullptr)
{
if (fReactants != nullptr) {
fReactants.reset();
}
fSampledMinTimeStep = DBL_MAX;
fSampledMinTimeStep = DBL_MAX;
fHasAlreadyReachedNullTime = false;
}
G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
const G4Track& trackA, const G4double& userMinTimeStep)
G4double G4DNAIndependentReactionTimeStepper::CalculateStep(const G4Track& trackA,
const G4double& userMinTimeStep)
{
auto pMoleculeA = GetMolecule(trackA);
InitializeForNewTrack();
@@ -82,14 +81,13 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
fCheckedTracks.insert(trackA.GetTrackID());
#ifdef G4VERBOSE
if(fVerbose != 0)
{
if (fVerbose != 0) {
G4cout << "________________________________________________________________"
"_______"
<< G4endl;
G4cout << "G4DNAIndependentReactionTimeStepper::CalculateStep" << G4endl;
G4cout << "Check done for molecule : " << pMoleculeA->GetName() << " ("
<< trackA.GetTrackID() << ") " << G4endl;
G4cout << "Check done for molecule : " << pMoleculeA->GetName() << " (" << trackA.GetTrackID()
<< ") " << G4endl;
}
#endif
@@ -97,54 +95,41 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
const auto pReactantList = fMolecularReactionTable->CanReactWith(pMolConfA);
if(pReactantList == nullptr)
{
#ifdef G4VERBOSE
if(fVerbose > 1)
{
G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
G4cout << "!!! WARNING" << G4endl;
G4cout << "G4DNAIndependentReactionTimeStepper::CalculateStep will "
"return infinity "
"for the reaction because the molecule "
<< pMoleculeA->GetName()
<< " does not have any reactants given in the reaction table."
<< G4endl;
G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
if (pReactantList == nullptr) {
if(fVerbose > 1) {
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will return infinity "
"for the reaction because the molecule "
<< pMoleculeA->GetName() << " does not have any reactants given in the reaction table."
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateStep",
"G4DNAIndependentReactionTimeStepper03", JustWarning, msg);
}
#endif
return DBL_MAX;
}
auto nbReactives = (G4int)pReactantList->size();
auto nbReactives = (G4int)pReactantList->size();
if(nbReactives == 0)
{
#ifdef G4VERBOSE
// DEBUG
if(fVerbose != 0)
{
G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
G4cout << "!!! WARNING" << G4endl;
G4cout << "G4DNAIndependentReactionTimeStepper::CalculateStep will "
"return infinity "
"for the reaction because the molecule "
<< pMoleculeA->GetName()
<< " does not have any reactants given in the reaction table."
<< "This message can also result from a wrong implementation of "
"the reaction table."
<< G4endl;
G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
if (nbReactives == 0) {
if(fVerbose != 0){
G4ExceptionDescription msg;
msg << "G4DNAIndependentReactionTimeStepper::CalculateStep will "
"return infinity "
"for the reaction because the molecule "
<< pMoleculeA->GetName() << " does not have any reactants given in the reaction table."
<< "This message can also result from a wrong implementation of "
"the reaction table."
<< G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateStep",
"G4DNAIndependentReactionTimeStepper04", JustWarning, msg);
}
#endif
return DBL_MAX;
}
fReactants = std::make_shared<vector<G4Track*>>();
fReactionModel->Initialise(pMolConfA, trackA);
for(G4int i = 0; i < nbReactives; ++i)
{
for (G4int i = 0; i < nbReactives; ++i) {
auto pMoleculeB = (*pReactantList)[i];
G4int key = pMoleculeB->GetMoleculeID();
G4int key = pMoleculeB->GetMoleculeID();
// fRCutOff = G4IRTUtils::GetRCutOff(1 * ps);
fRCutOff = G4IRTUtils::GetRCutOff();
@@ -153,51 +138,40 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
const G4double Reff = fReactionModel->GetReactionRadius(i);
std::vector<std::pair<G4TrackList::iterator, G4double>> resultIndices;
resultIndices.clear();
G4ChemicalMoleculeFinder::Instance()->FindNearestInRange(
trackA, key, fRCutOff, resultIndices);
G4ChemicalMoleculeFinder::Instance()->FindNearestInRange(trackA, key, fRCutOff, resultIndices);
if(resultIndices.empty())
{
if (resultIndices.empty()) {
continue;
}
for(auto& it : resultIndices)
{
for (auto& it : resultIndices) {
G4Track* pTrackB = *(std::get<0>(it));
if(pTrackB == &trackA)
{
if (pTrackB == &trackA) {
continue;
}
if(pTrackB == nullptr)
{
if (pTrackB == nullptr) {
G4ExceptionDescription exceptionDescription;
exceptionDescription << "No trackB no valid";
G4Exception("G4DNAIndependentReactionTimeStepper"
"::CalculateStep()",
"G4DNAIndependentReactionTimeStepper007", FatalException,
exceptionDescription);
}else
{
if(fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end())
{
G4Exception(
"G4DNAIndependentReactionTimeStepper"
"::CalculateStep()",
"G4DNAIndependentReactionTimeStepper007", FatalException, exceptionDescription);
}
else {
if (fCheckedTracks.find(pTrackB->GetTrackID()) != fCheckedTracks.end()) {
continue;
}
Utils utils(trackA, *pTrackB);
auto pMolB = GetMolecule(pTrackB);
auto pMolConfB = pMolB->GetMolecularConfiguration();
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)
{
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;
}
@@ -206,15 +180,12 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
}
}
}
else
{
else {
G4double tempMinET = GetTimeToEncounter(trackA, *pTrackB);
if(tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime())
{
if (tempMinET < 0 || tempMinET > G4Scheduler::Instance()->GetEndTime()) {
continue;
}
if(tempMinET >= fSampledMinTimeStep)
{
if (tempMinET >= fSampledMinTimeStep) {
continue;
}
fSampledMinTimeStep = tempMinET;
@@ -226,23 +197,19 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
}
#ifdef G4VERBOSE
if(fVerbose != 0)
{
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: ";
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++)
{
for (it = fReactants->begin(); it != fReactants->end(); it++) {
G4Track* trackB = *it;
G4cout << GetMolecule(trackB)->GetName() << " (" << trackB->GetTrackID()
<< ") \t ";
G4cout << GetMolecule(trackB)->GetName() << " (" << trackB->GetTrackID() << ") \t ";
}
G4cout << G4endl;
}
@@ -251,126 +218,107 @@ G4double G4DNAIndependentReactionTimeStepper::CalculateStep(
return fSampledMinTimeStep;
}
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(
const Utils& utils)
void G4DNAIndependentReactionTimeStepper::CheckAndRecordResults(const Utils& utils)
{
if(utils.fTrackB.GetTrackStatus() != fAlive)
{
if (utils.fTrackB.GetTrackStatus() != fAlive) {
return;
}
if(&utils.fTrackB == &utils.fTrackA)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "A track is reacting with itself"
if (&utils.fTrackB == &utils.fTrackA) {
G4ExceptionDescription msg;
msg << "A track is reacting with itself"
" (which is impossible) ie fpTrackA == trackB"
<< G4endl;
exceptionDescription << "Molecule A is of type : "
<< utils.fpMoleculeA->GetName()
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.fTrackB.GetTrackID() << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper003", FatalErrorInArgument,
exceptionDescription);
msg);
}
if(fabs(utils.fTrackB.GetGlobalTime() - utils.fTrackA.GetGlobalTime()) >
utils.fTrackA.GetGlobalTime() * (1. - 1. / 100))
if (fabs(utils.fTrackB.GetGlobalTime() - utils.fTrackA.GetGlobalTime())
> utils.fTrackA.GetGlobalTime() * (1. - 1. / 100))
{
// DEBUG
G4ExceptionDescription exceptionDescription;
exceptionDescription
<< "The interacting tracks are not synchronized in time" << G4endl;
exceptionDescription
<< "trackB->GetGlobalTime() != fpTrackA.GetGlobalTime()" << G4endl;
G4ExceptionDescription msg;
msg << "The interacting tracks are not synchronized in time" << G4endl;
msg << "trackB->GetGlobalTime() != fpTrackA.GetGlobalTime()" << G4endl;
exceptionDescription << "fpTrackA : trackID : "
<< utils.fTrackA.GetTrackID()
msg << "fpTrackA : trackID : " << utils.fTrackA.GetTrackID()
<< "\t Name :" << utils.fpMoleculeA->GetName()
<< "\t fpTrackA->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackA.GetGlobalTime(), "Time")
<< G4endl;
<< G4BestUnit(utils.fTrackA.GetGlobalTime(), "Time") << G4endl;
exceptionDescription << "trackB : trackID : " << utils.fTrackB.GetTrackID()
msg << "trackB : trackID : " << utils.fTrackB.GetTrackID()
<< "\t Name :" << utils.fpMoleculeB->GetName()
<< "\t trackB->GetGlobalTime() = "
<< G4BestUnit(utils.fTrackB.GetGlobalTime(), "Time")
<< G4endl;
<< G4BestUnit(utils.fTrackB.GetGlobalTime(), "Time") << G4endl;
G4Exception("G4DNAIndependentReactionTimeStepper::RetrieveResults",
"G4DNAIndependentReactionTimeStepper004", FatalErrorInArgument,
exceptionDescription);
msg);
}
fReactants->push_back(const_cast<G4Track*>(&utils.fTrackB));
}
std::unique_ptr<G4ITReactionChange>
G4DNAIndependentReactionTimeStepper::FindReaction(
std::unique_ptr<G4ITReactionChange> G4DNAIndependentReactionTimeStepper::FindReaction(
G4ITReactionSet* pReactionSet, const G4double& currentStepTime,
const G4double& /*previousStepTime*/,
const G4bool& /*reachedUserStepTimeLimit*/)
const G4double& /*previousStepTime*/, const G4bool& /*reachedUserStepTimeLimit*/)
{
if(pReactionSet == nullptr)
{
if (pReactionSet == nullptr) {
return nullptr;
}
G4ITReactionPerTime& reactionPerTime = pReactionSet->GetReactionsPerTime();
if(reactionPerTime.empty())
{
if (reactionPerTime.empty()) {
return nullptr;
}
for(auto reaction_i = reactionPerTime.begin();
reaction_i != reactionPerTime.end(); reaction_i = reactionPerTime.begin())
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;
if(pTrackA->GetTrackStatus() == fStopAndKill)
{
if (pTrackA->GetTrackStatus() == fStopAndKill) {
continue;
}
G4Track* pTrackB = (*reaction_i)->GetReactant(pTrackA);
if(pTrackB->GetTrackStatus() == fStopAndKill)
{
if (pTrackB->GetTrackStatus() == fStopAndKill) {
continue;
}
if(pTrackB == pTrackA)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "The IT reaction process sent back a reaction "
if (pTrackB == pTrackA) {
G4ExceptionDescription msg;
msg << "The IT reaction process sent back a reaction "
"between trackA and trackB. ";
exceptionDescription << "The problem is trackA == trackB";
msg << "The problem is trackA == trackB";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper02", FatalErrorInArgument,
exceptionDescription);
msg);
}
pReactionSet->SelectThisReaction(*reaction_i);
if(fpReactionProcess != nullptr &&
fpReactionProcess->TestReactibility(*pTrackA, *pTrackB, currentStepTime,
false))
if (fpReactionProcess != nullptr
&& fpReactionProcess->TestReactibility(*pTrackA, *pTrackB, currentStepTime, false))
{
if((fSampledPositions.find(pTrackA->GetTrackID()) ==
fSampledPositions.end() &&
(fSampledPositions.find(pTrackB->GetTrackID()) ==
fSampledPositions.end())))
if ((fSampledPositions.find(pTrackA->GetTrackID()) == fSampledPositions.end()
&& (fSampledPositions.find(pTrackB->GetTrackID()) == fSampledPositions.end())))
{
G4ExceptionDescription exceptionDescription;
exceptionDescription
<< "The positions of trackA and trackB have no counted ";
G4ExceptionDescription msg;
msg << "The positions of trackA and trackB have no counted ";
G4Exception("G4DNAIndependentReactionTimeStepper::FindReaction",
"G4DNAIndependentReactionTimeStepper0001",
FatalErrorInArgument, exceptionDescription);
"G4DNAIndependentReactionTimeStepper0001", FatalErrorInArgument,
msg);
}
pTrackA->SetPosition(fSampledPositions[pTrackA->GetTrackID()]);
pTrackB->SetPosition(fSampledPositions[pTrackB->GetTrackID()]);
auto pReactionChange =
fpReactionProcess->MakeReaction(*pTrackA, *pTrackB);
if(pReactionChange == nullptr)
{
auto pReactionChange = fpReactionProcess->MakeReaction(*pTrackA, *pTrackB);
if (pReactionChange == nullptr) {
return nullptr;
}
return pReactionChange;
@@ -379,8 +327,7 @@ G4DNAIndependentReactionTimeStepper::FindReaction(
return nullptr;
}
void G4DNAIndependentReactionTimeStepper::SetReactionModel(
G4VDNAReactionModel* pReactionModel)
void G4DNAIndependentReactionTimeStepper::SetReactionModel(G4VDNAReactionModel* pReactionModel)
{
fReactionModel = pReactionModel;
}
@@ -395,85 +342,68 @@ void G4DNAIndependentReactionTimeStepper::SetVerbose(G4int flag)
fVerbose = flag;
}
G4double G4DNAIndependentReactionTimeStepper::GetTimeToEncounter(
const G4Track& trackA, const G4Track& trackB)
G4double G4DNAIndependentReactionTimeStepper::GetTimeToEncounter(const G4Track& trackA,
const G4Track& trackB)
{
G4double timeToReaction =
dynamic_cast<G4DiffusionControlledReactionModel*>(fReactionModel)
->GetTimeToEncounter(trackA, trackB);
G4double timeToReaction = dynamic_cast<G4DiffusionControlledReactionModel*>(fReactionModel)
->GetTimeToEncounter(trackA, trackB);
return timeToReaction;
}
void G4DNAIndependentReactionTimeStepper::SetReactionProcess(
G4VITReactionProcess* pReactionProcess)
void G4DNAIndependentReactionTimeStepper::SetReactionProcess(G4VITReactionProcess* pReactionProcess)
{
fpReactionProcess = pReactionProcess;
}
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(
G4double /*currentGlobalTime*/, G4double definedMinTimeStep)
G4double G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep(G4double /*currentGlobalTime*/,
G4double definedMinTimeStep)
{
G4double fTSTimeStep = DBL_MAX;
fCheckedTracks.clear();
for(auto pTrack : *fpTrackContainer->GetMainList())
{
if(pTrack == nullptr)
{
G4ExceptionDescription exceptionDescription;
exceptionDescription << "No track found.";
for (auto pTrack : *fpTrackContainer->GetMainList()) {
if (pTrack == nullptr) {
G4ExceptionDescription msg;
msg << "No track found.";
G4Exception("G4DNAIndependentReactionTimeStepper::CalculateMinTimeStep",
"G4DNAIndependentReactionTimeStepper006",
FatalErrorInArgument, exceptionDescription);
"G4DNAIndependentReactionTimeStepper006", FatalErrorInArgument,
msg);
continue;
}
G4TrackStatus trackStatus = pTrack->GetTrackStatus();
if(trackStatus == fStopAndKill || trackStatus == fStopButAlive)
{
if (trackStatus == fStopAndKill || trackStatus == fStopButAlive) {
continue;
}
G4double sampledMinTimeStep = CalculateStep(*pTrack, definedMinTimeStep);
G4double sampledMinTimeStep = CalculateStep(*pTrack, definedMinTimeStep);
G4TrackVectorHandle reactants = GetReactants();
if(sampledMinTimeStep < fTSTimeStep)
{
if (sampledMinTimeStep < fTSTimeStep) {
fTSTimeStep = sampledMinTimeStep;
fReactionSet->CleanAllReaction();
if(reactants)
{
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack),
reactants);
if (reactants) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), reactants);
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for(const auto& it : *fReactants)
{
for (const auto& it : *fReactants) {
auto pTrackB = it;
// G4cout<<"position : "<<pTrackB->GetTrackID()<<G4endl;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
}
else if(fTSTimeStep == sampledMinTimeStep && G4bool(reactants))
{
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack),
reactants);
else if (fTSTimeStep == sampledMinTimeStep && G4bool(reactants)) {
fReactionSet->AddReactions(fTSTimeStep, const_cast<G4Track*>(pTrack), reactants);
fSampledPositions[pTrack->GetTrackID()] = pTrack->GetPosition();
for(const auto& it : *fReactants)
{
for (const auto& it : *fReactants) {
auto pTrackB = it;
// G4cout<<"position : "<<pTrackB->GetTrackID()<<G4endl;
fSampledPositions[pTrackB->GetTrackID()] = pTrackB->GetPosition();
}
ResetReactants();
}
else if(reactants)
{
else if (reactants) {
ResetReactants();
}
}
return fTSTimeStep;
}
@@ -0,0 +1,106 @@
//
// ********************************************************************
// * 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 "G4DNAIonChargeDecreaseModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4GenericIon.hh"
#include "G4DummyModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAIonChargeDecreaseModel::G4DNAIonChargeDecreaseModel(
const G4ParticleDefinition*, const G4String& nam)
: G4VEmModel(nam)
{
// dummy for the time being
fDummy = new G4DummyModel();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeDecreaseModel::Initialise(const G4ParticleDefinition* part,
const G4DataVector& v)
{
if (part != G4GenericIon::GenericIon()) {
G4ExceptionDescription ed;
ed << "Wrong particle type <" << part->GetParticleName()
<< "> - only G4GenericIon is allowed";
G4Exception("G4DNAIonChargeDecreaseModel::Initialise(...)",
"em2001", FatalException, ed);
}
// this pointer should defined once before initialisation of
// concrete models
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
// should be set once for each model
fDummy->SetParticleChange(fParticleChangeForGamma);
}
// initialisation of concrete models - put extra model here
fDummy->Initialise(part, v);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeDecreaseModel::StartTracking(G4Track* track)
{
fDynParticle = track->GetDynamicParticle();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAIonChargeDecreaseModel::CrossSectionPerVolume(const G4Material* mat,
const G4ParticleDefinition* p,
G4double ekin,
G4double, G4double)
{
G4int Q = G4lrint(fDynParticle->GetCharge()/CLHEP::eplus);
if (Q <= 0) { return 0.0; }
// select model
fCurrentModel = fDummy;
// compute concrete cross section
return fCurrentModel->CrossSectionPerVolume(mat, p, ekin);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeDecreaseModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dp,
G4double, G4double)
{
// sample secondaries by the selected model
fCurrentModel->SampleSecondaries(fvect, couple, dp);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -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. *
// ********************************************************************
//
//
#include "G4DNAIonChargeIncreaseModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4GenericIon.hh"
#include "G4DummyModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4DNAIonChargeIncreaseModel::G4DNAIonChargeIncreaseModel(
const G4ParticleDefinition*, const G4String& nam)
: G4VEmModel(nam)
{
// dummy for the time being
fDummy = new G4DummyModel();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeIncreaseModel::Initialise(const G4ParticleDefinition* part,
const G4DataVector& v)
{
if (part != G4GenericIon::GenericIon()) {
G4ExceptionDescription ed;
ed << "Wrong particle type <" << part->GetParticleName()
<< "> - only G4GenericIon is allowed";
G4Exception("G4DNAIonChargeIncreaseModel::Initialise(...)",
"em2001", FatalException, ed);
}
// this pointer should defined once before initialisation of
// concrete models
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
// should be set once for each model
fDummy->SetParticleChange(fParticleChangeForGamma);
}
// initialisation of concrete models - put extra model here
fDummy->Initialise(part, v);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeIncreaseModel::StartTracking(G4Track* track)
{
fDynParticle = track->GetDynamicParticle();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4double G4DNAIonChargeIncreaseModel::CrossSectionPerVolume(const G4Material* mat,
const G4ParticleDefinition* p,
G4double ekin,
G4double, G4double)
{
G4int Z = p->GetAtomicNumber();
G4int Q = G4lrint(fDynParticle->GetCharge()/CLHEP::eplus);
if (Q >= Z) { return 0.0; }
// select model
fCurrentModel = fDummy;
// compute concrete cross section
return fCurrentModel->CrossSectionPerVolume(mat, p, ekin);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAIonChargeIncreaseModel::SampleSecondaries(std::vector<G4DynamicParticle*>* fvect,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dp,
G4double, G4double)
{
// sample secondaries by the selected model
fCurrentModel->SampleSecondaries(fvect, couple, dp);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -190,13 +190,18 @@ G4DNAMakeReaction::FindReaction(G4ITReactionSet* pReactionSet,
std::vector<std::unique_ptr<G4ITReactionChange>> ReactionInfo;
ReactionInfo.clear();
auto stepper = dynamic_cast<G4DNAIndependentReactionTimeStepper*>(fpTimeStepper);
if(stepper != nullptr){
auto pReactionChange = stepper->
FindReaction(pReactionSet,currentStepTime);
if (pReactionChange != nullptr)
{
ReactionInfo.push_back(std::move(pReactionChange));
}
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());
}
return ReactionInfo;
}
@@ -0,0 +1,180 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNAMultipleIonisationManager.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#include "G4DNAMultipleIonisationManager.hh"
#include "G4FindDataDir.hh"
#include "G4Scheduler.hh"
#include "G4SystemOfUnits.hh"
#include "G4Molecule.hh"
#include "G4VITTrackHolder.hh"
#include "G4H2O.hh"
#include "G4DNAChemistryManager.hh"
//------------------------------------------------------------------------------
void G4DNAMultipleIonisationManager::CreateMultipleIonisedWaterMolecule(
MultipleIonisedModification mod, G4int* shell_level,
const G4Track* incoming_track)
{
if (!G4DNAChemistryManager::IsActivated()) { return; }
G4int num_shells{0};
switch (mod) {
case eDoubleIonisedMolecule:
num_shells = 2;
break;
case eTripleIonisedMolecule:
num_shells = 3;
break;
case eQuadrupleIonisedMolecule:
num_shells = 4;
break;
default: // never happen
return;
}
auto* H2O = new G4Molecule(G4H2O::Definition());
for (G4int i = 0; i < num_shells; i++) {
H2O->IonizeMolecule(4 - shell_level[i]);
}
constexpr G4double kT0 = 1.0 * picosecond;
auto* H2O_track = H2O->BuildTrack(kT0, incoming_track->GetPosition());
H2O_track->SetParentID(incoming_track->GetTrackID());
H2O_track->SetTrackStatus(fStopButAlive);
H2O_track->SetKineticEnergy(0.0);
G4VITTrackHolder::Instance()->Push(H2O_track);
}
//------------------------------------------------------------------------------
G4bool G4DNAMultipleIonisationManager::CheckShellEnergy(
MultipleIonisedModification mod, G4double* shell_energy)
{
G4int num_shells{0};
switch (mod) {
case eDoubleIonisedMolecule:
num_shells = 2;
break;
case eTripleIonisedMolecule:
num_shells = 3;
break;
case eQuadrupleIonisedMolecule:
num_shells = 4;
break;
default: // never happen
break;
}
G4bool stop_process{false};
for (int i = 0; i < num_shells; i++) {
if (shell_energy[i] < 0.0) {
stop_process = true;
break;
}
}
return stop_process;
}
//------------------------------------------------------------------------------
void G4DNAMultipleIonisationManager::LoadAlphaParam(
const G4String& filepath, G4double Z, G4double A)
{
const char* path = G4FindDataDir("G4LEDATA");
if (path == nullptr) {
G4Exception("G4DNAMultipleIonisationManager::LoadAlphaParam","em0006",
FatalException,"G4LEDATA environment variable not set.");
}
std::stringstream fullpath;
fullpath << path << "/" << filepath;
std::fstream fin(fullpath.str());
G4double e, a;
std::string line = "";
while (getline(fin, line)) {
std::stringstream ss;
ss << line;
ss >> e >> a;
Eion_.push_back(e * Z * A * MeV);
alpha_.push_back(a);
}
num_node_ = (G4int)Eion_.size();
fin.close();
}
//------------------------------------------------------------------------------
G4double G4DNAMultipleIonisationManager::GetAlphaParam(G4double energy)
{
auto find_lower_bound = [this](G4double e) {
auto low = 0;
auto upp = num_node_ - 1;
if (e < Eion_[0]) { return low; }
while (low <= upp) {
const auto mid = static_cast<int>((low + upp) * 0.5);
if (e < Eion_[mid]) { upp = mid - 1; }
else { low = mid + 1; }
if (upp < 0) { upp = 0; }
}
return upp;
};
auto interp_log_log = [this](G4int bin1, G4double e) {
if (e < Eion_[0]) { return alpha_[0]; }
const auto num_bin = num_node_ - 1;
const auto bin2 = bin1 + 1;
G4double value{0.0};
if (bin2 <= num_bin) {
auto log10_e = std::log10(e);
auto log10_e1 = Eion_[bin1];
auto log10_e2 = Eion_[bin2];
auto log10_a1 = alpha_[bin1];
auto log10_a2 = alpha_[bin2];
if (log10_a1 != 0.0 && log10_a2 != 0.0) {
log10_e1 = std::log10(log10_e1);
log10_e2 = std::log10(log10_e2);
log10_a1 = std::log10(log10_a1);
log10_a2 = std::log10(log10_a2);
value = log10_a1 + (log10_a2 - log10_a1)
* (log10_e - log10_e1) / (log10_e2 - log10_e1);
value = std::pow(10.0, value);
}
} else {
value = alpha_[num_bin];
}
return value;
};
const auto bin1 = find_lower_bound(energy);
return interp_log_log(bin1, energy);
}
@@ -0,0 +1,366 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNAQuadrupleIonisationModel.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#include "G4DNAQuadrupleIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4IonTable.hh"
#include "G4GenericIon.hh"
#include "G4DNARuddAngle.hh"
#include "G4Pow.hh"
#include <sstream>
namespace {
G4DNAWaterIonisationStructure water_structure;
G4Pow* g4pow = G4Pow::GetInstance();
} // end of anonymous namespace
//==============================================================================
// constructor
G4DNAQuadrupleIonisationModel::G4DNAQuadrupleIonisationModel(
const G4ParticleDefinition* p, const G4String& model_name)
: G4DNADoubleIonisationModel(p, model_name)
{
// Quadruple-ionisation energy
energy_threshold_ = 88.0 * eV;
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisationModel::Initialise(
const G4ParticleDefinition* particle, const G4DataVector&)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNAQuadrupleIonisationModel::Initialise()" << G4endl;
}
proton_def_ = G4Proton::ProtonDefinition();
alpha_def_ = G4DNAGenericIonsManager::Instance()->GetIon("alpha++");
carbon_def_ = G4IonTable::GetIonTable()->GetIon(6, 12);
constexpr G4double kScaleFactor = 1.0 * m * m;
mioni_manager_ = new G4DNAMultipleIonisationManager();
G4double Z{0.0}, A{0.0};
G4String alpha_param_file{"dna/multipleionisation_alphaparam_champion.dat"};
if (particle == proton_def_) {
// *************************************************************************
// for protons
auto proton = proton_def_->GetParticleName();
elow_tab_[proton] = model_elow_tab_[1];
eupp_tab_[proton] = 3.0 * MeV;
// load cross-section data for single ionization process
auto xs_proton = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_proton->LoadData("dna/sigma_ionisation_p_rudd");
xs_tab_[proton] = xs_proton;
// set energy limits
SetLowEnergyLimit(elow_tab_[proton]);
SetHighEnergyLimit(eupp_tab_[proton]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_p.dat";
}
Z = static_cast<G4double>(proton_def_->GetAtomicNumber());
A = static_cast<G4double>(proton_def_->GetAtomicMass());
} else if (particle == alpha_def_) {
//**************************************************************************
// for alpha particles
auto alpha = alpha_def_->GetParticleName();
elow_tab_[alpha] = model_elow_tab_[4];
eupp_tab_[alpha] = 23.0 * MeV;
// load cross-section data for single ionization process
auto xs_alpha = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_alpha->LoadData("dna/sigma_ionisation_alphaplusplus_rudd");
xs_tab_[alpha] = xs_alpha;
// set energy limits
SetLowEnergyLimit(elow_tab_[alpha]);
SetHighEnergyLimit(eupp_tab_[alpha]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_alphaplusplus.dat";
}
Z = static_cast<G4double>(alpha_def_->GetAtomicNumber());
A = static_cast<G4double>(alpha_def_->GetAtomicMass());
} else if (particle == G4GenericIon::GenericIonDefinition()) {
// *************************************************************************
// for carbon ions
auto carbon = carbon_def_->GetParticleName();
elow_tab_[carbon] = model_elow_tab_[5] * carbon_def_->GetAtomicMass();
eupp_tab_[carbon] = 120.0 * MeV;
// load cross-section data for single ionization process
auto xs_carbon = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_carbon->LoadData("dna/sigma_ionisation_c_rudd");
xs_tab_[carbon] = xs_carbon;
// set energy limits
SetLowEnergyLimit(elow_tab_[carbon]);
SetHighEnergyLimit(eupp_tab_[carbon]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_c.dat";
}
Z = static_cast<G4double>(carbon_def_->GetAtomicNumber());
A = static_cast<G4double>(carbon_def_->GetAtomicMass());
}
// load alpha parameter
mioni_manager_->LoadAlphaParam(alpha_param_file, Z, A);
if (verbose_level_ > 0) {
G4cout << "G4DNAQuadrupleIonisationModel is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV for "
<< particle->GetParticleName()
<< G4endl;
}
water_density_ = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(
G4Material::GetMaterial("G4_WATER"));
atom_deex_ = G4LossTableManager::Instance()->AtomDeexcitation();
if (is_initialized_) { return; }
particle_change_ = GetParticleChangeForGamma();
is_initialized_ = true;
}
//------------------------------------------------------------------------------
G4double G4DNAQuadrupleIonisationModel::CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNAQuadrupleIonisationModel::CrossSectionPerVolume()"
<< G4endl;
}
// Calculate total cross section for model
if (pdef != proton_def_ && pdef != alpha_def_ && pdef != carbon_def_) {
return 0.0;
}
static G4double water_dens = (*water_density_)[material->GetIndex()];
const auto& pname = pdef->GetParticleName();
const auto low_energy_lim = GetLowEnergyLimit(pname);
const auto upp_energy_lim = GetUppEnergyLimit(pname);
G4double sigma{0.0};
if (ekin <= upp_energy_lim) {
if (ekin < low_energy_lim) { ekin = low_energy_lim; }
CrossSectionDataTable::iterator pos = xs_tab_.find(pname);
if (pos == xs_tab_.end()) {
G4Exception("G4DNAQuadrupleIonisationModel::CrossSectionPerVolume",
"em0002", FatalException,
"Model not applicable to particle type.");
}
G4DNACrossSectionDataSet* table = pos->second;
if (table != nullptr) {
auto scale_param = mioni_manager_->GetAlphaParam(ekin);
scale_param = ::g4pow->powA(scale_param, 3.0);
sigma = table->FindValue(ekin) * scale_param;
}
}
if (verbose_level_ > 2) {
std::stringstream msg;
msg << "----------------------------------------------------------------\n";
msg << " G4DNAQuadrupleIonisationModel - XS INFO START\n";
msg << " - Kinetic energy(eV): " << ekin/eV << ", Particle : "
<< pdef->GetParticleName() << "\n";
msg << " - Cross section per water molecule (cm^2): "
<< sigma / cm / cm << "\n";
msg << " - Cross section per water molecule (cm^-1): "
<< sigma * water_dens / (1.0 / cm) << "\n";
msg << " G4DNAQuadrupleIonisationModel - XS INFO END\n";
msg << "----------------------------------------------------------------\n";
G4cout << msg.str() << G4endl;
}
return (sigma * water_dens);
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisationModel::SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling SampleSecondaries() of G4DNAQuadrupleIonisationModel"
<< G4endl;
}
// get the definition for this parent particle
auto pdef = particle->GetDefinition();
// get kinetic energy
auto ekin = particle->GetKineticEnergy();
// get particle name
const auto& pname = pdef->GetParticleName();
// get energy limits
const auto low_energy_lim = GetLowEnergyLimit(pname);
// ***************************************************************************
// stop the transportation process of this parent particle
// if its kinetic energy is below the lower limit
if (ekin < low_energy_lim) {
particle_change_->SetProposedKineticEnergy(0.0);
particle_change_->ProposeTrackStatus(fStopAndKill);
particle_change_->ProposeLocalEnergyDeposit(ekin);
return;
}
// ***************************************************************************
constexpr G4int kNumSecondaries = 4;
constexpr G4double kDeltaTheta = pi * 0.5;
G4int ioni_shell[kNumSecondaries] = {0, 0, 0, 0};
G4double shell_energy[kNumSecondaries];
auto scale_param = mioni_manager_->GetAlphaParam(ekin);
scale_param = ::g4pow->powA(scale_param, 3.0);
G4bool is_continue{true};
while (1) {
ioni_shell[0] = RandomSelect(ekin, scale_param, pname);
ioni_shell[1] = RandomSelect(ekin, scale_param, pname);
ioni_shell[2] = RandomSelect(ekin, scale_param, pname);
ioni_shell[3] = RandomSelect(ekin, scale_param, pname);
is_continue =
(ioni_shell[0] == ioni_shell[1] && ioni_shell[1] == ioni_shell[2]) ||
(ioni_shell[1] == ioni_shell[2] && ioni_shell[2] == ioni_shell[3]) ||
(ioni_shell[2] == ioni_shell[3] && ioni_shell[3] == ioni_shell[0]) ||
(ioni_shell[3] == ioni_shell[0] && ioni_shell[0] == ioni_shell[1]) ||
(ioni_shell[0] == ioni_shell[1] && ioni_shell[1] == ioni_shell[2] &&
ioni_shell[2] == ioni_shell[3]);
if (!is_continue) { break; }
}
G4double tot_ioni_energy{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
shell_energy[i] = ::water_structure.IonisationEnergy(ioni_shell[i]);
tot_ioni_energy += shell_energy[i];
}
if (ekin < tot_ioni_energy || tot_ioni_energy < energy_threshold_) {
return;
}
// generate secondary electrons
G4double theta{0.0}, phi{0.0}, tot_ekin2{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
tot_ekin2 += GenerateSecondaries(vsec, couple, particle, ioni_shell[i],
theta, phi, shell_energy[i]);
theta += kDeltaTheta;
}
// This should never happen
if (mioni_manager_->CheckShellEnergy(eQuadrupleIonisedMolecule,
shell_energy)) {
G4Exception("G4DNAQuadrupleIonisatioModel::SampleSecondaries()",
"em2050", FatalException, "Negative local energy deposit");
}
// ***************************************************************************
// update kinematics for this parent particle
const auto primary_dir = particle->GetMomentumDirection();
particle_change_->ProposeMomentumDirection(primary_dir);
const auto scattered_energy = ekin - tot_ioni_energy - tot_ekin2;
// update total amount of shell energy
tot_ioni_energy = shell_energy[0] + shell_energy[1] +
shell_energy[2] + shell_energy[3];
if (stat_code_) {
particle_change_->SetProposedKineticEnergy(ekin);
particle_change_->ProposeLocalEnergyDeposit(
ekin - scattered_energy);
} else {
particle_change_->SetProposedKineticEnergy(scattered_energy);
particle_change_->ProposeLocalEnergyDeposit(tot_ioni_energy);
}
// ***************************************************************************
// generate triple-ionized water molecules (H2O^4+)
const auto the_track = particle_change_->GetCurrentTrack();
mioni_manager_->CreateMultipleIonisedWaterMolecule(
eQuadrupleIonisedMolecule, ioni_shell, the_track);
// ***************************************************************************
}
@@ -48,7 +48,6 @@
#include "G4Pow.hh"
#include "G4Alpha.hh"
#include "G4Proton.hh"
#include "G4AutoLock.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -59,11 +58,9 @@ const std::vector<G4double>* G4DNARuddIonisationExtendedModel::fpWaterDensity =
namespace
{
G4Mutex ionDNAMutex = G4MUTEX_INITIALIZER;
const G4double scaleFactor = CLHEP::m*CLHEP::m;
const G4double tolerance = 1*CLHEP::eV;
const G4double Ry = 13.6*CLHEP::eV;
const G4double Gj[5] = {0.99, 1.11, 1.11, 0.52, 1.};
// Following values provided by M. Dingfelder (priv. comm)
const G4double Bj[5] = {12.60*CLHEP::eV, 14.70*CLHEP::eV, 18.40*CLHEP::eV,
@@ -86,6 +83,8 @@ G4DNARuddIonisationExtendedModel::G4DNARuddIonisationExtendedModel(const G4Parti
// Define default angular generator
SetAngularDistribution(new G4DNARuddAngle());
if (nullptr == xshelium) { LoadData(); }
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -99,93 +98,98 @@ G4DNARuddIonisationExtendedModel::~G4DNARuddIonisationExtendedModel()
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNARuddIonisationExtendedModel::LoadData()
{
// initialisation of static data once
isFirst = true;
G4String filename("dna/sigma_ionisation_h_rudd");
xsdata[0] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[0]->LoadData(filename);
filename = "dna/sigma_ionisation_p_rudd";
xsdata[1] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[1]->LoadData(filename);
filename = "dna/sigma_ionisation_alphaplusplus_rudd";
xsdata[2] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[2]->LoadData(filename);
filename = "dna/sigma_ionisation_li_rudd";
xsdata[3] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[3]->LoadData(filename);
filename = "dna/sigma_ionisation_be_rudd";
xsdata[4] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[4]->LoadData(filename);
filename = "dna/sigma_ionisation_b_rudd";
xsdata[5] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[5]->LoadData(filename);
filename = "dna/sigma_ionisation_c_rudd";
xsdata[6] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[6]->LoadData(filename);
filename = "dna/sigma_ionisation_n_rudd";
xsdata[7] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[7]->LoadData(filename);
filename = "dna/sigma_ionisation_o_rudd";
xsdata[8] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[8]->LoadData(filename);
filename = "dna/sigma_ionisation_si_rudd";
xsdata[14] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[14]->LoadData(filename);
filename = "dna/sigma_ionisation_fe_rudd";
xsdata[26] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[26]->LoadData(filename);
filename = "dna/sigma_ionisation_alphaplus_rudd";
xsalphaplus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsalphaplus->LoadData(filename);
filename = "dna/sigma_ionisation_he_rudd";
xshelium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xshelium->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 G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector&)
{
if(p != fParticle) { SetParticle(p); }
if (p != fParticle) { SetParticle(p); }
// initialisation of static data once
if(nullptr == xsdata[0]) {
G4AutoLock l(&ionDNAMutex);
if(nullptr == xsdata[0]) {
isFirst = true;
G4String filename("dna/sigma_ionisation_h_rudd");
xsdata[0] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[0]->LoadData(filename);
filename = "dna/sigma_ionisation_p_rudd";
xsdata[1] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[1]->LoadData(filename);
filename = "dna/sigma_ionisation_alphaplusplus_rudd";
xsdata[2] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[2]->LoadData(filename);
filename = "dna/sigma_ionisation_li_rudd";
xsdata[3] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[3]->LoadData(filename);
filename = "dna/sigma_ionisation_be_rudd";
xsdata[4] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[4]->LoadData(filename);
filename = "dna/sigma_ionisation_b_rudd";
xsdata[5] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[5]->LoadData(filename);
filename = "dna/sigma_ionisation_c_rudd";
xsdata[6] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[6]->LoadData(filename);
filename = "dna/sigma_ionisation_n_rudd";
xsdata[7] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[7]->LoadData(filename);
filename = "dna/sigma_ionisation_o_rudd";
xsdata[8] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[8]->LoadData(filename);
filename = "dna/sigma_ionisation_si_rudd";
xsdata[14] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[14]->LoadData(filename);
filename = "dna/sigma_ionisation_fe_rudd";
xsdata[26] = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsdata[26]->LoadData(filename);
filename = "dna/sigma_ionisation_alphaplus_rudd";
xsalphaplus = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xsalphaplus->LoadData(filename);
filename = "dna/sigma_ionisation_he_rudd";
xshelium = new G4DNACrossSectionDataSet(new G4LogLogInterpolation, CLHEP::eV, scaleFactor);
xshelium->LoadData(filename);
}
// to avoid possible threading problem fill this vector only once
auto water = G4NistManager::Instance()->FindMaterial("G4_WATER");
fpWaterDensity =
G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(water);
l.unlock();
// particle change object may be externally set
if (nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
}
// initialisation once in each thread
if(nullptr == fParticleChangeForGamma) {
fParticleChangeForGamma = GetParticleChangeForGamma();
if (!isInitialised) {
isInitialised = true;
const G4String& pname = fParticle->GetParticleName();
if(pname == "proton") {
if (pname == "proton") {
idx = 1;
xscurrent = xsdata[1];
fElow = fLowestEnergy;
} else if(pname == "hydrogen") {
} else if (pname == "hydrogen") {
idx = 0;
xscurrent = xsdata[0];
fElow = fLowestEnergy;
} else if(pname == "alpha") {
} else if (pname == "alpha") {
idx = 1;
xscurrent = xsdata[2];
isHelium = true;
fElow = fLimitEnergy;
} else if(pname == "alpha+") {
} else if (pname == "alpha+") {
idx = 1;
isHelium = true;
xscurrent = xsalphaplus;
@@ -197,7 +201,7 @@ void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
sCoefficient[0]=0.7;
sCoefficient[1]=0.15;
sCoefficient[2]=0.15;
} else if(pname == "helium") {
} else if (pname == "helium") {
idx = 0;
isHelium = true;
fElow = fLimitEnergy;
@@ -210,6 +214,9 @@ void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
sCoefficient[2]=0.25;
} else {
isIon = true;
idx = -1;
xscurrent = xsdata[1];
fElow = fLowestEnergy;
}
// defined stationary mode
statCode = G4EmParameters::Instance()->DNAStationary();
@@ -219,8 +226,8 @@ void G4DNARuddIonisationExtendedModel::Initialise(const G4ParticleDefinition* p,
if (verbose > 0) {
G4cout << "### G4DNARuddIonisationExtendedModel::Initialise(..) " << pname
<< "/n idx=" << idx << " Amass=" << fAmass
<< " isIon=" << isIon << " isHelium=" << isHelium << G4endl;
<< "/n idx=" << idx << " isIon=" << isIon
<< " isHelium=" << isHelium << G4endl;
}
}
}
@@ -231,17 +238,7 @@ void G4DNARuddIonisationExtendedModel::SetParticle(const G4ParticleDefinition* p
{
fParticle = p;
fMass = p->GetPDGMass();
fAmass = p->GetAtomicMass();
// for generic ions idx is dynamic, -1 means that data for the ion does not exist
if(isIon) {
G4int i = p->GetAtomicNumber();
idx = -1;
if (i < RUDDZMAX && nullptr != xsdata[i]) {
idx = i;
fElow = fAmass*fLowestEnergy;
}
}
fMassRate = (isIon) ? CLHEP::proton_mass_c2/fMass : 1.0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -260,33 +257,18 @@ G4DNARuddIonisationExtendedModel::CrossSectionPerVolume(const G4Material* materi
// ion may be different
if (fParticle != part) { SetParticle(part); }
// initilise mass rate
fMassRate = 1.0;
// ion shoud be stopped - check on kinetic energy and not scaled energy
if (kinE < fLowestEnergy) { return DBL_MAX; }
G4double sigma = 0.;
// use ion table if available for given energy
// for proton, hydrogen, alpha, alpha+, and helium no scaling to proton x-section
if (idx == 0 || idx == 1) {
sigma = (kinE > fElow) ? xscurrent->FindValue(kinE)
: xscurrent->FindValue(fElow)*kinE/fElow;
G4double e = kinE*fMassRate;
// for ions with data above limit energy
} else if (idx > 1) {
sigma = (kinE > fElow) ? xsdata[idx]->FindValue(kinE)
: xsdata[idx]->FindValue(fElow)*kinE/fElow;
G4double sigma = (e > fElow) ? xscurrent->FindValue(e)
: xscurrent->FindValue(fElow) * e / fElow;
// scaling from proton
} else {
fMassRate = CLHEP::proton_mass_c2/fMass;
G4double e = kinE*fMassRate;
sigma = (e > fLowestEnergy) ? xsdata[1]->FindValue(e)
: xsdata[1]->FindValue(fLowestEnergy)*e/fLowestEnergy;
if (idx == -1) {
sigma *= fEmCorrections->EffectiveChargeSquareRatio(part, material, kinE);
}
sigma *= density;
if (verbose > 1) {
@@ -318,14 +300,14 @@ G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicParticl
return;
}
G4int shell = SelectShell(kinE);
G4int shell = SelectShell(kinE*fMassRate);
G4double bindingEnergy = (useDNAWaterStructure)
? waterStructure.IonisationEnergy(shell) : Bj[shell];
//Si: additional protection if tcs interpolation method is modified
if (kinE < bindingEnergy) return;
G4double esec = SampleElectronEnergy(kinE, bindingEnergy, shell);
if (kinE < bindingEnergy) { return; }
G4double esec = SampleElectronEnergy(kinE, shell);
G4double esum = 0.0;
// sample deexcitation
@@ -342,9 +324,8 @@ G4DNARuddIonisationExtendedModel::SampleSecondaries(std::vector<G4DynamicParticl
fAtomDeexcitation->GenerateParticles(fvect, ashell, Z, 0, 0);
// compute energy sum from de-excitation
std::size_t nn = fvect->size();
for (std::size_t i=0; i<nn; ++i) {
esum += (*fvect)[i]->GetKineticEnergy();
for (auto const & ptr : *fvect) {
esum += ptr->GetKineticEnergy();
}
}
// check energy balance
@@ -386,131 +367,30 @@ G4int G4DNARuddIonisationExtendedModel::SelectShell(G4double e)
{
G4double sum = 0.0;
G4double xs;
for(G4int i=0; i<5; ++i) {
if (idx == 0 || idx == 1) {
auto ptr = xscurrent->GetComponent(i);
xs = (e > fElow) ? ptr->FindValue(e) : ptr->FindValue(fElow)*e/fElow;
} else if (idx > 1) {
auto ptr = xsdata[idx]->GetComponent(i);
xs = (e > fElow) ? ptr->FindValue(e) : ptr->FindValue(fElow)*e/fElow;
} else {
// use scaling from proton
auto ptr = xsdata[1]->GetComponent(i);
G4double x = e*fMassRate;
xs = (x >= fLowestEnergy) ? ptr->FindValue(x)
: ptr->FindValue(fLowestEnergy)*x/fLowestEnergy;
}
for (G4int i=0; i<5; ++i) {
auto ptr = xscurrent->GetComponent(i);
xs = (e > fElow) ? ptr->FindValue(e) : ptr->FindValue(fElow)*e/fElow;
sum += xs;
fTemp[i] = sum;
}
sum *= G4UniformRand();
for(G4int i=0; i<5; ++i) {
if(sum <= fTemp[i]) { return i; }
for (G4int i=0; i<5; ++i) {
if (sum <= fTemp[i]) { return i; }
}
return 0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationExtendedModel::SampleElectronEnergy(G4double kine,
G4double eexc,
G4int shell)
G4double G4DNARuddIonisationExtendedModel::MaxEnergy(G4double kine, G4int shell)
{
// kinematic limit
G4double tau = kine/fMass;
G4double gam = 1.0 + tau;
G4double emax = 2.0*CLHEP::electron_mass_c2*tau*(tau + 2.0);
// compute cumulative probability function
G4double step = 1*CLHEP::eV;
auto nn = (G4int)(emax/step);
nn = std::max(nn, 10);
step = emax/(G4double)nn;
// find max probability
G4double pmax = ProbabilityFunction(kine, 0.0, eexc, shell);
//G4cout << "E(keV)=" << kine/keV << " emax=" << emax/keV
// << " pmax(0)=" << pmax << " shell=" << shell << " nn=" << nn << G4endl;
G4double e2 = 0.0; // backup energy
G4double e0 = 0.0; // energy with max probability
G4double e = 0.0;
for (G4int i=0; i<nn; ++i) {
e += step;
G4double prob = ProbabilityFunction(kine, e, eexc, shell);
if (prob < pmax) {
e2 = 2*e;
break;
}
pmax = prob;
e0 = e;
}
//G4cout << " E0(keV)=" << e0/keV << " pmax=" << pmax << G4endl;
pmax *= 1.05;
// regression method with two regions
G4double e1 = emax;
G4double p1 = 0.0;
if (2*e0 < emax) {
e1 = e0 + 0.25*(emax - e0);
p1 = ProbabilityFunction(kine, e1, eexc, shell);
}
G4double s2 = p1*(emax - e1);
s2 /= (s2 + e1*pmax);
G4double s1 = 1.0 - s2;
// sampling
G4int count = 0;
G4double ymax, y, deltae;
for (G4int i = 0; i<100000; ++i) {
G4double q = G4UniformRand();
if (q <= s1) {
ymax = pmax;
deltae = e1 * q / s1;
} else {
ymax = p1;
deltae = e1 + (emax - e1)* (q - s1) / s2;
}
y = ProbabilityFunction(kine, deltae, eexc, shell);
//G4cout << " " << i << ". deltae=" << deltae/CLHEP::keV
// << " y=" << y << " ymax=" << ymax << G4endl;
if (y > ymax && count < 10) {
++count;
G4cout << "G4DNARuddIonisationExtendedModel::SampleElectronEnergy warning: "
<< fParticle->GetParticleName() << " E(keV)=" << kine/CLHEP::keV
<< " Edelta(keV)=" << deltae/CLHEP::keV
<< " y=" << y << " ymax=" << ymax << " n=" << i << G4endl;
}
if (ymax * G4UniformRand() < y) {
return deltae;
}
}
deltae = e2;
return deltae;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationExtendedModel::ProbabilityFunction(G4double kine,
G4double deltae,
G4double bindingEnergy,
G4int shell)
{
// 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 A1, B1, C1, D1, E1, A2, B2, C2, D2, alphaConst;
// Initialisation of sampling
G4double A1, B1, C1, D1, E1, A2, B2, C2, D2;
if (shell == 4) {
//Data For Liquid Water K SHELL from Dingfelder (Protons in Water)
A1 = 1.25;
@@ -537,32 +417,166 @@ G4double G4DNARuddIonisationExtendedModel::ProbabilityFunction(G4double kine,
D2 = 0.04;
alphaConst = 0.64;
}
G4double bEnergy = Bj[shell];
G4double w = deltae/bEnergy;
G4double u = Ry/bEnergy;
G4double tau = kine/fMass;
G4double gam = 1.0 + tau;;
G4double v2 = 0.5*CLHEP::electron_mass_c2*tau*(tau + 2.0)/(bEnergy*gam*gam);
G4double v = std::sqrt(v2);
G4double wc = 4.*v2 - 2.*v - 0.25*u;
G4double x = alphaConst*(w - wc)/v;
G4double y = (x > -15.) ? 1.0 + G4Exp(x) : 1.0;
bEnergy = Bj[shell];
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));
G4double F1 = L1 + H1;
G4double F2 = (L2 * H2) / (L2 + H2);
F1 = L1 + H1;
F2 = (L2 * H2) / (L2 + H2);
return emax;
}
G4double res = CorrectionFactor(kine, shell) * (F1 + w*F2) * Gj[shell] /
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationExtendedModel::SampleElectronEnergy(G4double kine,
G4int shell)
{
G4double emax = MaxEnergy(kine, shell);
// compute cumulative probability function
G4double step = 1*CLHEP::eV;
auto nn = (G4int)(emax/step);
nn = std::min(std::max(nn, 10), 100);
step = emax/(G4double)nn;
// find max probability
G4double pmax = ProbabilityFunction(kine, 0.0, shell);
//G4cout << "## E(keV)=" << kine/keV << " emax=" << emax/keV
// << " pmax(0)=" << pmax << " shell=" << shell << " nn=" << nn << G4endl;
G4double e0 = 0.0; // energy with max probability
// 2 areas after point with max probability
G4double e1 = emax;
G4double e2 = emax;
G4double p1 = 0.0;
G4double p2 = 0.0;
const G4double f = 0.25;
// find max probability
G4double e = 0.0;
G4double p = 0.0;
for (G4int i=0; i<nn; ++i) {
e += step;
p = ProbabilityFunction(kine, e, shell);
if (p > pmax) {
pmax = p;
e0 = e;
} else {
break;
}
}
// increase step to be more effective
step *= 2.0;
// 2-nd area
for (G4int i=0; i<nn; ++i) {
e += step;
if (std::abs(e - emax) < step) {
e1 = emax;
break;
}
p = ProbabilityFunction(kine, e, shell);
if (p < f*pmax) {
p1 = p;
e1 = e;
break;
}
}
// 3-d area
if (e < emax) {
for (G4int i=0; i<nn; ++i) {
e += step;
if (std::abs(e - emax) < step) {
e2 = emax;
break;
}
p = ProbabilityFunction(kine, e, shell);
if (p < f*p1) {
p2 = p;
e2 = e;
break;
}
}
}
pmax *= 1.05;
// regression method with 3 regions
G4double s0 = pmax*e1;
G4double s1 = s0 + p1 * (e2 - e1);
G4double s2 = s1 + p2 * (emax - e2);
s0 = (s0 == s1) ? 1.0 : s0 / s2;
s1 = (s1 == s2) ? 1.0 : s1 / s2;
//G4cout << "pmax=" << pmax << " e1(keV)=" << e1/keV << " p1=" << p1 << " e2(keV)=" << e2/keV
// << " p2=" << p2 << " s0=" << s0 << " s1=" << s1 << " s2=" << s2 << G4endl;
// sampling
G4int count = 0;
G4double ymax, y, deltae;
for (G4int i = 0; i<100000; ++i) {
G4double q = G4UniformRand();
if (q <= s0) {
ymax = pmax;
deltae = e1 * q / s0;
} else if (q <= s1) {
ymax = p1;
deltae = e1 + (e2 - e1) * (q - s0) / (s1 - s0);
} else {
ymax = p2;
deltae = e2 + (emax - e2) * (q - s1) / (1.0 - s1);
}
y = ProbabilityFunction(kine, deltae, shell);
//G4cout << " " << i << ". deltae=" << deltae/CLHEP::keV
// << " y=" << y << " ymax=" << ymax << G4endl;
if (y > ymax && count < 10) {
++count;
G4cout << "G4DNARuddIonisationExtendedModel::SampleElectronEnergy warning: "
<< fParticle->GetParticleName() << " E(keV)=" << kine/CLHEP::keV
<< " Edelta(keV)=" << deltae/CLHEP::keV
<< " y=" << y << " ymax=" << ymax << " n=" << i << G4endl;
}
if (ymax * G4UniformRand() <= y) {
return deltae;
}
}
deltae = std::min(e0 + step, 0.5*emax);
return deltae;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4DNARuddIonisationExtendedModel::ProbabilityFunction(G4double kine,
G4double deltae,
G4int shell)
{
// 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 = deltae/bEnergy;
G4double x = alphaConst*(w - wc)/v;
G4double y = (x > -15.) ? 1.0 + G4Exp(x) : 1.0;
G4double res = CorrectionFactor(kine, shell) * (F1 + w*F2) /
(fGpow->powN((1. + w)/u, 3) * y);
if(isHelium) {
G4double energyTransfer = deltae + bindingEnergy;
if (isHelium) {
G4double energyTransfer = deltae + bEnergy;
G4double Zeff = 2.0 -
(sCoefficient[0] * S_1s(kine, energyTransfer, slaterEffectiveCharge[0], 1.) +
sCoefficient[1] * S_2s(kine, energyTransfer, slaterEffectiveCharge[1], 2.) +
@@ -579,9 +593,8 @@ G4double G4DNARuddIonisationExtendedModel::ComputeProbabilityFunction(
const G4ParticleDefinition* p, G4double e, G4double deltae, G4int shell)
{
if (fParticle != p) { SetParticle(p); }
G4double bEnergy = (useDNAWaterStructure)
? waterStructure.IonisationEnergy(shell) : Bj[shell];
return ProbabilityFunction(e, deltae, bEnergy, shell);
MaxEnergy(e, shell);
return ProbabilityFunction(e, deltae, shell);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,355 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNATripleIonisationModel.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
// Reference: J.Meesungnoen et. al, DOI: 10.1021/jp058037z
//
#include "G4DNATripleIonisationModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4UAtomicDeexcitation.hh"
#include "G4LossTableManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4DNAMolecularMaterial.hh"
#include "G4IonTable.hh"
#include "G4GenericIon.hh"
#include "G4DNARuddAngle.hh"
#include <sstream>
namespace {
G4DNAWaterIonisationStructure water_structure;
} // end of anonymous namespace
//==============================================================================
// constructor
G4DNATripleIonisationModel::G4DNATripleIonisationModel(
const G4ParticleDefinition* p, const G4String& model_name)
: G4DNADoubleIonisationModel(p, model_name)
{
// Triple-ionisation energy
energy_threshold_ = 65.0 * eV;
}
//------------------------------------------------------------------------------
void G4DNATripleIonisationModel::Initialise(
const G4ParticleDefinition* particle, const G4DataVector&)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNATripleIonisationModel::Initialise()" << G4endl;
}
proton_def_ = G4Proton::ProtonDefinition();
alpha_def_ = G4DNAGenericIonsManager::Instance()->GetIon("alpha++");
carbon_def_ = G4IonTable::GetIonTable()->GetIon(6, 12);
constexpr G4double kScaleFactor = 1.0 * m * m;
mioni_manager_ = new G4DNAMultipleIonisationManager();
G4double Z{0.0}, A{0.0};
G4String alpha_param_file{"dna/multipleionisation_alphaparam_champion.dat"};
if (particle == proton_def_) {
// *************************************************************************
// for protons
auto proton = proton_def_->GetParticleName();
elow_tab_[proton] = model_elow_tab_[1];
eupp_tab_[proton] = 3.0 * MeV;
// load cross-section data for single ionization process
auto xs_proton = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_proton->LoadData("dna/sigma_ionisation_p_rudd");
xs_tab_[proton] = xs_proton;
// set energy limits
SetLowEnergyLimit(elow_tab_[proton]);
SetHighEnergyLimit(eupp_tab_[proton]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_p.dat";
}
Z = static_cast<G4double>(proton_def_->GetAtomicNumber());
A = static_cast<G4double>(proton_def_->GetAtomicMass());
} else if (particle == alpha_def_) {
//**************************************************************************
// for alpha particles
auto alpha = alpha_def_->GetParticleName();
elow_tab_[alpha] = model_elow_tab_[4];
eupp_tab_[alpha] = 23.0 * MeV;
// load cross-section data for single ionization process
auto xs_alpha = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_alpha->LoadData("dna/sigma_ionisation_alphaplusplus_rudd");
xs_tab_[alpha] = xs_alpha;
// set energy limits
SetLowEnergyLimit(elow_tab_[alpha]);
SetHighEnergyLimit(eupp_tab_[alpha]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_alphaplusplus.dat";
}
Z = static_cast<G4double>(alpha_def_->GetAtomicNumber());
A = static_cast<G4double>(alpha_def_->GetAtomicMass());
} else if (particle == G4GenericIon::GenericIonDefinition()) {
// *************************************************************************
// for carbon ions
auto carbon = carbon_def_->GetParticleName();
elow_tab_[carbon] = model_elow_tab_[5] * carbon_def_->GetAtomicMass();
eupp_tab_[carbon] = 120.0 * MeV;
// load cross-section data for single ionization process
auto xs_carbon = new G4DNACrossSectionDataSet(
new G4LogLogInterpolation, eV, kScaleFactor);
xs_carbon->LoadData("dna/sigma_ionisation_c_rudd");
xs_tab_[carbon] = xs_carbon;
// set energy limits
SetLowEnergyLimit(elow_tab_[carbon]);
SetHighEnergyLimit(eupp_tab_[carbon]);
if (!use_champion_param_) {
alpha_param_file = "dna/multipleionisation_alphaparam_c.dat";
}
Z = static_cast<G4double>(carbon_def_->GetAtomicNumber());
A = static_cast<G4double>(carbon_def_->GetAtomicMass());
}
// load alpha parameter
mioni_manager_->LoadAlphaParam(alpha_param_file, Z, A);
if (verbose_level_ > 0) {
G4cout << "G4DNATripleIonisationModel is initialized " << G4endl
<< "Energy range: "
<< LowEnergyLimit() / eV << " eV - "
<< HighEnergyLimit() / keV << " keV for "
<< particle->GetParticleName()
<< G4endl;
}
water_density_ = G4DNAMolecularMaterial::Instance()->GetNumMolPerVolTableFor(
G4Material::GetMaterial("G4_WATER"));
atom_deex_ = G4LossTableManager::Instance()->AtomDeexcitation();
if (is_initialized_) { return; }
particle_change_ = GetParticleChangeForGamma();
is_initialized_ = true;
}
//------------------------------------------------------------------------------
G4double G4DNATripleIonisationModel::CrossSectionPerVolume(
const G4Material* material, const G4ParticleDefinition* pdef,
G4double ekin, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling G4DNATripleIonisationModel::CrossSectionPerVolume()"
<< G4endl;
}
// Calculate total cross section for model
if (pdef != proton_def_ && pdef != alpha_def_ && pdef != carbon_def_) {
return 0.0;
}
static G4double water_dens = (*water_density_)[material->GetIndex()];
const auto& pname = pdef->GetParticleName();
const auto low_energy_lim = GetLowEnergyLimit(pname);
const auto upp_energy_lim = GetUppEnergyLimit(pname);
G4double sigma{0.0};
if (ekin <= upp_energy_lim) {
if (ekin < low_energy_lim) { ekin = low_energy_lim; }
CrossSectionDataTable::iterator pos = xs_tab_.find(pname);
if (pos == xs_tab_.end()) {
G4Exception("G4DNATripleIonisationModel::CrossSectionPerVolume",
"em0002", FatalException,
"Model not applicable to particle type.");
}
G4DNACrossSectionDataSet* table = pos->second;
if (table != nullptr) {
const auto a = mioni_manager_->GetAlphaParam(ekin);
sigma = table->FindValue(ekin) * a * a;
}
}
if (verbose_level_ > 2) {
std::stringstream msg;
msg << "----------------------------------------------------------------\n";
msg << " G4DNATripleIonisationModel - XS INFO START\n";
msg << " - Kinetic energy(eV): " << ekin/eV << ", Particle : "
<< pdef->GetParticleName() << "\n";
msg << " - Cross section per water molecule (cm^2): "
<< sigma / cm / cm << "\n";
msg << " - Cross section per water molecule (cm^-1): "
<< sigma * water_dens / (1.0 / cm) << "\n";
msg << " G4DNATripleIonisationModel - XS INFO END\n";
msg << "----------------------------------------------------------------\n";
G4cout << msg.str() << G4endl;
}
return (sigma * water_dens);
}
//------------------------------------------------------------------------------
void G4DNATripleIonisationModel::SampleSecondaries(
std::vector<G4DynamicParticle*>* vsec, const G4MaterialCutsCouple* couple,
const G4DynamicParticle* particle, G4double, G4double)
{
if (verbose_level_ > 3) {
G4cout << "Calling SampleSecondaries() of G4DNATripleIonisationModel"
<< G4endl;
}
// get the definition for this parent particle
auto pdef = particle->GetDefinition();
// get kinetic energy
auto ekin = particle->GetKineticEnergy();
// get particle name
const auto& pname = pdef->GetParticleName();
// get energy limits
const auto low_energy_lim = GetLowEnergyLimit(pname);
// ***************************************************************************
// stop the transportation process of this parent particle
// if its kinetic energy is below the lower limit
if (ekin < low_energy_lim) {
particle_change_->SetProposedKineticEnergy(0.0);
particle_change_->ProposeTrackStatus(fStopAndKill);
particle_change_->ProposeLocalEnergyDeposit(ekin);
return;
}
// ***************************************************************************
constexpr G4int kNumSecondaries = 3;
constexpr G4double kDeltaTheta = pi * 0.666666667;
G4int ioni_shell[kNumSecondaries] = {0, 0, 0};
G4double shell_energy[kNumSecondaries];
auto scale_param = mioni_manager_->GetAlphaParam(ekin);
scale_param *= scale_param;
G4bool is_continue{true};
while (1) {
ioni_shell[0] = RandomSelect(ekin, scale_param, pname);
ioni_shell[1] = RandomSelect(ekin, scale_param, pname);
ioni_shell[2] = RandomSelect(ekin, scale_param, pname);
is_continue = (ioni_shell[0] == ioni_shell[1] &&
ioni_shell[1] == ioni_shell[2]);
if (!is_continue) { break; }
}
G4double tot_ioni_energy{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
shell_energy[i] = ::water_structure.IonisationEnergy(ioni_shell[i]);
tot_ioni_energy += shell_energy[i];
}
if (ekin < tot_ioni_energy || tot_ioni_energy < energy_threshold_) {
return;
}
// generate secondary electrons
G4double theta{0.0}, phi{0.0}, tot_ekin2{0.0};
for (int i = 0; i < kNumSecondaries; i++) {
tot_ekin2 += GenerateSecondaries(vsec, couple, particle, ioni_shell[i],
theta, phi, shell_energy[i]);
theta += kDeltaTheta;
}
// This should never happen
if (mioni_manager_->CheckShellEnergy(eTripleIonisedMolecule, shell_energy)) {
G4Exception("G4DNATripleIonisatioModel::SampleSecondaries()",
"em2050", FatalException, "Negative local energy deposit");
}
// ***************************************************************************
// update kinematics for this parent particle
const auto primary_dir = particle->GetMomentumDirection();
particle_change_->ProposeMomentumDirection(primary_dir);
const auto scattered_energy = ekin - tot_ioni_energy - tot_ekin2;
// update total amount of shell energy
tot_ioni_energy = shell_energy[0] + shell_energy[1] + shell_energy[2];
if (stat_code_) {
particle_change_->SetProposedKineticEnergy(ekin);
particle_change_->ProposeLocalEnergyDeposit(
ekin - scattered_energy);
} else {
particle_change_->SetProposedKineticEnergy(scattered_energy);
particle_change_->ProposeLocalEnergyDeposit(tot_ioni_energy);
}
// ***************************************************************************
// generate triple-ionized water molecules (H2O^3+)
const auto the_track = particle_change_->GetCurrentTrack();
mioni_manager_->CreateMultipleIonisedWaterMolecule(
eTripleIonisedMolecule, ioni_shell, the_track);
// ***************************************************************************
}
@@ -31,27 +31,20 @@
#include "G4VEmProcess.hh"
#include "G4DNAGenericIonsManager.hh"
#include "G4Proton.hh"
// Available models
#include "G4DNADingfelderChargeDecreaseModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
class G4DNAChargeDecrease : public G4VEmProcess
{
public:
G4DNAChargeDecrease(const G4String& processName ="DNAChargeDecrease",
G4ProcessType type = fElectromagnetic);
G4ProcessType type = fElectromagnetic);
~G4DNAChargeDecrease() override;
~G4DNAChargeDecrease() override = default;
G4bool IsApplicable(const G4ParticleDefinition&) override;
virtual void PrintInfo();
void ProcessDescription(std::ostream& outFile) const override;
protected:
@@ -59,7 +52,7 @@ protected:
private:
G4bool isInitialised{false};
G4bool isInitialised{false};
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -30,26 +30,21 @@
#define G4DNAChargeIncrease_h 1
#include "G4VEmProcess.hh"
#include "G4DNAGenericIonsManager.hh"
// Available models
#include "G4DNADingfelderChargeIncreaseModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
class G4DNAChargeIncrease : public G4VEmProcess
{
public:
G4DNAChargeIncrease(const G4String& processName ="DNAChargeIncrease",
G4ProcessType type = fElectromagnetic);
G4ProcessType type = fElectromagnetic);
~G4DNAChargeIncrease() override;
~G4DNAChargeIncrease() override = default;
G4bool IsApplicable(const G4ParticleDefinition&) override;
virtual void PrintInfo();
void ProcessDescription(std::ostream& outFile) const override;
protected:
@@ -57,7 +52,7 @@ protected:
private:
G4bool isInitialised{false};
G4bool isInitialised{false};
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,58 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNADoubleIonisation.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#ifndef G4DNA_DOUBLE_IONISATION_HH_
#define G4DNA_DOUBLE_IONISATION_HH_
#include "G4VEmProcess.hh"
#include "G4DNAGenericIonsManager.hh"
class G4DNADoubleIonisation : public G4VEmProcess {
public:
G4DNADoubleIonisation(const G4String& processName = "G4DNADoubleIonisation",
G4ProcessType type = fElectromagnetic);
virtual ~G4DNADoubleIonisation() = default;
virtual G4bool IsApplicable(const G4ParticleDefinition&);
virtual void PrintInfo();
protected:
virtual void InitialiseProcess(const G4ParticleDefinition*);
private:
G4bool is_initialized_;
};
#endif // G4DNA_DOUBLE_IONISATION_HH_
@@ -0,0 +1,57 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNAQuadrupleIonisation.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#ifndef G4DNA_QUADRUPLE_IONISATION_HH_
#define G4DNA_QUADRUPLE_IONISATION_HH_
#include "G4VEmProcess.hh"
#include "G4DNAGenericIonsManager.hh"
class G4DNAQuadrupleIonisation : public G4VEmProcess {
public:
G4DNAQuadrupleIonisation(const G4String& pname ="DNAQuadrupleIonisation",
G4ProcessType type = fElectromagnetic);
virtual ~G4DNAQuadrupleIonisation() = default;
virtual G4bool IsApplicable(const G4ParticleDefinition&);
virtual void PrintInfo();
protected:
virtual void InitialiseProcess(const G4ParticleDefinition*);
private:
G4bool is_initialized_;
};
#endif // G4DNA_QUADRUPLE_IONISATION_HH_
@@ -0,0 +1,58 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNATripleIonisation.hh
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#ifndef G4DNA_TRIPLE_IONISATION_HH_
#define G4DNA_TRIPLE_IONISATION_HH_
#include "G4VEmProcess.hh"
#include "G4DNAGenericIonsManager.hh"
class G4DNATripleIonisation : public G4VEmProcess {
public:
G4DNATripleIonisation(const G4String& pname ="DNATripleIonisation",
G4ProcessType type = fElectromagnetic);
virtual ~G4DNATripleIonisation() = default;
virtual G4bool IsApplicable(const G4ParticleDefinition&);
virtual void PrintInfo();
protected:
virtual void InitialiseProcess(const G4ParticleDefinition*);
private:
G4bool is_initialized_;
};
#endif // G4DNA_TRIPLE_IONISATION_HH_
@@ -31,8 +31,8 @@
// 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
@@ -41,7 +41,7 @@
// 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
#ifndef G4DNAWaterDissociationDisplacer_h
@@ -59,26 +59,31 @@ class G4DNAWaterDissociationDisplacer: public G4VMolecularDissociationDisplacer
public:
G4DNAWaterDissociationDisplacer();
~G4DNAWaterDissociationDisplacer() override;
std::vector<G4ThreeVector>
GetProductsDisplacement(const G4MolecularDissociationChannel*) const
override;
G4ThreeVector
GetMotherMoleculeDisplacement(const G4MolecularDissociationChannel*) const
override;
G4ThreeVector radialDistributionOfElectron() const;
G4ThreeVector radialDistributionOfProducts(G4double r_rms) const;
static G4double ElectronProbaDistribution(G4double r);
G4CT_COUNT_DEF(Ionisation_DissociationDecay)
G4CT_COUNT_DEF(A1B1_DissociationDecay)
G4CT_COUNT_DEF(B1A1_DissociationDecay)
G4CT_COUNT_DEF(B1A1_DissociationDecay2)
G4CT_COUNT_DEF(AutoIonisation)
G4CT_COUNT_DEF(DissociativeAttachment)
G4CT_COUNT_DEF(DoubleIonisation_DissociationDecay1)
G4CT_COUNT_DEF(DoubleIonisation_DissociationDecay2)
G4CT_COUNT_DEF(DoubleIonisation_DissociationDecay3)
G4CT_COUNT_DEF(TripleIonisation_DissociationDecay)
G4CT_COUNT_DEF(QuadrupleIonisation_DissociationDecay)
private:
G4double ke;
G4DNAModelSubType dnaSubType;
@@ -23,6 +23,9 @@ geant4_add_module(G4emdna-processes
G4DNAVibExcitation.hh
G4DNAScavengerProcess.hh
G4DNAPolyNucleotideReactionProcess.hh
G4DNADoubleIonisation.hh
G4DNATripleIonisation.hh
G4DNAQuadrupleIonisation.hh
SOURCES
G4DNAAttachment.cc
G4DNABrownianTransportation.cc
@@ -42,7 +45,10 @@ geant4_add_module(G4emdna-processes
G4DNASecondOrderReaction.cc
G4DNAVibExcitation.cc
G4DNAScavengerProcess.cc
G4DNAPolyNucleotideReactionProcess.cc)
G4DNAPolyNucleotideReactionProcess.cc
G4DNADoubleIonisation.cc
G4DNATripleIonisation.cc
G4DNAQuadrupleIonisation.cc)
geant4_module_link_libraries(G4emdna-processes
PUBLIC
@@ -27,77 +27,59 @@
#include "G4DNAChargeDecrease.hh"
#include "G4SystemOfUnits.hh"
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4DNADingfelderChargeDecreaseModel.hh"
#include "G4DNAIonChargeDecreaseModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
using namespace std;
G4DNAChargeDecrease::G4DNAChargeDecrease(const G4String& processName,
G4ProcessType type) :
G4VEmProcess(processName, type)
{
SetBuildTableFlag(false);
SetProcessSubType(fLowEnergyChargeDecrease);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4DNAChargeDecrease::~G4DNAChargeDecrease()
= default;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4bool G4DNAChargeDecrease::IsApplicable(const G4ParticleDefinition& p)
{
G4DNAGenericIonsManager *instance;
instance = G4DNAGenericIonsManager::Instance();
return (&p == G4Proton::ProtonDefinition()
|| &p == instance->GetIon("alpha++") || &p == instance->GetIon("alpha+"));
G4String name = p.GetParticleName();
return (p.IsGeneralIon() ||
name == "proton" || name == "alpha+" || name == "alpha");
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAChargeDecrease::InitialiseProcess(const G4ParticleDefinition* p)
{
if(!isInitialised)
{
if (!isInitialised) {
isInitialised = true;
SetBuildTableFlag(false);
G4String name = p->GetParticleName();
auto mod = EmModel();
if (nullptr == mod) {
G4String name = p->GetParticleName();
if(name == "proton")
{
if(EmModel() == nullptr)
{
SetEmModel(new G4DNADingfelderChargeDecreaseModel);
EmModel()->SetLowEnergyLimit(100 * eV);
EmModel()->SetHighEnergyLimit(100 * MeV);
if (name == "proton" || name == "alpha+" || name == "alpha") {
SetEmModel(new G4DNADingfelderChargeDecreaseModel());
} else {
SetEmModel(new G4DNAIonChargeDecreaseModel());
}
AddEmModel(1, EmModel());
}
if(name == "alpha" || name == "alpha+")
{
if(EmModel() == nullptr)
{
SetEmModel(new G4DNADingfelderChargeDecreaseModel);
EmModel()->SetLowEnergyLimit(1 * keV);
EmModel()->SetHighEnergyLimit(400 * MeV);
}
AddEmModel(1, EmModel());
}
G4EmParameters* param = G4EmParameters::Instance();
EmModel(0)->SetLowEnergyLimit(param->MinKinEnergy());
EmModel(0)->SetHighEnergyLimit(param->MaxKinEnergy());
AddEmModel(1, EmModel(0));
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4DNAChargeDecrease::PrintInfo()
void G4DNAChargeDecrease::ProcessDescription(std::ostream& out) const
{
G4cout << " Total cross sections computed from " << EmModel()->GetName()
<< " model" << G4endl;
out << " Total cross sections computed from " << EmModel()->GetName()
<< " model" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -27,76 +27,59 @@
#include "G4DNAChargeIncrease.hh"
#include "G4SystemOfUnits.hh"
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4DNADingfelderChargeIncreaseModel.hh"
#include "G4DNAIonChargeIncreaseModel.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
using namespace std;
G4DNAChargeIncrease::G4DNAChargeIncrease(const G4String& processName,
G4ProcessType type) :
G4VEmProcess(processName, type)
{
SetBuildTableFlag(false);
SetProcessSubType(fLowEnergyChargeIncrease);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4DNAChargeIncrease::~G4DNAChargeIncrease()
= default;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4bool G4DNAChargeIncrease::IsApplicable(const G4ParticleDefinition& p)
{
G4DNAGenericIonsManager *instance;
instance = G4DNAGenericIonsManager::Instance();
return (&p == instance->GetIon("hydrogen") || &p == instance->GetIon("alpha+")
|| &p == instance->GetIon("helium"));
G4String name = p.GetParticleName();
return (p.IsGeneralIon() ||
name == "hydrogen" || name == "alpha+" || name == "helium");
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4DNAChargeIncrease::InitialiseProcess(const G4ParticleDefinition* p)
{
if(!isInitialised)
{
if (!isInitialised) {
isInitialised = true;
SetBuildTableFlag(false);
G4String name = p->GetParticleName();
auto mod = EmModel();
if (nullptr == mod) {
G4String name = p->GetParticleName();
if(name == "hydrogen")
{
if(EmModel() == nullptr)
{
SetEmModel(new G4DNADingfelderChargeIncreaseModel);
EmModel()->SetLowEnergyLimit(100 * eV);
EmModel()->SetHighEnergyLimit(100 * MeV);
if (name == "hydrogen" || name == "alpha+" || name == "helium") {
SetEmModel(new G4DNADingfelderChargeIncreaseModel());
} else {
SetEmModel(new G4DNAIonChargeIncreaseModel());
}
AddEmModel(1, EmModel());
}
if(name == "alpha+" || name == "helium")
{
if(EmModel() == nullptr)
{
SetEmModel(new G4DNADingfelderChargeIncreaseModel);
EmModel()->SetLowEnergyLimit(1 * keV);
EmModel()->SetHighEnergyLimit(400 * MeV);
}
AddEmModel(1, EmModel());
}
G4EmParameters* param = G4EmParameters::Instance();
EmModel(0)->SetLowEnergyLimit(param->MinKinEnergy());
EmModel(0)->SetHighEnergyLimit(param->MaxKinEnergy());
AddEmModel(1, EmModel(0));
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4DNAChargeIncrease::PrintInfo()
void G4DNAChargeIncrease::ProcessDescription(std::ostream& out) const
{
G4cout << " Total cross sections computed from " << EmModel()->GetName()
<< " model" << G4endl;
out << " Total cross sections computed from " << EmModel()->GetName()
<< " model" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,115 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNADoubleIonisation.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#include "G4DNADoubleIonisation.hh"
#include "G4DNADoubleIonisationModel.hh"
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4SystemOfUnits.hh"
#include "G4GenericIon.hh"
#include "G4Positron.hh"
//------------------------------------------------------------------------------
G4DNADoubleIonisation::G4DNADoubleIonisation(
const G4String& pname, G4ProcessType type)
: G4VEmProcess(pname, type),
is_initialized_(false)
{
SetProcessSubType(fLowEnergyDoubleIonisation);
}
//------------------------------------------------------------------------------
G4bool G4DNADoubleIonisation::IsApplicable(const G4ParticleDefinition& p)
{
return (
&p == G4Proton::Proton() ||
&p == G4DNAGenericIonsManager::Instance()->GetIon("alpha++") ||
&p == G4GenericIon::GenericIonDefinition()
);
}
//------------------------------------------------------------------------------
void G4DNADoubleIonisation::InitialiseProcess(const G4ParticleDefinition* p)
{
if (is_initialized_) { return; }
is_initialized_ = true;
SetBuildTableFlag(false);
const auto name = p->GetParticleName();
if (name == "proton") {
if (!EmModel()) {
auto ptr = new G4DNADoubleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(3.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "alpha") {
if (!EmModel()) {
auto ptr = new G4DNADoubleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(23.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "GenericIon") {
// for carbon ions (12C6+)
if (!EmModel()) {
auto ptr = new G4DNADoubleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(120 * MeV);
}
AddEmModel(1, EmModel());
}
}
//------------------------------------------------------------------------------
void G4DNADoubleIonisation::PrintInfo()
{
if (EmModel(1)) {
G4cout << " Total cross sections computed from " << EmModel(0)->GetName()
<< " and " << EmModel(1)->GetName() << " models" << G4endl;
} else {
G4cout << " Total cross sections computed from " << EmModel()->GetName()
<< G4endl;
}
}
@@ -216,7 +216,9 @@ void G4DNAElectronHoleRecombination::MakeReaction(const G4Track& track)
G4bool G4DNAElectronHoleRecombination::FindReactant(const G4Track& track)
{
if (GetMolecule(track)->GetCharge() <= 0)
// NOTE(Shogo OKADA, 2024-04-05 Fri.): Changed this branch condition to
// select only H2O+ ions involved in electron-hole recombination
if (GetMolecule(track)->GetCharge() != 1)
{
return false;
}
@@ -0,0 +1,115 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNAQuadrupleIonisation.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#include "G4DNAQuadrupleIonisation.hh"
#include "G4DNAQuadrupleIonisationModel.hh"
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4SystemOfUnits.hh"
#include "G4GenericIon.hh"
#include "G4Positron.hh"
//------------------------------------------------------------------------------
G4DNAQuadrupleIonisation::G4DNAQuadrupleIonisation(
const G4String& pname, G4ProcessType type)
: G4VEmProcess(pname, type),
is_initialized_(false)
{
SetProcessSubType(fLowEnergyQuadrupleIonisation);
}
//------------------------------------------------------------------------------
G4bool G4DNAQuadrupleIonisation::IsApplicable(const G4ParticleDefinition& p)
{
return (
&p == G4Proton::Proton() ||
&p == G4DNAGenericIonsManager::Instance()->GetIon("alpha++") ||
&p == G4GenericIon::GenericIonDefinition()
);
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisation::InitialiseProcess(const G4ParticleDefinition* p)
{
if (is_initialized_) { return; }
is_initialized_ = true;
SetBuildTableFlag(false);
const auto name = p->GetParticleName();
if (name == "proton") {
if (!EmModel()) {
auto ptr = new G4DNAQuadrupleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(3.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "alpha") {
if (!EmModel()) {
auto ptr = new G4DNAQuadrupleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(23.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "GenericIon") {
// for carbon ions (12C6+)
if (!EmModel()) {
auto ptr = new G4DNAQuadrupleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(120.0 * MeV);
}
AddEmModel(1, EmModel());
}
}
//------------------------------------------------------------------------------
void G4DNAQuadrupleIonisation::PrintInfo()
{
if (EmModel(1)) {
G4cout << " Total cross sections computed from " << EmModel(0)->GetName()
<< " and " << EmModel(1)->GetName() << " models" << G4endl;
} else {
G4cout << " Total cross sections computed from "
<< EmModel()->GetName() << G4endl;
}
}
@@ -0,0 +1,115 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// G4DNATripleIonisation.cc
//
// Created at 2024/04/03 (Thu.)
// Author: Shogo OKADA @KEK-CRC (shogo.okada@kek.jp)
//
#include "G4DNATripleIonisation.hh"
#include "G4DNATripleIonisationModel.hh"
#include "G4LowEnergyEmProcessSubType.hh"
#include "G4SystemOfUnits.hh"
#include "G4GenericIon.hh"
#include "G4Positron.hh"
//------------------------------------------------------------------------------
G4DNATripleIonisation::G4DNATripleIonisation(
const G4String& pname, G4ProcessType type)
: G4VEmProcess(pname, type),
is_initialized_(false)
{
SetProcessSubType(fLowEnergyTripleIonisation);
}
//------------------------------------------------------------------------------
G4bool G4DNATripleIonisation::IsApplicable(const G4ParticleDefinition& p)
{
return (
&p == G4Proton::Proton() ||
&p == G4DNAGenericIonsManager::Instance()->GetIon("alpha++") ||
&p == G4GenericIon::GenericIonDefinition()
);
}
//------------------------------------------------------------------------------
void G4DNATripleIonisation::InitialiseProcess(const G4ParticleDefinition* p)
{
if (is_initialized_) { return; }
is_initialized_ = true;
SetBuildTableFlag(false);
const auto name = p->GetParticleName();
if (name == "proton") {
if (!EmModel()) {
auto ptr = new G4DNATripleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(3.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "alpha") {
if (!EmModel()) {
auto ptr = new G4DNATripleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(23.0 * MeV);
}
AddEmModel(1, EmModel());
} else if (name == "GenericIon") {
// for carbon ions (12C6+)
if (!EmModel()) {
auto ptr = new G4DNATripleIonisationModel();
SetEmModel(ptr);
ptr->SetLowEnergyLimit(0.0 * keV);
ptr->SetHighEnergyLimit(120.0 * MeV);
}
AddEmModel(1, EmModel());
}
}
//------------------------------------------------------------------------------
void G4DNATripleIonisation::PrintInfo()
{
if (EmModel(1)) {
G4cout << " Total cross sections computed from " << EmModel(0)->GetName()
<< " and " << EmModel(1)->GetName() << " models" << G4endl;
} else {
G4cout << " Total cross sections computed from "
<< EmModel()->GetName() << G4endl;
}
}
@@ -76,6 +76,22 @@ G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
DissociativeAttachment)
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
DoubleIonisation_DissociationDecay1)
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
DoubleIonisation_DissociationDecay2)
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
DoubleIonisation_DissociationDecay3)
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
TripleIonisation_DissociationDecay)
G4CT_COUNT_IMPL(G4DNAWaterDissociationDisplacer,
QuadrupleIonisation_DissociationDecay)
/*
//------------------------------------------------------------------------------
#ifdef _WATER_DISPLACER_USE_KREIPL_
@@ -124,7 +140,7 @@ G4double G4DNAWaterDissociationDisplacer::ElectronProbaDistribution(G4double r)
*/
G4DNAWaterDissociationDisplacer::G4DNAWaterDissociationDisplacer()
:
ke(1.7*eV)
/*#ifdef _WATER_DISPLACER_USE_KREIPL_
fFastElectronDistrib(0., 5., 0.001)
@@ -151,7 +167,7 @@ G4DNAWaterDissociationDisplacer::G4DNAWaterDissociationDisplacer()
proba += eps;
// G4cout << G4BestUnit(r*nanometer, "Length") << G4endl;
}*/
dnaSubType = G4EmParameters::Instance()->DNAeSolvationSubType();
dnaSubType = G4EmParameters::Instance()->DNAeSolvationSubType();
// SetVerbose(1);
}
@@ -159,317 +175,505 @@ G4DNAWaterDissociationDisplacer::G4DNAWaterDissociationDisplacer()
G4DNAWaterDissociationDisplacer::~G4DNAWaterDissociationDisplacer()
{
;
}
//------------------------------------------------------------------------------
G4ThreeVector
G4DNAWaterDissociationDisplacer::
GetMotherMoleculeDisplacement(const G4MolecularDissociationChannel*
theDecayChannel) const
G4ThreeVector G4DNAWaterDissociationDisplacer::GetMotherMoleculeDisplacement(
const G4MolecularDissociationChannel* theDecayChannel) const
{
G4int decayType = theDecayChannel->GetDisplacementType();
G4double RMSMotherMoleculeDisplacement(0.);
G4int decayType = theDecayChannel->GetDisplacementType();
G4double RMSMotherMoleculeDisplacement(0.0);
switch (decayType)
{
case Ionisation_DissociationDecay:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case A1B1_DissociationDecay:
RMSMotherMoleculeDisplacement = 0. * nanometer;
break;
case B1A1_DissociationDecay:
RMSMotherMoleculeDisplacement = 0. * nanometer;
break;
case B1A1_DissociationDecay2:
RMSMotherMoleculeDisplacement = 0. * nanometer;
break;
case AutoIonisation:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case DissociativeAttachment:
RMSMotherMoleculeDisplacement = 0. * nanometer;
break;
}
switch (decayType) {
case Ionisation_DissociationDecay:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case A1B1_DissociationDecay:
RMSMotherMoleculeDisplacement = 0.0 * nanometer;
break;
case B1A1_DissociationDecay:
RMSMotherMoleculeDisplacement = 0.0 * nanometer;
break;
case B1A1_DissociationDecay2:
RMSMotherMoleculeDisplacement = 0.0 * nanometer;
break;
case AutoIonisation:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case DissociativeAttachment:
RMSMotherMoleculeDisplacement = 0.0 * nanometer;
break;
case DoubleIonisation_DissociationDecay1:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case DoubleIonisation_DissociationDecay2:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case DoubleIonisation_DissociationDecay3:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case TripleIonisation_DissociationDecay:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
case QuadrupleIonisation_DissociationDecay:
RMSMotherMoleculeDisplacement = 2.0 * nanometer;
break;
}
if (RMSMotherMoleculeDisplacement == 0)
{
return G4ThreeVector(0, 0, 0);
}
auto RandDirection =
radialDistributionOfProducts(RMSMotherMoleculeDisplacement);
if (RMSMotherMoleculeDisplacement == 0) {
return G4ThreeVector(0, 0, 0);
}
return RandDirection;
auto RandDirection =
radialDistributionOfProducts(RMSMotherMoleculeDisplacement);
return RandDirection;
}
//------------------------------------------------------------------------------
vector<G4ThreeVector>
G4DNAWaterDissociationDisplacer::
GetProductsDisplacement(const G4MolecularDissociationChannel* pDecayChannel) const
vector<G4ThreeVector> G4DNAWaterDissociationDisplacer::GetProductsDisplacement(
const G4MolecularDissociationChannel* pDecayChannel) const
{
G4int nbProducts = pDecayChannel->GetNbProducts();
vector<G4ThreeVector> theProductDisplacementVector(nbProducts);
G4int nbProducts = pDecayChannel->GetNbProducts();
vector<G4ThreeVector> theProductDisplacementVector(nbProducts);
typedef map<const G4MoleculeDefinition*, G4double> RMSmap;
RMSmap theRMSmap;
typedef map<const G4MoleculeDefinition*, G4double> RMSmap;
RMSmap theRMSmap;
G4int decayType = pDecayChannel->GetDisplacementType();
G4int decayType = pDecayChannel->GetDisplacementType();
switch (decayType)
{
case Ionisation_DissociationDecay:
{
if (fVerbose != 0)
{
G4cout << "Ionisation_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4double RdmValue = G4UniformRand();
if (RdmValue < 0.5)
{
// H3O
theRMSmap[G4H3O::Definition()] = 0. * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.8 * nanometer;
}
else
{
// H3O
theRMSmap[G4H3O::Definition()] = 0.8 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0. * nanometer;
}
for (int i = 0; i < nbProducts; i++)
{
auto pProduct = pDecayChannel->GetProduct(i);
G4double theRMSDisplacement = theRMSmap[pProduct->GetDefinition()];
if (theRMSDisplacement == 0.)
{
theProductDisplacementVector[i] = G4ThreeVector();
}
else
{
auto RandDirection = radialDistributionOfProducts(theRMSDisplacement);
theProductDisplacementVector[i] = RandDirection;
}
}
break;
switch (decayType) {
case Ionisation_DissociationDecay:
{
if (fVerbose != 0) {
G4cout << "Ionisation_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
case A1B1_DissociationDecay:
{
if (fVerbose != 0)
{
G4cout << "A1B1_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4double theRMSDisplacement = 2.4 * nanometer;
G4double RdmValue = G4UniformRand();
if (RdmValue < 0.5) {
// H3O
theRMSmap[G4H3O::Definition()] = 0.0 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.8 * nanometer;
} else {
// H3O
theRMSmap[G4H3O::Definition()] = 0.8 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.0 * nanometer;
}
for (G4int i = 0; i < nbProducts; i++) {
auto pProduct = pDecayChannel->GetProduct(i);
G4double theRMSDisplacement = theRMSmap[pProduct->GetDefinition()];
if (theRMSDisplacement == 0.0) {
theProductDisplacementVector[i] = G4ThreeVector();
} else {
auto RandDirection =
radialDistributionOfProducts(theRMSDisplacement);
for (G4int i = 0; i < nbProducts; i++)
{
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4OH::Definition())
{
theProductDisplacementVector[i] = -1. / 18. * RandDirection;
}
else if (pProduct->GetDefinition() == G4Hydrogen::Definition())
{
theProductDisplacementVector[i] = +17. / 18. * RandDirection;
}
}
break;
}
case B1A1_DissociationDecay:
{
if (fVerbose != 0)
{
G4cout << "B1A1_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4double theRMSDisplacement = 0.8 * nanometer;
auto RandDirection =
radialDistributionOfProducts(theRMSDisplacement);
G4int NbOfOH = 0;
for (G4int i = 0; i < nbProducts; ++i)
{
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4H2::Definition())
{
// In the paper of Kreipl (2009)
// theProductDisplacementVector[i] = -2. / 18. * RandDirection;
// Based on momentum conservation
theProductDisplacementVector[i] = -16. / 18. * RandDirection;
}
else if (pProduct->GetDefinition() == G4OH::Definition())
{
// In the paper of Kreipl (2009)
// G4ThreeVector OxygenDisplacement = +16. / 18. * RandDirection;
// Based on momentum conservation
G4ThreeVector OxygenDisplacement = +2. / 18. * RandDirection;
G4double OHRMSDisplacement = 1.1 * nanometer;
auto OHDisplacement =
radialDistributionOfProducts(OHRMSDisplacement);
if (NbOfOH == 0)
{
OHDisplacement = 0.5 * OHDisplacement;
}
else
{
OHDisplacement = -0.5 * OHDisplacement;
}
theProductDisplacementVector[i] =
OHDisplacement + OxygenDisplacement;
++NbOfOH;
}
}
break;
}
case B1A1_DissociationDecay2:
{
if(fVerbose != 0){
G4cout<<"B1A1_DissociationDecay2"<<G4endl;
G4cout<<"Channel's name: "<<pDecayChannel->GetName()<<G4endl;
radialDistributionOfProducts(theRMSDisplacement);
theProductDisplacementVector[i] = RandDirection;
}
}
break;
}
case A1B1_DissociationDecay:
{
if (fVerbose != 0) {
G4cout << "A1B1_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4int NbOfH = 0;
for(G4int i =0; i < nbProducts; ++i)
{
auto pProduct = pDecayChannel->GetProduct(i);
if(pProduct->GetDefinition() == G4Oxygen::Definition()){
constexpr G4double theRMSDisplacement = 2.4 * nanometer;
auto RandDirection = radialDistributionOfProducts(theRMSDisplacement);
for (G4int i = 0; i < nbProducts; i++) {
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4OH::Definition()) {
theProductDisplacementVector[i] = -1.0 / 18.0 * RandDirection;
} else if (pProduct->GetDefinition() == G4Hydrogen::Definition()) {
theProductDisplacementVector[i] = +17.0 / 18.0 * RandDirection;
}
}
break;
}
case B1A1_DissociationDecay:
{
if (fVerbose != 0) {
G4cout << "B1A1_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
constexpr G4double theRMSDisplacement = 0.8 * nanometer;
auto RandDirection = radialDistributionOfProducts(theRMSDisplacement);
G4int NbOfOH = 0;
for (G4int i = 0; i < nbProducts; ++i) {
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4H2::Definition()) {
// In the paper of Kreipl (2009)
// theProductDisplacementVector[i] = -2.0 / 18.0 * RandDirection;
// Based on momentum conservation
theProductDisplacementVector[i] = -16.0 / 18.0 * RandDirection;
} else if (pProduct->GetDefinition() == G4OH::Definition()) {
// In the paper of Kreipl (2009)
// G4ThreeVector OxygenDisplacement = +16.0 / 18.0 * RandDirection;
// Based on momentum conservation
G4ThreeVector OxygenDisplacement = +2.0 / 18.0 * RandDirection;
constexpr G4double OHRMSDisplacement = 1.1 * nanometer;
auto OHDisplacement =
radialDistributionOfProducts(OHRMSDisplacement);
if (NbOfOH == 0) {
OHDisplacement = 0.5 * OHDisplacement;
} else {
OHDisplacement = -0.5 * OHDisplacement;
}
theProductDisplacementVector[i] =
OHDisplacement + OxygenDisplacement;
++NbOfOH;
}
}
break;
}
case B1A1_DissociationDecay2:
{
if (fVerbose != 0){
G4cout << "B1A1_DissociationDecay2" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4int NbOfH = 0;
for (G4int i = 0; i < nbProducts; ++i) {
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4Oxygen::Definition()) {
// O(3p)
theProductDisplacementVector[i] = G4ThreeVector(0,0,0);
}
else if(pProduct->GetDefinition() == G4Hydrogen::Definition()){
theProductDisplacementVector[i] = G4ThreeVector(0, 0, 0);
} else if (pProduct->GetDefinition() == G4Hydrogen::Definition()) {
// H
G4double HRMSDisplacement = 1.6 * nanometer;
constexpr G4double HRMSDisplacement = 1.6 * nanometer;
auto HDisplacement =
radialDistributionOfProducts(HRMSDisplacement);
radialDistributionOfProducts(HRMSDisplacement);
if(NbOfH==0) HDisplacement = 0.5*HDisplacement;
else HDisplacement = -0.5*HDisplacement;
if (NbOfH == 0) {
HDisplacement = 0.5 * HDisplacement;
} else {
HDisplacement = -0.5 * HDisplacement;
}
theProductDisplacementVector[i] = HDisplacement;
++NbOfH;
}
}
break;
}
case AutoIonisation:
{
if (fVerbose != 0) {
G4cout << "AutoIonisation" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
case AutoIonisation:
{
if (fVerbose != 0)
{
G4cout << "AutoIonisation" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4double RdmValue = G4UniformRand();
G4double RdmValue = G4UniformRand();
if (RdmValue < 0.5)
{
// H3O
theRMSmap[G4H3O::Definition()] = 0. * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.8 * nanometer;
}
else
{
// H3O
theRMSmap[G4H3O::Definition()] = 0.8 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0. * nanometer;
}
for (G4int i = 0; i < nbProducts; i++)
{
auto pProduct = pDecayChannel->GetProduct(i);
auto theRMSDisplacement = theRMSmap[pProduct->GetDefinition()];
if (theRMSDisplacement == 0)
{
theProductDisplacementVector[i] = G4ThreeVector();
}
else
{
auto RandDirection =
radialDistributionOfProducts(theRMSDisplacement);
theProductDisplacementVector[i] = RandDirection;
}
if (pProduct->GetDefinition() == G4Electron_aq::Definition())
{
theProductDisplacementVector[i] = radialDistributionOfElectron();
}
}
break;
if (RdmValue < 0.5) {
// H3O
theRMSmap[G4H3O::Definition()] = 0.0 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.8 * nanometer;
} else {
// H3O
theRMSmap[G4H3O::Definition()] = 0.8 * nanometer;
// OH
theRMSmap[G4OH::Definition()] = 0.0 * nanometer;
}
case DissociativeAttachment:
{
if (fVerbose != 0)
{
G4cout << "DissociativeAttachment" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
G4double theRMSDisplacement = 0.8 * nanometer;
for (G4int i = 0; i < nbProducts; i++) {
auto pProduct = pDecayChannel->GetProduct(i);
auto theRMSDisplacement = theRMSmap[pProduct->GetDefinition()];
if (theRMSDisplacement == 0) {
theProductDisplacementVector[i] = G4ThreeVector();
} else {
auto RandDirection =
radialDistributionOfProducts(theRMSDisplacement);
G4int NbOfOH = 0;
for (G4int i = 0; i < nbProducts; ++i)
{
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4H2::Definition())
{
// In the paper of Kreipl (2009)
// theProductDisplacementVector[i] = -2. / 18. * RandDirection;
// Based on momentum conservation
theProductDisplacementVector[i] = -16. / 18. * RandDirection;
}
else if (pProduct->GetDefinition() == G4OH::Definition())
{
// In the paper of Kreipl (2009)
// G4ThreeVector OxygenDisplacement = +16. / 18. * RandDirection;
// Based on momentum conservation
G4ThreeVector OxygenDisplacement = +2. / 18. * RandDirection;
G4double OHRMSDisplacement = 1.1 * nanometer;
auto OHDisplacement =
radialDistributionOfProducts(OHRMSDisplacement);
if (NbOfOH == 0)
{
OHDisplacement = 0.5 * OHDisplacement;
}
else
{
OHDisplacement = -0.5 * OHDisplacement;
}
theProductDisplacementVector[i] = OHDisplacement +
OxygenDisplacement;
++NbOfOH;
}
}
break;
radialDistributionOfProducts(theRMSDisplacement);
theProductDisplacementVector[i] = RandDirection;
}
if (pProduct->GetDefinition() == G4Electron_aq::Definition()) {
theProductDisplacementVector[i] = radialDistributionOfElectron();
}
}
}
return theProductDisplacementVector;
break;
}
case DissociativeAttachment:
{
if (fVerbose != 0) {
G4cout << "DissociativeAttachment" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
constexpr G4double theRMSDisplacement = 0.8 * nanometer;
auto RandDirection = radialDistributionOfProducts(theRMSDisplacement);
G4int NbOfOH = 0;
for (G4int i = 0; i < nbProducts; ++i) {
auto pProduct = pDecayChannel->GetProduct(i);
if (pProduct->GetDefinition() == G4H2::Definition()) {
// In the paper of Kreipl (2009)
// theProductDisplacementVector[i] = -2.0 / 18.0 * RandDirection;
// Based on momentum conservation
theProductDisplacementVector[i] = -16.0 / 18.0 * RandDirection;
} else if (pProduct->GetDefinition() == G4OH::Definition()) {
// In the paper of Kreipl (2009)
// G4ThreeVector OxygenDisplacement = +16.0 / 18.0 * RandDirection;
// Based on momentum conservation
G4ThreeVector OxygenDisplacement = +2.0 / 18.0 * RandDirection;
constexpr G4double OHRMSDisplacement = 1.1 * nanometer;
auto OHDisplacement =
radialDistributionOfProducts(OHRMSDisplacement);
if (NbOfOH == 0) {
OHDisplacement = 0.5 * OHDisplacement;
} else {
OHDisplacement = -0.5 * OHDisplacement;
}
theProductDisplacementVector[i] = OHDisplacement +
OxygenDisplacement;
++NbOfOH;
}
}
break;
}
case DoubleIonisation_DissociationDecay1:
{
if (fVerbose != 0) {
G4cout << "DoubleIonisation_DissociationDecay1" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
// Ref.) B. Gervais, et al., DOI: 10.1016/j.radphyschem.2005.09.01
// Decay Channel #1: H2O^2+ -> 2H+ + O(3P) -> 2H3O+ + O(3P)
theRMSmap[G4H3O::Definition()] = 1.2 * nanometer;
theRMSmap[G4Oxygen::Definition()] = 0.0 * nanometer;
for (G4int i = 0, num_H3O = 0; i < nbProducts; i++) {
const auto prod_def = pDecayChannel->GetProduct(i)->GetDefinition();
if (prod_def == G4H3O::Definition()) {
num_H3O++;
if (num_H3O == 2) {
constexpr G4double H3Op_rms = 0.3 * nanometer;
theRMSmap[G4H3O::Definition()] = H3Op_rms;
}
}
theProductDisplacementVector[i]
= radialDistributionOfProducts(theRMSmap[prod_def]);
}
break;
}
case DoubleIonisation_DissociationDecay2:
{
if (fVerbose != 0) {
G4cout << "DoubleIonisation_DissociationDecay2" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
// Ref.) B. Gervais, et al., DOI: 10.1016/j.radphyschem.2005.09.01
// Decay Channel #2: H2O^2+ -> H+ + H* + O+ -> 2H3O+ + H* + *OH + O(3P)
theRMSmap[G4H3O::Definition()] = 1.2 * nanometer;
theRMSmap[G4Oxygen::Definition()] = 0.0 * nanometer;
theRMSmap[G4Hydrogen::Definition()] = 0.8 * nanometer;
theRMSmap[G4OH::Definition()] = 0.3 * nanometer;
const auto OH_disp = radialDistributionOfProducts(
theRMSmap[G4OH::Definition()]);
for (G4int i = 0, num_H3O = 0; i < nbProducts; i++) {
const auto prod_def = pDecayChannel->GetProduct(i)->GetDefinition();
if (prod_def == G4H3O::Definition()) {
num_H3O++;
if (num_H3O == 2) {
constexpr G4double OH_rms = 0.3 * nanometer;
theProductDisplacementVector[i]
= radialDistributionOfProducts(OH_rms);
theProductDisplacementVector[i] += OH_disp;
continue;
}
} else if (prod_def == G4OH::Definition()) {
theProductDisplacementVector[i] = OH_disp;
continue;
}
theProductDisplacementVector[i]
= radialDistributionOfProducts(theRMSmap[prod_def]);
}
break;
}
case DoubleIonisation_DissociationDecay3:
{
if (fVerbose != 0) {
G4cout << "DoubleIonisation_DissociationDecay3" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
// Ref.) B. Gervais, et al., DOI: 10.1016/j.radphyschem.2005.09.01
// Decay Channel #3: H2O^2+ -> H+ + OH+ -> 2H3O+ + O(3P)
theRMSmap[G4H3O::Definition()] = 1.2 * nanometer;
theRMSmap[G4Oxygen::Definition()] = 0.0 * nanometer;
for (G4int i = 0; i < nbProducts; i++) {
const auto prod_def = pDecayChannel->GetProduct(i)->GetDefinition();
theProductDisplacementVector[i]
= radialDistributionOfProducts(theRMSmap[prod_def]);
}
break;
}
case TripleIonisation_DissociationDecay:
{
if (fVerbose != 0) {
G4cout << "TripleIonisation_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
// Ref.) B. Gervais, et al., DOI: 10.1016/j.radphyschem.2005.09.01
// Decay Channel: H2O^3+ -> 3H3O+ + *OH + O(3P)
//
// ** Detaied decay chain **
// H2O^3+ -> O+ + H3O+ + H3O+
// |
// --> H2O+ + O(3P)
// |
// --> *OH + H3O+
theRMSmap[G4H3O::Definition()] = 1.2 * nanometer;
theRMSmap[G4Oxygen::Definition()] = 0.0 * nanometer;
theRMSmap[G4OH::Definition()] = 0.3 * nanometer;
const auto OH_disp = radialDistributionOfProducts(
theRMSmap[G4OH::Definition()]);
for (G4int i = 0, num_H3O = 0; i < nbProducts; i++) {
const auto prod_def = pDecayChannel->GetProduct(i)->GetDefinition();
if (prod_def == G4H3O::Definition()) {
num_H3O++;
if (num_H3O == 3) {
constexpr G4double H3Op_rms = 0.3 * nanometer;
theProductDisplacementVector[i]
= radialDistributionOfProducts(H3Op_rms);
theProductDisplacementVector[i] += OH_disp;
continue;
}
} else if (prod_def == G4OH::Definition()) {
theProductDisplacementVector[i] = OH_disp;
continue;
}
theProductDisplacementVector[i]
= radialDistributionOfProducts(theRMSmap[prod_def]);
}
break;
}
case QuadrupleIonisation_DissociationDecay:
{
if (fVerbose != 0) {
G4cout << "QuadrupleIonisation_DissociationDecay" << G4endl;
G4cout << "Channel's name: " << pDecayChannel->GetName() << G4endl;
}
// Ref.) B. Gervais, et al., DOI: 10.1016/j.radphyschem.2005.09.01
// Decay Channel: H2O^4+ -> 4H3O+ + 2*OH + O(3P)
//
// ** Detaied decay chain **
// H2O^4+ -> O^2+ + H3O+ + H3O+
// |
// --> H2O+ + H2O+ + O(3P)
// | |
// | --> *OH + H3O+
// |
// --> *OH + H3O+
theRMSmap[G4H3O::Definition()] = 1.2 * nanometer;
theRMSmap[G4Oxygen::Definition()] = 0.0 * nanometer;
theRMSmap[G4OH::Definition()] = 0.3 * nanometer;
const auto OH_disp1 = radialDistributionOfProducts(
theRMSmap[G4OH::Definition()]);
const auto OH_disp2 = radialDistributionOfProducts(
theRMSmap[G4OH::Definition()]);
for (G4int i = 0, num_H3O = 0, num_OH = 0; i < nbProducts; i++) {
const auto prod_def = pDecayChannel->GetProduct(i)->GetDefinition();
if (prod_def == G4H3O::Definition()) {
num_H3O++;
constexpr G4double H3Op_rms = 0.3 * nanometer;
if (num_H3O == 3) {
theProductDisplacementVector[i]
= radialDistributionOfProducts(H3Op_rms);
theProductDisplacementVector[i] += OH_disp1;
continue;
} else if (num_H3O == 4) {
theProductDisplacementVector[i]
= radialDistributionOfProducts(H3Op_rms);
theProductDisplacementVector[i] += OH_disp2;
continue;
}
} else if (prod_def == G4OH::Definition()) {
num_OH++;
if (num_OH == 1) {
theProductDisplacementVector[i] = OH_disp1;
} else {
theProductDisplacementVector[i] = OH_disp2;
}
continue;
}
theProductDisplacementVector[i]
= radialDistributionOfProducts(theRMSmap[prod_def]);
}
break;
}
}
return theProductDisplacementVector;
}
//------------------------------------------------------------------------------
@@ -478,12 +682,12 @@ G4ThreeVector
G4DNAWaterDissociationDisplacer::
radialDistributionOfProducts(G4double Rrms) const
{
static const double inverse_sqrt_3 = 1. / sqrt(3.);
double sigma = Rrms * inverse_sqrt_3;
double x = G4RandGauss::shoot(0., sigma);
double y = G4RandGauss::shoot(0., sigma);
double z = G4RandGauss::shoot(0., sigma);
return G4ThreeVector(x, y, z);
static const double inverse_sqrt_3 = 1.0 / sqrt(3.0);
double sigma = Rrms * inverse_sqrt_3;
double x = G4RandGauss::shoot(0.0, sigma);
double y = G4RandGauss::shoot(0.0, sigma);
double z = G4RandGauss::shoot(0.0, sigma);
return G4ThreeVector(x, y, z);
}
//------------------------------------------------------------------------------
@@ -500,13 +704,18 @@ G4DNAWaterDissociationDisplacer::radialDistributionOfElectron() const
+ fElectronThermalization[bin_p1] * rand_value) *
G4RandomDirection();*/
G4ThreeVector pdf = G4ThreeVector(0,0,0);
G4ThreeVector pdf = G4ThreeVector(0, 0, 0);
if(dnaSubType == fRitchie1994eSolvation) DNA::Penetration::Ritchie1994::GetPenetration(ke,pdf);
else if(dnaSubType == fTerrisol1990eSolvation) DNA::Penetration::Terrisol1990::GetPenetration(ke,pdf);
else if(dnaSubType == fMeesungnoensolid2002eSolvation) DNA::Penetration::Meesungnoen2002_amorphous::GetPenetration(ke,pdf);
else if(dnaSubType == fKreipl2009eSolvation) DNA::Penetration::Kreipl2009::GetPenetration(ke,pdf);
else DNA::Penetration::Meesungnoen2002::GetPenetration(ke,pdf);
return pdf;
if (dnaSubType == fRitchie1994eSolvation) {
DNA::Penetration::Ritchie1994::GetPenetration(ke, pdf);
} else if (dnaSubType == fTerrisol1990eSolvation) {
DNA::Penetration::Terrisol1990::GetPenetration(ke, pdf);
} else if (dnaSubType == fMeesungnoensolid2002eSolvation) {
DNA::Penetration::Meesungnoen2002_amorphous::GetPenetration(ke, pdf);
} else if (dnaSubType == fKreipl2009eSolvation) {
DNA::Penetration::Kreipl2009::GetPenetration(ke, pdf);
} else {
DNA::Penetration::Meesungnoen2002::GetPenetration(ke, pdf);
}
return pdf;
}
@@ -51,13 +51,6 @@ class G4DNAMolecularReactionTable;
class G4VITStepModel;
class G4MoleculeDefinition;
enum TimeStepModel
{
fSBS,
fIRT,
fIRT_syn
};
class G4VUserChemistryList
{
public:
@@ -6,9 +6,9 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2023-12-11 V. Ivanchenko (emlowen-V11-01-12)
## 2023-12-11 V. Ivanchenko (emlowen-V11-02-00)
- G4MicroElecInelasticModel_new - fixed Coverity report on memory leak at exit,
minimal code clean-up.
likely partially; minimal code clean-up.
- G4MicroElecLOPhononModel - minor clean-up
# 2023-11-06 Ben Morgan (emlowen-V11-01-11)
@@ -6,14 +6,46 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-06-06 V.Ivanchenko (emstand-V11-01-26)
## 2024-06-06 I.Semeniouk & D.Bernard (emstand-V11-02-09)
- new G4OrePowellAtRestModel - Orel & Powell orto positronium decay model AtRest
- new G4SimpleoPsAtRestModel - simples orto para positronium chooser
## 2024-06-06 V.Ivanchenko (emstand-V11-02-08)
- G4BetheHeitler5DModel - fixed computation of sinTheta
## 2024-05-28 V.Ivanchenko
## 2024-06-04 Gabriele Cosmo (emstand-V11-02-07)
- Fixed compilation warning on macOS/XCode for implicit type conversion
on G4eplusAnnihilation.
## 2024-05-28 V.Ivanchenko (emstand-V11-02-06)
- G4BetheHeitler5DModel - added checks on arguments of G4Exp in SampleSecondaries(..)
method to avoid FPE problems in the case of -O3 optimisation
- G4eplusAnnihilation - use more const class members, changed model ID definition
for produced tracks
## 2024-01-23 V.Ivanchenko (emstand-V11-01-25)
## 2024-05-23 V.Ivanchenko (emstand-V11-02-05)
- G4UrbanMscModel - L.Urban optimized DistanceToBoundary step limitation
algorithm currently used only in Opt3 EM physics
## 2024-05-14 V.Ivanchenko (emstand-V11-02-04)
- G4SimplePositronAtRestModel, G4AllisonAtRestModel - new classes to sample
positron annihilation
- G4eeToTwoGammaModel - cosmetic change
- G4eplusTo2GammaOKVIModel - removed sampling at rest
- G4eplusAnnihilation - added selection of AtRest model, implement ApplyCuts
for AtRest, implement choice of positron annihilation model at rest
## 2024-02-20 V.Ivanchenko (emstand-V11-02-03)
- G4eeToTwoGammaModel - fixed precision lost in sampling of final state
for the very high energy (ATLAS report)
## 2024-02-06 V.Ivanchenko (emstand-V11-02-02)
- G4IonFluctuations - disable previous MR - return to 11.2 version
## 2024-01-27 V.Ivanchenko (emstand-V11-02-01)
- G4IonFluctuations - fixed problem report #2580 - ion fluctuations at high energy
## 2024-01-23 V.Ivanchenko (emstand-V11-02-00)
- G4IonICRU73Data - fixed bug #2586 for the case if target material has
an element with Z>92, improve debug printouts. In the Lindhard-Sorensen
model to compute dEdx the first try is to take it from ICRU73 or ICRU90
@@ -0,0 +1,73 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4AllisonPositronAtRestModel
//
// Author: Vladimir Ivanchenko
//
// Creation date: 14 May 2024
//
// Class Description:
//
// Allison AtRest positron 2-gamma annihilation model
// Electron of media is assumed to have the MaxwellBoltzmann
// distribution defined by the temperature of the media.
// Energy of mean ionisation should not be zero - some amount of free
// electrons should be in the media.
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
// Nature 4065 (1947) 435.
// Snyder et al, Physical Review 73 (1948) p.440.
//
// -------------------------------------------------------------------
//
#ifndef G4AllisonPositronAtRestModel_h
#define G4AllisonPositronAtRestModel_h 1
#include "G4VPositronAtRestModel.hh"
class G4AllisonPositronAtRestModel : public G4VPositronAtRestModel
{
public:
G4AllisonPositronAtRestModel();
~G4AllisonPositronAtRestModel() override = default;
void SampleSecondaries(std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const override;
void PrintGeneratorInformation() const override;
G4AllisonPositronAtRestModel& operator=
(const G4AllisonPositronAtRestModel& right) = delete;
G4AllisonPositronAtRestModel(const G4AllisonPositronAtRestModel&) = delete;
};
#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. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4OrePowellAtRestModel
//
// Author: I.Semeniouk & D.Bernard
//
// Creation date: 4 Juin 2024
//
// Class Description:
//
// Simple AtRest positron 3-gamma annihilation model.
// Electron of media is assumed to have zero kinetic energy.
// Ortho - Positronium three-photon annihilation by Ore and
// Powell, Phys. Rev. 75 (1949).
// Polarisation set randomly.
//
// -------------------------------------------------------------------
//
#ifndef G4OrePowellAtRestModel_h
#define G4OrePowellAtRestModel_h 1
#include "G4VPositronAtRestModel.hh"
class G4OrePowellAtRestModel : public G4VPositronAtRestModel
{
public:
G4OrePowellAtRestModel();
~G4OrePowellAtRestModel() override = default;
void SampleSecondaries(std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const override;
void PrintGeneratorInformation() const override;
G4OrePowellAtRestModel& operator=
(const G4OrePowellAtRestModel& right) = delete;
G4OrePowellAtRestModel(const G4OrePowellAtRestModel&) = delete;
};
#endif
@@ -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. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4SimplePositronAtRestModel
//
// Author: Vladimir Ivanchenko
//
// Creation date: 14 May 2024
//
// Class Description:
//
// Simple AtRest positron 2-gamma annihilation model.
// Electron of media is assumed to have zero kinetic energy.
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
// Nature 4065 (1947) 435.
//
// -------------------------------------------------------------------
//
#ifndef G4SimplePositronAtRestModel_h
#define G4SimplePositronAtRestModel_h 1
#include "G4VPositronAtRestModel.hh"
class G4SimplePositronAtRestModel : public G4VPositronAtRestModel
{
public:
G4SimplePositronAtRestModel();
~G4SimplePositronAtRestModel() override = default;
void SampleSecondaries(std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const override;
void PrintGeneratorInformation() const override;
G4SimplePositronAtRestModel& operator=
(const G4SimplePositronAtRestModel& right) = delete;
G4SimplePositronAtRestModel(const G4SimplePositronAtRestModel&) = delete;
};
#endif
@@ -0,0 +1,75 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4SimplePsAtRestModel
//
// Author: I.Semeniouk & D.Bernard
//
// Creation date: 4 Juin 2024
//
// Class Description:
//
// Simple switcher between positron 2-gamma annihilation at rest model and
// positron 2-gamma annihilation at rest model.
//
// -------------------------------------------------------------------
//
#ifndef G4SimplePsAtRestModel_h
#define G4SimplePsAtRestModel_h 1
#include "G4VPositronAtRestModel.hh"
class G4SimplePositronAtRestModel;
class G4OrePowellAtRestModel;
class G4SimplePsAtRestModel : public G4VPositronAtRestModel
{
public:
G4SimplePsAtRestModel();
~G4SimplePsAtRestModel() override;
void SampleSecondaries(std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const override;
void PrintGeneratorInformation() const override;
G4SimplePsAtRestModel& operator=
(const G4SimplePsAtRestModel& right) = delete;
G4SimplePsAtRestModel(const G4SimplePsAtRestModel&) = delete;
private:
G4double f3gFranction;
G4SimplePositronAtRestModel *model2g;
G4OrePowellAtRestModel *model3g;
};
#endif
@@ -44,8 +44,9 @@
//
// Class Description:
//
// Implementation of e+ annihilation into 2 gamma
// Implementation of e+ annihilation into 2 gamma on fly
// Annihilation at rest is sampled by G4VPositronAtRestModel
//
// -------------------------------------------------------------------
//
@@ -53,6 +54,7 @@
#define G4eeToTwoGammaModel_h 1
#include "G4VEmModel.hh"
#include <vector>
class G4ParticleChangeForGamma;
@@ -99,8 +101,6 @@ private:
G4double pi_rcl2;
const G4ParticleDefinition* theGamma;
G4ParticleChangeForGamma* fParticleChange;
static G4bool fSampleAtomicPDF;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -48,9 +48,12 @@
//
// Class Description:
//
// This class manages the process of e+ annihilation into 2 gammas
// This class manages the process of e+ annihilation at rest and on fly
// It is possible to enable ApplyCuts and Entanglement options via
// G4EmParameters class using UI commands or C++ interface.
// EM splitting or Russian roulette are allowed is corresponding options
// are enabled.
//
// -------------------------------------------------------------------
//
@@ -60,6 +63,7 @@
#include "G4VEmProcess.hh"
class G4ParticleDefinition;
class G4VPositronAtRestModel;
class G4eplusAnnihilation : public G4VEmProcess
{
@@ -95,11 +99,12 @@ protected:
void StreamProcessInfo(std::ostream& outFile) const override;
private:
G4bool isInitialised = false;
const G4ParticleDefinition* theGamma;
const G4ParticleDefinition* theElectron;
G4VPositronAtRestModel* fAtRestModel{nullptr};
G4int fEntanglementModelID;
G4bool isInitialised{false};
G4bool fEntangled{false};
G4bool fApplyCuts{false};
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -38,8 +38,18 @@
//
// Class Description:
//
// Implementation of e+ annihilation into 2 gamma
// Implementation of e+ annihilation into 2 or 3 gamma on fly
// Annihilation at rest is sampled by G4VPositronAtRestModel
// Implementation of 3-gamma annihilation is performed by
// G4eplusTo3GammaOKVIModel. Cross section of both models
// depend on cut parameter fDelta, which defines relative low-energy
// limit on 3d gamma energy. For computation of the cross section
// next to leading order radiative corrections are taken into account,
// atomic effects at low-energy are not considered.
//
// V.N.Baier, V.S. Fadin, V.A. Khose, E.A. Kuraev,
// Physics Reports 78 (1981) 293-393.
//
// -------------------------------------------------------------------
//
@@ -58,8 +68,7 @@ class G4eplusTo2GammaOKVIModel : public G4VEmModel
public:
explicit G4eplusTo2GammaOKVIModel(const G4ParticleDefinition* p = nullptr,
const G4String& nam = "eplus2ggOKVI");
G4eplusTo2GammaOKVIModel();
~G4eplusTo2GammaOKVIModel() override;
@@ -73,21 +82,21 @@ public:
G4double Z,
G4double A = 0.,
G4double cutEnergy = 0.,
G4double maxEnergy = DBL_MAX) final;
G4double maxEnergy = DBL_MAX) override;
G4double CrossSectionPerVolume(const G4Material*,
const G4ParticleDefinition*,
G4double kineticEnergy,
G4double cutEnergy = 0.0,
G4double maxEnergy = DBL_MAX) final;
G4double maxEnergy = DBL_MAX) override;
void SampleSecondaries(std::vector<G4DynamicParticle*>*,
const G4MaterialCutsCouple*,
const G4DynamicParticle*,
G4double tmin = 0.0,
G4double maxEnergy = DBL_MAX) final;
G4double maxEnergy = DBL_MAX) override;
inline void SetDelta(G4double val) { if(val > 0.0) { fDelta = val; } };
void SetDelta(G4double val) { if(val > 0.0) { fDeltaMin = val; } };
// hide assignment operator
G4eplusTo2GammaOKVIModel & operator=
@@ -97,16 +106,14 @@ public:
private:
const G4ParticleDefinition* theGamma;
G4ParticleChangeForGamma* fParticleChange;
G4eplusTo3GammaOKVIModel* f3GModel;
const G4DataVector* fCuts;
G4double fDelta;
G4double fGammaTh;
G4double fDeltaMin; // fixed minimal relative limit
G4double fDelta; // running limit - function of energy
G4double fGammaTh; // 3-gamma annihilation low-energy limit
static G4PhysicsVector* fCrossSection;
static G4PhysicsVector* fCrossSection3G;
static G4PhysicsVector* f3GProbability;
};
@@ -38,8 +38,11 @@
//
// Class Description:
//
// Implementation of e+ annihilation into 3 gamma
// Implementation of e+ annihilation into 3 gamma on fly
//
// V.N.Baier, V.S. Fadin, V.A. Khose, E.A. Kuraev,
// Physics Reports 78 (1981) 293-393.
//
// -------------------------------------------------------------------
//
@@ -60,7 +63,7 @@ public:
~G4eplusTo3GammaOKVIModel() override;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) final;
void Initialise(const G4ParticleDefinition*, const G4DataVector&) override;
G4double ComputeCrossSectionPerElectron(G4double kinEnergy);
@@ -100,8 +103,7 @@ public:
private:
G4double fDelta;
const G4ParticleDefinition* theGamma;
G4ParticleChangeForGamma* fParticleChange;
const G4ParticleDefinition* theGamma;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -3,6 +3,7 @@
geant4_add_module(G4emstandard
PUBLIC_HEADERS
G4ASTARStopping.hh
G4AllisonPositronAtRestModel.hh
G4AtimaEnergyLossModel.hh
G4AtimaFluctuations.hh
G4BetheBlochIonGasModel.hh
@@ -55,6 +56,9 @@ geant4_add_module(G4emstandard
G4SauterGavrilaAngularDistribution.hh
G4ScreeningMottCrossSection.hh
G4SeltzerBergerModel.hh
G4SimplePositronAtRestModel.hh
G4SimplePsAtRestModel.hh
G4OrePowellAtRestModel.hh
G4UniversalFluctuation.hh
G4UrbanFluctuation.hh
G4UrbanMscModel.hh
@@ -83,6 +87,7 @@ geant4_add_module(G4emstandard
G4ionIonisation.hh
SOURCES
G4ASTARStopping.cc
G4AllisonPositronAtRestModel.cc
G4AtimaEnergyLossModel.cc
G4AtimaFluctuations.cc
G4BetheBlochIonGasModel.cc
@@ -133,6 +138,9 @@ geant4_add_module(G4emstandard
G4SauterGavrilaAngularDistribution.cc
G4ScreeningMottCrossSection.cc
G4SeltzerBergerModel.cc
G4SimplePositronAtRestModel.cc
G4SimplePsAtRestModel.cc
G4OrePowellAtRestModel.cc
G4UniversalFluctuation.cc
G4UrbanFluctuation.cc
G4UrbanMscModel.cc
@@ -0,0 +1,143 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// GEANT4 Class file
//
//
// File name: G4AllisonPositronAtRestModel
//
// Author: Vladimir Ivanchenko
//
// Creation date: 14 May 2024
//
// -------------------------------------------------------------------
//
#include "G4AllisonPositronAtRestModel.hh"
#include "G4DynamicParticle.hh"
#include "G4Material.hh"
#include "Randomize.hh"
#include "G4Gamma.hh"
#include "G4RandomDirection.hh"
#include "G4ThreeVector.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4AllisonPositronAtRestModel::G4AllisonPositronAtRestModel()
: G4VPositronAtRestModel("Allison")
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4AllisonPositronAtRestModel::SampleSecondaries(
std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material* material) const
{
const G4double eGamma = CLHEP::electron_mass_c2;
// In rest frame of positronium gammas are back to back
const G4ThreeVector& dir1 = G4RandomDirection();
const G4ThreeVector& dir2 = -dir1;
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(),dir1,eGamma);
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(),dir2,eGamma);
// In rest frame the gammas are polarised perpendicular to each other - see
// Pryce and Ward, Nature No 4065 (1947) p.435.
// Snyder et al, Physical Review 73 (1948) p.440.
G4ThreeVector pol1 = (G4RandomDirection().cross(dir1)).unit();
G4ThreeVector pol2 = (pol1.cross(dir2)).unit();
// A positron in matter slows down and combines with an atomic electron to
// make a neutral atom called positronium, about half the size of a normal
// atom. I expect that when the energy of the positron is small enough,
// less than the binding energy of positronium (6.8 eV), it is
// energetically favourable for an electron from the outer orbitals of a
// nearby atom or molecule to transfer and bind to the positron, as in an
// ionic bond, leaving behind a mildly ionised nearby atom/molecule. I
// would expect the positronium to come away with a kinetic energy of a
// few eV on average. In its para (spin 0) state it annihilates into two
// photons, which in the rest frame of the positronium are collinear
// (back-to-back) due to momentum conservation. Because of the motion of the
// positronium, photons will be not quite back-to-back in the laboratory.
// The positroniuim acquires an energy of order its binding energy and
// doesn't have time to thermalise. Nevertheless, here we approximate its
// energy distribution by a Maxwell-Boltzman with mean energy <KE>. In terms
// of a more familiar concept of temperature, and the law of equipartition
// of energy of translational motion, <KE>=3kT/2. Each component of velocity
// has a distribution exp(-mv^2/2kT), which is a Gaussian of mean zero
// and variance kT/m=2<KE>/3m, where m is the positronium mass.
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
const G4double& meanKE = meanEnergyPerIonPair; // Just an alias
if (meanKE > 0.) { // Positronium has motion
// Mass of positronium
const G4double mass = 2.*CLHEP::electron_mass_c2;
// Mean <KE>=3kT/2, as described above
// const G4double T = 2.*meanKE/(3.*k_Boltzmann);
// Component velocities: Gaussian, variance kT/m=2<KE>/3m.
const G4double sigmav = std::sqrt(2.*meanKE/(3.*mass));
// This is in units where c=1
const G4double vx = G4RandGauss::shoot(0.,sigmav);
const G4double vy = G4RandGauss::shoot(0.,sigmav);
const G4double vz = G4RandGauss::shoot(0.,sigmav);
const G4ThreeVector v(vx,vy,vz); // In unit where c=1
const G4ThreeVector& beta = v; // so beta=v/c=v
aGamma1->Set4Momentum(aGamma1->Get4Momentum().boost(beta));
aGamma2->Set4Momentum(aGamma2->Get4Momentum().boost(beta));
// Rotate polarisation vectors
const G4ThreeVector& newDir1 = aGamma1->GetMomentumDirection();
const G4ThreeVector& newDir2 = aGamma2->GetMomentumDirection();
const G4ThreeVector& axis1 = dir1.cross(newDir1); // No need to be unit
const G4ThreeVector& axis2 = dir2.cross(newDir2); // No need to be unit
const G4double& angle1 = std::acos(dir1*newDir1);
const G4double& angle2 = std::acos(dir2*newDir2);
pol1.rotate(axis1, angle1);
pol2.rotate(axis2, angle2);
}
// use constructors optimal for massless particle
aGamma1->SetPolarization(pol1);
aGamma2->SetPolarization(pol2);
secParticles.push_back(aGamma1);
secParticles.push_back(aGamma2);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4AllisonPositronAtRestModel::PrintGeneratorInformation() const
{
G4cout << "\n" << G4endl;
G4cout << "Allison AtRest positron 2-gamma annihilation model." << G4endl;
G4cout << "Takes into account positronium motion in the media." << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -0,0 +1,153 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// GEANT4 Class file
//
//
// File name: G4OrePowellAtRestModel
//
// Author: I.Semeniouk & D.Bernard
//
// Creation date: 04 Juin 2024
//
// -------------------------------------------------------------------
//
#include "G4OrePowellAtRestModel.hh"
#include "G4DynamicParticle.hh"
#include "G4Material.hh"
#include "Randomize.hh"
#include "G4Gamma.hh"
#include "G4RandomDirection.hh"
#include "G4ThreeVector.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4OrePowellAtRestModel::G4OrePowellAtRestModel() : G4VPositronAtRestModel("OrePawell") {}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4OrePowellAtRestModel::SampleSecondaries(
std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const
{
static const G4double PositronMass = CLHEP::electron_mass_c2;
const G4double ymax = 8.1;
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
G4double cos12;
G4double cos13;
G4double r1;
G4double r2;
G4double r3;
G4double theta12;
G4double theta13;
G4double sin12;
G4double sin13;
G4double pdf;
G4double rndmv2[2];
G4double rndmv1;
do {
rndmv1 = rndmEngine->flat();
do {
rndmEngine->flatArray(2, rndmv2);
// energies of photon1 and photon2 normalized to electron rest mass
r1 = rndmv2[0];
r2 = rndmv2[1];
// energy conservation, with positronium assumed = 2 * electron rest mass
r3 = 2.0 - (r1+r2);
// cosine of angles between photons, from momentum conservation
cos12=(r3*r3 - r1*r1 -r2*r2)/(2*r1*r2);
cos13=(r2*r2 - r1*r1 -r3*r3)/(2*r1*r3);
// request both cosines < 1.
} while ( std::abs(cos12) > 1 || std::abs(cos13) > 1 );
theta12 = std::acos(cos12);
theta13 = - std::acos(cos13);
sin12 = std::sin(theta12);
sin13 = std::sin(theta13);
G4double cos23=cos12*cos13+sin12*sin13;
pdf = (1 - cos12)*(1 - cos12) + (1 - cos13)*(1 - cos13) + (1 - cos23)*(1 - cos23);
} while ( pdf < ymax * rndmv1 );
// END of Sampling
// photon directions in the decay plane, photon 1 along z, x perp to the plane.
G4ThreeVector PhotonMomentum1(0., 0., 1.);
G4ThreeVector PhotonMomentum2(0.,sin12,cos12);
G4ThreeVector PhotonMomentum3(0.,sin13,cos13);
// First Gamma direction
G4ThreeVector dir1 = G4RandomDirection();
PhotonMomentum1.rotateUz(dir1);
PhotonMomentum2.rotateUz(dir1);
PhotonMomentum3.rotateUz(dir1);
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum1,
r1 * PositronMass);
//Random polarization
G4double phi1 = CLHEP::twopi * G4UniformRand();
G4ThreeVector pol1(std::cos(phi1),std::sin(phi1),0.0);
pol1.rotateUz(PhotonMomentum1);
aGamma1->SetPolarization(pol1);
secParticles.push_back(aGamma1);
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum2,
r2 * PositronMass);
G4double phi2 = CLHEP::twopi * G4UniformRand();
G4ThreeVector pol2(std::cos(phi2),std::sin(phi2),0.0);
pol2.rotateUz(PhotonMomentum2);
aGamma2->SetPolarization(pol2);
secParticles.push_back(aGamma2);
auto aGamma3 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum3,
r3 * PositronMass);
G4double phi3 = CLHEP::twopi * G4UniformRand();
G4ThreeVector pol3(std::cos(phi3),std::sin(phi3),0.0);
pol3.rotateUz(PhotonMomentum3);
aGamma3->SetPolarization(pol3);
secParticles.push_back(aGamma3);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4OrePowellAtRestModel::PrintGeneratorInformation() const
{
G4cout << "Orel Powell AtRest positron 3-gamma annihilation model" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -0,0 +1,89 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// GEANT4 Class file
//
//
// File name: G4SimplePositronAtRestModel
//
// Author: Vladimir Ivanchenko
//
// Creation date: 14 May 2024
//
// -------------------------------------------------------------------
//
#include "G4SimplePositronAtRestModel.hh"
#include "G4DynamicParticle.hh"
#include "G4Material.hh"
#include "Randomize.hh"
#include "G4Gamma.hh"
#include "G4RandomDirection.hh"
#include "G4ThreeVector.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4SimplePositronAtRestModel::G4SimplePositronAtRestModel()
: G4VPositronAtRestModel("Simple")
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4SimplePositronAtRestModel::SampleSecondaries(
std::vector<G4DynamicParticle*>& secParticles,
G4double&, const G4Material*) const
{
G4ThreeVector dir1 = G4RandomDirection();
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), dir1,
CLHEP::electron_mass_c2);
G4double phi = CLHEP::twopi * G4UniformRand();
G4double cosphi = std::cos(phi);
G4double sinphi = std::sin(phi);
G4ThreeVector pol1(cosphi, sinphi, 0.0);
pol1.rotateUz(dir1);
aGamma1->SetPolarization(pol1);
secParticles.push_back(aGamma1);
G4ThreeVector dir2 = -dir1;
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), dir2,
CLHEP::electron_mass_c2);
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
pol2.rotateUz(dir1);
aGamma2->SetPolarization(pol2);
secParticles.push_back(aGamma2);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4SimplePositronAtRestModel::PrintGeneratorInformation() const
{
G4cout << "\n" << G4endl;
G4cout << "Simple AtRest positron 2-gamma annihilation model" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -0,0 +1,93 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
//
// GEANT4 Class file
//
//
// File name: G4SimplePsAtRestModel
//
// Author: I.Semeniouk & D.Bernard
//
// Creation date: 04 Juin 2024
//
// -------------------------------------------------------------------
//
#include "G4SimplePsAtRestModel.hh"
#include "G4SimplePositronAtRestModel.hh"
#include "G4OrePowellAtRestModel.hh"
#include "G4DynamicParticle.hh"
#include "Randomize.hh"
#include "G4RandomDirection.hh"
#include "G4ThreeVector.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4EmParameters.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4SimplePsAtRestModel::G4SimplePsAtRestModel()
: G4VPositronAtRestModel("SimplePs")
{
f3gFranction = G4EmParameters::Instance()->OrtoPsFraction();
model2g = new G4SimplePositronAtRestModel();
model3g = new G4OrePowellAtRestModel();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4SimplePsAtRestModel::SampleSecondaries(
std::vector<G4DynamicParticle*>& secParticles,
G4double& localEnergyDeposit, const G4Material* mat) const
{
// G4cout << "SampleSecondaries model " << GetName() << G4endl;
// G4cout << "3 gamma fraction " << f3gFranction << G4endl;
if ( G4UniformRand() > f3gFranction ) {
model2g->SampleSecondaries(secParticles,localEnergyDeposit,mat);
} else {
model3g->SampleSecondaries(secParticles,localEnergyDeposit,mat);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4SimplePsAtRestModel::PrintGeneratorInformation() const
{
G4cout << G4endl;
model2g->PrintGeneratorInformation();
model3g->PrintGeneratorInformation();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4SimplePsAtRestModel::~G4SimplePsAtRestModel()
{
delete model2g;
delete model3g;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -124,7 +124,7 @@ G4UrbanMscModel::G4UrbanMscModel(const G4String& nam)
G4UrbanMscModel::~G4UrbanMscModel()
{
if(isFirstInstance) {
for(auto & ptr : msc) { delete ptr; }
for(auto const & ptr : msc) { delete ptr; }
msc.clear();
}
}
@@ -504,8 +504,9 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
smallstep += 1.;
insideskin = false;
tgeom = geombig;
// initialisation at firs step and at the boundary
// initialisation at first step and at the boundary
if(firstStep || (stepStatus == fGeomBoundary))
{
rangeinit = currentRange;
@@ -520,22 +521,17 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
<< " tlimitmin= " << tlimitmin << " geomlimit= "
<< geomlimit <<G4endl;
*/
// constraint from the geometry
if((geomlimit < geombig) && (geomlimit > geommin))
{
// geomlimit is a geometrical step length
// transform it to true path length (estimation)
if(lambda0 > geomlimit) {
geomlimit = -lambda0*G4Log(1.-geomlimit/lambda0)+tlimitmin;
}
tgeom = (stepStatus == fGeomBoundary)
? geomlimit/facgeom : 2.*geomlimit/facgeom;
}
else
{
tgeom = geombig;
}
}
// constraint from the geometry
if((geomlimit < geombig) && (geomlimit > geommin))
{
// geomlimit is a geometrical step length
// transform it to true path length (estimation)
if(lambda0 > geomlimit) {
geomlimit = -lambda0*G4Log(1.-geomlimit/lambda0)+tlimitmin;
}
tgeom = (stepStatus == fGeomBoundary) ? geomlimit/facgeom
: facrange*rangeinit + stepmin;
}
//step limit
@@ -83,14 +83,10 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
using namespace std;
G4bool G4eeToTwoGammaModel::fSampleAtomicPDF = false;
G4eeToTwoGammaModel::G4eeToTwoGammaModel(const G4ParticleDefinition*,
const G4String& nam)
: G4VEmModel(nam),
pi_rcl2(pi*classic_electr_radius*classic_electr_radius)
pi_rcl2(CLHEP::pi*CLHEP::classic_electr_radius*CLHEP::classic_electr_radius)
{
theGamma = G4Gamma::Gamma();
fParticleChange = nullptr;
@@ -105,27 +101,7 @@ G4eeToTwoGammaModel::~G4eeToTwoGammaModel() = default;
void G4eeToTwoGammaModel::Initialise(const G4ParticleDefinition*,
const G4DataVector&)
{
if(IsMaster()) {
G4int verbose = G4EmParameters::Instance()->Verbose();
// redo initialisation for each new run
fSampleAtomicPDF = false;
const auto& materialTable = G4Material::GetMaterialTable();
for (const auto& material: *materialTable) {
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
if (meanEnergyPerIonPair > 0.) {
fSampleAtomicPDF = true;
if(verbose > 0) {
G4cout << "### G4eeToTwoGammaModel: for " << material->GetName() << " mean energy per ion pair is "
<< meanEnergyPerIonPair/CLHEP::eV << " eV" << G4endl;
}
}
}
}
// If no materials have meanEnergyPerIonPair set. This is probably the usual
// case, since most applications are not senstive to the slight
// non-collinearity of gammas in eeToTwoGamma. Do not issue any warning.
if(fParticleChange) { return; }
if (nullptr != fParticleChange) { return; }
fParticleChange = GetParticleChangeForGamma();
}
@@ -137,13 +113,13 @@ G4eeToTwoGammaModel::ComputeCrossSectionPerElectron(G4double kineticEnergy)
// Calculates the cross section per electron of annihilation into two photons
// from the Heilter formula.
G4double ekin = std::max(eV,kineticEnergy);
G4double ekin = std::max(CLHEP::eV, kineticEnergy);
G4double tau = ekin/electron_mass_c2;
G4double tau = ekin/CLHEP::electron_mass_c2;
G4double gam = tau + 1.0;
G4double gamma2= gam*gam;
G4double bg2 = tau * (tau+2.0);
G4double bg = sqrt(bg2);
G4double bg = std::sqrt(bg2);
G4double cross = pi_rcl2*((gamma2+4*gam+1.)*G4Log(gam+bg) - (gam+3.)*bg)
/ (bg2*(gam+1.));
@@ -178,183 +154,46 @@ G4double G4eeToTwoGammaModel::CrossSectionPerVolume(
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
// Nature 4065 (1947) 435.
void G4eeToTwoGammaModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
const G4MaterialCutsCouple* pCutsCouple,
void G4eeToTwoGammaModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
const G4MaterialCutsCouple*,
const G4DynamicParticle* dp,
G4double,
G4double)
{
G4double posiKinEnergy = dp->GetKineticEnergy();
G4DynamicParticle *aGamma1, *aGamma2;
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
// Case at rest
if(posiKinEnergy == 0.0) {
const G4double eGamma = electron_mass_c2;
// In rest frame of positronium gammas are back to back
const G4ThreeVector& dir1 = G4RandomDirection();
const G4ThreeVector& dir2 = -dir1;
aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(),dir1,eGamma);
aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(),dir2,eGamma);
// In rest frame the gammas are polarised perpendicular to each other - see
// Pryce and Ward, Nature No 4065 (1947) p.435.
// Snyder et al, Physical Review 73 (1948) p.440.
G4ThreeVector pol1 = (G4RandomDirection().cross(dir1)).unit();
G4ThreeVector pol2 = (pol1.cross(dir2)).unit();
// But the positronium is moving...
// A positron in matter slows down and combines with an atomic electron to
// make a neutral “atom” called positronium, about half the size of a normal
// atom. I expect that when the energy of the positron is small enough,
// less than the binding energy of positronium (6.8 eV), it is
// energetically favourable for an electron from the outer orbitals of a
// nearby atom or molecule to transfer and bind to the positron, as in an
// ionic bond, leaving behind a mildly ionised nearby atom/molecule. I
// would expect the positronium to come away with a kinetic energy of a
// few eV on average. In its para (spin 0) state it annihilates into two
// photons, which in the rest frame of the positronium are collinear
// (back-to-back) due to momentum conservation. Because of the motion of the
// positronium, photons will be not quite back-to-back in the laboratory.
// The positroniuim acquires an energy of order its binding energy and
// doesn't have time to thermalise. Nevertheless, here we approximate its
// energy distribution by a Maxwell-Boltzman with mean energy <KE>. In terms
// of a more familiar concept of temperature, and the law of equipartition
// of energy of translational motion, <KE>=3kT/2. Each component of velocity
// has a distribution exp(-mv^2/2kT), which is a Gaussian of mean zero
// and variance kT/m=2<KE>/3m, where m is the positronium mass.
// We take <KE> = material->GetIonisation()->GetMeanEnergyPerIonPair().
if(fSampleAtomicPDF) {
const G4Material* material = pCutsCouple->GetMaterial();
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
const G4double& meanKE = meanEnergyPerIonPair; // Just an alias
if (meanKE > 0.) { // Positronium haas motion
// Mass of positronium
const G4double mass = 2.*electron_mass_c2;
// Mean <KE>=3kT/2, as described above
// const G4double T = 2.*meanKE/(3.*k_Boltzmann);
// Component velocities: Gaussian, variance kT/m=2<KE>/3m.
const G4double sigmav = std::sqrt(2.*meanKE/(3.*mass));
// This is in units where c=1
const G4double vx = G4RandGauss::shoot(0.,sigmav);
const G4double vy = G4RandGauss::shoot(0.,sigmav);
const G4double vz = G4RandGauss::shoot(0.,sigmav);
const G4ThreeVector v(vx,vy,vz); // In unit where c=1
const G4ThreeVector& beta = v; // so beta=v/c=v
aGamma1->Set4Momentum(aGamma1->Get4Momentum().boost(beta));
aGamma2->Set4Momentum(aGamma2->Get4Momentum().boost(beta));
// Rotate polarisation vectors
const G4ThreeVector& newDir1 = aGamma1->GetMomentumDirection();
const G4ThreeVector& newDir2 = aGamma2->GetMomentumDirection();
const G4ThreeVector& axis1 = dir1.cross(newDir1); // No need to be unit
const G4ThreeVector& axis2 = dir2.cross(newDir2); // No need to be unit
const G4double& angle1 = std::acos(dir1*newDir1);
const G4double& angle2 = std::acos(dir2*newDir2);
if (axis1 != G4ThreeVector()) pol1.rotate(axis1,angle1);
if (axis2 != G4ThreeVector()) pol2.rotate(axis2,angle2);
}
}
aGamma1->SetPolarization(pol1.x(),pol1.y(),pol1.z());
aGamma2->SetPolarization(pol2.x(),pol2.y(),pol2.z());
} else { // Positron interacts in flight
G4ThreeVector posiDirection = dp->GetMomentumDirection();
G4double tau = posiKinEnergy/electron_mass_c2;
G4double gam = tau + 1.0;
G4double tau2 = tau + 2.0;
G4double sqgrate = sqrt(tau/tau2)*0.5;
G4double sqg2m1 = sqrt(tau*tau2);
// limits of the energy sampling
G4double epsilmin = 0.5 - sqgrate;
G4double epsilmax = 0.5 + sqgrate;
G4double epsilqot = epsilmax/epsilmin;
//
// sample the energy rate of the created gammas
//
G4double epsil, greject;
do {
epsil = epsilmin*G4Exp(G4Log(epsilqot)*rndmEngine->flat());
greject = 1. - epsil + (2.*gam*epsil-1.)/(epsil*tau2*tau2);
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
} while( greject < rndmEngine->flat());
//
// scattered Gamma angles. ( Z - axis along the parent positron)
//
G4double cost = (epsil*tau2-1.)/(epsil*sqg2m1);
if(std::abs(cost) > 1.0) {
G4cout << "### G4eeToTwoGammaModel WARNING cost= " << cost
<< " positron Ekin(MeV)= " << posiKinEnergy
<< " gamma epsil= " << epsil
<< G4endl;
if(cost > 1.0) cost = 1.0;
else cost = -1.0;
}
G4double sint = sqrt((1.+cost)*(1.-cost));
G4double phi = twopi * rndmEngine->flat();
//
// kinematic of the created pair
//
G4double totalEnergy = posiKinEnergy + 2.0*electron_mass_c2;
G4double phot1Energy = epsil*totalEnergy;
G4ThreeVector phot1Direction(sint*cos(phi), sint*sin(phi), cost);
phot1Direction.rotateUz(posiDirection);
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
phi = twopi * rndmEngine->flat();
G4double cosphi = cos(phi);
G4double sinphi = sin(phi);
G4ThreeVector pol(cosphi, sinphi, 0.0);
pol.rotateUz(phot1Direction);
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
G4double phot2Energy =(1.-epsil)*totalEnergy;
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
G4ThreeVector phot2Direction = dir.unit();
// create G4DynamicParticle object for the particle2
aGamma2 = new G4DynamicParticle (theGamma, phot2Direction, phot2Energy);
//!!! likely problematic direction to be checked
pol.set(-sinphi, cosphi, 0.0);
pol.rotateUz(phot1Direction);
cost = pol*phot2Direction;
pol -= cost*phot2Direction;
pol = pol.unit();
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
/*
G4cout << "Annihilation on fly: e0= " << posiKinEnergy
<< " m= " << electron_mass_c2
<< " e1= " << phot1Energy
<< " e2= " << phot2Energy << " dir= " << dir
<< " -> " << phot1Direction << " "
<< phot2Direction << G4endl;
*/
}
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
// kill primary positron
fParticleChange->SetProposedKineticEnergy(0.0);
fParticleChange->ProposeTrackStatus(fStopAndKill);
// Case at rest not considered anymore inside this model
G4LorentzVector lv(dp->GetMomentum(),
dp->GetKineticEnergy() + 2*CLHEP::electron_mass_c2);
G4double eGammaCMS = 0.5 * lv.mag();
G4ThreeVector dir1 = G4RandomDirection();
G4double phi = CLHEP::twopi * G4UniformRand();
G4double cosphi = std::cos(phi);
G4double sinphi = std::sin(phi);
G4ThreeVector pol1(cosphi, sinphi, 0.0);
pol1.rotateUz(dir1);
G4LorentzVector lv1(eGammaCMS*dir1, eGammaCMS);
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
pol2.rotateUz(dir1);
// transformation to lab system
lv1.boost(lv.boostVector());
lv -= lv1;
//!!! boost of polarisation vector is not yet implemented
// use constructors optimal for massless particle
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), lv1.vect());
aGamma1->SetPolarization(pol1);
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), lv.vect());
aGamma2->SetPolarization(pol2);
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -54,12 +54,13 @@
#include "G4PhysicalConstants.hh"
#include "G4MaterialCutsCouple.hh"
#include "G4Gamma.hh"
#include "G4Electron.hh"
#include "G4Positron.hh"
#include "G4eeToTwoGammaModel.hh"
#include "G4EmBiasingManager.hh"
#include "G4EntanglementAuxInfo.hh"
#include "G4eplusAnnihilationEntanglementClipBoard.hh"
#include "G4SimplePositronAtRestModel.hh"
#include "G4AllisonPositronAtRestModel.hh"
#include "G4EmParameters.hh"
#include "G4PhysicsModelCatalog.hh"
@@ -68,12 +69,10 @@
G4eplusAnnihilation::G4eplusAnnihilation(const G4String& name)
: G4VEmProcess(name)
{
theGamma = G4Gamma::Gamma();
theElectron = G4Electron::Electron();
SetCrossSectionType(fEmDecreasing);
SetBuildTableFlag(false);
SetStartFromNullFlag(false);
SetSecondaryParticle(theGamma);
SetSecondaryParticle(G4Gamma::Gamma());
SetProcessSubType(fAnnihilation);
enableAtRestDoIt = true;
mainSecondaries = 2;
@@ -82,7 +81,10 @@ G4eplusAnnihilation::G4eplusAnnihilation(const G4String& name)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4eplusAnnihilation::~G4eplusAnnihilation() = default;
G4eplusAnnihilation::~G4eplusAnnihilation()
{
delete fAtRestModel;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -104,13 +106,28 @@ G4double G4eplusAnnihilation::AtRestGetPhysicalInteractionLength(
void G4eplusAnnihilation::InitialiseProcess(const G4ParticleDefinition*)
{
if(!isInitialised) {
if (!isInitialised) {
isInitialised = true;
if(nullptr == EmModel(0)) { SetEmModel(new G4eeToTwoGammaModel()); }
EmModel(0)->SetLowEnergyLimit(MinKinEnergy());
EmModel(0)->SetHighEnergyLimit(MaxKinEnergy());
AddEmModel(1, EmModel(0));
}
auto param = G4EmParameters::Instance();
// AtRest model should be chosen only once
if (nullptr == fAtRestModel) {
auto type = param->PositronAtRestModelType();
if (type == fAllisonPositronium) {
fAtRestModel = new G4AllisonPositronAtRestModel();
} else {
fAtRestModel = new G4SimplePositronAtRestModel();
}
}
// Check that entanglement is switched on
// It may be set by the UI command "/process/em/QuantumEntanglement true".
fEntangled = param->QuantumEntanglement();
fApplyCuts = param->ApplyCuts();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -122,136 +139,96 @@ void G4eplusAnnihilation::StreamProcessInfo(std::ostream&) const
G4VParticleChange* G4eplusAnnihilation::AtRestDoIt(const G4Track& track,
const G4Step& step)
// Performs the e+ e- annihilation when both particles are assumed at rest.
{
// positron at rest should be killed
fParticleChange.InitializeForPostStep(track);
fParticleChange.SetProposedKineticEnergy(0.);
fParticleChange.ProposeTrackStatus(fStopAndKill);
DefineMaterial(track.GetMaterialCutsCouple());
G4int idx = (G4int)CurrentMaterialCutsCoupleIndex();
G4double ene(0.0);
G4VEmModel* model = SelectModel(ene, idx);
auto couple = step.GetPreStepPoint()->GetMaterialCutsCouple();
DefineMaterial(couple);
G4double gammaCut = GetGammaEnergyCut();
// define new weight for primary and secondaries
G4double weight = fParticleChange.GetParentWeight();
// apply cuts
if (fApplyCuts && gammaCut > CLHEP::electron_mass_c2) {
fParticleChange.ProposeLocalEnergyDeposit(2*CLHEP::electron_mass_c2);
return &fParticleChange;
}
// sample secondaries
secParticles.clear();
G4double gammaCut = GetGammaEnergyCut();
model->SampleSecondaries(&secParticles, MaterialCutsCouple(),
track.GetDynamicParticle(), gammaCut);
G4int num0 = (G4int)secParticles.size();
G4double edep = 0.0;
fAtRestModel->SampleSecondaries(secParticles, edep, couple->GetMaterial());
// define new weight for primary and secondaries
G4double weight = fParticleChange.GetParentWeight();
std::size_t num0 = secParticles.size();
// splitting or Russian roulette
if(biasManager) {
if(biasManager->SecondaryBiasingRegion(idx)) {
if (nullptr != biasManager) {
G4int idx = couple->GetIndex();
if (biasManager->SecondaryBiasingRegion(idx) &&
!biasManager->GetDirectionalSplitting()) {
G4VEmModel* mod = nullptr;
G4double eloss = 0.0;
weight *= biasManager->ApplySecondaryBiasing(
secParticles, track, model, &fParticleChange, eloss,
idx, gammaCut, step.GetPostStepPoint()->GetSafety());
if(eloss > 0.0) {
eloss += fParticleChange.GetLocalEnergyDeposit();
fParticleChange.ProposeLocalEnergyDeposit(eloss);
}
weight *= biasManager->ApplySecondaryBiasing(secParticles, track, mod,
&fParticleChange, eloss,
idx, gammaCut);
edep += eloss;
}
}
// save secondaries
G4int num = (G4int)secParticles.size();
std::size_t num = secParticles.size();
// Check that entanglement is switched on... (the following flag is
// set by /process/em/QuantumEntanglement).
G4bool entangled = G4EmParameters::Instance()->QuantumEntanglement();
// ...and that we have two gammas with both gammas' energies above
// gammaCut (entanglement is only programmed for e+ e- -> gamma gamma).
G4bool entangledgammagamma = false;
if (entangled) {
if (num == 2) {
entangledgammagamma = true;
for (const auto* p: secParticles) {
if (p->GetDefinition() != theGamma ||
p->GetKineticEnergy() < gammaCut) {
entangledgammagamma = false;
}
}
}
}
// Prepare a shared pointer for psossible use below. If it is used, the
// Prepare a shared pointer only for two first gamma. If it is used, the
// shared pointer is copied into the tracks through G4EntanglementAuxInfo.
// This ensures the clip board lasts until both tracks are destroyed.
// It is assumed that 2 first secondary particles are the most energetic gamma
std::shared_ptr<G4eplusAnnihilationEntanglementClipBoard> clipBoard;
if (entangledgammagamma) {
if (fEntangled && num >= 2) {
clipBoard = std::make_shared<G4eplusAnnihilationEntanglementClipBoard>();
clipBoard->SetParentParticleDefinition(track.GetDefinition());
}
if(num > 0) {
if (num > 0) {
const G4double time = track.GetGlobalTime();
const G4ThreeVector& pos = track.GetPosition();
auto touch = track.GetTouchableHandle();
for (std::size_t i=0; i<num; ++i) {
G4DynamicParticle* dp = secParticles[i];
G4Track* t = new G4Track(dp, time, pos);
t->SetTouchableHandle(touch);
if (fEntangled && i < 2) {
// entangledgammagamma is only true when there are only two gammas
// (See code above where entangledgammagamma is calculated.)
if (i == 0) { // First gamma
clipBoard->SetTrackA(t);
} else if (i == 1) { // Second gamma
clipBoard->SetTrackB(t);
}
t->SetAuxiliaryTrackInformation
(fEntanglementModelID, new G4EntanglementAuxInfo(clipBoard));
}
if (nullptr != biasManager) {
t->SetWeight(weight * biasManager->GetWeight((G4int)i));
} else {
t->SetWeight(weight);
}
pParticleChange->AddSecondary(t);
fParticleChange.SetNumberOfSecondaries(num);
G4double edep = fParticleChange.GetLocalEnergyDeposit();
G4double time = track.GetGlobalTime();
for (G4int i=0; i<num; ++i) {
if (secParticles[i]) {
G4DynamicParticle* dp = secParticles[i];
const G4ParticleDefinition* p = dp->GetParticleDefinition();
G4double e = dp->GetKineticEnergy();
G4bool good = true;
if(ApplyCuts()) {
if (p == theGamma) {
if (e < gammaCut) { good = false; }
} else if (p == theElectron) {
if (e < GetElectronEnergyCut()) { good = false; }
}
// added secondary if it is good
}
if (good) {
G4Track* t = new G4Track(dp, time, track.GetPosition());
t->SetTouchableHandle(track.GetTouchableHandle());
if (entangledgammagamma) {
// entangledgammagamma is only true when there are only two gammas
// (See code above where entangledgammagamma is calculated.)
if (i == 0) { // First gamma
clipBoard->SetTrackA(t);
} else if (i == 1) { // Second gamma
clipBoard->SetTrackB(t);
}
t->SetAuxiliaryTrackInformation
(fEntanglementModelID,new G4EntanglementAuxInfo(clipBoard));
}
if (biasManager) {
t->SetWeight(weight * biasManager->GetWeight(i));
} else {
t->SetWeight(weight);
}
pParticleChange->AddSecondary(t);
// define type of secondary
if(i < mainSecondaries) { t->SetCreatorModelID(secID); }
else if(i < num0) {
if(p == theGamma) {
t->SetCreatorModelID(fluoID);
} else {
t->SetCreatorModelID(augerID);
}
} else {
t->SetCreatorModelID(biasID);
}
/*
G4cout << "Secondary(post step) has weight " << t->GetWeight()
<< ", Ekin= " << t->GetKineticEnergy()/MeV << " MeV "
<< GetProcessName() << " fluoID= " << fluoID
<< " augerID= " << augerID <<G4endl;
*/
} else {
delete dp;
edep += e;
}
}
// define type of secondary
if (i < num0) {
t->SetCreatorModelID(secID);
}
else {
t->SetCreatorModelID(biasID);
}
}
fParticleChange.ProposeLocalEnergyDeposit(edep);
}
fParticleChange.ProposeLocalEnergyDeposit(edep);
return &fParticleChange;
}
@@ -35,6 +35,7 @@
//
// Creation date: 29.03.2018
//
//
// -------------------------------------------------------------------
//
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -53,6 +54,7 @@
#include "G4DataVector.hh"
#include "G4PhysicsVector.hh"
#include "G4PhysicsLogVector.hh"
#include "G4RandomDirection.hh"
#include "Randomize.hh"
#include "G4ParticleChangeForGamma.hh"
#include "G4Log.hh"
@@ -60,64 +62,70 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
using namespace std;
G4PhysicsVector* G4eplusTo2GammaOKVIModel::fCrossSection = nullptr;
G4PhysicsVector* G4eplusTo2GammaOKVIModel::fCrossSection3G = nullptr;
G4PhysicsVector* G4eplusTo2GammaOKVIModel::f3GProbability = nullptr;
G4eplusTo2GammaOKVIModel::G4eplusTo2GammaOKVIModel(const G4ParticleDefinition*,
const G4String& nam)
: G4VEmModel(nam),
fDelta(0.001),
fGammaTh(MeV)
G4eplusTo2GammaOKVIModel::G4eplusTo2GammaOKVIModel()
: G4VEmModel("eplus2ggOKVI"),
fDeltaMin(0.001),
fDelta(fDeltaMin),
fGammaTh(CLHEP::MeV)
{
theGamma = G4Gamma::Gamma();
fParticleChange = nullptr;
fCuts = nullptr;
f3GModel = new G4eplusTo3GammaOKVIModel();
SetTripletModel(f3GModel);
// instantiate vectors once
if (nullptr == fCrossSection) {
G4double emin = 10*CLHEP::eV;
G4double emax = 100*CLHEP::TeV;
G4int nbins = 20*G4lrint(std::log10(emax/emin));
fCrossSection = new G4PhysicsLogVector(emin, emax, nbins, true);
f3GProbability = new G4PhysicsLogVector(emin, emax, nbins, true);
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4eplusTo2GammaOKVIModel::~G4eplusTo2GammaOKVIModel() = default;
G4eplusTo2GammaOKVIModel::~G4eplusTo2GammaOKVIModel()
{
if (IsMaster()) {
delete fCrossSection;
delete f3GProbability;
fCrossSection = nullptr;
f3GProbability = nullptr;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4eplusTo2GammaOKVIModel::Initialise(const G4ParticleDefinition* p,
const G4DataVector& cuts)
{
f3GModel->Initialise(p, cuts);
fCuts = &cuts;
fGammaTh = G4EmParameters::Instance()->LowestTripletEnergy();
f3GModel->SetDelta(fDelta);
if(IsMaster()) {
if(!fCrossSection) {
G4double emin = 10*eV;
G4double emax = 100*TeV;
G4int nbins = 20*G4lrint(std::log10(emax/emin));
fCrossSection = new G4PhysicsLogVector(emin, emax, nbins, true);
fCrossSection3G = new G4PhysicsLogVector(emin, emax, nbins, true);
f3GProbability = new G4PhysicsLogVector(emin, emax, nbins, true);
for(G4int i=0; i<= nbins; ++i) {
G4double e = fCrossSection->Energy(i);
G4double cs2 = ComputeCrossSectionPerElectron(e);
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(e);
cs2 += cs3;
fCrossSection->PutValue(i, cs2);
fCrossSection3G->PutValue(i, cs3);
f3GProbability->PutValue(i, cs3/cs2);
}
fCrossSection->FillSecondDerivatives();
fCrossSection3G->FillSecondDerivatives();
f3GProbability->FillSecondDerivatives();
}
}
// here particle change is set for the triplet model
if(fParticleChange) { return; }
fParticleChange = GetParticleChangeForGamma();
if (nullptr == fParticleChange) {
fParticleChange = GetParticleChangeForGamma();
}
// initialialise 3-gamma model before new run
f3GModel->Initialise(p, cuts);
fGammaTh = G4EmParameters::Instance()->LowestTripletEnergy();
// initialise vectors
if (IsMaster()) {
std::size_t num = fCrossSection->GetVectorLength();
for (std::size_t i=0; i<num; ++i) {
G4double e = fCrossSection->Energy(i);
G4double cs2 = ComputeCrossSectionPerElectron(e);
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(e);
cs2 += cs3;
fCrossSection->PutValue(i, cs2);
G4double y = (cs2 > 0.0) ? cs3/cs2 : 0.0;
f3GProbability->PutValue(i, y);
}
fCrossSection->FillSecondDerivatives();
f3GProbability->FillSecondDerivatives();
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -129,16 +137,20 @@ G4eplusTo2GammaOKVIModel::ComputeCrossSectionPerElectron(G4double kinEnergy)
// photons from the Heilter formula with the radiation correction to 3 gamma
// annihilation channel. (A.A.) rho is changed
G4double ekin = std::max(eV,kinEnergy);
G4double tau = ekin/electron_mass_c2;
G4double ekin = std::max(CLHEP::eV, kinEnergy);
G4double tau = ekin/CLHEP::electron_mass_c2;
G4double gam = tau + 1.0;
G4double gamma2 = gam*gam;
G4double bg2 = tau * (tau+2.0);
G4double bg = sqrt(bg2);
G4double bg = std::sqrt(bg2);
G4double rho = (gamma2+4.*gam+1.)*G4Log(gam+bg)/(gamma2-1.)
- (gam+3.)/(sqrt(gam*gam - 1.));
- (gam+3.)/(std::sqrt(gam*gam - 1.));
G4double eGammaCMS = CLHEP::electron_mass_c2 * std::sqrt(0.5*(tau + 2.0));
fDelta = std::max(fDeltaMin, fGammaTh/eGammaCMS);
f3GModel->SetDelta(fDelta);
static const G4double pir2 = pi*classic_electr_radius*classic_electr_radius;
static const G4double pir2 =
CLHEP::pi*CLHEP::classic_electr_radius*CLHEP::classic_electr_radius;
G4double cross = (pir2*rho + alpha_rcl2*2.*G4Log(fDelta)*rho*rho)/(gam+1.);
return cross;
@@ -175,143 +187,54 @@ G4double G4eplusTo2GammaOKVIModel::CrossSectionPerVolume(
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
// Nature 4065 (1947) 435.
void
G4eplusTo2GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
const G4MaterialCutsCouple* mcc,
const G4DynamicParticle* dp,
G4double, G4double)
void G4eplusTo2GammaOKVIModel::SampleSecondaries(
std::vector<G4DynamicParticle*>* vdp,
const G4MaterialCutsCouple* couple,
const G4DynamicParticle* dp,
G4double, G4double)
{
G4double posiKinEnergy = dp->GetKineticEnergy();
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
if(rndmEngine->flat() < f3GProbability->Value(posiKinEnergy)) {
G4double cutd = std::max(fGammaTh,(*fCuts)[mcc->GetIndex()])
/(posiKinEnergy + electron_mass_c2);
// check cut to avoid production of 3d gamma below
if(cutd > fDelta) {
G4double cs30 = fCrossSection3G->Value(posiKinEnergy);
f3GModel->SetDelta(cutd);
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(posiKinEnergy);
if(rndmEngine->flat()*cs30 < cs3) {
f3GModel->SampleSecondaries(vdp, mcc, dp);
return;
}
} else {
f3GModel->SampleSecondaries(vdp, mcc, dp);
return;
}
}
G4DynamicParticle *aGamma1, *aGamma2;
// Case at rest
if(posiKinEnergy == 0.0) {
G4double cost = 2.*rndmEngine->flat()-1.;
G4double sint = sqrt((1. - cost)*(1. + cost));
G4double phi = twopi * rndmEngine->flat();
G4ThreeVector dir(sint*cos(phi), sint*sin(phi), cost);
phi = twopi * rndmEngine->flat();
G4double cosphi = cos(phi);
G4double sinphi = sin(phi);
G4ThreeVector pol(cosphi, sinphi, 0.0);
pol.rotateUz(dir);
aGamma1 = new G4DynamicParticle(theGamma, dir, electron_mass_c2);
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
aGamma2 = new G4DynamicParticle(theGamma,-dir, electron_mass_c2);
pol.set(-sinphi, cosphi, 0.0);
pol.rotateUz(dir);
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
} else {
G4ThreeVector posiDirection = dp->GetMomentumDirection();
G4double tau = posiKinEnergy/electron_mass_c2;
G4double gam = tau + 1.0;
G4double tau2 = tau + 2.0;
G4double sqgrate = sqrt(tau/tau2)*0.5;
G4double sqg2m1 = sqrt(tau*tau2);
// limits of the energy sampling
G4double epsilmin = 0.5 - sqgrate;
G4double epsilmax = 0.5 + sqgrate;
G4double epsilqot = epsilmax/epsilmin;
//
// sample the energy rate of the created gammas
//
G4double epsil, greject;
do {
epsil = epsilmin*G4Exp(G4Log(epsilqot)*rndmEngine->flat());
greject = 1. - epsil + (2.*gam*epsil-1.)/(epsil*tau2*tau2);
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
} while( greject < rndmEngine->flat());
//
// scattered Gamma angles. ( Z - axis along the parent positron)
//
G4double cost = (epsil*tau2-1.)/(epsil*sqg2m1);
if(std::abs(cost) > 1.0) {
G4cout << "### G4eplusTo2GammaOKVIModel WARNING cost= " << cost
<< " positron Ekin(MeV)= " << posiKinEnergy
<< " gamma epsil= " << epsil
<< G4endl;
if(cost > 1.0) cost = 1.0;
else cost = -1.0;
}
G4double sint = sqrt((1.+cost)*(1.-cost));
G4double phi = twopi * rndmEngine->flat();
//
// kinematic of the created pair
//
G4double TotalAvailableEnergy = posiKinEnergy + 2.0*electron_mass_c2;
G4double phot1Energy = epsil*TotalAvailableEnergy;
G4ThreeVector phot1Direction(sint*cos(phi), sint*sin(phi), cost);
phot1Direction.rotateUz(posiDirection);
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
phi = twopi * rndmEngine->flat();
G4double cosphi = cos(phi);
G4double sinphi = sin(phi);
G4ThreeVector pol(cosphi, sinphi, 0.0);
pol.rotateUz(phot1Direction);
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
G4double phot2Energy =(1.-epsil)*TotalAvailableEnergy;
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
G4ThreeVector phot2Direction = dir.unit();
// create G4DynamicParticle object for the particle2
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
//!!! likely problematic direction to be checked
pol.set(-sinphi, cosphi, 0.0);
pol.rotateUz(phot1Direction);
cost = pol*phot2Direction;
pol -= cost*phot2Direction;
pol = pol.unit();
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
}
/*
G4cout << "Annihilation in fly: e0= " << posiKinEnergy
<< " m= " << electron_mass_c2
<< " e1= " << phot1Energy
<< " e2= " << phot2Energy << " dir= " << dir
<< " -> " << phot1Direction << " "
<< phot2Direction << G4endl;
*/
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
// kill primary positron
fParticleChange->SetProposedKineticEnergy(0.0);
fParticleChange->ProposeTrackStatus(fStopAndKill);
// Case at rest not considered anymore
G4double posiKinEnergy = dp->GetKineticEnergy();
G4LorentzVector lv(dp->GetMomentum(),
posiKinEnergy + 2*CLHEP::electron_mass_c2);
G4double eGammaCMS = 0.5 * lv.mag();
if (G4UniformRand() < f3GProbability->Value(posiKinEnergy)) {
fDelta = std::max(fDeltaMin, fGammaTh/eGammaCMS);
f3GModel->SetDelta(fDelta);
f3GModel->SampleSecondaries(vdp, couple, dp);
return;
}
G4ThreeVector dir1 = G4RandomDirection();
G4double phi = CLHEP::twopi * G4UniformRand();
G4double cosphi = std::cos(phi);
G4double sinphi = std::sin(phi);
G4ThreeVector pol1(cosphi, sinphi, 0.0);
pol1.rotateUz(dir1);
G4LorentzVector lv1(eGammaCMS*dir1, eGammaCMS);
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
pol2.rotateUz(dir1);
// transformation to lab system
lv1.boost(lv.boostVector());
lv -= lv1;
//!!! boost of polarisation vector is not yet implemented
// use constructors optimal for massless particle
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), lv1.vect());
aGamma1->SetPolarization(pol1);
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), lv.vect());
aGamma2->SetPolarization(pol2);
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -62,7 +62,6 @@ G4eplusTo3GammaOKVIModel::G4eplusTo3GammaOKVIModel(const G4ParticleDefinition*,
: G4VEmModel(nam), fDelta(0.001)
{
theGamma = G4Gamma::Gamma();
fParticleChange = nullptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -73,11 +72,7 @@ G4eplusTo3GammaOKVIModel::~G4eplusTo3GammaOKVIModel() = default;
void G4eplusTo3GammaOKVIModel::Initialise(const G4ParticleDefinition*,
const G4DataVector&)
{
// here particle change is set for the triplet model
if(fParticleChange) { return; }
fParticleChange = GetParticleChangeForGamma();
}
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -183,8 +178,8 @@ G4eplusTo3GammaOKVIModel::ComputeCrossSectionPerElectron(G4double kinEnergy)
// Calculates the cross section per electron of annihilation into 3 photons
// from the Heilter formula.
G4double ekin = std::max(eV,kinEnergy);
G4double tau = ekin/electron_mass_c2;
G4double ekin = std::max(CLHEP::eV, kinEnergy);
G4double tau = ekin/CLHEP::electron_mass_c2;
G4double gam = tau + 1.0;
G4double gamma2 = gam*gam;
G4double bg2 = tau * (tau+2.0);
@@ -204,10 +199,6 @@ G4double G4eplusTo3GammaOKVIModel::ComputeCrossSectionPerAtom(
G4double kineticEnergy, G4double Z,
G4double, G4double, G4double)
{
// Calculates the cross section per atom of annihilation into two photons
G4double cross = Z*ComputeCrossSectionPerElectron(kineticEnergy);
return cross;
}
@@ -238,149 +229,78 @@ G4eplusTo3GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
const G4DynamicParticle* dp,
G4double, G4double)
{
// let us perform sampling in C.M.S. reference frame of e- at rest and e+ on fly
G4double posiKinEnergy = dp->GetKineticEnergy();
G4DynamicParticle *aGamma1, *aGamma2;
G4DynamicParticle* aGamma3 = nullptr;
G4double border;
G4LorentzVector lv(dp->GetMomentum(),
posiKinEnergy + 2*CLHEP::electron_mass_c2);
G4double eGammaCMS = 0.5 * lv.mag();
if(posiKinEnergy < 500*MeV) {
border = 1. - (electron_mass_c2)/(2*(posiKinEnergy + electron_mass_c2));
} else {
border = 1. - (100*electron_mass_c2)/(2*(posiKinEnergy + electron_mass_c2));
}
border = std::min(border, 0.9999);
// the limit value fDelta is defined by a class, which call this method
// thickness of border defined by C.M.S. energy
G4double border =
1.0 - std::min(std::max(CLHEP::electron_mass_c2/eGammaCMS, fDelta), 0.1);
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
// Case at rest
if(posiKinEnergy == 0.0) {
G4double cost = 2.*rndmEngine->flat()-1.;
G4double sint = sqrt((1. - cost)*(1. + cost));
G4double phi = twopi * rndmEngine->flat();
G4ThreeVector dir(sint*cos(phi), sint*sin(phi), cost);
phi = twopi * rndmEngine->flat();
G4double cosphi = cos(phi);
G4double sinphi = sin(phi);
G4ThreeVector pol(cosphi, sinphi, 0.0);
pol.rotateUz(dir);
aGamma1 = new G4DynamicParticle(theGamma, dir, electron_mass_c2);
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
aGamma2 = new G4DynamicParticle(theGamma,-dir, electron_mass_c2);
pol.set(-sinphi, cosphi, 0.0);
pol.rotateUz(dir);
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
G4ThreeVector posiDirection = dp->GetMomentumDirection();
} else {
G4ThreeVector posiDirection = dp->GetMomentumDirection();
// (A.A.) LIMITS FOR 1st GAMMA
G4double xmin = 0.01;
G4double xmax = 0.667; // CHANGE to 3/2
// (A.A.) LIMITS FOR 1st GAMMA
G4double xmin = 0.01;
G4double xmax = 0.667; // CHANGE to 3/2
G4double d1, d0, x1, x2, dmax, x2min;
G4double d1, d0, x1, x2, dmax, x2min;
// (A.A.) sampling of x1 x2 x3 (whole cycle of rejection)
do {
x1 = 1/((1/xmin) - ((1/xmin)-(1/xmax))*rndmEngine->flat());
dmax = ComputeFS(posiKinEnergy, x1,1.-x1,border);
x2min = 1.-x1;
x2 = 1 - rndmEngine->flat()*(1-x2min);
d1 = dmax*rndmEngine->flat();
d0 = ComputeFS(posiKinEnergy,x1,x2,2-x1-x2);
}
while(d0 < d1);
G4double x3 = 2 - x1 - x2;
//
// angles between Gammas
//
G4double psi13 = 2*asin(sqrt(std::abs((x1+x3-1)/(x1*x3))));
G4double psi12 = 2*asin(sqrt(std::abs((x1+x2-1)/(x1*x2))));
// sin^t
//G4double phi = twopi * rndmEngine->flat();
//G4double psi = acos(x3); // Angle of the plane
//
// kinematic of the created pair
//
G4double TotalAvailableEnergy = posiKinEnergy + 2.0*electron_mass_c2;
G4double phot1Energy = 0.5*x1*TotalAvailableEnergy;
G4double phot2Energy = 0.5*x2*TotalAvailableEnergy;
G4double phot3Energy = 0.5*x3*TotalAvailableEnergy;
// (A.A.) sampling of x1 x2 x3 (whole cycle of rejection)
do {
x1 = 1./((1./xmin) - ((1./xmin)-(1./xmax))*rndmEngine->flat());
dmax = ComputeFS(eGammaCMS, x1, 1.-x1, border);
x2min = 1. - x1;
x2 = 1 - rndmEngine->flat()*(1. - x2min);
d1 = dmax*rndmEngine->flat();
d0 = ComputeFS(eGammaCMS, x1, x2, 2.-x1-x2);
}
while(d0 < d1);
G4double x3 = 2 - x1 - x2;
//
// angles between Gammas
//
G4double psi13 = 2*std::asin(std::sqrt(std::abs((x1+x3-1.)/(x1*x3))));
G4double psi12 = 2*std::asin(std::sqrt(std::abs((x1+x2-1.)/(x1*x2))));
//
// kinematic of the created pair
//
G4double phot1Energy = x1*eGammaCMS;
G4double phot2Energy = x2*eGammaCMS;
G4double phot3Energy = x3*eGammaCMS;
// DIRECTIONS
// DIRECTIONS
// The azimuthal angles of ql and q3 with respect to some plane
// through the beam axis are generated at random.
// The azimuthal angles of q1 and q3 with respect to some plane
// through the beam axis are generated at random.
G4ThreeVector phot1Direction(0, 0, 1);
G4ThreeVector phot2Direction(0, sin(psi12), cos(psi12));
G4ThreeVector phot3Direction(0, sin(psi13), cos(psi13));
G4ThreeVector phot1Direction(0, 0, 1);
G4ThreeVector phot2Direction(0, std::sin(psi12), std::cos(psi12));
G4ThreeVector phot3Direction(0, std::sin(psi13), std::cos(psi13));
phot1Direction.rotateUz(posiDirection);
phot2Direction.rotateUz(posiDirection);
phot3Direction.rotateUz(posiDirection);
G4LorentzVector lv1(phot1Energy*phot1Direction, phot1Energy);
G4LorentzVector lv2(phot2Energy*phot2Direction, phot2Energy);
G4LorentzVector lv3(phot3Energy*phot3Direction, phot3Energy);
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
aGamma3 = new G4DynamicParticle (theGamma,phot3Direction, phot3Energy);
auto boostV = lv.boostVector();
lv1.boost(boostV);
lv2.boost(boostV);
lv3.boost(boostV);
auto aGamma1 = new G4DynamicParticle (theGamma, lv1.vect());
auto aGamma2 = new G4DynamicParticle (theGamma, lv2.vect());
auto aGamma3 = new G4DynamicParticle (theGamma, lv3.vect());
//POLARIZATION - ???
/*
phi = twopi * rndmEngine->flat();
G4double cosphi = cos(phi);
G4double sinphi = sin(phi);
G4ThreeVector pol(cosphi, sinphi, 0.0);
pol.rotateUz(phot1Direction);
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
G4double phot2Energy =(1.-epsil)*TotalAvailableEnergy;
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
G4ThreeVector phot2Direction = dir.unit();
// create G4DynamicParticle object for the particle2
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
//!!! likely problematic direction to be checked
pol.set(-sinphi, cosphi, 0.0);
pol.rotateUz(phot1Direction);
cost = pol*phot2Direction;
pol -= cost*phot2Direction;
pol = pol.unit();
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
*/
}
/*
G4cout << "Annihilation in fly: e0= " << posiKinEnergy
<< " m= " << electron_mass_c2
<< " e1= " << phot1Energy
<< " e2= " << phot2Energy << " dir= " << dir
<< " -> " << phot1Direction << " "
<< phot2Direction << G4endl;
*/
//!!! POLARIZATION - not yet implemented
vdp->push_back(aGamma1);
vdp->push_back(aGamma2);
if(aGamma3 != nullptr) { vdp->push_back(aGamma3); }
// kill primary positron
fParticleChange->SetProposedKineticEnergy(0.0);
fParticleChange->ProposeTrackStatus(fStopAndKill);
vdp->push_back(aGamma3);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
+86 -45
View File
@@ -6,28 +6,69 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-05-22 V.Ivanchenko (emutils-V11-01-28)
## 2024-06-19 S.Johnson (emutils-V11-02-10)
- G4EmParameters - fix segmentation fault when data is unavailable
## 2024-06-06 I.Semeniouk & D.Bernard (emutils-V11-02-09)
- G4EmParameters, G4EmParametersMessenger - added orto Positronion fraction flag
## 2024-05-27 V.Ivanchenko (emutils-V11-02-08)
- G4VEmProcess - extended info printout for e+ annihilation at rest
- G4VEmProcess, G4VEnergyLossProcess - improved identification of model ID
for atomic de-excitation (fluorescence, Auger e-, PIXE).
## 2024-05-22 V.Ivanchenko (emutils-V11-02-07)
- G4EmUtility - simplify computation of cross section maximum for discrete
processes to fix the problem of FPE if -O3 compiler option is used.
## 2024-04-21 Gabriele Cosmo (emutils-V11-01-27)
## 2024-05-20 H. Tran (emutils-V11-02-06)
- G4EmParameters, G4EmLowEParameters, G4EmLowEParametersMessenger - added dna
chemistry time step model
## 2024-05-14 V.Ivanchenko (emutils-V11-02-05)
- G4EmParameters, G4EmParametersMessenger - added enumerator and a new flag
G4PositronAtRestModel, which allows selectrion and configuration of
the model of positron annihilation at rest.
- G4VPositronAtRestModel - new virtual interface
- G4EmBiasingManager - cosmetic change
## 2024-05-04 V.Ivanchenko (emutils-V11-02-04)
- G4EmDataRegistry - new class to keep EM data tables
- G4EmDataHandler - extended functionality
- G4LossTableManager - identify master thread using std method
- G4LossTableBUilder - more accurate use of static members and methods
- G4VEmModel, G4VEmProcess, G4VEnergyLossProcess, G4EmTableUtil - update
according to change in the data
- G4VMscModel - move initialisation of tables for model to G4EmTableUtil
## 2024-04-21 Gabriele Cosmo (emutils-V11-02-03)
- Fixed compilation error in G4EmConfigurator on Windows VC++ with
C++20 Standard enabled.
Based on [GitHub PR#69](https://github.com/Geant4/geant4/pull/69).
## 2023-12-15 V.Ivanchenko (emutils-V11-01-26)
- G4VEmProcess, G4VEnergyLossProcess - minor CPU optimisation by reduction
of number of calls for Log of kinetic energy
## 2023-04-04 V.Ivanchenko (emutils-V11-02-02)
- G4EmParameters - increased low-limit on maxKinEnergy parameter from
10 MeV to 600 MeV in order to have standard ionisation and
multiple scattering always defined for DNA physics configurations.
## 2023-12-01 John Allison (emutils-V11-01-25)
## 2024-04-03 S.Okada (emutils-V11-02-01)
- G4LowEnergyEmProcessSubType
- add fLowEnergyTripleIonisation and fLowEnergyQuadrupleIonisation
for implementing multiple-ionization processes in Geant4-DNA
## 2023-12-15 V.Ivanchenko (emutils-V11-02-00)
- G4VEmProcess, G4VEnergyLossProcess - minor CPU optimisation by reduction
of number of calls for Log of kinetic energy
## 2022-12-01 John Allison (emutils-V11-01-25)
- G4EmParametersMessenger:
- Fix "/process/eloss/setFluctModel" - change "eloss" to "eLoss".
## 2023-11-08 V.Ivanchenko (emutils-V11-01-24)
- G4VEmModel - fixed memory leak at exit
- G4VEmModel - fixed memory leak at exit
## 2023-11-07 V.Ivanchenko (emutils-V11-01-23)
- G4EmSaturation - fixed problem #2572 (txenglish@lanl.gov)
- G4EmSaturation - fixed problem #2572 (txenglish@lanl.gov)
## 2023-11-03 J.Hahnfeld (emutils-V11-01-22)
- `G4TransportationWithMsc`: Initialize all members.
@@ -42,8 +83,8 @@ It must **not** be used as a substitute for writing good git commit messages!
- `G4TransportationWithMsc`: Always update momentum direction.
## 2023-10-10 V.Ivanchenko (emutils-V11-01-18)
- G4VEmModel - restore SetLPMFlag(..) method to allow build of CMSSW with the
Geant4 master and G4HepEm version of CMSSW; no change of any result
- G4VEmModel - restore SetLPMFlag(..) method to allow build of CMSSW with the
Geant4 master and G4HepEm version of CMSSW; no change of any result
is expected; added warning about use of obsolete method.
## 2023-10-06 V.Ivanchenko (emutils-V11-01-17)
@@ -66,7 +107,7 @@ It must **not** be used as a substitute for writing good git commit messages!
- G4EmProcessSubType - new fGammaReflection = 26
## 2023-09-04 V.Ivanchenko (emutils-V11-01-14)
- G4VEmModel - do not destruct G4ElementData, do not define LPM flag
- G4VEmModel - do not destruct G4ElementData, do not define LPM flag
## 2023-06-16 V.Ivanchenko (emutils-V11-01-13)
- G4LossTableManager - fixed trivial Coverity report
@@ -119,14 +160,14 @@ It must **not** be used as a substitute for writing good git commit messages!
## 2023-02-21 V.Ivanchenko (emutils-V11-01-02)
- G4EmExtraParameters - fixed AddPAIModel(...) method and improved comments
- G4EmExtraParametersMessenger - fixed broadcasting
- G4EmExtraParametersMessenger - fixed broadcasting
## 2023-01-10 V.Ivanchenko (emutils-V11-01-01)
- G4EmParameters - added extra member and access method to G4LEDATA path
allowing check environment variable for the EM data only once
## 2022-12-11 V.Ivanchenko (emutils-V11-01-00)
- G4EmParameters, G4EmParametersMessenger, added parameter, UI command,
- G4EmParameters, G4EmParametersMessenger, added parameter, UI command,
GetSet methods - MscPositronCorrection
## 2022-11-23 Gabriele Cosmo (emutils-V11-00-38)
@@ -160,11 +201,11 @@ It must **not** be used as a substitute for writing good git commit messages!
number of bins per decade
## 2022-08-25 V.Ivanchenko (emutils-V11-00-33)
- G4EmExtraParameters - safe definition of StepFuction for the
- G4EmExtraParameters - safe definition of StepFuction for the
G4GenericIon, related to problem #2495
## 2022-07-08 J.Apostolakis (emutils-V11-00-32)
- Fix in `G4TransportationWithMsc`: StartTracking now calls
- Fix in `G4TransportationWithMsc`: StartTracking now calls
corresponding method of G4Transportation (to initialise values
used for propagation in field.)
@@ -187,7 +228,7 @@ It must **not** be used as a substitute for writing good git commit messages!
## 2022-06-07 V.Ivanchenko (emutils-V11-00-27)
- G4VEnergyLossProcess - moved out common computations to G4EmTableUtil,
use G4EmDataHandler, removed unused headers and methods
use G4EmDataHandler, removed unused headers and methods
## 2022-05-31 V.Ivanchenko (emutils-V11-00-26)
- G4VEmModel - fixed Coverity warning
@@ -200,23 +241,23 @@ It must **not** be used as a substitute for writing good git commit messages!
- G4EmTableUtil - added extra methods
- G4VEmModel, G4VEmProcess, G4VEnergyLossProcess,
G4VMultipleScattering, G4LossTableManager - use new utiity methods,
updated sampling of random element in compounds and random
updated sampling of random element in compounds and random
isotopes, code cleanup
- G4EmParameters - added extra parameter: type for of fluctuation model
## 2022-05-20 Z.Li (emutils-V11-00-23)
- G4EmLowEParameters, change default photon database to EPICS2017
## 2022-05-13 V.Ivanchenko (emutils-V11-00-22)
## 2022-05-13 V.Ivanchenko (emutils-V11-00-22)
- G4EmUtility - added methods to sample isotopes or element
- G4VEmModel, G4EmCalculator, G4EmConfigurator - use G4EmUtility
## 2022-05-12 V.Ivanchenko (emutils-V11-00-21)
- G4EmUtility - removed precision lost in energy value at
- G4EmUtility - removed precision lost in energy value at
initialisation of integral method
- G4VEmProcess, G4VEnergyLossProcess - for integral method
use master thread cross section type and pointers directly
simplifing initialisation
simplifing initialisation
## 2022-05-11 J.Hahnfeld (emutils-V11-00-20)
- Remove dependency on `G4magneticfield`
@@ -235,22 +276,22 @@ It must **not** be used as a substitute for writing good git commit messages!
- many files: run clang-tidy. Use default ctors; keywords nullptr, auto, using
## 2022-04-23 V.Ivanchenko (emutils-V11-00-16)
- G4EmConfigurator - implement model per region for G4TransportationWithMsc
- G4EmConfigurator - implement model per region for G4TransportationWithMsc
- GNUmakefile, source.cmake - updated accordingly
## 2022-04-19 J.Hahnfeld (emutil-V11-00-15)
- Create `G4TransportationWithMsc` process, add flag to `G4EmParameters`
## 2022-04-13 V.Ivanchenko (emutils-V11-00-14)
- G4VEnergyLossProcess, G4VEmProcess - use G4EmUtility to compute cross
section shape parameters
- G4VEnergyLossProcess, G4VEmProcess - use G4EmUtility to compute cross
section shape parameters
- G4VMultipleScattering - updated arguments for AddEmModel, SetEmModel,
and EmModel methods from G4VEmModel* to G4VMscModel*
- G4EmConfigurator - updated interfaces
## 2022-04-10 V.Ivanchenko (emutils-V11-00-13)
- G4EmUtility - added new static methods to prepare data structures for
integral method using EM tables or using GetCrossSection(..) method
- G4EmUtility - added new static methods to prepare data structures for
integral method using EM tables or using GetCrossSection(..) method
from G4VDiscreteProcess based class, this will allow using it for hadronics
- G4VEnergyLossProcess, G4VEmProcess, G4VMultipleScattering - minor clean-up
@@ -265,7 +306,7 @@ It must **not** be used as a substitute for writing good git commit messages!
- G4LowEnergyEmProcessSubType - add fLowEnergyScavenger (66) for DNAScavenger process
## 2022-03-24 V.Ivanchenko (emutils-V11-00-09)
- G4VEnergyLossProcess - fix fluctuation model pointer if an extra
- G4VEnergyLossProcess - fix fluctuation model pointer if an extra
model is added on top of the default list of models
## 2022-03-17 V.Ivanchenko (emutils-V11-00-08)
@@ -297,7 +338,7 @@ It must **not** be used as a substitute for writing good git commit messages!
the lambda table defined for full energy range: LambdaPhysicsVector(..),
CrossSEctionPerVolume(...), FindLambdaMax(...). No change is expected for
the default physics configuration, fix mainly affect positron annihilation
processes at high energies.
processes at high energies.
## 2022-01-05 V.Ivanchenko (emutils-V11-00-02)
- Complete internal redesign started in 2021, results are identical
@@ -324,11 +365,11 @@ It must **not** be used as a substitute for writing good git commit messages!
10 November 21: S. Guatelli (emutils-V10-07-37)
- changed ANSTO parameters in UI interface commands
30 October 21: V.Ivanchenko (emutils-V10-07-36)
- G4VEnergyLossProcess - exclude ion corrections only from d, t, alpha
in order to fix #2440
- G4ionEffectiveCharge - return back limit on effective charge
- G4ionEffectiveCharge - return back limit on effective charge
from 0.5 to 1 (used in previous releases)
25 October 21: V.Ivanchenko (emutils-V10-07-35)
@@ -343,7 +384,7 @@ It must **not** be used as a substitute for writing good git commit messages!
12 October 21: V.Ivanchenko (emutils-V10-07-33)
- G4ionEffectiveCharge - code clean-up
- G4EmCorrections - do not use spline in various internal vectors,
because correction values are small and smooth, clean-up ion
because correction values are small and smooth, clean-up ion
correction computations
- G4VEnergyLossProcess - code clean-up for ions
@@ -356,8 +397,8 @@ It must **not** be used as a substitute for writing good git commit messages!
G4LossTableBuilder - implemented updated numbering scheme for
secondary particle production, deprecate duplicate printout
of processes and models, move list of EM parameters printout
before printout on processes, code format improved
G4EmParameters, G4EmParametersMessenger - removed obsolete
before printout on processes, code format improved
G4EmParameters, G4EmParametersMessenger - removed obsolete
methods, added protection agains duplicate printout
23 September 21: A.Ribon (emutils-V10-07-30)
@@ -387,19 +428,19 @@ It must **not** be used as a substitute for writing good git commit messages!
18 July 21: V.Ivanchenko (emutils-V10-07-24)
- G4VEmFluctuationModel - changed interface - both cut value and
max energy transfer are parameters of main methods; this
max energy transfer are parameters of main methods; this
is needed in order to fix problem #2390
- G4VEnergyLossProcess, G4EmModelManager - adopted above interface
change
change
11 July 21: V.Ivanchenko (emutils-V10-07-23)
- G4VEmProcess, G4VEnergyLossProcess, G4VMultipleScattering,
G4LossTableBuilder, G4VEmModel, G4VMscModel, G4LossTableManager
implement and use base material approach only if base materials
are defined, this should bring a minor speed-up of the code and little
- G4VEmProcess, G4VEnergyLossProcess, G4VMultipleScattering,
G4LossTableBuilder, G4VEmModel, G4VMscModel, G4LossTableManager
implement and use base material approach only if base materials
are defined, this should bring a minor speed-up of the code and little
reduction of memory; fixed problems for the case, when materials
are changed between runs
- G4LossTableBuilder - base material flag may be disabled
- G4LossTableBuilder - base material flag may be disabled
08 June 21: V.Ivanchenko (emutils-V10-07-22)
- G4VEmProcess, G4VEnergyLossProcess - fixed computation of cross
@@ -408,19 +449,19 @@ It must **not** be used as a substitute for writing good git commit messages!
- G4LossTableBuilder - fixed debug printout
01 June 21: V.Ivanchenko (emutils-V10-07-21)
- G4VEmProcess, G4VEnergyLossProcess - an attempt to improve
integral option
- G4VEmProcess, G4VEnergyLossProcess - an attempt to improve
integral option
26 May 21: V.Ivanchenko (emutils-V10-07-20)
- G4VEmProcess, G4VEnergyLossProcess, G4EmDataHandler - updated
- G4VEmProcess, G4VEnergyLossProcess, G4EmDataHandler - updated
method RetrievePhysicsTable(...)
15 May 21: V.Ivanchenko (emutils-V10-07-19)
- G4VEmProcess, G4VEnergyLossProcess, G4EmTableType, G4EmBiasingManager,
G4LossTableManager - updated integral approach by introduction of a
cross section shape type and different actions depending on the type;
addition of cache for cross section and range; removed unused methods;
attempt to reduce number of "if" operators in the run time; integral
cross section shape type and different actions depending on the type;
addition of cache for cross section and range; removed unused methods;
attempt to reduce number of "if" operators in the run time; integral
and spline flags are set to each process individually
- G4VMultipleScattering - fixed problem observed by CMS for specific
Physics List
@@ -0,0 +1,40 @@
//
// ********************************************************************
// * 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 _G4CHEMTIMESTEPMODEL_HH
#define _G4CHEMTIMESTEPMODEL_HH
enum class G4ChemTimeStepModel
{
Unknown = 0,
SBS,
IRT,
IRT_syn,
};
#endif
@@ -106,7 +106,7 @@ public:
G4VEmModel* currentModel,
G4ParticleChangeForLoss* pParticleChange,
G4double& eloss,
G4int coupleIdx,
G4int coupleIdx,
G4double tcut,
G4double safety = 0.0);
@@ -48,10 +48,13 @@
#ifndef G4EmDataHandler_h
#define G4EmDataHandler_h 1
#include <vector>
#include "globals.hh"
#include "G4PhysicsTable.hh"
#include "G4PhysicsVector.hh"
#include <vector>
#include "G4EmTableType.hh"
#include "G4EmElementSelector.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -63,31 +66,34 @@ class G4EmDataHandler
{
public:
explicit G4EmDataHandler(size_t nTable);
explicit G4EmDataHandler(std::size_t nTable, const G4String& nam="");
~G4EmDataHandler();
// add table
size_t SetTable(G4PhysicsTable*);
std::size_t SetTable(G4PhysicsTable*);
// update existing table
void UpdateTable(G4PhysicsTable*, size_t idx);
void UpdateTable(G4PhysicsTable*, std::size_t idx);
// save table pointer
void SaveTable(G4PhysicsTable*, std::size_t idx);
// assuming that the table is already defined
G4PhysicsTable* MakeTable(size_t idx);
G4PhysicsTable* MakeTable(std::size_t idx);
// existing table may be substituted
G4PhysicsTable* MakeTable(G4PhysicsTable*, size_t idx);
G4PhysicsTable* MakeTable(G4PhysicsTable*, std::size_t idx);
// clean existing table
void CleanTable(size_t idx);
void CleanTable(std::size_t idx);
G4bool StorePhysicsTable(size_t idx,
G4bool StorePhysicsTable(std::size_t idx,
const G4ParticleDefinition* part,
const G4String& fname,
G4bool ascii);
G4bool RetrievePhysicsTable(size_t idx,
G4bool RetrievePhysicsTable(std::size_t idx,
const G4ParticleDefinition* part,
const G4String& fname,
G4bool ascii, G4bool spline);
@@ -96,19 +102,66 @@ public:
const G4VEmProcess* GetMasterProcess(size_t idx) const;
inline const G4PhysicsTable* GetTable(size_t idx) const {
const G4PhysicsTable* GetTable(std::size_t idx) const {
return (idx < tLength) ? data[idx] : nullptr;
}
inline G4PhysicsTable* Table(size_t idx) const {
G4PhysicsTable* Table(std::size_t idx) const {
return (idx < tLength) ? data[idx] : nullptr;
}
inline const G4PhysicsVector* GetVector(size_t itable, size_t ivec) const
{ return (*(data[itable]))[ivec]; }
const G4PhysicsVector* GetVector(std::size_t itable, std::size_t ivec) const {
return (*(data[itable]))[ivec];
}
inline const std::vector<G4PhysicsTable*>& GetTables() const { return data; }
const std::vector<G4PhysicsTable*>& GetTables() const {
return data;
}
std::vector<G4double>* EnergyOfCrossSectionMax() const {
return fMaxXS;
}
void SetEnergyOfCrossSectionMax(std::vector<G4double>* p) {
if (p != fMaxXS) {
delete fMaxXS;
fMaxXS = p;
}
}
std::vector<G4TwoPeaksXS*>* TwoPeaksXS() const {
return fXSpeaks;
}
void SetTwoPeaksXS(std::vector<G4TwoPeaksXS*>* p) {
if (p != fXSpeaks) {
delete fXSpeaks;
fXSpeaks = p;
}
}
std::vector<G4EmElementSelector*>* GetElementSelectors(std::size_t i) {
return (i < eLength) ? fElemSelectors[i] : nullptr;
}
void SetElementSelectors(std::vector<G4EmElementSelector*>*, std::size_t);
G4CrossSectionType CrossSectionType() const {
return fXSType;
}
void SetCrossSectionType(G4CrossSectionType val) {
fXSType = val;
}
const G4String& GetName() const {
return fName;
}
void SetUseBaseParticleTable(G4bool val) {
fUseBaseParticleTable = val;
}
// hide assignment operator
G4EmDataHandler & operator=(const G4EmDataHandler &right) = delete;
G4EmDataHandler(const G4EmDataHandler&) = delete;
@@ -116,8 +169,15 @@ public:
private:
std::vector<G4PhysicsTable*> data;
size_t tLength;
std::vector<G4double>* fMaxXS;
std::vector<G4TwoPeaksXS*>* fXSpeaks;
std::vector<std::vector<G4EmElementSelector*>* > fElemSelectors;
std::vector<const G4VEmProcess*> masterProcess;
std::size_t tLength{0};
std::size_t eLength{0};
G4CrossSectionType fXSType{fEmNoIntegral};
G4String fName;
G4bool fUseBaseParticleTable{false};
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -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. *
// ********************************************************************
//
// 18 April 2024 V.Ivanchenko
//
// This is a singleton class to store shared EM physics data.
// The access to data is possible only by data name.
// Once created data pointers does not changed or deleted until the
// end of the job, this class is responsible for destruction.
//
#ifndef G4EmDataRegistry_h
#define G4EmDataRegistry_h 1
#include <vector>
#include "G4EmDataHandler.hh"
class G4EmDataRegistry
{
public:
static G4EmDataRegistry* Instance();
~G4EmDataRegistry();
// create or access data handler
// nTable - number of tables in a new handler
G4EmDataHandler* GetHandlerByName(const G4String&, std::size_t nTable);
// register a new handler
void Register(G4EmDataHandler*);
// hide assignment operator
G4EmDataRegistry& operator=(const G4EmDataRegistry &right) = delete;
G4EmDataRegistry(const G4EmDataRegistry&) = delete;
private:
G4EmDataRegistry();
G4EmDataHandler* EmDataHandler(const G4String&);
static G4EmDataRegistry* instance;
std::vector<G4EmDataHandler*> fDataHandlers;
};
#endif
@@ -51,6 +51,7 @@
#include "globals.hh"
#include "G4DNAModelSubType.hh"
#include "G4EmFluoDirectory.hh"
#include "G4ChemTimeStepModel.hh"
#include <vector>
class G4EmLowEParametersMessenger;
@@ -92,6 +93,9 @@ public:
void SetDNAStationary(G4bool val);
G4bool DNAStationary() const;
void SetChemTimeStepModel(G4ChemTimeStepModel val);
G4ChemTimeStepModel GetChemTimeStepModel() const;
void SetDNAElectronMsc(G4bool val);
G4bool DNAElectronMsc() const;
@@ -145,6 +149,7 @@ private:
G4bool dnaMsc;
G4DNAModelSubType dnaElectronSolvation;
G4ChemTimeStepModel fTimeStepModel;
G4EmFluoDirectory fFluoDirectory;
@@ -93,6 +93,7 @@ private:
G4UIcmdWithAString* pixeeXsCmd;
G4UIcmdWithAString* livCmd;
G4UIcmdWithAString* dnaSolCmd;
G4UIcmdWithAString* dnaChemModel;
G4UIcmdWithAString* direFluoCmd;
G4UIcmdWithAString* meCmd;
@@ -60,8 +60,9 @@
#include "G4EmFluoDirectory.hh"
#include "G4EmSaturation.hh"
#include "G4ThreeVector.hh"
#include "G4ChemTimeStepModel.hh"
#include <vector>
#include <map>
enum G4eSingleScatteringType
{
fWVI = 0,
@@ -83,6 +84,12 @@ enum G4EmFluctuationType
fUrbanFluctuation
};
enum G4PositronAtRestModelType
{
fSimplePositronium = 0,
fAllisonPositronium
};
class G4EmParametersMessenger;
class G4EmExtraParameters;
class G4EmLowEParameters;
@@ -173,6 +180,12 @@ public:
void SetFluctuationType(G4EmFluctuationType val);
G4EmFluctuationType FluctuationType() const;
void SetPositronAtRestModelType(G4PositronAtRestModelType val);
G4PositronAtRestModelType PositronAtRestModelType() const;
void SetOrtoPsFraction(G4double val);
G4double OrtoPsFraction() const;
void SetDNAFast(G4bool val);
G4bool DNAFast() const;
@@ -327,6 +340,9 @@ public:
void SetDNAeSolvationSubType(G4DNAModelSubType val);
G4DNAModelSubType DNAeSolvationSubType() const;
//DNA chemistry model
void SetTimeStepModel(const G4ChemTimeStepModel& model);
G4ChemTimeStepModel GetTimeStepModel() const;
//5d
void SetConversionType(G4int val);
G4int GetConversionType() const;
@@ -469,6 +485,8 @@ private:
G4NuclearFormfactorType nucFormfactor;
G4eSingleScatteringType fSStype;
G4EmFluctuationType fFluct;
G4PositronAtRestModelType fPositronium;
G4double fOrtoPsFraction;
G4String fDirLEDATA;
};
@@ -142,6 +142,8 @@ private:
G4UIcmdWithAString* nffCmd;
G4UIcmdWithAString* ssCmd;
G4UIcmdWithAString* fluc1Cmd;
G4UIcmdWithAString* posiCmd;
G4UIcmdWithADouble* ortoCmd;
G4UIcommand* dumpCmd;
@@ -61,7 +61,7 @@ class G4LossTableBuilder
public:
G4LossTableBuilder(G4bool master=true);
explicit G4LossTableBuilder(G4bool master);
~G4LossTableBuilder();
@@ -88,18 +88,16 @@ public:
void InitialiseBaseMaterials(const G4PhysicsTable* table=nullptr);
// access methods
const std::vector<G4int>* GetCoupleIndexes() const;
static const std::vector<G4int>* GetCoupleIndexes();
const std::vector<G4double>* GetDensityFactors() const;
static const std::vector<G4double>* GetDensityFactors();
G4bool GetFlag(size_t idx);
static G4bool GetFlag(std::size_t idx);
G4bool GetBaseMaterialFlag();
static G4bool GetBaseMaterialFlag();
inline void SetSplineFlag(G4bool flag);
inline void SetInitialisationFlag(G4bool flag);
inline void SetBaseMaterialActive(G4bool flag);
G4LossTableBuilder & operator=(const G4LossTableBuilder &right) = delete;
@@ -111,10 +109,10 @@ private:
G4bool splineFlag = true;
G4bool isInitialized = false;
G4bool baseMatFlag = false;
G4bool isBaseMatActive = true;
G4bool isInitializer = false;
G4bool isInitializer;
static G4bool baseMatFlag;
static std::vector<G4double>* theDensityFactor;
static std::vector<G4int>* theDensityIdx;
static std::vector<G4bool>* theFlag;
@@ -124,19 +122,15 @@ inline void G4LossTableBuilder::SetSplineFlag(G4bool flag)
{
splineFlag = flag;
}
/*
inline void G4LossTableBuilder::SetInitialisationFlag(G4bool flag)
{
isInitialized = flag;
}
*/
inline void G4LossTableBuilder::SetBaseMaterialActive(G4bool flag)
{
isBaseMatActive = flag;
if(!flag) {
baseMatFlag = false;
isInitialized = false;
}
}
//....oooOO0OOooo.......oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -281,7 +281,8 @@ private:
G4bool all_tables_are_built{false};
G4bool startInitialisation{false};
G4bool isMaster{true};
G4bool resetParam{true};
G4bool isMaster{false};
std::vector<G4VEnergyLossProcess*> loss_vector;
std::vector<PD> part_vector;
@@ -40,8 +40,8 @@
#ifndef G4LowEnergyEmProcessSubType_h
#define G4LowEnergyEmProcessSubType_h 1
enum G4LowEnergyEmProcessSubType
{
enum G4LowEnergyEmProcessSubType
{
fLowEnergyElastic = 51,
fLowEnergyExcitation = 52,
fLowEnergyIonisation = 53,
@@ -57,7 +57,9 @@ enum G4LowEnergyEmProcessSubType
fLowEnergyDoubleCap = 63,
fLowEnergyIoniTransfer = 64,
fLowEnergyStaticMol = 65,
fLowEnergyScavenger = 66
fLowEnergyScavenger = 66,
fLowEnergyTripleIonisation = 67,
fLowEnergyQuadrupleIonisation = 68
};
#endif
@@ -371,8 +371,6 @@ public:
inline void SetFluctuationFlag(G4bool val);
inline void SetMasterThread(G4bool val);
inline G4bool IsMaster() const;
inline void SetUseBaseMaterials(G4bool val);
@@ -389,10 +387,12 @@ public:
inline void SetLocked(G4bool);
// obsolete method
// obsolete methods
[[deprecated("Use G4EmParameters::Instance()->SetLPM instead")]]
void SetLPMFlag(G4bool);
void SetMasterThread(G4bool);
// hide assignment operator
G4VEmModel & operator=(const G4VEmModel &right) = delete;
G4VEmModel(const G4VEmModel&) = delete;
@@ -707,13 +707,6 @@ inline void G4VEmModel::SetFluctuationFlag(G4bool val)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline void G4VEmModel::SetMasterThread(G4bool val)
{
isMaster = val;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline G4bool G4VEmModel::IsMaster() const
{
return isMaster;
@@ -85,8 +85,6 @@ public:
// Virtual methods to be implemented in concrete processes
//------------------------------------------------------------------------
virtual G4bool IsApplicable(const G4ParticleDefinition& p) override = 0;
void ProcessDescription(std::ostream& outFile) const override;
protected:
@@ -197,15 +195,15 @@ protected:
//------------------------------------------------------------------------
// Specific methods to set, access, modify models and basic parameters
//------------------------------------------------------------------------
// Select model in run time
inline G4VEmModel* SelectModel(G4double kinEnergy, size_t);
inline G4VEmModel* SelectModel(G4double kinEnergy, std::size_t);
public:
// Select model by energy and couple index
inline G4VEmModel* SelectModelForMaterial(G4double kinEnergy,
size_t idxCouple) const;
std::size_t idxCouple) const;
// Add model for region, smaller value of order defines which
// model will be selected for a given energy interval
@@ -218,7 +216,7 @@ public:
inline G4int NumberOfModels() const;
// return a model from the local list
inline G4VEmModel* EmModel(size_t index = 0) const;
inline G4VEmModel* EmModel(std::size_t index = 0) const;
// Access to active model
inline const G4VEmModel* GetCurrentModel() const;
@@ -287,7 +285,7 @@ protected:
inline void SetSecondaryParticle(const G4ParticleDefinition* p);
inline size_t CurrentMaterialCutsCoupleIndex() const;
inline std::size_t CurrentMaterialCutsCoupleIndex() const;
inline const G4MaterialCutsCouple* MaterialCutsCouple() const;
@@ -369,7 +367,7 @@ protected:
private:
const std::vector<G4double>* theDensityFactor = nullptr;
const std::vector<G4int>* theDensityIdx = nullptr;
const std::vector<G4int>* theDensityIdx = nullptr;
// ======== parameters =========
G4double minKinEnergy;
@@ -404,12 +402,12 @@ protected:
G4int augerID = _AugerElectron;
G4int biasID = _EM;
G4int tripletID = _TripletElectron;
size_t currentCoupleIndex = 0;
size_t basedCoupleIndex = 0;
size_t coupleIdxLambda = 0;
size_t idxLambda = 0;
std::size_t currentCoupleIndex = 0;
std::size_t basedCoupleIndex = 0;
std::size_t coupleIdxLambda = 0;
std::size_t idxLambda = 0;
G4bool isTheMaster = true;
G4bool isTheMaster = false;
G4bool baseMat = false;
private:
@@ -442,7 +440,7 @@ private:
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline size_t G4VEmProcess::CurrentMaterialCutsCoupleIndex() const
inline std::size_t G4VEmProcess::CurrentMaterialCutsCoupleIndex() const
{
return currentCoupleIndex;
}
@@ -472,15 +470,15 @@ inline G4double G4VEmProcess::GetElectronEnergyCut()
inline void G4VEmProcess::DefineMaterial(const G4MaterialCutsCouple* couple)
{
if(couple != currentCouple) {
if (couple != currentCouple) {
currentCouple = couple;
baseMaterial = currentMaterial = couple->GetMaterial();
basedCoupleIndex = currentCoupleIndex = couple->GetIndex();
fFactor = biasFactor;
mfpKinEnergy = DBL_MAX;
if(baseMat) {
if (baseMat) {
basedCoupleIndex = (*theDensityIdx)[currentCoupleIndex];
if(nullptr != currentMaterial->GetBaseMaterial())
if (nullptr != currentMaterial->GetBaseMaterial())
baseMaterial = currentMaterial->GetBaseMaterial();
fFactor *= (*theDensityFactor)[currentCoupleIndex];
}
@@ -490,7 +488,7 @@ inline void G4VEmProcess::DefineMaterial(const G4MaterialCutsCouple* couple)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline
G4VEmModel* G4VEmProcess::SelectModel(G4double kinEnergy, size_t)
G4VEmModel* G4VEmProcess::SelectModel(G4double kinEnergy, std::size_t)
{
if(1 < numberOfModels) {
currentModel = modelManager->SelectModel(kinEnergy, currentCoupleIndex);
@@ -503,7 +501,7 @@ G4VEmModel* G4VEmProcess::SelectModel(G4double kinEnergy, size_t)
inline
G4VEmModel* G4VEmProcess::SelectModelForMaterial(G4double kinEnergy,
size_t idxCouple) const
std::size_t idxCouple) const
{
return modelManager->SelectModel(kinEnergy, idxCouple);
}
@@ -803,7 +801,7 @@ inline G4int G4VEmProcess::NumberOfModels() const
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
inline G4VEmModel* G4VEmProcess::EmModel(size_t index) const
inline G4VEmModel* G4VEmProcess::EmModel(std::size_t index) const
{
return (index < emModels.size()) ? emModels[index] : nullptr;
}
@@ -488,6 +488,8 @@ private:
G4int secID = _DeltaElectron;
G4int tripletID = _TripletElectron;
G4int biasID = _DeltaEBelowCut;
G4int epixeID = _ePIXE;
G4int gpixeID = _GammaPIXE;
G4int mainSecondaries = 1;
std::size_t basedCoupleIndex = 0;
@@ -509,11 +511,11 @@ private:
G4bool tablesAreBuilt = false;
G4bool spline = true;
G4bool isIon = false;
G4bool isIonisation = true;
G4bool isIonisation = false;
G4bool useDeexcitation = false;
G4bool biasFlag = false;
G4bool weightFlag = false;
G4bool isMaster = true;
G4bool isMaster = false;
G4bool baseMat = false;
G4bool actLinLossLimit = false;
G4bool actLossFluc = false;
@@ -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. *
// ********************************************************************
//
// GEANT4 Class header file
//
// File name: G4VPositronAtRestModel
//
// Author: V. Ivanchenko
//
// Creation date: 13 May 2024
//
// Class Description:
// Abstract base class for sampling of positron annihilation at rest
// There is a requirement to implementation of the virtual method
// SampleSecondaries(...):
// in the list of dynamic particles two first should be the most
// energetic gamma from the annihilation. The number of produced
// particles is not limited.
//
// -------------------------------------------------------------------
//
#ifndef G4VPositronAtRestModel_h
#define G4VPositronAtRestModel_h 1
#include "globals.hh"
#include <vector>
class G4Material;
class G4DynamicParticle;
class G4VPositronAtRestModel
{
public:
explicit G4VPositronAtRestModel(const G4String& name) : fName(name) {};
virtual ~G4VPositronAtRestModel() = default;
virtual void SampleSecondaries(std::vector<G4DynamicParticle*>& secParticles,
G4double& localEnergyDeposit,
const G4Material*) const = 0;
virtual void PrintGeneratorInformation() const = 0;
const G4String& GetName() const { return fName; };
G4VPositronAtRestModel& operator=
(const G4VPositronAtRestModel& right) = delete;
G4VPositronAtRestModel(const G4VPositronAtRestModel&) = delete;
private:
G4String fName;
};
#endif
@@ -8,12 +8,14 @@ geant4_add_module(G4emutils
G4AtomicShellEnumerator.hh
G4DNAModelSubType.hh
G4DummyModel.hh
G4ChemTimeStepModel.hh
G4ElectronIonPair.hh
G4EmBiasingManager.hh
G4EmCalculator.hh
G4EmConfigurator.hh
G4EmCorrections.hh
G4EmDataHandler.hh
G4EmDataRegistry.hh
G4EmElementSelector.hh
G4EmExtraParameters.hh
G4EmExtraParametersMessenger.hh
@@ -48,6 +50,7 @@ geant4_add_module(G4emutils
G4VEnergyLossProcess.hh
G4VMscModel.hh
G4VMultipleScattering.hh
G4VPositronAtRestModel.hh
G4VSubCutProducer.hh
G4ionEffectiveCharge.hh
SOURCES
@@ -59,6 +62,7 @@ geant4_add_module(G4emutils
G4EmConfigurator.cc
G4EmCorrections.cc
G4EmDataHandler.cc
G4EmDataRegistry.cc
G4EmElementSelector.cc
G4EmExtraParameters.cc
G4EmExtraParametersMessenger.cc
@@ -41,6 +41,7 @@
//
#include "G4EmDataHandler.hh"
#include "G4EmDataRegistry.hh"
#include "G4ParticleDefinition.hh"
#include "G4EmParameters.hh"
#include "G4PhysicsTableHelper.hh"
@@ -49,27 +50,43 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataHandler::G4EmDataHandler(size_t n) : tLength(n)
G4EmDataHandler::G4EmDataHandler(std::size_t n, const G4String& nam)
: tLength(n), fName(nam)
{
data.resize(n, nullptr);
fMaxXS = new std::vector<G4double>;
fXSpeaks = new std::vector<G4TwoPeaksXS*>;
G4EmDataRegistry::Instance()->Register(this);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataHandler::~G4EmDataHandler()
{
for(size_t i=0; i<tLength; ++i) {
for(size_t j = i+1; j<tLength; ++j) {
if(data[j] == data[i]) { data[j] = nullptr; }
if (!fUseBaseParticleTable) {
for (std::size_t i=0; i<tLength; ++i) {
CleanTable(i);
}
CleanTable(i);
delete fMaxXS;
delete fXSpeaks;
}
if (!fElemSelectors.empty()) {
for (auto const & ptr : fElemSelectors) {
if (nullptr != ptr) {
for (auto const & p : *ptr) { delete p; }
}
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
size_t G4EmDataHandler::SetTable(G4PhysicsTable* ptr)
std::size_t G4EmDataHandler::SetTable(G4PhysicsTable* ptr)
{
for (std::size_t i=0; i<tLength; ++i) {
if (ptr == data[i]) { return i; }
}
data.push_back(ptr);
++tLength;
return tLength-1;
@@ -77,11 +94,12 @@ size_t G4EmDataHandler::SetTable(G4PhysicsTable* ptr)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4EmDataHandler::UpdateTable(G4PhysicsTable* ptr, size_t idx)
void G4EmDataHandler::UpdateTable(G4PhysicsTable* ptr, std::size_t idx)
{
// update table pointer but not delete previous
if(idx < tLength) {
if(ptr != data[idx]) { data[idx] = ptr; }
if (idx < tLength) {
if (ptr != data[idx]) { data[idx] = ptr; }
data[idx] = G4PhysicsTableHelper::PreparePhysicsTable(data[idx]);
} else {
G4cout << "### G4EmDataHandler::UpdateTable fail for idx=" << idx
<< " length=" << tLength << G4endl;
@@ -90,10 +108,19 @@ void G4EmDataHandler::UpdateTable(G4PhysicsTable* ptr, size_t idx)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4PhysicsTable* G4EmDataHandler::MakeTable(size_t i)
void G4EmDataHandler::SaveTable(G4PhysicsTable* ptr, std::size_t idx)
{
size_t idx = i;
if(idx >= tLength) {
if (idx < tLength) {
data[idx] = ptr;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4PhysicsTable* G4EmDataHandler::MakeTable(std::size_t i)
{
std::size_t idx = i;
if (idx >= tLength) {
data.push_back(nullptr);
idx = tLength;
++tLength;
@@ -104,13 +131,13 @@ G4PhysicsTable* G4EmDataHandler::MakeTable(size_t i)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4PhysicsTable* G4EmDataHandler::MakeTable(G4PhysicsTable* ptr, size_t i)
G4PhysicsTable* G4EmDataHandler::MakeTable(G4PhysicsTable* ptr, std::size_t i)
{
size_t idx = i;
std::size_t idx = i;
// create new table only if index corresponds to the
// position in the vector
if(idx < tLength) {
if(ptr != data[idx]) {
if (idx < tLength) {
if (ptr != data[idx]) {
CleanTable(idx);
data[idx] = ptr;
}
@@ -119,24 +146,27 @@ G4PhysicsTable* G4EmDataHandler::MakeTable(G4PhysicsTable* ptr, size_t i)
idx = tLength;
++tLength;
}
data[idx] = G4PhysicsTableHelper::PreparePhysicsTable(ptr);
data[idx] = G4PhysicsTableHelper::PreparePhysicsTable(data[idx]);
return data[idx];
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4EmDataHandler::CleanTable(size_t i)
void G4EmDataHandler::CleanTable(std::size_t i)
{
if(i < tLength && nullptr != data[i]) {
data[i]->clearAndDestroy();
delete data[i];
data[i] = nullptr;
if (i < tLength && nullptr != data[i]) {
auto ptr = data[i];
ptr->clearAndDestroy();
delete ptr;
for (std::size_t j=0; j<tLength; ++j) {
if (ptr == data[j]) { data[j] = nullptr; }
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool G4EmDataHandler::StorePhysicsTable(size_t idx,
G4bool G4EmDataHandler::StorePhysicsTable(std::size_t idx,
const G4ParticleDefinition* part,
const G4String& fname,
G4bool ascii)
@@ -160,7 +190,7 @@ G4bool G4EmDataHandler::StorePhysicsTable(size_t idx,
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool G4EmDataHandler::RetrievePhysicsTable(size_t idx,
G4bool G4EmDataHandler::RetrievePhysicsTable(std::size_t idx,
const G4ParticleDefinition* part,
const G4String& fname,
G4bool ascii, G4bool spline)
@@ -192,9 +222,25 @@ void G4EmDataHandler::SetMasterProcess(const G4VEmProcess* ptr)
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
const G4VEmProcess* G4EmDataHandler::GetMasterProcess(size_t idx) const
const G4VEmProcess* G4EmDataHandler::GetMasterProcess(std::size_t idx) const
{
return (idx < masterProcess.size()) ? masterProcess[idx] : nullptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4EmDataHandler::SetElementSelectors(std::vector<G4EmElementSelector*>* p,
std::size_t i)
{
if (i < eLength) {
if (fElemSelectors[i] != p) {
delete fElemSelectors[i];
}
fElemSelectors[i] = p;
} else {
fElemSelectors.push_back(p);
++eLength;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,113 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//---------------------------------------------------------------------------
//
// GEANT4 Class file
//
// Author: V.Ivanchenko 18.04.2024
//
//----------------------------------------------------------------------------
#include "G4EmDataRegistry.hh"
#include "G4AutoLock.hh"
G4EmDataRegistry* G4EmDataRegistry::instance = nullptr;
namespace
{
G4Mutex theEmData = G4MUTEX_INITIALIZER;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
G4EmDataRegistry* G4EmDataRegistry::Instance()
{
if (instance == nullptr) {
static G4EmDataRegistry manager;
instance = &manager;
}
return instance;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataRegistry::G4EmDataRegistry()
{
fDataHandlers.reserve(50);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataRegistry::~G4EmDataRegistry()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataHandler*
G4EmDataRegistry::GetHandlerByName(const G4String& nam, std::size_t n)
{
// handler already exist
G4EmDataHandler* ptr = EmDataHandler(nam);
if (nullptr != ptr) { return ptr; }
// create a new handler
G4AutoLock l(&theEmData);
ptr = EmDataHandler(nam);
if (nullptr == ptr) {
ptr = new G4EmDataHandler(n, nam);
}
l.unlock();
return ptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4EmDataRegistry::Register(G4EmDataHandler* ptr)
{
if (nullptr == ptr) { return; }
for (auto const & p : fDataHandlers) {
if (p == ptr) { return; }
}
fDataHandlers.push_back(ptr);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4EmDataHandler* G4EmDataRegistry::EmDataHandler(const G4String& nam)
{
G4EmDataHandler* ptr = nullptr;
if (fDataHandlers.empty()) { return ptr; }
for (auto const & p : fDataHandlers) {
if (p->GetName() == nam) {
ptr = p;
break;
}
}
return ptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -76,6 +76,7 @@ void G4EmLowEParameters::Initialise()
dnaStationary = false;
dnaMsc = false;
dnaElectronSolvation = fMeesungnoen2002eSolvation;
fTimeStepModel = G4ChemTimeStepModel::Unknown;
fFluoDirectory = fluoDefault;
namePIXE = "Empirical";
@@ -195,6 +196,16 @@ G4DNAModelSubType G4EmLowEParameters::DNAeSolvationSubType() const
return dnaElectronSolvation;
}
void G4EmLowEParameters::SetChemTimeStepModel(G4ChemTimeStepModel val)
{
fTimeStepModel = val;
}
G4ChemTimeStepModel G4EmLowEParameters::GetChemTimeStepModel() const
{
return fTimeStepModel;
}
void G4EmLowEParameters::SetPIXECrossSectionModel(const G4String& sss)
{
namePIXE = sss;
@@ -51,7 +51,6 @@
#include "G4UIcmdWith3VectorAndUnit.hh"
#include "G4UImanager.hh"
#include "G4EmLowEParameters.hh"
#include <sstream>
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -164,6 +163,13 @@ G4EmLowEParametersMessenger::G4EmLowEParametersMessenger(G4EmLowEParameters* ptr
dnaSolCmd->AvailableForStates(G4State_PreInit);
dnaSolCmd->SetToBeBroadcasted(false);
dnaChemModel = new G4UIcmdWithAString("/process/chem/TimeStepModel",this);
dnaChemModel->SetGuidance("The name of DNA chemistry time step model");
dnaChemModel->SetParameterName("TimeStepModel",true);
dnaChemModel->SetCandidates("SBS IRT IRT_syn");
dnaChemModel->AvailableForStates(G4State_PreInit);
dnaChemModel->SetToBeBroadcasted(false);
meCmd = new G4UIcmdWithAString("/process/em/AddMicroElecRegion",this);
meCmd->SetGuidance("Activate MicroElec model in the G4Region");
meCmd->SetParameterName("MicroElec",true);
@@ -225,6 +231,7 @@ G4EmLowEParametersMessenger::~G4EmLowEParametersMessenger()
delete pixeeXsCmd;
delete livCmd;
delete dnaSolCmd;
delete dnaChemModel;
delete direFluoCmd;
delete meCmd;
delete dnaCmd;
@@ -278,6 +285,16 @@ void G4EmLowEParametersMessenger::SetNewValue(G4UIcommand* command,
ttt = fKreipl2009eSolvation;
}
theParameters->SetDNAeSolvationSubType(ttt);
} else if (command == dnaChemModel) {
G4ChemTimeStepModel stepM = G4ChemTimeStepModel::Unknown;
if(newValue == "IRT") {
stepM = G4ChemTimeStepModel::IRT;
} else if(newValue == "SBS") {
stepM = G4ChemTimeStepModel::SBS;
} else if (newValue == "IRT_syn") {
stepM = G4ChemTimeStepModel::IRT_syn;
}
theParameters->SetChemTimeStepModel(stepM);
} else if (command == direFluoCmd) {
G4EmFluoDirectory ttt = fluoDefault;
if(newValue == "Bearden") { ttt = fluoBearden; }
@@ -160,6 +160,7 @@ void G4EmParameters::Initialise()
safetyFactor = 0.6;
lambdaLimit = 1.0*CLHEP::mm;
factorScreen = 1.0;
fOrtoPsFraction = 0.0375; // 0.75 * 0.05
nbinsPerDecade = 7;
verbose = 1;
@@ -174,7 +175,14 @@ void G4EmParameters::Initialise()
fSStype = fWVI;
fFluct = fUniversalFluctuation;
fDirLEDATA = G4String(G4FindDataDir("G4LEDATA"));
const char* data_dir = G4FindDataDir("G4LEDATA");
if (nullptr != data_dir) {
fDirLEDATA = G4String(data_dir);
}
else {
G4Exception("G4EmParameters::Initialise()", "em0003", JustWarning,
"G4LEDATA data directory was not found.");
}
}
void G4EmParameters::SetLossFluctuations(G4bool val)
@@ -582,13 +590,13 @@ G4double G4EmParameters::MinKinEnergy() const
void G4EmParameters::SetMaxEnergy(G4double val)
{
if(IsLocked()) { return; }
if(val > std::max(minKinEnergy,9.99*CLHEP::MeV) && val < 1.e+7*CLHEP::TeV) {
if(val > std::max(minKinEnergy,599.9*CLHEP::MeV) && val < 1.e+7*CLHEP::TeV) {
maxKinEnergy = val;
} else {
G4ExceptionDescription ed;
ed << "Value of MaxKinEnergy is out of range: "
<< val/CLHEP::GeV
<< " GeV is ignored; allowed range 10 MeV - 1.e+7 TeV";
<< " GeV is ignored; allowed range 600 MeV - 1.e+7 TeV";
PrintWarning(ed);
}
}
@@ -1032,6 +1040,29 @@ G4EmFluctuationType G4EmParameters::FluctuationType() const
return fFluct;
}
void G4EmParameters::SetPositronAtRestModelType(G4PositronAtRestModelType val)
{
if(IsLocked()) { return; }
fPositronium = val;
}
G4PositronAtRestModelType G4EmParameters::PositronAtRestModelType() const
{
return fPositronium;
}
void G4EmParameters::SetOrtoPsFraction(G4double val)
{
if(IsLocked()) { return; }
fOrtoPsFraction = val;
}
G4double G4EmParameters::OrtoPsFraction() const
{
return fOrtoPsFraction;
}
void G4EmParameters::SetMscStepLimitType(G4MscStepLimitType val)
{
if(IsLocked()) { return; }
@@ -1453,6 +1484,13 @@ void G4EmParameters::StreamInfo(std::ostream& os) const
<< fCParameters->DNAElectronMsc() << "\n";
os << "Use DNA e- solvation model type "
<< fCParameters->DNAeSolvationSubType() << "\n";
auto chemModel = fCParameters->GetChemTimeStepModel();
if(fCParameters->GetChemTimeStepModel() != G4ChemTimeStepModel::Unknown)
{
std::vector<G4String> ChemModel{"Unknown","SBS","IRT","IRT_syn"};
os << "Use DNA Chemistry model "
<< ChemModel.at((std::size_t)chemModel) << "\n";
}
os << "=======================================================================" << G4endl;
}
os.precision(prec);
@@ -1485,4 +1523,14 @@ G4bool G4EmParameters::IsLocked() const
fStateManager->GetCurrentState() != G4State_Idle));
}
void G4EmParameters::SetTimeStepModel(const G4ChemTimeStepModel& model)
{
fCParameters-> SetChemTimeStepModel(model);
}
G4ChemTimeStepModel G4EmParameters::GetTimeStepModel() const
{
return fCParameters->GetChemTimeStepModel();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -438,6 +438,20 @@ G4EmParametersMessenger::G4EmParametersMessenger(G4EmParameters* ptr)
fluc1Cmd->AvailableForStates(G4State_PreInit);
fluc1Cmd->SetToBeBroadcasted(false);
posiCmd = new G4UIcmdWithAString("/process/em/setPositronAtRestModel",this);
posiCmd->SetGuidance("Define model of positron annihilation at rest");
posiCmd->SetParameterName("Posi",true);
posiCmd->SetCandidates("Simple Allison");
posiCmd->AvailableForStates(G4State_PreInit);
posiCmd->SetToBeBroadcasted(false);
ortoCmd = new G4UIcmdWithADouble("/process/em/setOrtoPositronFraction",this);
ortoCmd->SetGuidance("Define model of positron annihilation at rest");
ortoCmd->SetParameterName("frac",false);
ortoCmd->SetRange("frac >= 0.0 && frac <= 1.0");
ortoCmd->AvailableForStates(G4State_PreInit,G4State_Idle);
ortoCmd->SetToBeBroadcasted(false);
tripletCmd = new G4UIcmdWithAnInteger("/process/gconv/conversionType",this);
tripletCmd->SetGuidance("gamma conversion triplet/nuclear generation type:");
tripletCmd->SetGuidance("0 - (default) both triplet and nuclear");
@@ -526,6 +540,8 @@ G4EmParametersMessenger::~G4EmParametersMessenger()
delete nffCmd;
delete ssCmd;
delete fluc1Cmd;
delete posiCmd;
delete ortoCmd;
delete dumpCmd;
}
@@ -715,6 +731,12 @@ void G4EmParametersMessenger::SetNewValue(G4UIcommand* command,
if(newValue == "Dummy") { x = fDummyFluctuation; }
else if(newValue == "Urban") { x = fUrbanFluctuation; }
theParameters->SetFluctuationType(x);
} else if (command == posiCmd) {
G4PositronAtRestModelType x = fSimplePositronium;
if(newValue == "Allison") { x = fAllisonPositronium; }
theParameters->SetPositronAtRestModelType(x);
} else if ( command==ortoCmd ) {
theParameters->SetOrtoPsFraction(ortoCmd->GetNewDoubleValue(newValue));
} else if ( command==tripletCmd ) {
theParameters->SetConversionType(tripletCmd->GetNewIntValue(newValue));
} else if ( command==onIsolatedCmd ) {
@@ -66,7 +66,6 @@ G4EmTableUtil::PrepareEmProcess(G4VEmProcess* proc,
G4VEmModel* mod = modelManager->GetModel(i);
if(nullptr == mod) { continue; }
mod->SetPolarAngleLimit(plimit);
mod->SetMasterThread(master);
if(mod->HighEnergyLimit() > maxKinEnergy) {
mod->SetHighEnergyLimit(maxKinEnergy);
}
@@ -248,7 +247,7 @@ void G4EmTableUtil::BuildLambdaTable(G4VEmProcess* proc,
G4PhysicsTableHelper::SetPhysicsVector(theLambdaTable, i, aVector);
}
// build high energy table
if(nullptr != theLambdaTablePrim) {
if(nullptr != theLambdaTablePrim && minKinEnergyPrim < maxKinEnergy) {
delete (*theLambdaTablePrim)[i];
// start not from zero and always use spline
@@ -352,7 +351,7 @@ G4EmTableUtil::CheckIon(G4VEnergyLossProcess* proc,
if(part->GetParticleType() == "nucleus") {
G4String pname = part->GetParticleName();
if(pname != "deuteron" && pname != "triton" &&
pname != "alpha+" && pname != "alpha") {
pname != "He3" && pname != "alpha+" && pname != "alpha") {
const G4ParticleDefinition* theGIon = G4GenericIon::GenericIon();
isIon = true;
@@ -383,7 +382,7 @@ void G4EmTableUtil::UpdateModels(G4VEnergyLossProcess* proc,
const G4int nModels,
G4int& secID, G4int& biasID,
G4int& mainSec, const G4bool baseMat,
const G4bool isMaster, const G4bool useAGen)
const G4bool, const G4bool useAGen)
{
// defined ID of secondary particles
G4int stype = proc->GetProcessSubType();
@@ -398,7 +397,6 @@ void G4EmTableUtil::UpdateModels(G4VEnergyLossProcess* proc,
// initialisation of models
for(G4int i=0; i<nModels; ++i) {
G4VEmModel* mod = modelManager->GetModel(i);
mod->SetMasterThread(isMaster);
mod->SetAngularGeneratorFlag(useAGen);
if(mod->HighEnergyLimit() > maxKinEnergy) {
mod->SetHighEnergyLimit(maxKinEnergy);
@@ -546,7 +544,6 @@ void G4EmTableUtil::PrepareMscProcess(G4VMultipleScattering* proc,
for(G4int i=0; i<numberOfModels; ++i) {
G4VMscModel* msc = proc->GetModelByIndex(i);
msc->SetIonisation(nullptr, &part);
msc->SetMasterThread(master);
msc->SetPolarAngleLimit(param->MscThetaLimit());
G4double emax = std::min(msc->HighEnergyLimit(),param->MaxKinEnergy());
msc->SetHighEnergyLimit(emax);
@@ -566,15 +563,37 @@ void G4EmTableUtil::BuildMscProcess(G4VMultipleScattering* proc,
auto param = G4EmParameters::Instance();
G4int verb = param->Verbose();
if(!master && firstPart == &part) {
// initialisation of models
G4bool baseMat = masterProc->UseBaseMaterial();
for(G4int i=0; i<nModels; ++i) {
G4VMscModel* msc = proc->GetModelByIndex(i);
G4VMscModel* msc0 = masterProc->GetModelByIndex(i);
msc->SetUseBaseMaterials(baseMat);
msc->SetCrossSectionTable(msc0->GetCrossSectionTable(), false);
msc->InitialiseLocal(&part, msc0);
if (firstPart == &part) {
G4LossTableBuilder* bld = G4LossTableManager::Instance()->GetTableBuilder();
G4bool baseMat = bld->GetBaseMaterialFlag();
if (master) {
for (G4int i=0; i<nModels; ++i) {
G4VMscModel* msc = proc->GetModelByIndex(i);
msc->SetUseBaseMaterials(baseMat);
// table is always built for low mass particles
if (part.GetParticleName() != "GenericIon" &&
(part.GetPDGMass() < CLHEP::GeV || msc->ForceBuildTableFlag())) {
G4double emin =
std::max(msc->LowEnergyLimit(), msc->LowEnergyActivationLimit());
G4double emax =
std::min(msc->HighEnergyLimit(), msc->HighEnergyActivationLimit());
emin = std::max(emin, param->MinKinEnergy());
emax = std::min(emax, param->MaxKinEnergy());
if (emin < emax) {
auto table = bld->BuildTableForModel(msc->GetCrossSectionTable(),
msc, &part, emin, emax, true);
msc->SetCrossSectionTable(table, true);
}
}
}
} else {
for (G4int i=0; i<nModels; ++i) {
G4VMscModel* msc = proc->GetModelByIndex(i);
G4VMscModel* msc0 = masterProc->GetModelByIndex(i);
msc->SetUseBaseMaterials(baseMat);
msc->SetCrossSectionTable(msc0->GetCrossSectionTable(), false);
msc->InitialiseLocal(&part, msc0);
}
}
}
if(!param->IsPrintLocked()) {
@@ -671,7 +690,7 @@ G4bool G4EmTableUtil::RetrieveTable(G4VProcess* ptr,
{
G4bool res = true;
if (nullptr == aTable) { return res; }
if (0 < verb) {
if (1 < verb) {
G4cout << tname << " table for " << part->GetParticleName()
<< " will be retrieved " << G4endl;
}
@@ -685,7 +704,7 @@ G4bool G4EmTableUtil::RetrieveTable(G4VProcess* ptr,
}
if (0 < verb) {
G4cout << tname << " table for " << part->GetParticleName()
<< " is Retrieved from <" << name << ">"
<< " is retrieved from <" << name << ">"
<< G4endl;
}
} else {
@@ -66,6 +66,7 @@
#include "G4LossTableManager.hh"
#include "G4EmParameters.hh"
G4bool G4LossTableBuilder::baseMatFlag = false;
std::vector<G4double>* G4LossTableBuilder::theDensityFactor = nullptr;
std::vector<G4int>* G4LossTableBuilder::theDensityIdx = nullptr;
std::vector<G4bool>* G4LossTableBuilder::theFlag = nullptr;
@@ -73,19 +74,13 @@ std::vector<G4bool>* G4LossTableBuilder::theFlag = nullptr;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
G4LossTableBuilder::G4LossTableBuilder(G4bool master)
: isInitializer(master)
{
theParameters = G4EmParameters::Instance();
if (nullptr == theFlag) {
if (!master) {
G4ExceptionDescription ed;
ed << "The table builder is instantiated in a worker thread ";
G4Exception("G4LossTableBuilder::G4LossTableBuilder ", "em0001",
JustWarning, ed);
}
theDensityFactor = new std::vector<G4double>;
theDensityIdx = new std::vector<G4int>;
theFlag = new std::vector<G4bool>;
isInitializer = true;
}
}
@@ -105,14 +100,14 @@ G4LossTableBuilder::~G4LossTableBuilder()
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
const std::vector<G4int>* G4LossTableBuilder::GetCoupleIndexes() const
const std::vector<G4int>* G4LossTableBuilder::GetCoupleIndexes()
{
return theDensityIdx;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
const std::vector<G4double>* G4LossTableBuilder::GetDensityFactors() const
const std::vector<G4double>* G4LossTableBuilder::GetDensityFactors()
{
return theDensityFactor;
}
@@ -121,7 +116,6 @@ const std::vector<G4double>* G4LossTableBuilder::GetDensityFactors() const
G4bool G4LossTableBuilder::GetFlag(std::size_t idx)
{
if (theFlag->empty()) { InitialiseBaseMaterials(); }
return (idx < theFlag->size()) ? (*theFlag)[idx] : false;
}
@@ -129,7 +123,6 @@ G4bool G4LossTableBuilder::GetFlag(std::size_t idx)
G4bool G4LossTableBuilder::GetBaseMaterialFlag()
{
if (theFlag->empty()) { InitialiseBaseMaterials(); }
return baseMatFlag;
}
@@ -150,6 +143,7 @@ G4LossTableBuilder::BuildDEDXTable(G4PhysicsTable* dedxTable,
for (std::size_t i=0; i<nCouples; ++i) {
auto pv0 = static_cast<G4PhysicsLogVector*>((*(list[0]))[i]);
//if (0 == i) G4cout << i << ". pv0=" << pv0 << " t:" << list[0] << G4endl;
if(pv0 == nullptr) { continue; }
std::size_t npoints = pv0->GetVectorLength();
auto pv = new G4PhysicsLogVector(*pv0);
@@ -157,6 +151,7 @@ G4LossTableBuilder::BuildDEDXTable(G4PhysicsTable* dedxTable,
G4double dedx = 0.0;
for (std::size_t k=0; k<n_processes; ++k) {
const G4PhysicsVector* pv1 = (*(list[k]))[i];
//if (0 == i) G4cout << " " << k << ". pv1=" << pv1 << " t:" << list[k] << G4endl;
dedx += (*pv1)[j];
}
pv->PutValue(j, dedx);
@@ -311,64 +306,49 @@ void G4LossTableBuilder::InitialiseBaseMaterials(const G4PhysicsTable* table)
// reserve memory
theFlag->resize(nCouples, true);
if(nullptr == table) { return; }
if(baseMatFlag) {
theDensityFactor->resize(nCouples,1.0);
theDensityIdx->resize(nCouples);
}
theDensityFactor->resize(nCouples,1.0);
theDensityIdx->resize(nCouples, 0);
// define default flag and index of used material cut couple
for(G4int i=0; i<(G4int)nCouples; ++i) {
(*theFlag)[i] = table->GetFlag(i);
if(baseMatFlag) { (*theDensityIdx)[i] = i; }
for (G4int i=0; i<(G4int)nCouples; ++i) {
(*theFlag)[i] = (nullptr == table) ? true : table->GetFlag(i);
(*theDensityIdx)[i] = i;
}
isInitialized = true;
if(baseMatFlag) {
// use base materials
for(G4int i=0; i<(G4int)nCouples; ++i) {
// base material is needed only for a couple which is not
// initialised and for which tables will be computed
auto couple = theCoupleTable->GetMaterialCutsCouple(i);
auto pcuts = couple->GetProductionCuts();
auto mat = couple->GetMaterial();
auto bmat = mat->GetBaseMaterial();
if (!baseMatFlag) { return; }
// base material exists - find it and check if it can be reused
if(nullptr != bmat) {
for(G4int j=0; j<(G4int)nCouples; ++j) {
if(j == i) { continue; }
auto bcouple = theCoupleTable->GetMaterialCutsCouple(j);
// use base materials
for (G4int i=0; i<(G4int)nCouples; ++i) {
// base material is needed only for a couple which is not
// initialised and for which tables will be computed
auto couple = theCoupleTable->GetMaterialCutsCouple(i);
auto pcuts = couple->GetProductionCuts();
auto mat = couple->GetMaterial();
auto bmat = mat->GetBaseMaterial();
if(bcouple->GetMaterial() == bmat &&
bcouple->GetProductionCuts() == pcuts) {
// base material exists - find it and check if it can be reused
if(nullptr != bmat) {
for(G4int j=0; j<(G4int)nCouples; ++j) {
if(j == i) { continue; }
auto bcouple = theCoupleTable->GetMaterialCutsCouple(j);
// based couple exist in the same region
(*theDensityFactor)[i] = mat->GetDensity()/bmat->GetDensity();
(*theDensityIdx)[i] = j;
(*theFlag)[i] = false;
if(bcouple->GetMaterial() == bmat &&
bcouple->GetProductionCuts() == pcuts) {
// ensure that there will no double initialisation
(*theDensityFactor)[j] = 1.0;
(*theDensityIdx)[j] = j;
(*theFlag)[j] = true;
break;
}
// based couple exist in the same region
(*theDensityFactor)[i] = mat->GetDensity()/bmat->GetDensity();
(*theDensityIdx)[i] = j;
(*theFlag)[i] = false;
// ensure that there will no double initialisation
(*theDensityFactor)[j] = 1.0;
(*theDensityIdx)[j] = j;
(*theFlag)[j] = true;
break;
}
}
}
}
/*
G4cout << "### G4LossTableBuilder::InitialiseBaseMaterials: flag="
<< baseMatFlag << G4endl;
for(std::size_t i=0; i<nCouples; ++i) {
G4cout << "CoupleIdx=" << i << " Flag= " << (*theFlag)[i] << " "
<< theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial()->GetName()
<< " TableFlag= " << table->GetFlag(i)
<< " " << (*table)[i]
<< G4endl;
}
*/
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@@ -382,13 +362,12 @@ G4LossTableBuilder::BuildTableForModel(G4PhysicsTable* aTable,
{
// check input
G4PhysicsTable* table = G4PhysicsTableHelper::PreparePhysicsTable(aTable);
if(nullptr == table) { return table; }
if(emin >= emax) {
table->clearAndDestroy();
delete table;
table = nullptr;
return table;
if (nullptr == table) { return table; }
if (aTable != nullptr && aTable != table) {
aTable->clearAndDestroy();
delete aTable;
}
InitialiseBaseMaterials(table);
G4int nbins = theParameters->NumberOfBinsPerDecade();
@@ -396,21 +375,25 @@ G4LossTableBuilder::BuildTableForModel(G4PhysicsTable* aTable,
const G4ProductionCutsTable* theCoupleTable=
G4ProductionCutsTable::GetProductionCutsTable();
std::size_t numOfCouples = theCoupleTable->GetTableSize();
/*
G4cout << " G4LossTableBuilder::BuildTableForModel Ncouple=" << numOfCouples
<< " isMaster=" << isInitializer << " model:" << model->GetName()
<< " " << part->GetParticleName() << G4endl;
*/
G4PhysicsLogVector* aVector = nullptr;
for(G4int i=0; i<(G4int)numOfCouples; ++i) {
if ((*theFlag)[i]) {
//G4cout << i << ". " << (*theFlag)[i] << " " << table->GetFlag(i) << G4endl;
if (table->GetFlag(i)) {
// create physics vector and fill it
auto couple = theCoupleTable->GetMaterialCutsCouple(i);
delete (*table)[i];
// if start from zero then change the scale
const G4Material* mat = couple->GetMaterial();
G4double tmin = std::max(emin,model->MinPrimaryEnergy(mat,part));
G4double tmin = std::max(emin, model->MinPrimaryEnergy(mat,part));
if(0.0 >= tmin) { tmin = CLHEP::eV; }
G4int n = nbins;
@@ -424,10 +407,12 @@ G4LossTableBuilder::BuildTableForModel(G4PhysicsTable* aTable,
if(nullptr != aVector) {
//G4cout << part->GetParticleName() << " in " << mat->GetName()
// << " tmin= " << tmin << G4endl;
// << " emin= " << tmin << " emax=" << emax << " n=" << n << G4endl;
for(G4int j=0; j<=n; ++j) {
aVector->PutValue(j, model->Value(couple, part,
aVector->Energy(j)));
G4double e = aVector->Energy(j);
G4double y = model->Value(couple, part, e);
//G4cout << " " << j << ") E=" << e << " y=" << y << G4endl;
aVector->PutValue(j, y);
}
if(spline) { aVector->FillSecondDerivatives(); }
}
@@ -71,7 +71,6 @@
#include "G4EmTableType.hh"
#include "G4Region.hh"
#include "G4PhysicalConstants.hh"
#include "G4Threading.hh"
#include "G4Gamma.hh"
#include "G4Positron.hh"
@@ -79,9 +78,11 @@
#include "G4Neutron.hh"
#include "G4MuonPlus.hh"
#include "G4MuonMinus.hh"
#include "G4GenericIon.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
static std::once_flag applyOnce;
G4ThreadLocal G4LossTableManager* G4LossTableManager::instance = nullptr;
G4LossTableManager* G4LossTableManager::Instance()
@@ -132,13 +133,12 @@ G4LossTableManager::~G4LossTableManager()
G4LossTableManager::G4LossTableManager()
{
theParameters = G4EmParameters::Instance();
verbose = theParameters->Verbose();
theElectron = G4Electron::Electron();
theGenericIon= nullptr;
if(G4Threading::IsWorkerThread()) {
verbose = theParameters->WorkerVerbose();
isMaster = false;
}
// only one thread is the master
std::call_once(applyOnce, [this]() { isMaster = true; });
verbose = isMaster ? theParameters->Verbose() : theParameters->WorkerVerbose();
tableBuilder = new G4LossTableBuilder(isMaster);
emCorrections = new G4EmCorrections(verbose);
@@ -182,7 +182,7 @@ void G4LossTableManager::Clear()
void G4LossTableManager::Register(G4VEnergyLossProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
for (G4int i=0; i<n_loss; ++i) {
if(loss_vector[i] == p) { return; }
}
@@ -206,13 +206,20 @@ void G4LossTableManager::Register(G4VEnergyLossProcess* p)
void G4LossTableManager::ResetParameters()
{
// initialisation once per run
if (!resetParam) { return; }
resetParam = false;
startInitialisation = true;
verbose = theParameters->Verbose();
if(!isMaster) {
verbose = theParameters->WorkerVerbose();
} else {
if(verbose > 0) { theParameters->Dump(); }
}
tableBuilder->SetInitialisationFlag(false);
tableBuilder->InitialiseBaseMaterials();
if (nullptr != nielCalculator) { nielCalculator->Initialise(); }
emCorrections->SetVerbose(verbose);
if(nullptr != emConfigurator) { emConfigurator->SetVerbose(verbose); };
if(nullptr != emElectronIonPair) { emElectronIonPair->SetVerbose(verbose); };
@@ -220,13 +227,19 @@ void G4LossTableManager::ResetParameters()
atomDeexcitation->SetVerboseLevel(verbose);
atomDeexcitation->InitialiseAtomicDeexcitation();
}
if (1 < verbose) {
G4cout << "====== G4LossTableManager::ResetParameters "
<< " Nloss=" << loss_vector.size()
<< " run=" << run << " master=" << isMaster
<< G4endl;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
void G4LossTableManager::DeRegister(G4VEnergyLossProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
for (G4int i=0; i<n_loss; ++i) {
if(loss_vector[i] == p) {
loss_vector[i] = nullptr;
@@ -239,7 +252,7 @@ void G4LossTableManager::DeRegister(G4VEnergyLossProcess* p)
void G4LossTableManager::Register(G4VMultipleScattering* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t n = msc_vector.size();
for (std::size_t i=0; i<n; ++i) {
if(msc_vector[i] == p) { return; }
@@ -255,7 +268,7 @@ void G4LossTableManager::Register(G4VMultipleScattering* p)
void G4LossTableManager::DeRegister(G4VMultipleScattering* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t msc = msc_vector.size();
for (std::size_t i=0; i<msc; ++i) {
if(msc_vector[i] == p) {
@@ -269,7 +282,7 @@ void G4LossTableManager::DeRegister(G4VMultipleScattering* p)
void G4LossTableManager::Register(G4VEmProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t n = emp_vector.size();
for (std::size_t i=0; i<n; ++i) {
if(emp_vector[i] == p) { return; }
@@ -285,7 +298,7 @@ void G4LossTableManager::Register(G4VEmProcess* p)
void G4LossTableManager::DeRegister(G4VEmProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t emp = emp_vector.size();
for (std::size_t i=0; i<emp; ++i) {
if(emp_vector[i] == p) {
@@ -299,7 +312,7 @@ void G4LossTableManager::DeRegister(G4VEmProcess* p)
void G4LossTableManager::Register(G4VProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t n = p_vector.size();
for (std::size_t i=0; i<n; ++i) {
if(p_vector[i] == p) { return; }
@@ -315,7 +328,7 @@ void G4LossTableManager::Register(G4VProcess* p)
void G4LossTableManager::DeRegister(G4VProcess* p)
{
if(!p) { return; }
if (nullptr == p) { return; }
std::size_t emp = p_vector.size();
for (std::size_t i=0; i<emp; ++i) {
if(p_vector[i] == p) {
@@ -377,7 +390,7 @@ void G4LossTableManager::RegisterExtraParticle(
const G4ParticleDefinition* part,
G4VEnergyLossProcess* p)
{
if(!p || !part) { return; }
if (nullptr == p || nullptr == part) { return; }
for (G4int i=0; i<n_loss; ++i) {
if(loss_vector[i] == p) { return; }
}
@@ -428,32 +441,26 @@ G4LossTableManager::PreparePhysicsTable(const G4ParticleDefinition* particle,
G4cout << "G4LossTableManager::PreparePhysicsTable for "
<< particle->GetParticleName()
<< " and " << p->GetProcessName() << " run= " << run
<< " loss_vector " << loss_vector.size() << G4endl;
}
if(!startInitialisation) {
ResetParameters();
if (1 < verbose) {
G4cout << "====== G4LossTableManager::PreparePhysicsTable start ====="
<< G4endl;
}
<< " loss_vector " << loss_vector.size()
<< " run=" << run << " master=" << isMaster
<< G4endl;
}
// start initialisation for the first run
if( -1 == run ) {
if(emConfigurator) { emConfigurator->PrepareModels(particle, p); }
if (nullptr != emConfigurator) { emConfigurator->PrepareModels(particle, p); }
// initialise particles for given process
for (G4int j=0; j<n_loss; ++j) {
if (p == loss_vector[j] && !part_vector[j]) {
if (p == loss_vector[j] && nullptr == part_vector[j]) {
part_vector[j] = particle;
if(particle->GetParticleName() == "GenericIon") {
if (particle->GetParticleName() == "GenericIon") {
theGenericIon = particle;
}
}
}
}
startInitialisation = true;
ResetParameters();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -465,22 +472,17 @@ G4LossTableManager::PreparePhysicsTable(const G4ParticleDefinition* particle,
if (1 < verbose) {
G4cout << "G4LossTableManager::PreparePhysicsTable for "
<< particle->GetParticleName()
<< " and " << p->GetProcessName() << G4endl;
}
if(!startInitialisation) {
ResetParameters();
if (1 < verbose) {
G4cout << "====== G4LossTableManager::PreparePhysicsTable start ====="
<< G4endl;
}
<< " and " << p->GetProcessName()
<< " run=" << run << " master=" << isMaster
<< G4endl;
}
// start initialisation for the first run
if( -1 == run ) {
if(emConfigurator) { emConfigurator->PrepareModels(particle, p); }
if (nullptr != emConfigurator) { emConfigurator->PrepareModels(particle, p); }
}
startInitialisation = true;
ResetParameters();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -492,22 +494,17 @@ G4LossTableManager::PreparePhysicsTable(const G4ParticleDefinition* particle,
if (1 < verbose) {
G4cout << "G4LossTableManager::PreparePhysicsTable for "
<< particle->GetParticleName()
<< " and " << p->GetProcessName() << G4endl;
}
if(!startInitialisation) {
ResetParameters();
if (1 < verbose) {
G4cout << "====== G4LossTableManager::PreparePhysicsTable start ====="
<< G4endl;
}
<< " and " << p->GetProcessName()
<< " run=" << run << " master=" << isMaster
<< G4endl;
}
// start initialisation for the first run
if( -1 == run ) {
if(emConfigurator) { emConfigurator->PrepareModels(particle, p); }
if ( -1 == run ) {
if (nullptr != emConfigurator) { emConfigurator->PrepareModels(particle, p); }
}
startInitialisation = true;
ResetParameters();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -516,8 +513,9 @@ void
G4LossTableManager::BuildPhysicsTable(const G4ParticleDefinition*)
{
if(-1 == run && startInitialisation) {
if(emConfigurator) { emConfigurator->Clear(); }
if (nullptr != emConfigurator) { emConfigurator->Clear(); }
}
if (startInitialisation) { resetParam = true; }
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -526,7 +524,7 @@ void G4LossTableManager::LocalPhysicsTables(
const G4ParticleDefinition* aParticle,
G4VEnergyLossProcess* p)
{
if(1 < verbose) {
if (1 < verbose) {
G4cout << "### G4LossTableManager::LocalPhysicsTable() for "
<< aParticle->GetParticleName()
<< " and process " << p->GetProcessName()
@@ -534,20 +532,21 @@ void G4LossTableManager::LocalPhysicsTables(
}
if(-1 == run && startInitialisation) {
if(emConfigurator) { emConfigurator->Clear(); }
if (nullptr != emConfigurator) { emConfigurator->Clear(); }
firstParticle = aParticle;
}
if(startInitialisation) {
if (startInitialisation) {
++run;
if(1 < verbose) {
if (1 < verbose) {
G4cout << "===== G4LossTableManager::LocalPhysicsTable() for run "
<< run << " =====" << G4endl;
}
currentParticle = nullptr;
startInitialisation = false;
resetParam = true;
for (G4int i=0; i<n_loss; ++i) {
if(loss_vector[i]) {
if (nullptr != loss_vector[i]) {
tables_are_built[i] = false;
} else {
tables_are_built[i] = true;
@@ -611,39 +610,28 @@ void G4LossTableManager::BuildPhysicsTable(
}
// clear configurator
if(-1 == run && startInitialisation) {
if(emConfigurator) { emConfigurator->Clear(); }
if( nullptr != emConfigurator) { emConfigurator->Clear(); }
firstParticle = aParticle;
}
if(startInitialisation) {
++run;
resetParam = true;
startInitialisation = false;
if(1 < verbose) {
G4cout << "===== G4LossTableManager::BuildPhysicsTable() for run "
<< run << " ===== " << atomDeexcitation << G4endl;
}
currentParticle = nullptr;
all_tables_are_built= true;
}
// initialisation before any table is built
if ( startInitialisation && aParticle == firstParticle ) {
startInitialisation = false;
if(1 < verbose) {
G4cout << "### G4LossTableManager start initialisation for first particle "
<< firstParticle->GetParticleName()
<< G4endl;
}
if(nielCalculator) { nielCalculator->Initialise(); }
all_tables_are_built = false;
for (G4int i=0; i<n_loss; ++i) {
G4VEnergyLossProcess* el = loss_vector[i];
if(el) {
if(nullptr != el) {
isActive[i] = true;
part_vector[i] = el->Particle();
base_part_vector[i] = el->BaseParticle();
tables_are_built[i] = false;
all_tables_are_built= false;
tables_are_built[i] = false;
if(1 < verbose) {
G4cout << i <<". "<< el->GetProcessName();
if(el->Particle()) {
@@ -675,7 +663,7 @@ void G4LossTableManager::BuildPhysicsTable(
all_tables_are_built = true;
for(G4int i=0; i<n_loss; ++i) {
if(p == loss_vector[i] && !tables_are_built[i] && !base_part_vector[i]) {
if(p == loss_vector[i] && !tables_are_built[i] && nullptr == base_part_vector[i]) {
const G4ParticleDefinition* curr_part = part_vector[i];
if(1 < verbose) {
G4cout << "### Build Table for " << p->GetProcessName()
@@ -701,12 +689,6 @@ void G4LossTableManager::BuildPhysicsTable(
<< "all_tables_are_built= " << all_tables_are_built << " "
<< aParticle->GetParticleName() << " proc: " << p << G4endl;
}
if(all_tables_are_built) {
if(1 < verbose) {
G4cout << "%%%%% All dEdx and Range tables are built for master run= "
<< run << " %%%%%" << G4endl;
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
@@ -720,13 +702,13 @@ void G4LossTableManager::CopyTables(const G4ParticleDefinition* part,
if (!tables_are_built[j] && part == base_part_vector[j]) {
tables_are_built[j] = true;
// for base particle approach only ionisation table should be used
proc->SetDEDXTable(base_proc->IonisationTable(),fRestricted);
proc->SetDEDXTable(base_proc->DEDXunRestrictedTable(),fTotal);
proc->SetCSDARangeTable(base_proc->CSDARangeTable());
proc->SetRangeTableForLoss(base_proc->RangeTableForLoss());
proc->SetInverseRangeTable(base_proc->InverseRangeTable());
proc->SetLambdaTable(base_proc->LambdaTable());
proc->SetIonisation(base_proc->IsIonisationProcess());
if(proc->IsIonisationProcess()) {
range_vector[j] = base_proc->RangeTableForLoss();
inv_range_vector[j] = base_proc->InverseRangeTable();
@@ -736,7 +718,7 @@ void G4LossTableManager::CopyTables(const G4ParticleDefinition* part,
// << " added to map " << proc << G4endl;
}
if (1 < verbose) {
G4cout << "For " << proc->GetProcessName()
G4cout << " CopyTables for " << proc->GetProcessName()
<< " for " << part_vector[j]->GetParticleName()
<< " base_part= " << part->GetParticleName()
<< " tables are assigned"
@@ -752,7 +734,7 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
const G4ParticleDefinition* aParticle)
{
if(1 < verbose) {
G4cout << "G4LossTableManager::BuildTables() for "
G4cout << " G4LossTableManager::BuildTables(part) for "
<< aParticle->GetParticleName() << G4endl;
}
@@ -771,7 +753,7 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
for (i=0; i<n_loss; ++i) {
p = loss_vector[i];
if (p) {
if (nullptr != p) {
G4bool yes = (aParticle == part_vector[i]);
// possible case of process sharing between particle/anti-particle
@@ -819,8 +801,7 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
G4int nSubRegions = em->NumberOfSubCutoffRegions();
if (1 < verbose) {
G4cout << "G4LossTableManager::BuildTables() start to build range tables"
<< " and the sum of " << n_dedx << " processes"
G4cout << " Start to build the sum of " << n_dedx << " processes"
<< " iem= " << iem << " em= " << em->GetProcessName()
<< " buildCSDARange= " << theParameters->BuildCSDARange()
<< " nSubRegions= " << nSubRegions;
@@ -832,8 +813,7 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
// do not build tables if producer class is defined
if(subcutProducer) { nSubRegions = 0; }
dedx = em->DEDXTable();
em->SetIonisation(true);
dedx = em->DEDXTable();
em->SetDEDXTable(dedx, fIsIonisation);
if (1 < n_dedx) {
@@ -843,15 +823,6 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
em->SetDEDXTable(dedx, fRestricted);
}
/*
if(2==run && "e-" == aParticle->GetParticleName()) {
G4cout << "G4LossTableManager::BuildTables for e- " << dedx << G4endl;
G4cout << (*dedx) << G4endl;
G4cout << "%%%%% Instance ID= " << (*dedx)[0]->GetInstanceID() << G4endl;
G4cout << "%%%%% LastValue= " << (*dedx)[0]->GetLastValue() << G4endl;
G4cout << "%%%%% 1.2 " << (*(dedx))[0]->Value(1.2) << G4endl;
}
*/
dedx_vector[iem] = dedx;
G4PhysicsTable* range = em->RangeTableForLoss();
@@ -865,18 +836,13 @@ G4VEnergyLossProcess* G4LossTableManager::BuildTables(
tableBuilder->BuildRangeTable(dedx, range);
tableBuilder->BuildInverseRangeTable(range, invrange);
// if(1<verbose) G4cout << *dedx << G4endl;
em->SetRangeTableForLoss(range);
em->SetInverseRangeTable(invrange);
// if(1<verbose) G4cout << *range << G4endl;
std::vector<G4PhysicsTable*> listCSDA;
for (i=0; i<n_dedx; ++i) {
p = loss_list[i];
if(p != em) { p->SetIonisation(false); }
if(build_flags[i]) {
p->SetLambdaTable(p->BuildLambdaTable(fRestricted));
}
@@ -983,7 +949,7 @@ G4ElectronIonPair* G4LossTableManager::ElectronIonPair()
void G4LossTableManager::SetNIELCalculator(G4NIELCalculator* ptr)
{
if(ptr && ptr != nielCalculator) {
if(nullptr != ptr && ptr != nielCalculator) {
delete nielCalculator;
nielCalculator = ptr;
}
@@ -159,7 +159,6 @@ void G4TransportationWithMsc::PreparePhysicsTable(const G4ParticleDefinition& pa
if (fType == ScatteringType::MultipleScattering) {
for (G4int i = 0; i < numberOfModels; ++i) {
auto msc = static_cast<G4VMscModel*>(fModelManager->GetModel(i));
msc->SetMasterThread(master);
msc->SetPolarAngleLimit(theParameters->MscThetaLimit());
G4double emax = std::min(msc->HighEnergyLimit(), theParameters->MaxKinEnergy());
msc->SetHighEnergyLimit(emax);
@@ -74,7 +74,8 @@ G4VEmModel::G4VEmModel(const G4String& nam):
xsec.resize(nsec);
fEmManager = G4LossTableManager::Instance();
fEmManager->Register(this);
isMaster = fEmManager->IsMaster();
G4LossTableBuilder* bld = fEmManager->GetTableBuilder();
theDensityFactor = bld->GetDensityFactors();
theDensityIdx = bld->GetCoupleIndexes();
@@ -396,13 +397,7 @@ G4VEmModel::SetParticleChange(G4VParticleChange* p, G4VEmFluctuationModel* f)
void G4VEmModel::SetCrossSectionTable(G4PhysicsTable* p, G4bool isLocal)
{
if(p != xSectionTable) {
if(xSectionTable != nullptr && localTable) {
xSectionTable->clearAndDestroy();
delete xSectionTable;
}
xSectionTable = p;
}
xSectionTable = p;
localTable = isLocal;
}
@@ -419,6 +414,11 @@ void G4VEmModel::SetLPMFlag(G4bool)
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void G4VEmModel::SetMasterThread(G4bool)
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4VEmModel::ModelDescription(std::ostream& outFile) const
@@ -153,7 +153,7 @@ void G4VEmProcess::PreparePhysicsTable(const G4ParticleDefinition& part)
G4String pname = part.GetParticleName();
if(pname != "deuteron" && pname != "triton" &&
pname != "alpha" && pname != "alpha+" &&
pname != "He3" && pname != "alpha" && pname != "alpha+" &&
pname != "helium" && pname != "hydrogen") {
particle = G4GenericIon::GenericIon();
@@ -272,8 +272,14 @@ void G4VEmProcess::StreamInfo(std::ostream& out,
}
if(fXSType != fEmNoIntegral) { out << " XStype:" << fXSType; }
if(applyCuts) { out << " applyCuts:1 "; }
out << " SubType=" << GetProcessSubType();
if(biasFactor != 1.0) { out << " BiasingFactor= " << biasFactor; }
G4int subtype = GetProcessSubType();
out << " SubType=" << subtype;
if (subtype == fAnnihilation) {
G4int mod = theParameters->PositronAtRestModelType();
const G4String namp[2] = {"Simple", "Allison"};
out << " AtRestModel:" << namp[mod];
}
if(biasFactor != 1.0) { out << " BiasingFactor=" << biasFactor; }
out << " BuildTable=" << buildLambdaTable << G4endl;
if(buildLambdaTable) {
if(particle == &part) {
@@ -554,7 +560,7 @@ G4VParticleChange* G4VEmProcess::PostStepDoIt(const G4Track& track,
G4double time = track.GetGlobalTime();
G4int n1(0), n2(0);
if(num > mainSecondaries) {
if(num0 > mainSecondaries) {
currentModel->FillNumberOfSecondaries(n1, n2);
}
@@ -608,7 +614,7 @@ G4VParticleChange* G4VEmProcess::PostStepDoIt(const G4Track& track,
t->SetCreatorModelID(augerID);
}
} else {
t->SetCreatorModelID(secID);
t->SetCreatorModelID(biasID);
}
}
/*
@@ -218,6 +218,7 @@ G4VEnergyLossProcess::PreparePhysicsTable(const G4ParticleDefinition& part)
}
tablesAreBuilt = false;
if (GetProcessSubType() == fIonisation) { SetIonisation(true); }
G4LossTableBuilder* bld = lManager->GetTableBuilder();
lManager->PreparePhysicsTable(&part, this);
@@ -962,7 +963,18 @@ void G4VEnergyLossProcess::FillSecondariesAlongStep(G4double wt)
if(nullptr != t) {
t->SetWeight(weight);
pParticleChange->AddSecondary(t);
if(i >= n0) { t->SetCreatorModelID(biasID); }
G4int pdg = t->GetDefinition()->GetPDGEncoding();
if (i < n0) {
if (pdg == 22) {
t->SetCreatorModelID(gpixeID);
} else if (pdg == 11) {
t->SetCreatorModelID(epixeID);
} else {
t->SetCreatorModelID(biasID);
}
} else {
t->SetCreatorModelID(biasID);
}
}
}
scTracks.clear();
@@ -1110,17 +1122,19 @@ G4bool G4VEnergyLossProcess::StorePhysicsTable(
{
if (!isMaster || nullptr != baseParticle || part != particle ) return true;
for(std::size_t i=0; i<7; ++i) {
if(nullptr != theData->Table(i)) {
if(1 < verboseLevel) {
G4cout << "G4VEnergyLossProcess::StorePhysicsTable i=" << i
<< " " << particle->GetParticleName()
<< " " << GetProcessName()
<< " " << tnames[i] << " " << theData->Table(i) << G4endl;
}
if(!G4EmTableUtil::StoreTable(this, part, theData->Table(i),
dir, tnames[i], verboseLevel, ascii)) {
return false;
}
// ionisation table only for ionisation process
if (nullptr == theData->Table(i) || (!isIonisation && 1 == i)) {
continue;
}
if (-1 < verboseLevel) {
G4cout << "G4VEnergyLossProcess::StorePhysicsTable i=" << i
<< " " << particle->GetParticleName()
<< " " << GetProcessName()
<< " " << tnames[i] << " " << theData->Table(i) << G4endl;
}
if (!G4EmTableUtil::StoreTable(this, part, theData->Table(i),
dir, tnames[i], verboseLevel, ascii)) {
return false;
}
}
return true;
@@ -1134,6 +1148,8 @@ G4VEnergyLossProcess::RetrievePhysicsTable(const G4ParticleDefinition* part,
{
if (!isMaster || nullptr != baseParticle || part != particle ) return true;
for(std::size_t i=0; i<7; ++i) {
// ionisation table only for ionisation process
if (!isIonisation && 1 == i) { continue; }
if(!G4EmTableUtil::RetrieveTable(this, part, theData->Table(i), dir, tnames[i],
verboseLevel, ascii, spline)) {
return false;
@@ -74,7 +74,7 @@ G4VMscModel::~G4VMscModel() = default;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ParticleChangeForMSC*
G4VMscModel::GetParticleChangeForMSC(const G4ParticleDefinition* p)
G4VMscModel::GetParticleChangeForMSC(const G4ParticleDefinition*)
{
// recomputed for each new run
if(nullptr == safetyHelper) {
@@ -88,25 +88,6 @@ G4VMscModel::GetParticleChangeForMSC(const G4ParticleDefinition* p)
} else {
change = new G4ParticleChangeForMSC();
}
if(IsMaster() && nullptr != p) {
// table is always built for low mass particles
if(p->GetParticleName() != "GenericIon" &&
(p->GetPDGMass() < CLHEP::GeV || ForceBuildTableFlag()) ) {
G4EmParameters* param = G4EmParameters::Instance();
G4LossTableBuilder* builder =
G4LossTableManager::Instance()->GetTableBuilder();
G4double emin = std::max(LowEnergyLimit(), LowEnergyActivationLimit());
G4double emax = std::min(HighEnergyLimit(), HighEnergyActivationLimit());
emin = std::max(emin, param->MinKinEnergy());
emax = std::min(emax, param->MaxKinEnergy());
if(emin < emax) {
xSectionTable = builder->BuildTableForModel(xSectionTable, this, p,
emin, emax, useSpline);
}
}
}
return change;
}
@@ -141,25 +141,24 @@ void
G4VMultipleScattering::PreparePhysicsTable(const G4ParticleDefinition& part)
{
G4bool master = emManager->IsMaster();
if(nullptr == firstParticle) { firstParticle = &part; }
if (nullptr == firstParticle) { firstParticle = &part; }
emManager->PreparePhysicsTable(&part, this);
currParticle = nullptr;
if(firstParticle == &part) {
baseMat = emManager->GetTableBuilder()->GetBaseMaterialFlag();
G4EmTableUtil::PrepareMscProcess(this, part, modelManager,
stepLimit, facrange,
latDisplacement, master,
isIon, baseMat);
stepLimit, facrange,
latDisplacement, master,
isIon, baseMat);
numberOfModels = modelManager->NumberOfModels();
currentModel = GetModelByIndex(0);
if(nullptr == safetyHelper) {
if (nullptr == safetyHelper) {
safetyHelper = G4TransportationManager::GetTransportationManager()
->GetSafetyHelper();
->GetSafetyHelper();
safetyHelper->InitialiseHelper();
}
}
@@ -171,8 +170,8 @@ void G4VMultipleScattering::BuildPhysicsTable(const G4ParticleDefinition& part)
{
G4bool master = emManager->IsMaster();
if(firstParticle == &part) {
emManager->BuildPhysicsTable(firstParticle);
if(firstParticle == &part) {
emManager->BuildPhysicsTable(&part);
}
const G4VMultipleScattering* ptr = this;
if(!master) {
@@ -6,10 +6,14 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-01-10 Soon Yung Jun (xrays-V11-01-10)
## 2024-05-16 Vladimir Grichine (xrays-V11-02-02)
- G4XTRGaussRadModel.hh/.cc class was added with improved account
on the origin of theXTR photon
## 2024-01-10 Soon Yung Jun (xrays-V11-02-01)
- G4Scintillation::sample_time - refactor the scintillation time sampling
## 2023-12-16 Vladimir Grichine
## 2023-12-16 Vladimir Grichine (xrays-V11-02-00)
- G4GaussXTRadiator, G4VXTRenergyLoss - flexible summation in
SpectralXTRdEdx, clean-up in GetStackFactor based on std::complex methods
@@ -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. *
// ********************************************************************
//
///////////////////////////////////////////////////////////////////////////
//
// Process describing a radiator of X-ray transition radiation.
// Regular radiator with thicknesses of plates and gas gaps are Gauss-distributed.
// We suppose that:
// formation zone ~ mean thickness << absorption length
// for each material and in the range 1-100 keV. This allows us to simplify
// interference effects in radiator stack (GetStackFactor method).
// The XTR photons are moved to the end of radiator.
//
// History:
//
// 19.04.24 V. Grichine, first version
//
#ifndef G4XTRGaussRadModel_h
#define G4XTRGaussRadModel_h 1
#include "G4LogicalVolume.hh"
#include "G4Material.hh"
#include "G4VXTRenergyLoss.hh"
class G4XTRGaussRadModel : public G4VXTRenergyLoss
{
public:
explicit G4XTRGaussRadModel(
G4LogicalVolume* anEnvelope, G4double, G4double, G4Material*, G4Material*, G4double, G4double,
G4int, const G4String& processName = "XTRGaussRadModel");
~G4XTRGaussRadModel() override;
// reimplementation of base class function in analytical way
G4double SpectralXTRdEdx(G4double energy) override;
G4double GetStackFactor(G4double energy, G4double gamma,
G4double varAngle) override;
void ProcessDescription(std::ostream&) const override;
void DumpInfo() const override { ProcessDescription(G4cout); };
};
#endif
@@ -19,6 +19,7 @@ geant4_add_module(G4xrays
G4VTransitionRadiation.hh
G4VXTRenergyLoss.hh
G4XTRGammaRadModel.hh
G4XTRGaussRadModel.hh
G4XTRRegularRadModel.hh
G4XTRTransparentRegRadModel.hh
G4XrayReflection.hh
@@ -38,6 +39,7 @@ geant4_add_module(G4xrays
G4VTransitionRadiation.cc
G4VXTRenergyLoss.cc
G4XTRGammaRadModel.cc
G4XTRGaussRadModel.cc
G4XTRRegularRadModel.cc
G4XTRTransparentRegRadModel.cc
G4XrayReflection.cc)
@@ -144,10 +144,10 @@ G4double G4GaussXTRadiator::GetStackFactor(G4double energy,
G4complex ordernn = ( order1 + order2 )*nn;
G4complex Ha = exp( order1 );
G4complex Hb = exp( order2 );
G4complex Ha = std::exp( order1 );
G4complex Hb = std::exp( order2 );
G4complex H = Ha * Hb;
G4complex Hn = exp( ordernn );
G4complex Hn = std::exp( ordernn );
G4complex F1 = ( 1.0 - Ha ) * ( 1.0 - Hb ) * nn / ( 1. - H );
@@ -0,0 +1,191 @@
//
// ********************************************************************
// * 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. *
// ********************************************************************
//
// 19.04.24 V. Grichine, first version
//
#include "G4XTRGaussRadModel.hh"
#include "G4PhysicalConstants.hh"
#include "G4Material.hh"
#include "G4Element.hh"
#include "G4NistManager.hh"
using namespace std;
using namespace CLHEP;
////////////////////////////////////////////////////////////////////////////
// Constructor, destructor
G4XTRGaussRadModel::G4XTRGaussRadModel(
G4LogicalVolume* anEnvelope, G4double alphaPlate, G4double alphaGas, G4Material* foilMat, G4Material* gasMat,
G4double aa, G4double b, G4int n, const G4String& processName)
: G4VXTRenergyLoss(anEnvelope, foilMat, gasMat, aa, b, n, processName)
{
if( verboseLevel > 0 )
G4cout << "G4XTRGaussRadModel EM process is called"
<< G4endl;
fAlphaPlate = alphaPlate; // ~40
fAlphaGas = alphaGas; // ~10
fExitFlux = true; // XTR photons are moved to the end of radiator
}
///////////////////////////////////////////////////////////////////////////
G4XTRGaussRadModel::~G4XTRGaussRadModel() = default;
///////////////////////////////////////////////////////////////////////////
void G4XTRGaussRadModel::ProcessDescription(std::ostream& out) const
{
out << "Simulation of forward X-ray transition radiation generated by\n"
"relativistic charged particles crossing the interface between\n"
"two materials.\n";
}
///////////////////////////////////////////////////////////////////////////
G4double G4XTRGaussRadModel::SpectralXTRdEdx(G4double energy)
{
static constexpr G4double cofPHC = 4. * pi * hbarc;
G4double result, sum = 0., tmp, cof1, cof2, cofMin, theta2, theta2k;
G4double aMa, bMb, sigma, dump;
G4int k, kMax, kMin;
aMa = fPlateThick * GetPlateLinearPhotoAbs(energy);
bMb = fGasThick * GetGasLinearPhotoAbs(energy);
sigma = 0.5 * (aMa + bMb);
dump = std::exp(-fPlateNumber * sigma);
if(verboseLevel > 2)
G4cout << " dump = " << dump << G4endl;
tmp = (fSigma1 - fSigma2) / cofPHC / energy;
cof1 = fPlateThick * tmp;
cof2 = fGasThick * tmp;
cofMin = energy * (fPlateThick + fGasThick) / fGamma / fGamma;
cofMin += (fPlateThick * fSigma1 + fGasThick * fSigma2) / energy;
cofMin /= cofPHC;
theta2 = cofPHC / (energy * (fPlateThick + fGasThick));
kMin = G4int(cofMin);
if(cofMin > kMin)
kMin++;
kMax = kMin + 200; // 99; // 49; //
if(verboseLevel > 2)
{
G4cout << cof1 << " " << cof2 << " " << cofMin << G4endl;
G4cout << "kMin = " << kMin << "; kMax = " << kMax << G4endl;
}
for(k = kMin; k <= kMax; ++k)
{
tmp = pi * fPlateThick * (k + cof2) / (fPlateThick + fGasThick);
result = (k - cof1) * (k - cof1) * (k + cof2) * (k + cof2);
if(k == kMin && kMin == G4int(cofMin))
{
sum +=
0.5 * std::sin(tmp) * std::sin(tmp) * std::abs(k - cofMin) / result;
}
else
{
sum += std::sin(tmp) * std::sin(tmp) * std::abs(k - cofMin) / result;
}
theta2k = std::sqrt(theta2 * std::abs(k - cofMin));
if(verboseLevel > 2)
{
G4cout << k << " " << theta2k << " "
<< std::sin(tmp) * std::sin(tmp) * std::abs(k - cofMin) / result
<< " " << sum << G4endl;
}
}
result = 2 * (cof1 + cof2) * (cof1 + cof2) * sum / energy;
result *= dump * (-1 + dump + 2 * fPlateNumber);
return result;
}
///////////////////////////////////////////////////////////////////////////
//
// Approximation for radiator interference factor for the case of
// Gauss-distributed regular radiator. The plate and gas gap thicknesses
// are Gauss distributed with RMS
// sa and sb for plate and gas, respectively.
// The mean values of the plate and gas gap thicknesses
// are supposed to be about XTR formation zones.
// The XTR photons are moved to the end of radiator
G4double G4XTRGaussRadModel::GetStackFactor(G4double energy,
G4double gamma,
G4double varAngle)
{
G4double result(0.);
G4double Ma, Mb, aMa, bMb, sigma;
G4double sa = fPlateThick/fAlphaPlate;
G4double sb = fGasThick/fAlphaGas;
Ma = GetPlateLinearPhotoAbs(energy);
aMa = fPlateThick * Ma;
Mb = GetGasLinearPhotoAbs(energy);
bMb = fGasThick * Mb;
sigma = aMa + bMb; // m1*t1+m2*t2 dimensionless
G4double nn = G4double( fPlateNumber );
// Gauss fluctuation of foil and gas gaps according to
// RMS = sa = a/fAlphaPlate and RMS = sb = b/fAlphaGas
G4complex med(0.,1.);
G4complex Z1 = GetPlateComplexFZ( energy, gamma, varAngle);
G4complex por1 = -0.5*med*fPlateThick/Z1 - 0.125*sa*sa/Z1/Z1;
G4complex Z2 = GetGasComplexFZ( energy, gamma, varAngle);
G4complex por2 = -0.5*med*fGasThick/Z2 - 0.125*sb*sb/Z2/Z2;
G4complex npor = (por1+por2)*nn;
G4complex Ha = exp(por1);
G4complex Hb = exp(por2);
G4complex H = Ha*Hb;
G4complex Hn = exp(npor);
G4complex A = ( 1.0 - Ha ) * ( 1.0 - Hb ) / ( 1. - H );
G4complex B1 = ( 1.0 - Ha ) * ( 1.0 - Ha ) * Hb / ( 1. - H );
G4complex R = B1*( exp(-sigma*nn) - Hn )/( exp(-sigma) - H );
R += A * ( 1 - exp(-sigma*nn) ) / ( 1. - exp(-sigma) ); // -> A*nn
R *= OneInterfaceXTRdEdx(energy, gamma, varAngle);
result = 2.0 * std::real(R);
return result;
}