340 lines
12 KiB
C++
340 lines
12 KiB
C++
//
|
|
// ********************************************************************
|
|
// * 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. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Optical Photon WaveLength Shifting (WLS) Class Implementation
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// File: G4OpWLS2.cc
|
|
// Description: Discrete Process -- Wavelength Shifting of Optical Photons
|
|
// Version: 1.0
|
|
// Created: 2003-05-13
|
|
// Author: John Paul Archambault
|
|
// (Adaptation of G4Scintillation and G4OpAbsorption)
|
|
// Updated: 2005-07-28 - add G4ProcessType to constructor
|
|
// 2006-05-07 - add G4VWLSTimeGeneratorProfile
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "G4OpWLS2.hh"
|
|
#include "G4ios.hh"
|
|
#include "G4PhysicalConstants.hh"
|
|
#include "G4SystemOfUnits.hh"
|
|
#include "G4OpProcessSubType.hh"
|
|
#include "G4Poisson.hh"
|
|
#include "G4OpticalParameters.hh"
|
|
#include "G4WLSTimeGeneratorProfileDelta.hh"
|
|
#include "G4WLSTimeGeneratorProfileExponential.hh"
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
G4OpWLS2::G4OpWLS2(const G4String& processName, G4ProcessType type)
|
|
: G4VDiscreteProcess(processName, type)
|
|
{
|
|
WLSTimeGeneratorProfile = nullptr;
|
|
Initialise();
|
|
SetProcessSubType(fOpWLS);
|
|
theIntegralTable = nullptr;
|
|
|
|
if(verboseLevel > 0)
|
|
G4cout << GetProcessName() << " is created " << G4endl;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
G4OpWLS2::~G4OpWLS2()
|
|
{
|
|
if(theIntegralTable)
|
|
{
|
|
theIntegralTable->clearAndDestroy();
|
|
delete theIntegralTable;
|
|
}
|
|
delete WLSTimeGeneratorProfile;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
void G4OpWLS2::PreparePhysicsTable(const G4ParticleDefinition&)
|
|
{
|
|
Initialise();
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
void G4OpWLS2::Initialise()
|
|
{
|
|
G4OpticalParameters* params = G4OpticalParameters::Instance();
|
|
SetVerboseLevel(params->GetWLS2VerboseLevel());
|
|
UseTimeProfile(params->GetWLS2TimeProfile());
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
G4VParticleChange* G4OpWLS2::PostStepDoIt(const G4Track& aTrack,
|
|
const G4Step& aStep)
|
|
{
|
|
std::vector<G4Track*> proposedSecondaries;
|
|
aParticleChange.Initialize(aTrack);
|
|
aParticleChange.ProposeTrackStatus(fStopAndKill);
|
|
|
|
if(verboseLevel > 1)
|
|
{
|
|
G4cout << "\n** G4OpWLS2: Photon absorbed! **" << G4endl;
|
|
}
|
|
|
|
G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
|
|
G4MaterialPropertiesTable* MPT =
|
|
aTrack.GetMaterial()->GetMaterialPropertiesTable();
|
|
if(!MPT)
|
|
{
|
|
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
|
}
|
|
if(!MPT->GetProperty(kWLSCOMPONENT2))
|
|
{
|
|
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
|
}
|
|
|
|
G4int NumPhotons = 1;
|
|
if(MPT->ConstPropertyExists(kWLSMEANNUMBERPHOTONS2))
|
|
{
|
|
G4double MeanNumberOfPhotons =
|
|
MPT->GetConstProperty(kWLSMEANNUMBERPHOTONS2);
|
|
NumPhotons = G4int(G4Poisson(MeanNumberOfPhotons));
|
|
if(NumPhotons <= 0)
|
|
{
|
|
// return unchanged particle and no secondaries
|
|
aParticleChange.SetNumberOfSecondaries(0);
|
|
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
|
}
|
|
}
|
|
|
|
// Retrieve the WLS Integral for this material
|
|
// new G4PhysicsOrderedFreeVector allocated to hold CII's
|
|
G4double primaryEnergy = aTrack.GetDynamicParticle()->GetKineticEnergy();
|
|
G4double WLSTime = 0.;
|
|
G4PhysicsOrderedFreeVector* WLSIntegral = nullptr;
|
|
|
|
WLSTime = MPT->GetConstProperty(kWLSTIMECONSTANT2);
|
|
WLSIntegral = (G4PhysicsOrderedFreeVector*) ((*theIntegralTable)(
|
|
aTrack.GetMaterial()->GetIndex()));
|
|
|
|
// Max WLS Integral
|
|
G4double CIImax = WLSIntegral->GetMaxValue();
|
|
G4int NumberOfPhotons = NumPhotons;
|
|
|
|
for(G4int i = 0; i < NumPhotons; ++i)
|
|
{
|
|
G4double sampledEnergy;
|
|
// Make sure the energy of the secondary is less than that of the primary
|
|
for(G4int j = 1; j <= 100; ++j)
|
|
{
|
|
// Determine photon energy
|
|
G4double CIIvalue = G4UniformRand() * CIImax;
|
|
sampledEnergy = WLSIntegral->GetEnergy(CIIvalue);
|
|
if(sampledEnergy <= primaryEnergy)
|
|
break;
|
|
}
|
|
// If no such energy can be sampled, return one less secondary, or none
|
|
if(sampledEnergy > primaryEnergy)
|
|
{
|
|
if(verboseLevel > 1)
|
|
{
|
|
G4cout << " *** G4OpWLS2: One less WLS2 photon will be returned ***"
|
|
<< G4endl;
|
|
}
|
|
NumberOfPhotons--;
|
|
if(NumberOfPhotons == 0)
|
|
{
|
|
if(verboseLevel > 1)
|
|
{
|
|
G4cout << " *** G4OpWLS2: No WLS2 photon can be sampled for this "
|
|
"primary ***"
|
|
<< G4endl;
|
|
}
|
|
// return unchanged particle and no secondaries
|
|
aParticleChange.SetNumberOfSecondaries(0);
|
|
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
|
}
|
|
continue;
|
|
}
|
|
else if(verboseLevel > 1)
|
|
{
|
|
G4cout << "G4OpWLS2: Created photon with energy: " << 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);
|
|
|
|
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:
|
|
G4DynamicParticle* sec_dp =
|
|
new G4DynamicParticle(G4OpticalPhoton::OpticalPhoton(), photonMomentum);
|
|
sec_dp->SetPolarization(photonPolarization);
|
|
sec_dp->SetKineticEnergy(sampledEnergy);
|
|
|
|
G4double secTime = pPostStepPoint->GetGlobalTime() +
|
|
WLSTimeGeneratorProfile->GenerateTime(WLSTime);
|
|
G4ThreeVector secPos = pPostStepPoint->GetPosition();
|
|
G4Track* secTrack = new G4Track(sec_dp, secTime, secPos);
|
|
|
|
secTrack->SetTouchableHandle(aTrack.GetTouchableHandle());
|
|
secTrack->SetParentID(aTrack.GetTrackID());
|
|
|
|
proposedSecondaries.push_back(secTrack);
|
|
}
|
|
|
|
aParticleChange.SetNumberOfSecondaries(proposedSecondaries.size());
|
|
for(auto sec : proposedSecondaries)
|
|
{
|
|
aParticleChange.AddSecondary(sec);
|
|
}
|
|
if(verboseLevel > 1)
|
|
{
|
|
G4cout << "\n Exiting from G4OpWLS2::DoIt -- NumberOfSecondaries = "
|
|
<< aParticleChange.GetNumberOfSecondaries() << G4endl;
|
|
}
|
|
|
|
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
void G4OpWLS2::BuildPhysicsTable(const G4ParticleDefinition&)
|
|
{
|
|
if(theIntegralTable)
|
|
{
|
|
theIntegralTable->clearAndDestroy();
|
|
delete theIntegralTable;
|
|
theIntegralTable = nullptr;
|
|
}
|
|
|
|
const G4MaterialTable* materialTable = G4Material::GetMaterialTable();
|
|
G4int numOfMaterials = G4Material::GetNumberOfMaterials();
|
|
theIntegralTable = new G4PhysicsTable(numOfMaterials);
|
|
|
|
// loop for materials
|
|
for(G4int i = 0; i < numOfMaterials; ++i)
|
|
{
|
|
G4PhysicsOrderedFreeVector* physVector = new G4PhysicsOrderedFreeVector();
|
|
|
|
// Retrieve vector of WLS2 wavelength intensity for
|
|
// the material from the material's optical properties table.
|
|
G4MaterialPropertiesTable* MPT =
|
|
(*materialTable)[i]->GetMaterialPropertiesTable();
|
|
if(MPT)
|
|
{
|
|
G4MaterialPropertyVector* wlsVector = MPT->GetProperty(kWLSCOMPONENT2);
|
|
if(wlsVector)
|
|
{
|
|
// Retrieve the first intensity point in vector
|
|
// of (photon energy, intensity) pairs
|
|
G4double currentIN = (*wlsVector)[0];
|
|
if(currentIN >= 0.0)
|
|
{
|
|
// Create first (photon energy)
|
|
G4double currentPM = wlsVector->Energy(0);
|
|
G4double currentCII = 0.0;
|
|
physVector->InsertValues(currentPM, currentCII);
|
|
|
|
// Set previous values to current ones prior to loop
|
|
G4double prevPM = currentPM;
|
|
G4double prevCII = currentCII;
|
|
G4double prevIN = currentIN;
|
|
|
|
// loop over all (photon energy, intensity)
|
|
// pairs stored for this material
|
|
for(size_t j = 1; j < wlsVector->GetVectorLength(); ++j)
|
|
{
|
|
currentPM = wlsVector->Energy(j);
|
|
currentIN = (*wlsVector)[j];
|
|
currentCII =
|
|
prevCII + 0.5 * (currentPM - prevPM) * (prevIN + currentIN);
|
|
|
|
physVector->InsertValues(currentPM, currentCII);
|
|
|
|
prevPM = currentPM;
|
|
prevCII = currentCII;
|
|
prevIN = currentIN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
theIntegralTable->insertAt(i, physVector);
|
|
}
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
G4double G4OpWLS2::GetMeanFreePath(const G4Track& aTrack, G4double,
|
|
G4ForceCondition*)
|
|
{
|
|
G4double thePhotonEnergy = aTrack.GetDynamicParticle()->GetTotalEnergy();
|
|
G4double attLength = DBL_MAX;
|
|
G4MaterialPropertiesTable* MPT =
|
|
aTrack.GetMaterial()->GetMaterialPropertiesTable();
|
|
|
|
if(MPT)
|
|
{
|
|
G4MaterialPropertyVector* attVector = MPT->GetProperty(kWLSABSLENGTH2);
|
|
if(attVector)
|
|
{
|
|
attLength = attVector->Value(thePhotonEnergy, idx_wls2);
|
|
}
|
|
}
|
|
return attLength;
|
|
}
|
|
|
|
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
|
void G4OpWLS2::UseTimeProfile(const G4String name)
|
|
{
|
|
if(WLSTimeGeneratorProfile)
|
|
{
|
|
delete WLSTimeGeneratorProfile;
|
|
WLSTimeGeneratorProfile = nullptr;
|
|
}
|
|
if(name.compare("delta") == 0)
|
|
{
|
|
WLSTimeGeneratorProfile = new G4WLSTimeGeneratorProfileDelta("delta");
|
|
}
|
|
else if(name.compare("exponential") == 0)
|
|
{
|
|
WLSTimeGeneratorProfile =
|
|
new G4WLSTimeGeneratorProfileExponential("exponential");
|
|
}
|
|
else
|
|
{
|
|
G4Exception("G4OpWLS::UseTimeProfile", "em0202", FatalException,
|
|
"generator does not exist");
|
|
}
|
|
}
|