Import Geant4 11.4.0 source tree
This commit is contained in:
@@ -77,19 +77,18 @@
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4Cerenkov::G4Cerenkov(const G4String& processName, G4ProcessType type)
|
||||
: G4VProcess(processName, type)
|
||||
: G4VDiscreteProcess(processName, type)
|
||||
, fNumPhotons(0)
|
||||
{
|
||||
secID = G4PhysicsModelCatalog::GetModelID("model_Cerenkov");
|
||||
SetProcessSubType(fCerenkov);
|
||||
|
||||
thePhysicsTable = nullptr;
|
||||
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
Initialise();
|
||||
|
||||
if (verboseLevel > 0) {
|
||||
G4cout << GetProcessName() << " is created." << G4endl;
|
||||
}
|
||||
Initialise();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -118,17 +117,6 @@ void G4Cerenkov::ProcessDescription(std::ostream& out) const
|
||||
out << "Verbose level: " << params->GetCerenkovVerboseLevel();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4Cerenkov::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
{
|
||||
return (aParticleType.GetPDGCharge() != 0.0 &&
|
||||
aParticleType.GetPDGMass() != 0.0 &&
|
||||
aParticleType.GetParticleName() != "chargedgeantino" &&
|
||||
!aParticleType.IsShortLived())
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4Cerenkov::Initialise()
|
||||
{
|
||||
@@ -140,6 +128,15 @@ void G4Cerenkov::Initialise()
|
||||
SetVerboseLevel(params->GetCerenkovVerboseLevel());
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4Cerenkov::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
{
|
||||
return ((aParticleType.GetPDGCharge() != 0.0 &&
|
||||
aParticleType.GetPDGMass() != 0.0 &&
|
||||
!aParticleType.IsShortLived()) ||
|
||||
aParticleType.GetParticleName() == "unknown");
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4Cerenkov::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
@@ -287,6 +284,10 @@ G4VParticleChange* G4Cerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
G4double deltaVelocity = pPostStepPoint->GetVelocity() -
|
||||
pPreStepPoint->GetVelocity();
|
||||
auto touchableHandle = aStep.GetPreStepPoint()->GetTouchableHandle();
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
aParticleChange.SetNumberOfSecondaries(fNumPhotons);
|
||||
|
||||
@@ -300,18 +301,21 @@ G4VParticleChange* G4Cerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
G4double Pmin = Rindex->Energy(0);
|
||||
G4double Pmax = Rindex->GetMaxEnergy();
|
||||
G4double dp = Pmax - Pmin;
|
||||
G4double deltaNumberOfPhotons = MeanNumberOfPhotons1 - MeanNumberOfPhotons2;
|
||||
G4double maxNumberOfPhotons =
|
||||
std::max(MeanNumberOfPhotons1, MeanNumberOfPhotons2);
|
||||
|
||||
G4double nMax = Rindex->GetMaxValue();
|
||||
G4double BetaInverse = 1. / beta;
|
||||
|
||||
G4double maxCos = BetaInverse / nMax;
|
||||
G4double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos);
|
||||
G4double maxSin2 = 1.0 - maxCos * maxCos;
|
||||
|
||||
for(G4int i = 0; i < fNumPhotons; ++i)
|
||||
{
|
||||
// Determine photon energy
|
||||
G4double rand;
|
||||
G4double sampledEnergy, sampledRI;
|
||||
G4double sampledEnergy;
|
||||
G4double cosTheta, sin2Theta;
|
||||
|
||||
// sample an energy
|
||||
@@ -319,10 +323,9 @@ G4VParticleChange* G4Cerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
{
|
||||
rand = G4UniformRand();
|
||||
sampledEnergy = Pmin + rand * dp;
|
||||
sampledRI = Rindex->Value(sampledEnergy);
|
||||
cosTheta = BetaInverse / sampledRI;
|
||||
cosTheta = BetaInverse / Rindex->Value(sampledEnergy);
|
||||
|
||||
sin2Theta = (1.0 - cosTheta) * (1.0 + cosTheta);
|
||||
sin2Theta = 1.0 - cosTheta * cosTheta;
|
||||
rand = G4UniformRand();
|
||||
|
||||
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
|
||||
@@ -356,24 +359,18 @@ G4VParticleChange* G4Cerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
aCerenkovPhoton->SetPolarization(photonPolarization);
|
||||
aCerenkovPhoton->SetKineticEnergy(sampledEnergy);
|
||||
|
||||
G4double NumberOfPhotons, N;
|
||||
G4double NumberOfPhotons;
|
||||
|
||||
do
|
||||
{
|
||||
rand = G4UniformRand();
|
||||
NumberOfPhotons = MeanNumberOfPhotons1 -
|
||||
rand * (MeanNumberOfPhotons1 - MeanNumberOfPhotons2);
|
||||
N =
|
||||
G4UniformRand() * std::max(MeanNumberOfPhotons1, MeanNumberOfPhotons2);
|
||||
NumberOfPhotons = MeanNumberOfPhotons1 - rand * deltaNumberOfPhotons;
|
||||
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
|
||||
} while(N > NumberOfPhotons);
|
||||
} while(G4UniformRand() * maxNumberOfPhotons > NumberOfPhotons);
|
||||
|
||||
G4double delta = rand * aStep.GetStepLength();
|
||||
G4double deltaTime =
|
||||
delta /
|
||||
(pPreStepPoint->GetVelocity() +
|
||||
rand * (pPostStepPoint->GetVelocity() - pPreStepPoint->GetVelocity()) *
|
||||
0.5);
|
||||
delta / (pPreStepPoint->GetVelocity() + rand * deltaVelocity * 0.5);
|
||||
|
||||
G4double aSecondaryTime = t0 + deltaTime;
|
||||
G4ThreeVector aSecondaryPosition = x0 + rand * aStep.GetDeltaPosition();
|
||||
@@ -382,8 +379,7 @@ G4VParticleChange* G4Cerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
G4Track* aSecondaryTrack =
|
||||
new G4Track(aCerenkovPhoton, aSecondaryTime, aSecondaryPosition);
|
||||
|
||||
aSecondaryTrack->SetTouchableHandle(
|
||||
aStep.GetPreStepPoint()->GetTouchableHandle());
|
||||
aSecondaryTrack->SetTouchableHandle(touchableHandle);
|
||||
aSecondaryTrack->SetParentID(aTrack.GetTrackID());
|
||||
aSecondaryTrack->SetCreatorModelID(secID);
|
||||
aParticleChange.AddSecondary(aSecondaryTrack);
|
||||
@@ -408,7 +404,7 @@ void G4Cerenkov::PreparePhysicsTable(const G4ParticleDefinition&)
|
||||
G4double G4Cerenkov::GetMeanFreePath(const G4Track&, G4double,
|
||||
G4ForceCondition*)
|
||||
{
|
||||
return 1.;
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -417,6 +413,9 @@ G4double G4Cerenkov::PostStepGetPhysicalInteractionLength(
|
||||
{
|
||||
*condition = NotForced;
|
||||
G4double StepLimit = DBL_MAX;
|
||||
if (aTrack.GetDynamicParticle()->GetCharge() == 0.0) {
|
||||
return StepLimit;
|
||||
}
|
||||
fNumPhotons = 0;
|
||||
|
||||
const G4Material* aMaterial = aTrack.GetMaterial();
|
||||
@@ -424,11 +423,9 @@ G4double G4Cerenkov::PostStepGetPhysicalInteractionLength(
|
||||
|
||||
// If Physics Vector is not defined no Cerenkov photons
|
||||
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
|
||||
G4MaterialPropertiesTable* MPT =
|
||||
auto const MPT =
|
||||
((*materialTable)[materialIndex])->GetMaterialPropertiesTable();
|
||||
// if(!(*thePhysicsTable)[materialIndex])
|
||||
if(!MPT)
|
||||
{
|
||||
if (nullptr == MPT) {
|
||||
return StepLimit;
|
||||
}
|
||||
|
||||
@@ -649,3 +646,11 @@ void G4Cerenkov::SetVerboseLevel(G4int verbose)
|
||||
verboseLevel = verbose;
|
||||
G4OpticalParameters::Instance()->SetCerenkovVerboseLevel(verboseLevel);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4Cerenkov::DumpInfo() const
|
||||
{
|
||||
ProcessDescription(G4cout);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * 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 "G4CerenkovQuasiTrackInfo.hh"
|
||||
|
||||
G4Allocator<G4CerenkovQuasiTrackInfo>*& aCerenkovATIAllocator()
|
||||
{
|
||||
G4ThreadLocalStatic G4Allocator<G4CerenkovQuasiTrackInfo>* _instance =
|
||||
nullptr;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
G4CerenkovQuasiTrackInfo::G4CerenkovQuasiTrackInfo(
|
||||
const G4QuasiOpticalData& aOpticalData,
|
||||
G4double aPreNumPhotons, G4double aPostNumPhotons)
|
||||
: G4VAuxiliaryTrackInformation()
|
||||
, fQuasiOpticalData(aOpticalData)
|
||||
, fPreNumPhotons(aPreNumPhotons)
|
||||
, fPostNumPhotons(aPostNumPhotons)
|
||||
{}
|
||||
|
||||
void G4CerenkovQuasiTrackInfo::Print() const
|
||||
{
|
||||
G4cout << "Auxiliary track information for a Cerenkov step" << G4endl;
|
||||
}
|
||||
|
||||
G4CerenkovQuasiTrackInfo* G4CerenkovQuasiTrackInfo::Cast(
|
||||
const G4VAuxiliaryTrackInformation* const aATI)
|
||||
{
|
||||
G4CerenkovQuasiTrackInfo* CATI = nullptr;
|
||||
if(aATI != nullptr)
|
||||
{
|
||||
// No change will be done to the pointer and to the pointed data
|
||||
auto temp = const_cast<G4VAuxiliaryTrackInformation*>(aATI);
|
||||
CATI = dynamic_cast<G4CerenkovQuasiTrackInfo*>(temp);
|
||||
}
|
||||
return CATI;
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * 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. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// G4GeneralCerenkov
|
||||
//
|
||||
// Created 25.05.2025 V.Ivanchenko
|
||||
//
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#include "G4GeneralCerenkov.hh"
|
||||
#include "G4StandardCerenkovModel.hh"
|
||||
|
||||
#include "G4Material.hh"
|
||||
#include "G4MaterialPropertiesTable.hh"
|
||||
#include "G4OpticalParameters.hh"
|
||||
#include "G4PhysicsModelCatalog.hh"
|
||||
#include "G4EmProcessSubType.hh"
|
||||
#include "G4LogicalVolumeStore.hh"
|
||||
|
||||
std::vector<std::vector<const G4LogicalVolume*>* >* G4GeneralCerenkov::fLV = nullptr;
|
||||
std::vector<G4VXRayModel*>* G4GeneralCerenkov::fSharedModels = nullptr;
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4GeneralCerenkov::G4GeneralCerenkov(const G4String& nam, G4ProcessType type)
|
||||
: G4VDiscreteProcess(nam, type)
|
||||
{
|
||||
secID = G4PhysicsModelCatalog::GetModelID("model_Cerenkov");
|
||||
SetProcessSubType(fCerenkov);
|
||||
if (nullptr == fLV) {
|
||||
// initialise static data
|
||||
fSharedModels = new std::vector<G4VXRayModel*>;
|
||||
fLV = new std::vector<std::vector<const G4LogicalVolume*>* >;
|
||||
fLVNames = new std::vector<G4String>;
|
||||
|
||||
isInitializer = true;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4GeneralCerenkov::~G4GeneralCerenkov()
|
||||
{
|
||||
if (isInitializer) {
|
||||
delete fSharedModels;
|
||||
fSharedModels = nullptr;
|
||||
delete fLVNames;
|
||||
for (auto const & p : *fLV) {
|
||||
delete p;
|
||||
}
|
||||
delete fLV;
|
||||
fLV = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4GeneralCerenkov::IsApplicable(const G4ParticleDefinition&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::AddModelForVolume(G4VXRayModel* model,
|
||||
const G4String& nameLogVolume)
|
||||
{
|
||||
if (isPrepared || !isInitializer || nullptr == model) {
|
||||
G4ExceptionDescription ed;
|
||||
G4String nam;
|
||||
if (model != nullptr) { nam = model->GetName(); }
|
||||
ed << " Attempt to add Cerenkov model <" << nam << "> for LogicalVolume "
|
||||
<< nameLogVolume << " is failed!\n isPrepared:" << isPrepared
|
||||
<< " isInitilizer:" << isInitializer;
|
||||
G4Exception("G4GeneralCerenkov::AddModelForVolume", "em0304",
|
||||
FatalException, ed, "");
|
||||
return;
|
||||
}
|
||||
fSharedModels->push_back(model);
|
||||
fLVNames->push_back(nameLogVolume);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::PreparePhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
// definition of models is done only once
|
||||
if (isPrepared) { return; }
|
||||
isPrepared = true;
|
||||
|
||||
const G4OpticalParameters* params = G4OpticalParameters::Instance();
|
||||
fMaxBetaChange = params->GetCerenkovMaxBetaChange();
|
||||
fMaxPhotons = params->GetCerenkovMaxPhotonsPerStep();
|
||||
fStackingFlag = params->GetCerenkovStackPhotons();
|
||||
fTrackSecondariesFirst = params->GetCerenkovTrackSecondariesFirst();
|
||||
verboseLevel = params->GetCerenkovVerboseLevel();
|
||||
|
||||
auto nmod = fSharedModels->size();
|
||||
if (0 == nmod) {
|
||||
// the default model is added without association with a logical volume
|
||||
G4VXRayModel* mod = new G4StandardCerenkovModel();
|
||||
fSharedModels->push_back(mod);
|
||||
nmod = 1;
|
||||
}
|
||||
|
||||
fSecondaries.reserve(fMaxPhotons);
|
||||
nModels = (G4int)nmod;
|
||||
|
||||
// fill static data structures
|
||||
if (isInitializer) {
|
||||
const G4LogicalVolumeStore* lvs = G4LogicalVolumeStore::GetInstance();
|
||||
const auto & modAndVol = params->ActiveVolumes();
|
||||
|
||||
// preparation of logical volume vector per model
|
||||
fLV->reserve(nmod);
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
auto v = new std::vector<const G4LogicalVolume*>;
|
||||
fLV->push_back(v);
|
||||
}
|
||||
|
||||
for (auto const & lv : *lvs) {
|
||||
// only volumes with material property defined are considered
|
||||
auto const MPT = lv->GetMaterial()->GetMaterialPropertiesTable();
|
||||
if (nullptr == MPT) { continue; }
|
||||
|
||||
const G4String& lvname = lv->GetName();
|
||||
G4bool ok{false};
|
||||
// search for the default model in the list
|
||||
if (!modAndVol.empty()) {
|
||||
for (auto const & it : modAndVol) {
|
||||
if (it.second == lvname) {
|
||||
if (kCerenkovDefault == it.first) {
|
||||
(*fLV)[0]->push_back(lv);
|
||||
fLVNames->push_back(lvname);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) { continue; }
|
||||
|
||||
// search in external models
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
if (lvname == (*fLVNames)[i]) {
|
||||
(*fLV)[i]->push_back(lv);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) { continue; }
|
||||
|
||||
// temporary for backward compatibility search for a RINDEX of the volume
|
||||
if (nullptr != MPT->GetProperty(kRINDEX)) {
|
||||
(*fLV)[0]->push_back(lv);
|
||||
fLVNames->push_back(lvname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
// Initialisation of models is done only once
|
||||
if (isBuilt) { return; }
|
||||
isBuilt = true;
|
||||
if (nModels == 0) { return; }
|
||||
|
||||
// worker thread
|
||||
if (!isInitializer) {
|
||||
// worker initialisation - clone master models
|
||||
fModels.reserve(nModels);
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
auto newmod = new G4VXRayModel(*((*fSharedModels)[i]));
|
||||
fModels.push_back(newmod);
|
||||
G4double b = newmod->Initialise((*fLV)[i]);
|
||||
fBetaMin = std::min(fBetaMin, b);
|
||||
}
|
||||
} else if (verboseLevel > 0) {
|
||||
// needed for printout
|
||||
std::size_t nn = 0;
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
G4double b = (*fSharedModels)[i]->Initialise((*fLV)[i]);
|
||||
fBetaMin = std::min(fBetaMin, b);
|
||||
nn += ((*fLV)[i])->size();
|
||||
}
|
||||
G4long pres = G4cout.precision();
|
||||
G4cout.precision(6);
|
||||
G4cout << " " << GetProcessName() << std::setw(20) << " fBetaMin=" << fBetaMin
|
||||
<< " fMaxBetaChange=" << fMaxBetaChange << G4endl;
|
||||
G4cout << std::setw(20) << "fMaxNphot=" << fMaxPhotons
|
||||
<< " Nlv=" << nn << " fStackingFlag:" << fStackingFlag
|
||||
<< " fTrackSecondariesFirst:" << fTrackSecondariesFirst
|
||||
<< G4endl;
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
G4int n = (G4int)((*fLV)[i]->size());
|
||||
G4cout << std::setw(10) << (*fSharedModels)[i]->GetName()
|
||||
<< std::setw(30) << "Nvolumes=" << n << " Volumes:" << G4endl;
|
||||
G4cout << std::setw(12);
|
||||
for (G4int j=0; j<n; ++j) {
|
||||
G4cout << (*((*fLV)[i]))[j]->GetName() << " ";
|
||||
if (0 != j && (j/5)*5 == j) {
|
||||
G4cout << G4endl << std::setw(12);
|
||||
}
|
||||
}
|
||||
G4cout << G4endl;
|
||||
}
|
||||
G4cout.precision(pres);
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double
|
||||
G4GeneralCerenkov::PostStepGetPhysicalInteractionLength(const G4Track& aTrack,
|
||||
G4double,
|
||||
G4ForceCondition* cond)
|
||||
{
|
||||
*cond = NotForced;
|
||||
G4double limit = DBL_MAX;
|
||||
auto const dp = aTrack.GetDynamicParticle();
|
||||
if (dp->GetCharge() == 0.0) { return limit; }
|
||||
fCurrentModel = nullptr;
|
||||
fPreStepBeta = dp->GetBeta();
|
||||
if (fPreStepBeta <= fBetaMin) { return limit; }
|
||||
|
||||
auto volume = aTrack.GetVolume();
|
||||
if (nullptr == volume) { return limit; }
|
||||
|
||||
fCurrentLV = volume->GetLogicalVolume();
|
||||
auto const MPT = fCurrentLV->GetMaterial()->GetMaterialPropertiesTable();
|
||||
if (nullptr == MPT) { return limit; }
|
||||
|
||||
G4bool ok{false};
|
||||
for (G4int i=0; i<nModels; ++i) {
|
||||
auto const v = (*fLV)[i];
|
||||
std::size_t nn = v->size();
|
||||
for (std::size_t j = 0; j < nn; ++j) {
|
||||
if ((*v)[j] == fCurrentLV) {
|
||||
fCurrentModel = fModels[i];
|
||||
if (fCurrentModel->StepLimit(j, aTrack, fPreStepBeta, limit)) {
|
||||
*cond = StronglyForced;
|
||||
}
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) { break; }
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4VParticleChange* G4GeneralCerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
const G4Step& aStep)
|
||||
{
|
||||
aParticleChange.Initialize(aTrack);
|
||||
if (fCurrentModel == nullptr) { return &aParticleChange; }
|
||||
fCurrentModel->SampleXRays(fSecondaries, aStep);
|
||||
if (!fSecondaries.empty()) {
|
||||
|
||||
// X-rays
|
||||
auto touch = aStep.GetPreStepPoint()->GetTouchableHandle();
|
||||
G4int parent = aTrack.GetTrackID();
|
||||
for (auto & t : fSecondaries) {
|
||||
t->SetTouchableHandle(touch);
|
||||
t->SetParentID(parent);
|
||||
t->SetCreatorModelID(secID);
|
||||
aParticleChange.AddSecondary(t);
|
||||
}
|
||||
fSecondaries.clear();
|
||||
|
||||
// primary track suspended
|
||||
if (fTrackSecondariesFirst && aTrack.GetTrackStatus() == fAlive) {
|
||||
aParticleChange.ProposeTrackStatus(fSuspend);
|
||||
}
|
||||
}
|
||||
return &aParticleChange;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::ProcessDescription(std::ostream& out) const
|
||||
{
|
||||
out << "The Cerenkov effect simulates optical photons created by the\n";
|
||||
out << "passage of charged particles through matter. Materials need\n";
|
||||
out << "to have the property RINDEX (refractive index) defined." << G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::SetTrackSecondariesFirst(const G4bool state)
|
||||
{
|
||||
fTrackSecondariesFirst = state;
|
||||
G4OpticalParameters::Instance()->SetCerenkovTrackSecondariesFirst(
|
||||
fTrackSecondariesFirst);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::SetMaxBetaChangePerStep(const G4double value)
|
||||
{
|
||||
fMaxBetaChange = value;
|
||||
G4OpticalParameters::Instance()->SetCerenkovMaxBetaChange(value);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::SetMaxNumPhotonsPerStep(const G4int NumPhotons)
|
||||
{
|
||||
fMaxPhotons = NumPhotons;
|
||||
G4OpticalParameters::Instance()->SetCerenkovMaxPhotonsPerStep(fMaxPhotons);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::SetStackPhotons(const G4bool stackingFlag)
|
||||
{
|
||||
fStackingFlag = stackingFlag;
|
||||
G4OpticalParameters::Instance()->SetCerenkovStackPhotons(fStackingFlag);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4GeneralCerenkov::SetVerboseLevel(G4int verbose)
|
||||
{
|
||||
verboseLevel = verbose;
|
||||
G4OpticalParameters::Instance()->SetCerenkovVerboseLevel(verboseLevel);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double
|
||||
G4GeneralCerenkov::GetMeanFreePath(const G4Track&, G4double, G4ForceCondition*)
|
||||
{
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -0,0 +1,653 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * 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 "G4QuasiCerenkov.hh"
|
||||
#include "G4CerenkovQuasiTrackInfo.hh"
|
||||
|
||||
#include "G4ios.hh"
|
||||
#include "G4LossTableManager.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "G4MaterialCutsCouple.hh"
|
||||
#include "G4MaterialPropertiesTable.hh"
|
||||
#include "G4OpticalParameters.hh"
|
||||
#include "G4OpticalPhoton.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4ParticleMomentum.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4PhysicsFreeVector.hh"
|
||||
#include "G4Poisson.hh"
|
||||
#include "G4QuasiOpticalData.hh"
|
||||
#include "G4QuasiOpticalPhoton.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4PhysicsModelCatalog.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4QuasiCerenkov::G4QuasiCerenkov(const G4String& processName, G4ProcessType type)
|
||||
: G4VProcess(processName, type)
|
||||
, fNumPhotons(0)
|
||||
{
|
||||
secID = G4PhysicsModelCatalog::GetModelID("model_QuasiCerenkov");
|
||||
SetProcessSubType(fCerenkov);
|
||||
|
||||
thePhysicsTable = nullptr;
|
||||
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
G4cout << GetProcessName() << " is created." << G4endl;
|
||||
}
|
||||
Initialise();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4QuasiCerenkov::~G4QuasiCerenkov()
|
||||
{
|
||||
if(thePhysicsTable != nullptr)
|
||||
{
|
||||
thePhysicsTable->clearAndDestroy();
|
||||
delete thePhysicsTable;
|
||||
}
|
||||
}
|
||||
|
||||
void G4QuasiCerenkov::ProcessDescription(std::ostream& out) const
|
||||
{
|
||||
out << "The Cerenkov effect simulates optical photons created by the\n";
|
||||
out << "passage of charged particles through matter. Materials need\n";
|
||||
out << "to have the property RINDEX (refractive index) defined.\n";
|
||||
G4VProcess::DumpInfo();
|
||||
|
||||
G4OpticalParameters* params = G4OpticalParameters::Instance();
|
||||
out << "Maximum beta change per step: " << params->GetCerenkovMaxBetaChange();
|
||||
out << "Maximum photons per step: " << params->GetCerenkovMaxPhotonsPerStep();
|
||||
out << "Track secondaries first: "
|
||||
<< params->GetCerenkovTrackSecondariesFirst();
|
||||
out << "Stack photons: " << params->GetCerenkovStackPhotons();
|
||||
out << "Verbose level: " << params->GetCerenkovVerboseLevel();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4QuasiCerenkov::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
{
|
||||
return (aParticleType.GetPDGCharge() != 0.0 &&
|
||||
aParticleType.GetPDGMass() != 0.0 &&
|
||||
aParticleType.GetParticleName() != "chargedgeantino" &&
|
||||
!aParticleType.IsShortLived())
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::Initialise()
|
||||
{
|
||||
G4OpticalParameters* params = G4OpticalParameters::Instance();
|
||||
SetMaxBetaChangePerStep(params->GetCerenkovMaxBetaChange());
|
||||
SetMaxNumPhotonsPerStep(params->GetCerenkovMaxPhotonsPerStep());
|
||||
SetTrackSecondariesFirst(params->GetCerenkovTrackSecondariesFirst());
|
||||
SetStackPhotons(params->GetCerenkovStackPhotons());
|
||||
SetOffloadPhotons(params->GetCerenkovOffloadPhotons());
|
||||
SetVerboseLevel(params->GetCerenkovVerboseLevel());
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
if(thePhysicsTable)
|
||||
return;
|
||||
|
||||
const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
|
||||
std::size_t numOfMaterials = G4Material::GetNumberOfMaterials();
|
||||
|
||||
// Find the number of materials that have non-empty material property tables
|
||||
std::size_t numOfMaterialsWithMPT = 0;
|
||||
for(std::size_t i = 0; i < numOfMaterials; ++i)
|
||||
{
|
||||
if(((*theMaterialTable)[i])->GetMaterialPropertiesTable())
|
||||
{
|
||||
++numOfMaterialsWithMPT;
|
||||
}
|
||||
}
|
||||
|
||||
thePhysicsTable = new G4PhysicsTable(numOfMaterialsWithMPT);
|
||||
|
||||
// loop over materials
|
||||
std::size_t indexMPT = 0;
|
||||
for(std::size_t i = 0; i < numOfMaterials; ++i)
|
||||
{
|
||||
G4PhysicsFreeVector* cerenkovIntegral = nullptr;
|
||||
|
||||
// Retrieve vector of refraction indices for the material
|
||||
// from the material's optical properties table
|
||||
G4Material* aMaterial = (*theMaterialTable)[i];
|
||||
G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
|
||||
|
||||
if(MPT)
|
||||
{
|
||||
cerenkovIntegral = new G4PhysicsFreeVector();
|
||||
G4MaterialPropertyVector* refractiveIndex = MPT->GetProperty(kRINDEX);
|
||||
|
||||
if(refractiveIndex)
|
||||
{
|
||||
// Retrieve the first refraction index in vector
|
||||
// of (photon energy, refraction index) pairs
|
||||
G4double currentRI = (*refractiveIndex)[0];
|
||||
if(currentRI > 1.0)
|
||||
{
|
||||
// Create first (photon energy, Cerenkov Integral) pair
|
||||
G4double currentPM = refractiveIndex->Energy(0);
|
||||
G4double currentCAI = 0.0;
|
||||
|
||||
cerenkovIntegral->InsertValues(currentPM, currentCAI);
|
||||
|
||||
// Set previous values to current ones prior to loop
|
||||
G4double prevPM = currentPM;
|
||||
G4double prevCAI = currentCAI;
|
||||
G4double prevRI = currentRI;
|
||||
|
||||
// loop over all (photon energy, refraction index)
|
||||
// pairs stored for this material
|
||||
for(std::size_t ii = 1; ii < refractiveIndex->GetVectorLength(); ++ii)
|
||||
{
|
||||
currentRI = (*refractiveIndex)[ii];
|
||||
currentPM = refractiveIndex->Energy(ii);
|
||||
currentCAI = prevCAI + (currentPM - prevPM) * 0.5 *
|
||||
(1.0 / (prevRI * prevRI) +
|
||||
1.0 / (currentRI * currentRI));
|
||||
|
||||
cerenkovIntegral->InsertValues(currentPM, currentCAI);
|
||||
|
||||
prevPM = currentPM;
|
||||
prevCAI = currentCAI;
|
||||
prevRI = currentRI;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The Cerenkov integral for a given material will be inserted in
|
||||
// thePhysicsTable according to the position of the material in
|
||||
// the material table.
|
||||
thePhysicsTable->insertAt(indexMPT, cerenkovIntegral);
|
||||
fIndexMPT.insert(std::make_pair(i, indexMPT));
|
||||
++indexMPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4VParticleChange* G4QuasiCerenkov::PostStepDoIt(const G4Track& aTrack,
|
||||
const G4Step& aStep)
|
||||
// This routine is called for each tracking Step of a charged particle
|
||||
// in a radiator. A Poisson-distributed number of photons is generated
|
||||
// according to the Cerenkov formula, distributed evenly along the track
|
||||
// segment and uniformly azimuth w.r.t. the particle direction. The
|
||||
// parameters are then transformed into the Master Reference System, and
|
||||
// they are added to the particle change.
|
||||
|
||||
{
|
||||
aParticleChange.Initialize(aTrack);
|
||||
|
||||
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
|
||||
const G4Material* aMaterial = aTrack.GetMaterial();
|
||||
|
||||
G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
|
||||
G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
|
||||
|
||||
G4ThreeVector x0 = pPreStepPoint->GetPosition();
|
||||
G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
|
||||
G4double t0 = pPreStepPoint->GetGlobalTime();
|
||||
|
||||
G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
|
||||
if(!MPT)
|
||||
return pParticleChange;
|
||||
|
||||
G4MaterialPropertyVector* Rindex = MPT->GetProperty(kRINDEX);
|
||||
if(!Rindex)
|
||||
return pParticleChange;
|
||||
|
||||
G4double charge = aParticle->GetDefinition()->GetPDGCharge();
|
||||
|
||||
G4double beta1 = pPreStepPoint->GetBeta();
|
||||
G4double beta2 = pPostStepPoint->GetBeta();
|
||||
G4double beta = (beta1 + beta2) * 0.5;
|
||||
|
||||
G4double MeanNumberOfPhotons =
|
||||
GetAverageNumberOfPhotons(charge, beta, aMaterial, Rindex);
|
||||
G4double MeanNumberOfPhotons1 =
|
||||
GetAverageNumberOfPhotons(charge, beta1, aMaterial, Rindex);
|
||||
G4double MeanNumberOfPhotons2 =
|
||||
GetAverageNumberOfPhotons(charge, beta2, aMaterial, Rindex);
|
||||
|
||||
if(MeanNumberOfPhotons <= 0.0)
|
||||
{
|
||||
// return unchanged particle and no secondaries
|
||||
aParticleChange.SetNumberOfSecondaries(0);
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
MeanNumberOfPhotons *= aStep.GetStepLength();
|
||||
fNumPhotons = (G4int) G4Poisson(MeanNumberOfPhotons);
|
||||
|
||||
// third condition added to prevent infinite loop in do-while below,
|
||||
// see bugzilla 2555
|
||||
if(fNumPhotons <= 0 || !fStackingFlag ||
|
||||
std::max(MeanNumberOfPhotons1, MeanNumberOfPhotons2) < 1e-15)
|
||||
{
|
||||
// return unchanged particle and no secondaries
|
||||
aParticleChange.SetNumberOfSecondaries(0);
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
G4double deltaVelocity = pPostStepPoint->GetVelocity() -
|
||||
pPreStepPoint->GetVelocity();
|
||||
auto touchableHandle = aStep.GetPreStepPoint()->GetTouchableHandle();
|
||||
|
||||
if(fOffloadingFlag)
|
||||
{
|
||||
// Create a G4DynamicParticle with G4QuasiOpticalPhoton
|
||||
auto quasiPhoton = new G4DynamicParticle(
|
||||
G4QuasiOpticalPhoton::QuasiOpticalPhotonDefinition(),
|
||||
aParticle->GetMomentum());
|
||||
|
||||
// Create a new G4Track object with the quasi-optical photon
|
||||
G4Track* aSecondaryTrack = new G4Track(quasiPhoton, t0, x0);
|
||||
aSecondaryTrack->SetTouchableHandle(touchableHandle);
|
||||
aSecondaryTrack->SetParentID(aTrack.GetTrackID());
|
||||
aSecondaryTrack->SetCreatorModelID(secID);
|
||||
|
||||
// Attach auxiliary track information with associated metadata
|
||||
G4QuasiOpticalData quasiTrackData{aMaterial->GetIndex(), fNumPhotons,
|
||||
charge, aStep.GetStepLength(), pPreStepPoint->GetVelocity(),
|
||||
deltaVelocity, aStep.GetDeltaPosition()};
|
||||
aSecondaryTrack->SetAuxiliaryTrackInformation(secID,
|
||||
new G4CerenkovQuasiTrackInfo(quasiTrackData,
|
||||
MeanNumberOfPhotons1, MeanNumberOfPhotons2));
|
||||
aParticleChange.AddSecondary(aSecondaryTrack);
|
||||
|
||||
// Return early when offloading is enabled
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
aParticleChange.SetNumberOfSecondaries(fNumPhotons);
|
||||
|
||||
if(fTrackSecondariesFirst)
|
||||
{
|
||||
if(aTrack.GetTrackStatus() == fAlive)
|
||||
aParticleChange.ProposeTrackStatus(fSuspend);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
G4double Pmin = Rindex->Energy(0);
|
||||
G4double Pmax = Rindex->GetMaxEnergy();
|
||||
G4double dp = Pmax - Pmin;
|
||||
G4double deltaNumberOfPhotons = MeanNumberOfPhotons1 - MeanNumberOfPhotons2;
|
||||
G4double maxNumberOfPhotons =
|
||||
std::max(MeanNumberOfPhotons1, MeanNumberOfPhotons2);
|
||||
|
||||
G4double nMax = Rindex->GetMaxValue();
|
||||
G4double BetaInverse = 1. / beta;
|
||||
|
||||
G4double maxCos = BetaInverse / nMax;
|
||||
G4double maxSin2 = 1.0 - maxCos * maxCos;
|
||||
|
||||
for(G4int i = 0; i < fNumPhotons; ++i)
|
||||
{
|
||||
// Determine photon energy
|
||||
G4double rand;
|
||||
G4double sampledEnergy;
|
||||
G4double cosTheta, sin2Theta;
|
||||
|
||||
// sample an energy
|
||||
do
|
||||
{
|
||||
rand = G4UniformRand();
|
||||
sampledEnergy = Pmin + rand * dp;
|
||||
cosTheta = BetaInverse / Rindex->Value(sampledEnergy);
|
||||
|
||||
sin2Theta = 1.0 - cosTheta * cosTheta;
|
||||
rand = G4UniformRand();
|
||||
|
||||
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
|
||||
} while(rand * maxSin2 > sin2Theta);
|
||||
|
||||
// Create photon momentum direction vector. The momentum direction is still
|
||||
// with respect to the coordinate system where the primary particle
|
||||
// direction is aligned with the z axis
|
||||
rand = G4UniformRand();
|
||||
G4double phi = twopi * rand;
|
||||
G4double sinPhi = std::sin(phi);
|
||||
G4double cosPhi = std::cos(phi);
|
||||
G4double sinTheta = std::sqrt(sin2Theta);
|
||||
G4ParticleMomentum photonMomentum(sinTheta * cosPhi, sinTheta * sinPhi,
|
||||
cosTheta);
|
||||
|
||||
// Rotate momentum direction back to global reference system
|
||||
photonMomentum.rotateUz(p0);
|
||||
|
||||
// Determine polarization of new photon
|
||||
G4ThreeVector photonPolarization(cosTheta * cosPhi, cosTheta * sinPhi,
|
||||
-sinTheta);
|
||||
|
||||
// Rotate back to original coord system
|
||||
photonPolarization.rotateUz(p0);
|
||||
|
||||
// Generate a new photon:
|
||||
auto aCerenkovPhoton =
|
||||
new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(), photonMomentum);
|
||||
|
||||
aCerenkovPhoton->SetPolarization(photonPolarization);
|
||||
aCerenkovPhoton->SetKineticEnergy(sampledEnergy);
|
||||
|
||||
G4double NumberOfPhotons;
|
||||
|
||||
do
|
||||
{
|
||||
rand = G4UniformRand();
|
||||
NumberOfPhotons = MeanNumberOfPhotons1 - rand * deltaNumberOfPhotons;
|
||||
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
|
||||
} while(G4UniformRand() * maxNumberOfPhotons > NumberOfPhotons);
|
||||
|
||||
G4double delta = rand * aStep.GetStepLength();
|
||||
G4double deltaTime =
|
||||
delta / (pPreStepPoint->GetVelocity() + rand * deltaVelocity * 0.5);
|
||||
|
||||
G4double aSecondaryTime = t0 + deltaTime;
|
||||
G4ThreeVector aSecondaryPosition = x0 + rand * aStep.GetDeltaPosition();
|
||||
|
||||
// Generate new G4Track object:
|
||||
G4Track* aSecondaryTrack =
|
||||
new G4Track(aCerenkovPhoton, aSecondaryTime, aSecondaryPosition);
|
||||
|
||||
aSecondaryTrack->SetTouchableHandle(touchableHandle);
|
||||
aSecondaryTrack->SetParentID(aTrack.GetTrackID());
|
||||
aSecondaryTrack->SetCreatorModelID(secID);
|
||||
aParticleChange.AddSecondary(aSecondaryTrack);
|
||||
}
|
||||
|
||||
if(verboseLevel > 1)
|
||||
{
|
||||
G4cout << "\n Exiting from G4QuasiCerenkov::DoIt -- NumberOfSecondaries = "
|
||||
<< aParticleChange.GetNumberOfSecondaries() << G4endl;
|
||||
}
|
||||
|
||||
return pParticleChange;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::PreparePhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
Initialise();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiCerenkov::GetMeanFreePath(const G4Track&, G4double,
|
||||
G4ForceCondition*)
|
||||
{
|
||||
return 1.;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiCerenkov::PostStepGetPhysicalInteractionLength(
|
||||
const G4Track& aTrack, G4double, G4ForceCondition* condition)
|
||||
{
|
||||
*condition = NotForced;
|
||||
G4double StepLimit = DBL_MAX;
|
||||
fNumPhotons = 0;
|
||||
|
||||
const G4Material* aMaterial = aTrack.GetMaterial();
|
||||
std::size_t materialIndex = aMaterial->GetIndex();
|
||||
|
||||
// If Physics Vector is not defined no Cerenkov photons
|
||||
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
|
||||
G4MaterialPropertiesTable* MPT =
|
||||
((*materialTable)[materialIndex])->GetMaterialPropertiesTable();
|
||||
// if(!(*thePhysicsTable)[materialIndex])
|
||||
if(!MPT)
|
||||
{
|
||||
return StepLimit;
|
||||
}
|
||||
|
||||
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
|
||||
const G4MaterialCutsCouple* couple = aTrack.GetMaterialCutsCouple();
|
||||
|
||||
G4double kineticEnergy = aParticle->GetKineticEnergy();
|
||||
const G4ParticleDefinition* particleType = aParticle->GetDefinition();
|
||||
G4double mass = particleType->GetPDGMass();
|
||||
|
||||
G4double beta = aParticle->GetTotalMomentum() / aParticle->GetTotalEnergy();
|
||||
G4double gamma = aParticle->GetTotalEnergy() / mass;
|
||||
|
||||
G4MaterialPropertiesTable* aMaterialPropertiesTable =
|
||||
aMaterial->GetMaterialPropertiesTable();
|
||||
|
||||
G4MaterialPropertyVector* Rindex = nullptr;
|
||||
|
||||
if(aMaterialPropertiesTable)
|
||||
Rindex = aMaterialPropertiesTable->GetProperty(kRINDEX);
|
||||
|
||||
G4double nMax;
|
||||
if(Rindex)
|
||||
{
|
||||
nMax = Rindex->GetMaxValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
return StepLimit;
|
||||
}
|
||||
|
||||
G4double BetaMin = 1. / nMax;
|
||||
if(BetaMin >= 1.)
|
||||
return StepLimit;
|
||||
|
||||
G4double GammaMin = 1. / std::sqrt(1. - BetaMin * BetaMin);
|
||||
if(gamma < GammaMin)
|
||||
return StepLimit;
|
||||
|
||||
G4double kinEmin = mass * (GammaMin - 1.);
|
||||
G4double RangeMin =
|
||||
G4LossTableManager::Instance()->GetRange(particleType, kinEmin, couple);
|
||||
G4double Range = G4LossTableManager::Instance()->GetRange(
|
||||
particleType, kineticEnergy, couple);
|
||||
G4double Step = Range - RangeMin;
|
||||
|
||||
// If the step is smaller than G4ThreeVector::getTolerance(), it may happen
|
||||
// that the particle does not move. See bug 1992.
|
||||
static const G4double minAllowedStep = G4ThreeVector::getTolerance();
|
||||
if(Step < minAllowedStep)
|
||||
return StepLimit;
|
||||
|
||||
if(Step < StepLimit)
|
||||
StepLimit = Step;
|
||||
|
||||
// If user has defined an average maximum number of photons to be generated in
|
||||
// a Step, then calculate the Step length for that number of photons.
|
||||
if(fMaxPhotons > 0)
|
||||
{
|
||||
const G4double charge = aParticle->GetDefinition()->GetPDGCharge();
|
||||
G4double MeanNumberOfPhotons =
|
||||
GetAverageNumberOfPhotons(charge, beta, aMaterial, Rindex);
|
||||
Step = 0.;
|
||||
if(MeanNumberOfPhotons > 0.0)
|
||||
Step = fMaxPhotons / MeanNumberOfPhotons;
|
||||
if(Step > 0. && Step < StepLimit)
|
||||
StepLimit = Step;
|
||||
}
|
||||
|
||||
// If user has defined an maximum allowed change in beta per step
|
||||
if(fMaxBetaChange > 0.)
|
||||
{
|
||||
G4double dedx = G4LossTableManager::Instance()->GetDEDX(
|
||||
particleType, kineticEnergy, couple);
|
||||
G4double deltaGamma =
|
||||
gamma - 1. / std::sqrt(1. - beta * beta * (1. - fMaxBetaChange) *
|
||||
(1. - fMaxBetaChange));
|
||||
|
||||
Step = mass * deltaGamma / dedx;
|
||||
if(Step > 0. && Step < StepLimit)
|
||||
StepLimit = Step;
|
||||
}
|
||||
|
||||
*condition = StronglyForced;
|
||||
return StepLimit;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiCerenkov::GetAverageNumberOfPhotons(
|
||||
const G4double charge, const G4double beta, const G4Material* aMaterial,
|
||||
G4MaterialPropertyVector* Rindex) const
|
||||
// This routine computes the number of Cerenkov photons produced per
|
||||
// Geant4-unit (millimeter) in the current medium.
|
||||
{
|
||||
constexpr G4double Rfact = 369.81 / (eV * cm);
|
||||
if(beta <= 0.0)
|
||||
return 0.0;
|
||||
G4double BetaInverse = 1. / beta;
|
||||
|
||||
// Vectors used in computation of Cerenkov Angle Integral:
|
||||
// - Refraction Indices for the current material
|
||||
// - new G4PhysicsFreeVector allocated to hold CAI's
|
||||
std::size_t materialIndex = aMaterial->GetIndex();
|
||||
|
||||
// Retrieve the Cerenkov Angle Integrals for this material
|
||||
auto it = fIndexMPT.find(materialIndex);
|
||||
|
||||
std::size_t indexMPT = 0;
|
||||
if(it != fIndexMPT.end())
|
||||
{
|
||||
indexMPT = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "G4MaterialPropertiesTable for " << aMaterial->GetName()
|
||||
<< " is not found!" << G4endl;
|
||||
G4Exception("G4QuasiCerenkov::GetAverageNumberOfPhotons",
|
||||
"QuasiCerenkovCerenkov01", FatalException, ed);
|
||||
}
|
||||
|
||||
G4PhysicsVector* CerenkovAngleIntegrals = ((*thePhysicsTable)(indexMPT));
|
||||
|
||||
std::size_t length = CerenkovAngleIntegrals->GetVectorLength();
|
||||
if(0 == length)
|
||||
return 0.0;
|
||||
|
||||
// Min and Max photon energies
|
||||
G4double Pmin = Rindex->Energy(0);
|
||||
G4double Pmax = Rindex->GetMaxEnergy();
|
||||
|
||||
// Min and Max Refraction Indices
|
||||
G4double nMin = Rindex->GetMinValue();
|
||||
G4double nMax = Rindex->GetMaxValue();
|
||||
|
||||
// Max Cerenkov Angle Integral
|
||||
G4double CAImax = (*CerenkovAngleIntegrals)[length - 1];
|
||||
|
||||
G4double dp, ge;
|
||||
// If n(Pmax) < 1/Beta -- no photons generated
|
||||
if(nMax < BetaInverse)
|
||||
{
|
||||
dp = 0.0;
|
||||
ge = 0.0;
|
||||
}
|
||||
// otherwise if n(Pmin) >= 1/Beta -- photons generated
|
||||
else if(nMin > BetaInverse)
|
||||
{
|
||||
dp = Pmax - Pmin;
|
||||
ge = CAImax;
|
||||
}
|
||||
// If n(Pmin) < 1/Beta, and n(Pmax) >= 1/Beta, then we need to find a P such
|
||||
// that the value of n(P) == 1/Beta. Interpolation is performed by the
|
||||
// GetEnergy() and Value() methods of the G4MaterialPropertiesTable and
|
||||
// the Value() method of G4PhysicsVector.
|
||||
else
|
||||
{
|
||||
Pmin = Rindex->GetEnergy(BetaInverse);
|
||||
dp = Pmax - Pmin;
|
||||
|
||||
G4double CAImin = CerenkovAngleIntegrals->Value(Pmin);
|
||||
ge = CAImax - CAImin;
|
||||
|
||||
if(verboseLevel > 1)
|
||||
{
|
||||
G4cout << "CAImin = " << CAImin << G4endl << "ge = " << ge << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate number of photons
|
||||
G4double NumPhotons = Rfact * charge / eplus * charge / eplus *
|
||||
(dp - ge * BetaInverse * BetaInverse);
|
||||
|
||||
return NumPhotons;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::SetTrackSecondariesFirst(const G4bool state)
|
||||
{
|
||||
fTrackSecondariesFirst = state;
|
||||
G4OpticalParameters::Instance()->SetCerenkovTrackSecondariesFirst(
|
||||
fTrackSecondariesFirst);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::SetMaxBetaChangePerStep(const G4double value)
|
||||
{
|
||||
fMaxBetaChange = value * CLHEP::perCent;
|
||||
G4OpticalParameters::Instance()->SetCerenkovMaxBetaChange(value);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::SetMaxNumPhotonsPerStep(const G4int NumPhotons)
|
||||
{
|
||||
fMaxPhotons = NumPhotons;
|
||||
G4OpticalParameters::Instance()->SetCerenkovMaxPhotonsPerStep(fMaxPhotons);
|
||||
}
|
||||
|
||||
void G4QuasiCerenkov::SetStackPhotons(const G4bool stackingFlag)
|
||||
{
|
||||
fStackingFlag = stackingFlag;
|
||||
G4OpticalParameters::Instance()->SetCerenkovStackPhotons(fStackingFlag);
|
||||
}
|
||||
|
||||
void G4QuasiCerenkov::SetOffloadPhotons(const G4bool offloadingFlag)
|
||||
{
|
||||
fOffloadingFlag = offloadingFlag;
|
||||
G4OpticalParameters::Instance()->SetCerenkovOffloadPhotons(fOffloadingFlag);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::DumpPhysicsTable() const
|
||||
{
|
||||
G4cout << "Dump Physics Table!" << G4endl;
|
||||
for(std::size_t i = 0; i < thePhysicsTable->entries(); ++i)
|
||||
{
|
||||
(*thePhysicsTable)[i]->DumpValues();
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiCerenkov::SetVerboseLevel(G4int verbose)
|
||||
{
|
||||
verboseLevel = verbose;
|
||||
G4OpticalParameters::Instance()->SetCerenkovVerboseLevel(verboseLevel);
|
||||
}
|
||||
@@ -0,0 +1,947 @@
|
||||
// ********************************************************************
|
||||
// * 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 "G4QuasiScintillation.hh"
|
||||
#include "G4QuasiOpticalData.hh"
|
||||
#include "G4QuasiOpticalPhoton.hh"
|
||||
#include "G4ScintillationQuasiTrackInfo.hh"
|
||||
|
||||
#include "globals.hh"
|
||||
#include "G4DynamicParticle.hh"
|
||||
#include "G4EmProcessSubType.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "G4MaterialPropertiesTable.hh"
|
||||
#include "G4MaterialPropertyVector.hh"
|
||||
#include "G4OpticalParameters.hh"
|
||||
#include "G4ParticleMomentum.hh"
|
||||
#include "G4ParticleTypes.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4PhysicsFreeVector.hh"
|
||||
#include "G4PhysicsTable.hh"
|
||||
#include "G4Poisson.hh"
|
||||
#include "G4ScintillationTrackInformation.hh"
|
||||
#include "G4StepPoint.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4PhysicsModelCatalog.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4QuasiScintillation::G4QuasiScintillation(const G4String& processName,
|
||||
G4ProcessType type)
|
||||
: G4VRestDiscreteProcess(processName, type)
|
||||
, fIntegralTable1(nullptr)
|
||||
, fIntegralTable2(nullptr)
|
||||
, fIntegralTable3(nullptr)
|
||||
, fEmSaturation(nullptr)
|
||||
, fNumPhotons(0)
|
||||
{
|
||||
secID = G4PhysicsModelCatalog::GetModelID("model_QuasiScintillation");
|
||||
SetProcessSubType(fScintillation);
|
||||
|
||||
#ifdef G4DEBUG_SCINTILLATION
|
||||
ScintTrackEDep = 0.;
|
||||
ScintTrackYield = 0.;
|
||||
#endif
|
||||
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
G4cout << GetProcessName() << " is created " << G4endl;
|
||||
}
|
||||
Initialise();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4QuasiScintillation::~G4QuasiScintillation()
|
||||
{
|
||||
if(fIntegralTable1 != nullptr)
|
||||
{
|
||||
fIntegralTable1->clearAndDestroy();
|
||||
delete fIntegralTable1;
|
||||
}
|
||||
if(fIntegralTable2 != nullptr)
|
||||
{
|
||||
fIntegralTable2->clearAndDestroy();
|
||||
delete fIntegralTable2;
|
||||
}
|
||||
if(fIntegralTable3 != nullptr)
|
||||
{
|
||||
fIntegralTable3->clearAndDestroy();
|
||||
delete fIntegralTable3;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::ProcessDescription(std::ostream& out) const
|
||||
{
|
||||
out << "Scintillation simulates production of optical photons produced\n"
|
||||
"by a high energy particle traversing matter.\n"
|
||||
"Various material properties need to be defined.\n";
|
||||
G4VRestDiscreteProcess::DumpInfo();
|
||||
|
||||
G4OpticalParameters* params = G4OpticalParameters::Instance();
|
||||
out << "Track secondaries first: " << params->GetScintTrackSecondariesFirst();
|
||||
out << "Finite rise time: " << params->GetScintFiniteRiseTime();
|
||||
out << "Scintillation by particle type: " << params->GetScintByParticleType();
|
||||
out << "Save track information: " << params->GetScintTrackInfo();
|
||||
out << "Stack photons: " << params->GetScintStackPhotons();
|
||||
out << "Verbose level: " << params->GetScintVerboseLevel();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool
|
||||
G4QuasiScintillation::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
{
|
||||
if(aParticleType.GetParticleName() == "opticalphoton")
|
||||
return false;
|
||||
if(aParticleType.IsShortLived())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::PreparePhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
Initialise();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::Initialise()
|
||||
{
|
||||
G4OpticalParameters* params = G4OpticalParameters::Instance();
|
||||
SetTrackSecondariesFirst(params->GetScintTrackSecondariesFirst());
|
||||
SetOffloadPhotons(params->GetScintOffloadPhotons());
|
||||
SetFiniteRiseTime(params->GetScintFiniteRiseTime());
|
||||
SetScintillationByParticleType(params->GetScintByParticleType());
|
||||
SetScintillationTrackInfo(params->GetScintTrackInfo());
|
||||
SetStackPhotons(params->GetScintStackPhotons());
|
||||
SetVerboseLevel(params->GetScintVerboseLevel());
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::BuildPhysicsTable(const G4ParticleDefinition&)
|
||||
{
|
||||
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
|
||||
std::size_t numOfMaterials = G4Material::GetNumberOfMaterials();
|
||||
|
||||
// Find the number of materials that have non-empty material property tables
|
||||
std::size_t numOfMaterialsWithMPT = 0;
|
||||
for(std::size_t i = 0; i < numOfMaterials; ++i)
|
||||
{
|
||||
if(((*materialTable)[i])->GetMaterialPropertiesTable())
|
||||
{
|
||||
++numOfMaterialsWithMPT;
|
||||
}
|
||||
}
|
||||
|
||||
// create new physics table
|
||||
fIntegralTable1 = new G4PhysicsTable(numOfMaterialsWithMPT);
|
||||
fIntegralTable2 = new G4PhysicsTable(numOfMaterialsWithMPT);
|
||||
fIntegralTable3 = new G4PhysicsTable(numOfMaterialsWithMPT);
|
||||
|
||||
std::size_t indexMPT = 0;
|
||||
for(std::size_t i = 0; i < numOfMaterials; ++i)
|
||||
{
|
||||
// Retrieve vector of scintillation wavelength intensity for
|
||||
// the material from the material's optical properties table.
|
||||
G4MaterialPropertiesTable* MPT =
|
||||
((*materialTable)[i])->GetMaterialPropertiesTable();
|
||||
|
||||
if(MPT)
|
||||
{
|
||||
auto vector1 = new G4PhysicsFreeVector();
|
||||
auto vector2 = new G4PhysicsFreeVector();
|
||||
auto vector3 = new G4PhysicsFreeVector();
|
||||
|
||||
BuildInverseCdfTable(MPT->GetProperty(kSCINTILLATIONCOMPONENT1), vector1);
|
||||
BuildInverseCdfTable(MPT->GetProperty(kSCINTILLATIONCOMPONENT2), vector2);
|
||||
BuildInverseCdfTable(MPT->GetProperty(kSCINTILLATIONCOMPONENT3), vector3);
|
||||
|
||||
fIntegralTable1->insertAt(indexMPT, vector1);
|
||||
fIntegralTable2->insertAt(indexMPT, vector2);
|
||||
fIntegralTable3->insertAt(indexMPT, vector3);
|
||||
|
||||
fIndexMPT.insert(std::make_pair(i, indexMPT));
|
||||
++indexMPT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void
|
||||
G4QuasiScintillation::BuildInverseCdfTable(const G4MaterialPropertyVector* MPV,
|
||||
G4PhysicsFreeVector* vec) const
|
||||
// Build the inverse cumulative distribution function (C.D.F.) vector for the
|
||||
// scintillation photon spectrum from a given G4MaterialPropertyVector.
|
||||
// The resulting C.D.F. is stored in a G4PhysicsFreeVector, with values
|
||||
// representing the inverse C.D.F. as a function of photon energy.
|
||||
{
|
||||
if(MPV && (*MPV)[0] >= 0.0)
|
||||
{
|
||||
std::vector<G4double> cdf(MPV->GetVectorLength());
|
||||
cdf.front() = 0.0;
|
||||
for (std::size_t ii = 1; ii < MPV->GetVectorLength() ; ++ii)
|
||||
{
|
||||
cdf[ii] = cdf[ii - 1] + 0.5 * (MPV->Energy(ii) - MPV->Energy(ii-1))
|
||||
* ((*MPV)[ii] + (*MPV)[ii - 1]);
|
||||
}
|
||||
// Normalize for the inverse C.D.F. vector
|
||||
for (std::size_t ii = 0; ii < MPV->GetVectorLength(); ++ii)
|
||||
{
|
||||
cdf[ii] = cdf[ii] / cdf.back();
|
||||
vec->InsertValues(cdf[ii], MPV->Energy(ii));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4VParticleChange* G4QuasiScintillation::AtRestDoIt(const G4Track& aTrack,
|
||||
const G4Step& aStep)
|
||||
// This routine simply calls the equivalent PostStepDoIt since all the
|
||||
// necessary information resides in aStep.GetTotalEnergyDeposit()
|
||||
{
|
||||
return G4QuasiScintillation::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4VParticleChange* G4QuasiScintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
const G4Step& aStep)
|
||||
// This routine is called for each tracking step of a charged particle
|
||||
// in a scintillator. A Poisson/Gauss-distributed number of photons is
|
||||
// generated according to the scintillation yield formula, distributed
|
||||
// evenly along the track segment and uniformly into 4pi.
|
||||
{
|
||||
aParticleChange.Initialize(aTrack);
|
||||
fNumPhotons = 0;
|
||||
|
||||
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
|
||||
const G4Material* aMaterial = aTrack.GetMaterial();
|
||||
|
||||
G4StepPoint* pPreStepPoint = aStep.GetPreStepPoint();
|
||||
G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
|
||||
|
||||
G4ThreeVector x0 = pPreStepPoint->GetPosition();
|
||||
G4ThreeVector p0 = aStep.GetDeltaPosition().unit();
|
||||
G4double t0 = pPreStepPoint->GetGlobalTime();
|
||||
|
||||
G4double TotalEnergyDeposit = aStep.GetTotalEnergyDeposit();
|
||||
|
||||
G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
|
||||
if(!MPT)
|
||||
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
|
||||
G4int N_timeconstants = 1;
|
||||
|
||||
if(MPT->GetProperty(kSCINTILLATIONCOMPONENT3))
|
||||
N_timeconstants = 3;
|
||||
else if(MPT->GetProperty(kSCINTILLATIONCOMPONENT2))
|
||||
N_timeconstants = 2;
|
||||
else if(!(MPT->GetProperty(kSCINTILLATIONCOMPONENT1)))
|
||||
{
|
||||
// no components were specified
|
||||
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
G4double ResolutionScale = MPT->GetConstProperty(kRESOLUTIONSCALE);
|
||||
G4double MeanNumberOfPhotons;
|
||||
|
||||
G4double yield1 = 0.;
|
||||
G4double yield2 = 0.;
|
||||
G4double yield3 = 0.;
|
||||
G4double timeconstant1 = 0.;
|
||||
G4double timeconstant2 = 0.;
|
||||
G4double timeconstant3 = 0.;
|
||||
G4double sum_yields = 0.;
|
||||
|
||||
if(fScintillationByParticleType)
|
||||
{
|
||||
MeanNumberOfPhotons = GetScintillationYieldByParticleType(
|
||||
aTrack, aStep, yield1, yield2, yield3, timeconstant1, timeconstant2,
|
||||
timeconstant3);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield1 = MPT->ConstPropertyExists(kSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
// The default linear scintillation process
|
||||
// Units: [# scintillation photons / MeV]
|
||||
MeanNumberOfPhotons = MPT->GetConstProperty(kSCINTILLATIONYIELD);
|
||||
// Birk's correction via fEmSaturation and specifying scintillation by
|
||||
// by particle type are physically mutually exclusive
|
||||
if(fEmSaturation)
|
||||
MeanNumberOfPhotons *=
|
||||
(fEmSaturation->VisibleEnergyDepositionAtAStep(&aStep));
|
||||
else
|
||||
MeanNumberOfPhotons *= TotalEnergyDeposit;
|
||||
}
|
||||
sum_yields = yield1 + yield2 + yield3;
|
||||
|
||||
if(MeanNumberOfPhotons > 10.)
|
||||
{
|
||||
G4double sigma = ResolutionScale * std::sqrt(MeanNumberOfPhotons);
|
||||
fNumPhotons = G4int(G4RandGauss::shoot(MeanNumberOfPhotons, sigma) + 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
fNumPhotons = G4int(G4Poisson(MeanNumberOfPhotons));
|
||||
}
|
||||
|
||||
if(fNumPhotons <= 0 || !fStackingFlag)
|
||||
{
|
||||
// return unchanged particle and no secondaries
|
||||
aParticleChange.SetNumberOfSecondaries(0);
|
||||
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
aParticleChange.SetNumberOfSecondaries(fNumPhotons);
|
||||
|
||||
if(fTrackSecondariesFirst)
|
||||
{
|
||||
if(aTrack.GetTrackStatus() == fAlive)
|
||||
aParticleChange.ProposeTrackStatus(fSuspend);
|
||||
}
|
||||
|
||||
std::size_t materialIndex = aMaterial->GetIndex();
|
||||
auto it = fIndexMPT.find(materialIndex);
|
||||
|
||||
std::size_t indexMPT = 0;
|
||||
if(it != fIndexMPT.end())
|
||||
{
|
||||
indexMPT = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "G4MaterialPropertiesTable for " << aMaterial->GetName()
|
||||
<< " is not found!" << G4endl;
|
||||
G4Exception("G4QuasiScintillation::PostStepDoIt", "Scint04",
|
||||
FatalException, ed);
|
||||
}
|
||||
|
||||
// Retrieve the Scintillation Integral for this material
|
||||
// new G4PhysicsFreeVector allocated to hold CII's
|
||||
G4int numPhot = fNumPhotons;
|
||||
G4double scintTime = 0.;
|
||||
G4double riseTime = 0.;
|
||||
G4PhysicsFreeVector* scintIntegral = nullptr;
|
||||
G4ScintillationType scintType = Slow;
|
||||
|
||||
G4bool isNeutral = (aParticle->GetDefinition()->GetPDGCharge() == 0);
|
||||
G4double deltaVelocity = pPostStepPoint->GetVelocity() -
|
||||
pPreStepPoint->GetVelocity();
|
||||
auto touchableHandle = aStep.GetPreStepPoint()->GetTouchableHandle();
|
||||
|
||||
for(G4int scnt = 0; scnt < N_timeconstants; ++scnt)
|
||||
{
|
||||
// if there is 1 time constant it is #1, etc.
|
||||
if(scnt == 0)
|
||||
{
|
||||
if(N_timeconstants == 1)
|
||||
{
|
||||
numPhot = fNumPhotons;
|
||||
}
|
||||
else
|
||||
{
|
||||
numPhot = yield1 / sum_yields * fNumPhotons;
|
||||
}
|
||||
if(fScintillationByParticleType)
|
||||
{
|
||||
scintTime = timeconstant1;
|
||||
}
|
||||
else
|
||||
{
|
||||
scintTime = MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
}
|
||||
if(fFiniteRiseTime)
|
||||
{
|
||||
riseTime = MPT->GetConstProperty(kSCINTILLATIONRISETIME1);
|
||||
}
|
||||
scintType = Fast;
|
||||
scintIntegral = (G4PhysicsFreeVector*) ((*fIntegralTable1)(indexMPT));
|
||||
}
|
||||
else if(scnt == 1)
|
||||
{
|
||||
// to be consistent with old version (due to double->int conversion)
|
||||
if(N_timeconstants == 2)
|
||||
{
|
||||
numPhot = fNumPhotons - numPhot;
|
||||
}
|
||||
else
|
||||
{
|
||||
numPhot = yield2 / sum_yields * fNumPhotons;
|
||||
}
|
||||
if(fScintillationByParticleType)
|
||||
{
|
||||
scintTime = timeconstant2;
|
||||
}
|
||||
else
|
||||
{
|
||||
scintTime = MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(fFiniteRiseTime)
|
||||
{
|
||||
riseTime = MPT->GetConstProperty(kSCINTILLATIONRISETIME2);
|
||||
}
|
||||
scintType = Medium;
|
||||
scintIntegral = (G4PhysicsFreeVector*) ((*fIntegralTable2)(indexMPT));
|
||||
}
|
||||
else if(scnt == 2)
|
||||
{
|
||||
numPhot = yield3 / sum_yields * fNumPhotons;
|
||||
if(fScintillationByParticleType)
|
||||
{
|
||||
scintTime = timeconstant3;
|
||||
}
|
||||
else
|
||||
{
|
||||
scintTime = MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
if(fFiniteRiseTime)
|
||||
{
|
||||
riseTime = MPT->GetConstProperty(kSCINTILLATIONRISETIME3);
|
||||
}
|
||||
scintType = Slow;
|
||||
scintIntegral = (G4PhysicsFreeVector*) ((*fIntegralTable3)(indexMPT));
|
||||
}
|
||||
|
||||
if(!scintIntegral)
|
||||
continue;
|
||||
|
||||
if(fOffloadingFlag)
|
||||
{
|
||||
// Create a G4DynamicParticle with G4QuasiOpticalPhoton
|
||||
auto quasiPhoton = new G4DynamicParticle(
|
||||
G4QuasiOpticalPhoton::QuasiOpticalPhotonDefinition(),
|
||||
aParticle->GetMomentum());
|
||||
|
||||
// Create a new G4Track object with the quasi-optical photon
|
||||
G4Track* aSecondaryTrack = new G4Track(quasiPhoton, t0, x0);
|
||||
aSecondaryTrack->SetTouchableHandle(touchableHandle);
|
||||
aSecondaryTrack->SetParentID(aTrack.GetTrackID());
|
||||
aSecondaryTrack->SetCreatorModelID(secID);
|
||||
|
||||
// Attach auxiliary track information with associated metadata
|
||||
G4QuasiOpticalData quasiTrackData{aMaterial->GetIndex(), numPhot,
|
||||
aParticle->GetDefinition()->GetPDGCharge(), aStep.GetStepLength(),
|
||||
pPreStepPoint->GetVelocity(), deltaVelocity, aStep.GetDeltaPosition()};
|
||||
aSecondaryTrack->SetAuxiliaryTrackInformation(secID,
|
||||
new G4ScintillationQuasiTrackInfo(quasiTrackData, scintTime, riseTime));
|
||||
aParticleChange.AddSecondary(aSecondaryTrack);
|
||||
}
|
||||
|
||||
for(G4int i = 0; i < numPhot; ++i)
|
||||
{
|
||||
// Determine photon energy
|
||||
G4double sampledEnergy = scintIntegral->Value(G4UniformRand());
|
||||
|
||||
if(verboseLevel > 1)
|
||||
{
|
||||
G4cout << "sampledEnergy = " << sampledEnergy << G4endl;
|
||||
}
|
||||
|
||||
// Generate random photon direction
|
||||
G4double cost = 1. - 2. * G4UniformRand();
|
||||
G4double sint = std::sqrt((1. - cost) * (1. + cost));
|
||||
G4double phi = twopi * G4UniformRand();
|
||||
G4double sinp = std::sin(phi);
|
||||
G4double cosp = std::cos(phi);
|
||||
G4ParticleMomentum photonMomentum(sint * cosp, sint * sinp, cost);
|
||||
|
||||
// Determine polarization of new photon
|
||||
G4ThreeVector photonPolarization(cost * cosp, cost * sinp, -sint);
|
||||
G4ThreeVector perp = photonMomentum.cross(photonPolarization);
|
||||
phi = twopi * G4UniformRand();
|
||||
sinp = std::sin(phi);
|
||||
cosp = std::cos(phi);
|
||||
photonPolarization = (cosp * photonPolarization + sinp * perp).unit();
|
||||
|
||||
// Generate a new photon:
|
||||
auto scintPhoton = new G4DynamicParticle(opticalphoton, photonMomentum);
|
||||
scintPhoton->SetPolarization(photonPolarization);
|
||||
scintPhoton->SetKineticEnergy(sampledEnergy);
|
||||
|
||||
// Generate new G4Track object:
|
||||
G4double rand = (isNeutral) ? 1.0 : G4UniformRand();
|
||||
|
||||
// emission time distribution
|
||||
G4double delta = rand * aStep.GetStepLength();
|
||||
G4double deltaTime =
|
||||
delta / (pPreStepPoint->GetVelocity() + 0.5 * rand * deltaVelocity);
|
||||
if(riseTime == 0.0)
|
||||
{
|
||||
deltaTime -= scintTime * std::log(G4UniformRand());
|
||||
}
|
||||
else
|
||||
{
|
||||
deltaTime += sample_time(riseTime, scintTime);
|
||||
}
|
||||
|
||||
G4double secTime = t0 + deltaTime;
|
||||
G4ThreeVector secPosition = x0 + rand * aStep.GetDeltaPosition();
|
||||
|
||||
G4Track* secTrack = new G4Track(scintPhoton, secTime, secPosition);
|
||||
secTrack->SetTouchableHandle(touchableHandle);
|
||||
secTrack->SetParentID(aTrack.GetTrackID());
|
||||
secTrack->SetCreatorModelID(secID);
|
||||
if(fScintillationTrackInfo)
|
||||
secTrack->SetUserInformation(
|
||||
new G4ScintillationTrackInformation(scintType));
|
||||
aParticleChange.AddSecondary(secTrack);
|
||||
}
|
||||
}
|
||||
|
||||
if(verboseLevel > 1)
|
||||
{
|
||||
G4cout << "\n Exiting from G4QuasiScintillation::DoIt -- "
|
||||
<< " NumberOfSecondaries = "
|
||||
<< aParticleChange.GetNumberOfSecondaries() << G4endl;
|
||||
}
|
||||
|
||||
return G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiScintillation::GetMeanFreePath(const G4Track&, G4double,
|
||||
G4ForceCondition* condition)
|
||||
{
|
||||
*condition = StronglyForced;
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiScintillation::GetMeanLifeTime(const G4Track&,
|
||||
G4ForceCondition* condition)
|
||||
{
|
||||
*condition = Forced;
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiScintillation::sample_time(G4double tau1, G4double tau2)
|
||||
{
|
||||
// tau1: rise time and tau2: decay time
|
||||
// Loop checking, 07-Aug-2015, Vladimir Ivanchenko
|
||||
G4double t;
|
||||
|
||||
do
|
||||
{
|
||||
// The exponential distribution as an envelope function: very efficient
|
||||
t = -1.0 * tau2 * G4Log(1.0 - G4UniformRand());
|
||||
}
|
||||
while (G4UniformRand() > (1.0 - G4Exp(-t/tau1)));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4double G4QuasiScintillation::GetScintillationYieldByParticleType(
|
||||
const G4Track& aTrack, const G4Step& aStep, G4double& yield1,
|
||||
G4double& yield2, G4double& yield3, G4double& timeconstant1,
|
||||
G4double& timeconstant2, G4double& timeconstant3)
|
||||
{
|
||||
// new in 10.7, allow multiple time constants with ScintByParticleType
|
||||
// Get the G4MaterialPropertyVector containing the scintillation
|
||||
// yield as a function of the energy deposited and particle type
|
||||
// In 11.2, allow different time constants for different particles
|
||||
|
||||
G4ParticleDefinition* pDef = aTrack.GetDynamicParticle()->GetDefinition();
|
||||
G4MaterialPropertyVector* yieldVector = nullptr;
|
||||
G4MaterialPropertiesTable* MPT =
|
||||
aTrack.GetMaterial()->GetMaterialPropertiesTable();
|
||||
|
||||
// Protons
|
||||
if(pDef == G4Proton::ProtonDefinition())
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kPROTONSCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kPROTONSCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kPROTONSCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Deuterons
|
||||
else if(pDef == G4Deuteron::DeuteronDefinition())
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kDEUTERONSCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kDEUTERONSCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kDEUTERONSCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Tritons
|
||||
else if(pDef == G4Triton::TritonDefinition())
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kTRITONSCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kTRITONSCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kTRITONSCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Alphas
|
||||
else if(pDef == G4Alpha::AlphaDefinition())
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kALPHASCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kALPHASCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kALPHASCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kALPHASCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kALPHASCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kALPHASCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kALPHASCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kALPHASCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Ions (particles derived from G4VIon and G4Ions) and recoil ions
|
||||
// below the production cut from neutrons after hElastic
|
||||
else if(pDef->GetParticleType() == "nucleus" ||
|
||||
pDef == G4Neutron::NeutronDefinition())
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kIONSCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kIONSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kIONSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kIONSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kIONSCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kIONSCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kIONSCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kIONSCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Electrons (must also account for shell-binding energy
|
||||
// attributed to gamma from standard photoelectric effect)
|
||||
// and, default for particles not enumerated/listed above
|
||||
else
|
||||
{
|
||||
yieldVector = MPT->GetProperty(kELECTRONSCINTILLATIONYIELD);
|
||||
yield1 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONYIELD1)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONYIELD1)
|
||||
: 1.;
|
||||
yield2 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONYIELD2)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONYIELD2)
|
||||
: 0.;
|
||||
yield3 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONYIELD3)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONYIELD3)
|
||||
: 0.;
|
||||
timeconstant1 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONTIMECONSTANT1)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONTIMECONSTANT1)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT1);
|
||||
if(yield2 > 0.)
|
||||
{
|
||||
timeconstant2 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONTIMECONSTANT2)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONTIMECONSTANT2)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT2);
|
||||
}
|
||||
if(yield3 > 0.)
|
||||
{
|
||||
timeconstant3 = MPT->ConstPropertyExists(kELECTRONSCINTILLATIONTIMECONSTANT3)
|
||||
? MPT->GetConstProperty(kELECTRONSCINTILLATIONTIMECONSTANT3)
|
||||
: MPT->GetConstProperty(kSCINTILLATIONTIMECONSTANT3);
|
||||
}
|
||||
}
|
||||
|
||||
// Throw an exception if no scintillation yield vector is found
|
||||
if(yieldVector == nullptr)
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "\nG4QuasiScintillation::PostStepDoIt(): "
|
||||
<< "Request for scintillation yield for energy deposit and particle\n"
|
||||
<< "type without correct entry in MaterialPropertiesTable. A material\n"
|
||||
<< "property (vector) with name like PARTICLESCINTILLATIONYIELD is\n"
|
||||
<< "needed (hint: PARTICLE might not be the primary particle."
|
||||
<< G4endl;
|
||||
G4String comments = "Missing MaterialPropertiesTable entry - No correct "
|
||||
"entry in MaterialPropertiesTable";
|
||||
G4Exception("G4QuasiScintillation::PostStepDoIt", "Scint01", FatalException, ed,
|
||||
comments);
|
||||
return 0.; // NOLINT: required to help Coverity recognise this as exit point
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Calculate the scintillation light //
|
||||
///////////////////////////////////////
|
||||
// To account for potential nonlinearity and scintillation photon
|
||||
// density along the track, light (L) is produced according to:
|
||||
// L_currentStep = L(PreStepKE) - L(PreStepKE - EDep)
|
||||
|
||||
G4double ScintillationYield = 0.;
|
||||
G4double StepEnergyDeposit = aStep.GetTotalEnergyDeposit();
|
||||
G4double PreStepKineticEnergy = aStep.GetPreStepPoint()->GetKineticEnergy();
|
||||
|
||||
if(PreStepKineticEnergy <= yieldVector->GetMaxEnergy())
|
||||
{
|
||||
// G4double Yield1 = yieldVector->Value(PreStepKineticEnergy);
|
||||
// G4double Yield2 = yieldVector->Value(PreStepKineticEnergy -
|
||||
// StepEnergyDeposit); ScintillationYield = Yield1 - Yield2;
|
||||
ScintillationYield =
|
||||
yieldVector->Value(PreStepKineticEnergy) -
|
||||
yieldVector->Value(PreStepKineticEnergy - StepEnergyDeposit);
|
||||
}
|
||||
else
|
||||
{
|
||||
++fNumEnergyWarnings;
|
||||
if(verboseLevel > 0 && fNumEnergyWarnings <= 10)
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "\nG4QuasiScintillation::GetScintillationYieldByParticleType(): "
|
||||
<< "Request\n"
|
||||
<< "for scintillation light yield above the available energy range\n"
|
||||
<< "specified in G4MaterialPropertiesTable. A linear interpolation\n"
|
||||
<< "will be performed to compute the scintillation light yield using\n"
|
||||
<< "(L_max / E_max) as the photon yield per unit energy." << G4endl;
|
||||
G4String cmt = "\nScintillation yield may be unphysical!\n";
|
||||
|
||||
if(fNumEnergyWarnings == 10)
|
||||
{
|
||||
ed << G4endl << "*** Scintillation energy warnings stopped.";
|
||||
}
|
||||
G4Exception("G4QuasiScintillation::GetScintillationYieldByParticleType()",
|
||||
"Scint03", JustWarning, ed, cmt);
|
||||
}
|
||||
|
||||
// Units: [# scintillation photons]
|
||||
ScintillationYield = yieldVector->GetMaxValue() /
|
||||
yieldVector->GetMaxEnergy() * StepEnergyDeposit;
|
||||
}
|
||||
|
||||
#ifdef G4DEBUG_SCINTILLATION
|
||||
// Increment track aggregators
|
||||
ScintTrackYield += ScintillationYield;
|
||||
ScintTrackEDep += StepEnergyDeposit;
|
||||
|
||||
G4cout << "\n-- "
|
||||
<< "G4QuasiScintillation::GetScintillationYieldByParticleType() --\n"
|
||||
<< "--\n"
|
||||
<< "-- Name = "
|
||||
<< aTrack.GetParticleDefinition()->GetParticleName() << "\n"
|
||||
<< "-- TrackID = " << aTrack.GetTrackID() << "\n"
|
||||
<< "-- ParentID = " << aTrack.GetParentID() << "\n"
|
||||
<< "-- Current KE = " << aTrack.GetKineticEnergy() / MeV
|
||||
<< " MeV\n"
|
||||
<< "-- Step EDep = " << aStep.GetTotalEnergyDeposit() / MeV
|
||||
<< " MeV\n"
|
||||
<< "-- Track EDep = " << ScintTrackEDep / MeV << " MeV\n"
|
||||
<< "-- Vertex KE = " << aTrack.GetVertexKineticEnergy() / MeV
|
||||
<< " MeV\n"
|
||||
<< "-- Step yield = " << ScintillationYield << " photons\n"
|
||||
<< "-- Track yield = " << ScintTrackYield << " photons\n"
|
||||
<< G4endl;
|
||||
|
||||
// The track has terminated within or has left the scintillator volume
|
||||
if((aTrack.GetTrackStatus() == fStopButAlive) or
|
||||
(aStep.GetPostStepPoint()->GetStepStatus() == fGeomBoundary))
|
||||
{
|
||||
// Reset aggregators for the next track
|
||||
ScintTrackEDep = 0.;
|
||||
ScintTrackYield = 0.;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ScintillationYield;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::DumpPhysicsTable() const
|
||||
{
|
||||
if(fIntegralTable1)
|
||||
{
|
||||
for(std::size_t i = 0; i < fIntegralTable1->entries(); ++i)
|
||||
{
|
||||
((G4PhysicsFreeVector*) (*fIntegralTable1)[i])->DumpValues();
|
||||
}
|
||||
}
|
||||
if(fIntegralTable2)
|
||||
{
|
||||
for(std::size_t i = 0; i < fIntegralTable2->entries(); ++i)
|
||||
{
|
||||
((G4PhysicsFreeVector*) (*fIntegralTable2)[i])->DumpValues();
|
||||
}
|
||||
}
|
||||
if(fIntegralTable3)
|
||||
{
|
||||
for(std::size_t i = 0; i < fIntegralTable3->entries(); ++i)
|
||||
{
|
||||
((G4PhysicsFreeVector*) (*fIntegralTable3)[i])->DumpValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetTrackSecondariesFirst(const G4bool state)
|
||||
{
|
||||
fTrackSecondariesFirst = state;
|
||||
G4OpticalParameters::Instance()->SetScintTrackSecondariesFirst(
|
||||
fTrackSecondariesFirst);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetFiniteRiseTime(const G4bool state)
|
||||
{
|
||||
fFiniteRiseTime = state;
|
||||
G4OpticalParameters::Instance()->SetScintFiniteRiseTime(fFiniteRiseTime);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetScintillationByParticleType(const G4bool scintType)
|
||||
{
|
||||
if(fEmSaturation && scintType)
|
||||
{
|
||||
G4Exception("G4QuasiScintillation::SetScintillationByParticleType",
|
||||
"Scint02", JustWarning,
|
||||
"Redefinition: Birks Saturation is replaced by "
|
||||
"ScintillationByParticleType!");
|
||||
RemoveSaturation();
|
||||
}
|
||||
fScintillationByParticleType = scintType;
|
||||
G4OpticalParameters::Instance()->SetScintByParticleType(
|
||||
fScintillationByParticleType);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetScintillationTrackInfo(const G4bool trackType)
|
||||
{
|
||||
fScintillationTrackInfo = trackType;
|
||||
G4OpticalParameters::Instance()->SetScintTrackInfo(fScintillationTrackInfo);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetStackPhotons(const G4bool stackingFlag)
|
||||
{
|
||||
fStackingFlag = stackingFlag;
|
||||
G4OpticalParameters::Instance()->SetScintStackPhotons(fStackingFlag);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetOffloadPhotons(const G4bool offloadingFlag)
|
||||
{
|
||||
fOffloadingFlag = offloadingFlag;
|
||||
G4OpticalParameters::Instance()->SetScintOffloadPhotons(fOffloadingFlag);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4QuasiScintillation::SetVerboseLevel(G4int verbose)
|
||||
{
|
||||
verboseLevel = verbose;
|
||||
G4OpticalParameters::Instance()->SetScintVerboseLevel(verboseLevel);
|
||||
}
|
||||
@@ -149,11 +149,7 @@ void G4Scintillation::ProcessDescription(std::ostream& out) const
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4Scintillation::IsApplicable(const G4ParticleDefinition& aParticleType)
|
||||
{
|
||||
if(aParticleType.GetParticleName() == "opticalphoton")
|
||||
return false;
|
||||
if(aParticleType.IsShortLived())
|
||||
return false;
|
||||
return true;
|
||||
return (!aParticleType.IsShortLived());
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -280,6 +276,9 @@ G4VParticleChange* G4Scintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
G4double t0 = pPreStepPoint->GetGlobalTime();
|
||||
|
||||
G4double TotalEnergyDeposit = aStep.GetTotalEnergyDeposit();
|
||||
if (0.0 >= TotalEnergyDeposit) {
|
||||
G4VRestDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
||||
}
|
||||
|
||||
G4MaterialPropertiesTable* MPT = aMaterial->GetMaterialPropertiesTable();
|
||||
if(!MPT)
|
||||
@@ -381,12 +380,17 @@ G4VParticleChange* G4Scintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
|
||||
// Retrieve the Scintillation Integral for this material
|
||||
// new G4PhysicsFreeVector allocated to hold CII's
|
||||
std::size_t numPhot = fNumPhotons;
|
||||
G4int numPhot = fNumPhotons;
|
||||
G4double scintTime = 0.;
|
||||
G4double riseTime = 0.;
|
||||
G4PhysicsFreeVector* scintIntegral = nullptr;
|
||||
G4ScintillationType scintType = Slow;
|
||||
|
||||
G4bool isNeutral = (aParticle->GetDefinition()->GetPDGCharge() == 0);
|
||||
G4double deltaVelocity = pPostStepPoint->GetVelocity() -
|
||||
pPreStepPoint->GetVelocity();
|
||||
auto touchableHandle = aStep.GetPreStepPoint()->GetTouchableHandle();
|
||||
|
||||
for(G4int scnt = 0; scnt < N_timeconstants; ++scnt)
|
||||
{
|
||||
// if there is 1 time constant it is #1, etc.
|
||||
@@ -463,7 +467,7 @@ G4VParticleChange* G4Scintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
if(!scintIntegral)
|
||||
continue;
|
||||
|
||||
for(std::size_t i = 0; i < numPhot; ++i)
|
||||
for(G4int i = 0; i < numPhot; ++i)
|
||||
{
|
||||
// Determine photon energy
|
||||
G4double sampledEnergy = scintIntegral->Value(G4UniformRand());
|
||||
@@ -495,19 +499,12 @@ G4VParticleChange* G4Scintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
scintPhoton->SetKineticEnergy(sampledEnergy);
|
||||
|
||||
// Generate new G4Track object:
|
||||
G4double rand = G4UniformRand();
|
||||
if(aParticle->GetDefinition()->GetPDGCharge() == 0)
|
||||
{
|
||||
rand = 1.0;
|
||||
}
|
||||
G4double rand = (isNeutral) ? 1.0 : G4UniformRand();
|
||||
|
||||
// emission time distribution
|
||||
G4double delta = rand * aStep.GetStepLength();
|
||||
G4double deltaTime =
|
||||
delta /
|
||||
(pPreStepPoint->GetVelocity() +
|
||||
rand * (pPostStepPoint->GetVelocity() - pPreStepPoint->GetVelocity()) /
|
||||
2.);
|
||||
delta / (pPreStepPoint->GetVelocity() + 0.5 * rand * deltaVelocity);
|
||||
if(riseTime == 0.0)
|
||||
{
|
||||
deltaTime -= scintTime * std::log(G4UniformRand());
|
||||
@@ -521,8 +518,7 @@ G4VParticleChange* G4Scintillation::PostStepDoIt(const G4Track& aTrack,
|
||||
G4ThreeVector secPosition = x0 + rand * aStep.GetDeltaPosition();
|
||||
|
||||
G4Track* secTrack = new G4Track(scintPhoton, secTime, secPosition);
|
||||
secTrack->SetTouchableHandle(
|
||||
aStep.GetPreStepPoint()->GetTouchableHandle());
|
||||
secTrack->SetTouchableHandle(touchableHandle);
|
||||
secTrack->SetParentID(aTrack.GetTrackID());
|
||||
secTrack->SetCreatorModelID(secID);
|
||||
if(fScintillationTrackInfo)
|
||||
|
||||
@@ -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. *
|
||||
// ********************************************************************
|
||||
#include "G4ScintillationQuasiTrackInfo.hh"
|
||||
|
||||
G4Allocator<G4ScintillationQuasiTrackInfo>*& aScintillationATIAllocator()
|
||||
{
|
||||
G4ThreadLocalStatic G4Allocator<G4ScintillationQuasiTrackInfo>* _instance =
|
||||
nullptr;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
G4ScintillationQuasiTrackInfo::G4ScintillationQuasiTrackInfo(
|
||||
const G4QuasiOpticalData& aData, G4double aScintTime, G4double aRiseTime)
|
||||
: G4VAuxiliaryTrackInformation()
|
||||
, fQuasiOpticalData(aData)
|
||||
, fScintTime(aScintTime)
|
||||
, fRiseTime(aRiseTime)
|
||||
{}
|
||||
|
||||
void G4ScintillationQuasiTrackInfo::Print() const
|
||||
{
|
||||
G4cout << "Auxiliary track information for a scintillation step" << G4endl;
|
||||
}
|
||||
|
||||
G4ScintillationQuasiTrackInfo* G4ScintillationQuasiTrackInfo::Cast(
|
||||
const G4VAuxiliaryTrackInformation* const aATI)
|
||||
{
|
||||
G4ScintillationQuasiTrackInfo* SATI = nullptr;
|
||||
if(aATI != nullptr)
|
||||
{
|
||||
// No change will be done to the pointer and to the pointed data
|
||||
auto temp = const_cast<G4VAuxiliaryTrackInformation*>(aATI);
|
||||
SATI = dynamic_cast<G4ScintillationQuasiTrackInfo*>(temp);
|
||||
}
|
||||
return SATI;
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * 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. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// G4StandardCerenkovModel
|
||||
//
|
||||
// Created 25.05.2025 V.Ivanchenko
|
||||
//
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#include "G4StandardCerenkovModel.hh"
|
||||
|
||||
#include "G4ios.hh"
|
||||
#include "G4LossTableManager.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "G4MaterialCutsCouple.hh"
|
||||
#include "G4MaterialPropertiesTable.hh"
|
||||
#include "G4OpticalParameters.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4ParticleMomentum.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4PhysicsFreeVector.hh"
|
||||
#include "G4Poisson.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4OpticalPhoton.hh"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr G4double minAllowedStep = 0.001*CLHEP::mm;
|
||||
constexpr G4int nvec = 10; // number of slices in beta of projectile
|
||||
}
|
||||
|
||||
std::vector<G4double>* G4StandardCerenkovModel::fBetaLim = nullptr;
|
||||
std::vector<G4MaterialPropertyVector*>* G4StandardCerenkovModel::fRindex = nullptr;
|
||||
std::vector<std::vector<G4double>* >* G4StandardCerenkovModel::fMeanNumberOfPhotons = nullptr;
|
||||
std::vector<std::vector<std::vector<G4double>* >* >* G4StandardCerenkovModel::fIntegral = nullptr;
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4StandardCerenkovModel::G4StandardCerenkovModel()
|
||||
: G4VXRayModel("theCerenkov")
|
||||
{
|
||||
if (nullptr == fBetaLim) {
|
||||
isInitializer = true;
|
||||
fBetaLim = new std::vector<G4double>;
|
||||
fMeanNumberOfPhotons = new std::vector<std::vector<G4double>* >;
|
||||
fIntegral = new std::vector<std::vector<std::vector<G4double>* >* >;
|
||||
fRindex = new std::vector<G4MaterialPropertyVector*>;
|
||||
}
|
||||
fPhoton = G4OpticalPhoton::OpticalPhoton();
|
||||
fRfact = 369.81 / (CLHEP::eV * CLHEP::cm); // number of photons per mm
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4StandardCerenkovModel::~G4StandardCerenkovModel()
|
||||
{
|
||||
if (isInitializer && isInitialized) {
|
||||
delete fBetaLim;
|
||||
for (auto const & ptr : *fRindex) {
|
||||
delete ptr;
|
||||
}
|
||||
delete fRindex;
|
||||
for (auto const & ptr : *fMeanNumberOfPhotons) {
|
||||
delete ptr;
|
||||
}
|
||||
delete fMeanNumberOfPhotons;
|
||||
for (auto const & ptr : *fIntegral) {
|
||||
for (auto const & p : *ptr) {
|
||||
delete p;
|
||||
}
|
||||
delete ptr;
|
||||
}
|
||||
delete fIntegral;
|
||||
fIntegral = nullptr;
|
||||
fBetaLim = nullptr;
|
||||
fRindex = nullptr;
|
||||
fMeanNumberOfPhotons = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4StandardCerenkovModel::InitialiseModel()
|
||||
{
|
||||
G4double beta = 1.0;
|
||||
if (0 == nVolumes) { return; }
|
||||
if (isInitializer && !isInitialized) {
|
||||
isInitialized = true;
|
||||
fBetaLim->resize(nVolumes, 1.0);
|
||||
fRindex->resize(nVolumes, nullptr);
|
||||
fMeanNumberOfPhotons->resize(nVolumes, new std::vector<G4double>(nvec, 0.0));
|
||||
fIntegral->resize(nVolumes, nullptr);
|
||||
|
||||
for (std::size_t i = 0; i < nVolumes; ++i) {
|
||||
auto mat = ((*pLogicalVolumes)[i])->GetMaterial();
|
||||
auto MPT = mat->GetMaterialPropertiesTable();
|
||||
|
||||
if (nullptr == MPT) { continue; }
|
||||
G4MaterialPropertyVector* rindex = MPT->GetProperty(kRINDEX);
|
||||
if (nullptr == rindex) { continue; }
|
||||
(*fRindex)[i] = rindex;
|
||||
|
||||
G4double nMax = rindex->GetMaxValue();
|
||||
if (nMax <= 1.0) { continue; }
|
||||
G4double b = 1.0/nMax;
|
||||
(*fBetaLim)[i] = b;
|
||||
beta = std::min(beta, b);
|
||||
G4double dbeta = (1.0 - b)/(G4double)(nvec - 1);
|
||||
G4double b0 = b;
|
||||
std::size_t nn = rindex->GetVectorLength();
|
||||
if (0 == nn) { continue; }
|
||||
|
||||
auto iptr = new std::vector<std::vector<G4double>* >((std::size_t)nvec, nullptr);
|
||||
(*fIntegral)[i] = iptr;
|
||||
for (auto & ptr : *iptr) {
|
||||
ptr = new std::vector<G4double>(nn, 0.0);
|
||||
}
|
||||
|
||||
// Initialisation for charge = 1.0
|
||||
G4double y0 = AverageNumberOfPhotons(1.0, b0, (*rindex)[0]);
|
||||
(*(*fMeanNumberOfPhotons)[i])[0] = y0;
|
||||
if (1 == nn) { continue; }
|
||||
|
||||
// Initialisation for charge = 1.0
|
||||
for (G4int k = 0; k < nvec; ++k) {
|
||||
(*((*fIntegral)[i]))[k]->resize(nn, 0.0);
|
||||
G4double sum = 0.0;
|
||||
G4double e0 = rindex->GetMinEnergy();
|
||||
G4double deltae = rindex->GetMaxEnergy() - e0;
|
||||
for (std::size_t j = 1; j < nn; ++j) {
|
||||
G4double e = rindex->Energy(j);
|
||||
G4double y = AverageNumberOfPhotons(1.0, beta, (*rindex)[j]);
|
||||
sum += 0.5*(y - y0)*(e - e0);
|
||||
y0 = y;
|
||||
e0 = e;
|
||||
(*(*((*fIntegral)[i]))[k])[j] = sum;
|
||||
}
|
||||
if (deltae > 0.0) { (*(*fMeanNumberOfPhotons)[i])[k] = sum/deltae; }
|
||||
if (sum > 0.0) { sum = 1.0/sum; }
|
||||
for (std::size_t j = 1; j < nn; ++j) {
|
||||
G4double y = (*(*((*fIntegral)[i]))[k])[j]/sum;
|
||||
(*(*((*fIntegral)[i]))[k])[j] = y;
|
||||
}
|
||||
beta += dbeta;
|
||||
beta = std::min(beta, 1.0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < nVolumes; ++i) {
|
||||
beta = std::min(beta, (*fBetaLim)[i]);
|
||||
}
|
||||
}
|
||||
pBetaMin = beta;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
G4bool G4StandardCerenkovModel::StepLimitForVolume(G4double& limit)
|
||||
{
|
||||
G4double betaMin = (*fBetaLim)[pIndex];
|
||||
if (pPreStepBeta <= betaMin) { return false; }
|
||||
|
||||
// step limitation
|
||||
betaMin = std::max(betaMin, pPreStepBeta*pMaxBetaChange);
|
||||
|
||||
auto const dynPart = pCurrentTrack->GetDynamicParticle();
|
||||
fParticle = dynPart->GetDefinition();
|
||||
fPreStepKinE = dynPart->GetKineticEnergy();
|
||||
fCharge = fParticle->GetPDGCharge()/CLHEP::eplus;
|
||||
fMass = fParticle->GetPDGMass();
|
||||
G4double x = limit;
|
||||
|
||||
// If the step is smaller than G4ThreeVector::getTolerance(), it may happen
|
||||
// that the particle does not move. See bug 1992.
|
||||
if (x < minAllowedStep) { return false; }
|
||||
|
||||
// If user has defined an average maximum number of photons to be generated in
|
||||
// a Step, then calculate the Step length for that number of photons using preStep beta.
|
||||
G4double nmax = (*fRindex)[pIndex]->GetMaxValue();
|
||||
fMeanNPhotons = x * AverageNumberOfPhotons(fCharge, pPreStepBeta, nmax);
|
||||
if (pMaxPhotons < fMeanNPhotons) {
|
||||
x *= pMaxPhotons/fMeanNPhotons;
|
||||
x = std::max(x, minAllowedStep);
|
||||
}
|
||||
limit = x;
|
||||
return true;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4StandardCerenkovModel::SampleXRays(std::vector<G4Track*>& out,
|
||||
const G4Step& step)
|
||||
{
|
||||
auto const preStep = step.GetPreStepPoint();
|
||||
auto const postStep = step.GetPostStepPoint();
|
||||
G4double kinE = postStep->GetKineticEnergy();
|
||||
G4double beta = pPreStepBeta;
|
||||
G4double b = (*fBetaLim)[pIndex];
|
||||
G4double dbeta = (1.0 - b)/(G4double)(nvec - 1);
|
||||
G4int idx = std::max(G4int((beta - b)/dbeta), 0);
|
||||
idx = std::min(idx, nvec - 1);
|
||||
std::vector<G4double>* v = (*((*fIntegral)[pIndex]))[idx];
|
||||
|
||||
G4ThreeVector pos = preStep->GetPosition();
|
||||
G4ThreeVector dpos = postStep->GetPosition() - pos;
|
||||
G4ThreeVector dir = dpos.unit();
|
||||
G4double time = preStep->GetGlobalTime();
|
||||
G4double dt = postStep->GetGlobalTime() - time;
|
||||
G4double de = fPreStepKinE - kinE;
|
||||
|
||||
// define sub-steps inside the current step
|
||||
G4double x = (1.0 + fPreStepKinE/fMass);
|
||||
G4double delim = fMass*pMaxBetaChange*x*x*x;
|
||||
G4int nn = (G4int)(de/delim) + 1;
|
||||
x = 1.0/(G4double)nn;
|
||||
dpos *= x;
|
||||
dt *= x;
|
||||
de *= x;
|
||||
G4double delta = dpos.mag();
|
||||
fMeanNPhotons *= x;
|
||||
|
||||
// produce Cerenkov gamma - loop over sub-steps
|
||||
G4double ekin = fPreStepKinE;
|
||||
auto const rindex = (*fRindex)[pIndex];
|
||||
std::size_t ni = rindex->GetVectorLength();
|
||||
if (0 == ni) { return; }
|
||||
G4double emin = rindex->Energy(0);
|
||||
G4double mean = delta*fCharge*fCharge*(*(*fMeanNumberOfPhotons)[pIndex])[idx];
|
||||
|
||||
for (G4int i=0; i<nn; ++i) {
|
||||
G4int ngamma = (G4int)G4Poisson(mean);
|
||||
for (G4int j = 0; j < ngamma; ++j) {
|
||||
G4double q = G4UniformRand();
|
||||
G4double e = emin;
|
||||
G4double n = (*rindex)[0];
|
||||
if (ni > 1) {
|
||||
for (std::size_t k = 1; k < ni; ++k) {
|
||||
if ((*v)[k] <= q) {
|
||||
e = rindex->Energy(k - 1);
|
||||
e += (rindex->Energy(k) - e)*(q - (*v)[k - 1])/((*v)[k] - (*v)[k - 1]);
|
||||
n = (*rindex)[k - 1];
|
||||
n += ((*rindex)[k] - n)*(q - (*v)[k - 1])/((*v)[k] - (*v)[k - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
q = G4UniformRand();
|
||||
G4double t = time + q*dt;
|
||||
G4ThreeVector posnew = pos + q*dpos;
|
||||
G4double minCos = 1.0/(n*beta);
|
||||
G4double maxSin2 = (1.0 - minCos)*(1.0 + minCos);
|
||||
G4double cost, sint2;
|
||||
do {
|
||||
cost = 1.0 - G4UniformRand()*(1.0 - minCos);
|
||||
sint2 = (1.0 - cost)*(1.0 + cost);
|
||||
q = G4UniformRand();
|
||||
} while(q * maxSin2 > sint2);
|
||||
|
||||
G4double sint = std::sqrt(sint2);
|
||||
G4double phi = G4UniformRand()*CLHEP::twopi;
|
||||
G4double cosPhi = std::cos(phi);
|
||||
G4double sinPhi = std::sin(phi);
|
||||
G4ThreeVector dirnew(sint*cosPhi, sint*sinPhi, cost);
|
||||
dirnew.rotateUz(dir);
|
||||
|
||||
// Determine polarization of new photon
|
||||
G4ThreeVector photonPolarization(cost*cosPhi, cost*sinPhi, -sint);
|
||||
|
||||
// Rotate back to original coord system
|
||||
photonPolarization.rotateUz(dir);
|
||||
|
||||
auto dp = new G4DynamicParticle(fPhoton, dirnew, e);
|
||||
dp->SetPolarization(photonPolarization);
|
||||
auto track = new G4Track(dp, t, posnew);
|
||||
out.push_back(track);
|
||||
}
|
||||
pos += dpos;
|
||||
time += dt;
|
||||
ekin -= de;
|
||||
beta = std::sqrt(ekin * (ekin + 2*fMass))/(fMass + ekin);
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
void G4StandardCerenkovModel::ModelDescription(std::ostream& out) const
|
||||
{
|
||||
out << "The Cerenkov effect simulates optical photons created by the\n";
|
||||
out << "passage of charged particles through matter. Materials need\n";
|
||||
out << "to have the property RINDEX (refractive index) defined." << G4endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ void G4XrayReflection::SaveHenkeDataAsMaterialProperty()
|
||||
for (std::size_t i = 0; i < Ephot.size(); ++i) {
|
||||
G4double lambda = CLHEP::twopi * CLHEP::hbarc / Ephot[i];
|
||||
G4double lambda_sqr = lambda * lambda;
|
||||
RealIndex[i] = fmax(0, factor * lambda_sqr * f1[i]); // delta or 1-RealIndex
|
||||
RealIndex[i] = std::fmax(0, factor * lambda_sqr * f1[i]); // delta or 1-RealIndex
|
||||
ImagIndex[i] = factor * lambda_sqr * f2[i]; // beta or -ImagIndex
|
||||
if (GetVerboseLevel() > 2)
|
||||
G4cout << "Ephot=" << std::setw(10) << Ephot[i] / eV << " eV delta=" << std::setw(10)
|
||||
|
||||
Reference in New Issue
Block a user