Import Geant4 11.3.0.beta source tree
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// GEANT4 Class file
|
||||
//
|
||||
//
|
||||
// File name: G4AllisonPositronAtRestModel
|
||||
//
|
||||
// Author: Vladimir Ivanchenko
|
||||
//
|
||||
// Creation date: 14 May 2024
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "G4AllisonPositronAtRestModel.hh"
|
||||
#include "G4DynamicParticle.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4Gamma.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4AllisonPositronAtRestModel::G4AllisonPositronAtRestModel()
|
||||
: G4VPositronAtRestModel("Allison")
|
||||
{}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4AllisonPositronAtRestModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>& secParticles,
|
||||
G4double&, const G4Material* material) const
|
||||
{
|
||||
const G4double eGamma = CLHEP::electron_mass_c2;
|
||||
|
||||
// In rest frame of positronium gammas are back to back
|
||||
const G4ThreeVector& dir1 = G4RandomDirection();
|
||||
const G4ThreeVector& dir2 = -dir1;
|
||||
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(),dir1,eGamma);
|
||||
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(),dir2,eGamma);
|
||||
|
||||
// In rest frame the gammas are polarised perpendicular to each other - see
|
||||
// Pryce and Ward, Nature No 4065 (1947) p.435.
|
||||
// Snyder et al, Physical Review 73 (1948) p.440.
|
||||
G4ThreeVector pol1 = (G4RandomDirection().cross(dir1)).unit();
|
||||
G4ThreeVector pol2 = (pol1.cross(dir2)).unit();
|
||||
|
||||
// A positron in matter slows down and combines with an atomic electron to
|
||||
// make a neutral atom called positronium, about half the size of a normal
|
||||
// atom. I expect that when the energy of the positron is small enough,
|
||||
// less than the binding energy of positronium (6.8 eV), it is
|
||||
// energetically favourable for an electron from the outer orbitals of a
|
||||
// nearby atom or molecule to transfer and bind to the positron, as in an
|
||||
// ionic bond, leaving behind a mildly ionised nearby atom/molecule. I
|
||||
// would expect the positronium to come away with a kinetic energy of a
|
||||
// few eV on average. In its para (spin 0) state it annihilates into two
|
||||
// photons, which in the rest frame of the positronium are collinear
|
||||
// (back-to-back) due to momentum conservation. Because of the motion of the
|
||||
// positronium, photons will be not quite back-to-back in the laboratory.
|
||||
|
||||
// The positroniuim acquires an energy of order its binding energy and
|
||||
// doesn't have time to thermalise. Nevertheless, here we approximate its
|
||||
// energy distribution by a Maxwell-Boltzman with mean energy <KE>. In terms
|
||||
// of a more familiar concept of temperature, and the law of equipartition
|
||||
// of energy of translational motion, <KE>=3kT/2. Each component of velocity
|
||||
// has a distribution exp(-mv^2/2kT), which is a Gaussian of mean zero
|
||||
// and variance kT/m=2<KE>/3m, where m is the positronium mass.
|
||||
|
||||
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
|
||||
const G4double& meanKE = meanEnergyPerIonPair; // Just an alias
|
||||
|
||||
if (meanKE > 0.) { // Positronium has motion
|
||||
// Mass of positronium
|
||||
const G4double mass = 2.*CLHEP::electron_mass_c2;
|
||||
// Mean <KE>=3kT/2, as described above
|
||||
// const G4double T = 2.*meanKE/(3.*k_Boltzmann);
|
||||
// Component velocities: Gaussian, variance kT/m=2<KE>/3m.
|
||||
const G4double sigmav = std::sqrt(2.*meanKE/(3.*mass));
|
||||
// This is in units where c=1
|
||||
const G4double vx = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4double vy = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4double vz = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4ThreeVector v(vx,vy,vz); // In unit where c=1
|
||||
const G4ThreeVector& beta = v; // so beta=v/c=v
|
||||
aGamma1->Set4Momentum(aGamma1->Get4Momentum().boost(beta));
|
||||
aGamma2->Set4Momentum(aGamma2->Get4Momentum().boost(beta));
|
||||
|
||||
// Rotate polarisation vectors
|
||||
const G4ThreeVector& newDir1 = aGamma1->GetMomentumDirection();
|
||||
const G4ThreeVector& newDir2 = aGamma2->GetMomentumDirection();
|
||||
const G4ThreeVector& axis1 = dir1.cross(newDir1); // No need to be unit
|
||||
const G4ThreeVector& axis2 = dir2.cross(newDir2); // No need to be unit
|
||||
const G4double& angle1 = std::acos(dir1*newDir1);
|
||||
const G4double& angle2 = std::acos(dir2*newDir2);
|
||||
pol1.rotate(axis1, angle1);
|
||||
pol2.rotate(axis2, angle2);
|
||||
}
|
||||
|
||||
// use constructors optimal for massless particle
|
||||
aGamma1->SetPolarization(pol1);
|
||||
aGamma2->SetPolarization(pol2);
|
||||
|
||||
secParticles.push_back(aGamma1);
|
||||
secParticles.push_back(aGamma2);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4AllisonPositronAtRestModel::PrintGeneratorInformation() const
|
||||
{
|
||||
G4cout << "\n" << G4endl;
|
||||
G4cout << "Allison AtRest positron 2-gamma annihilation model." << G4endl;
|
||||
G4cout << "Takes into account positronium motion in the media." << G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// GEANT4 Class file
|
||||
//
|
||||
//
|
||||
// File name: G4OrePowellAtRestModel
|
||||
//
|
||||
// Author: I.Semeniouk & D.Bernard
|
||||
//
|
||||
// Creation date: 04 Juin 2024
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "G4OrePowellAtRestModel.hh"
|
||||
#include "G4DynamicParticle.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4Gamma.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4OrePowellAtRestModel::G4OrePowellAtRestModel() : G4VPositronAtRestModel("OrePawell") {}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4OrePowellAtRestModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>& secParticles,
|
||||
G4double&, const G4Material*) const
|
||||
{
|
||||
static const G4double PositronMass = CLHEP::electron_mass_c2;
|
||||
const G4double ymax = 8.1;
|
||||
|
||||
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
|
||||
|
||||
G4double cos12;
|
||||
G4double cos13;
|
||||
G4double r1;
|
||||
G4double r2;
|
||||
G4double r3;
|
||||
G4double theta12;
|
||||
G4double theta13;
|
||||
G4double sin12;
|
||||
G4double sin13;
|
||||
G4double pdf;
|
||||
|
||||
G4double rndmv2[2];
|
||||
G4double rndmv1;
|
||||
|
||||
do {
|
||||
rndmv1 = rndmEngine->flat();
|
||||
|
||||
do {
|
||||
rndmEngine->flatArray(2, rndmv2);
|
||||
// energies of photon1 and photon2 normalized to electron rest mass
|
||||
r1 = rndmv2[0];
|
||||
r2 = rndmv2[1];
|
||||
// energy conservation, with positronium assumed = 2 * electron rest mass
|
||||
r3 = 2.0 - (r1+r2);
|
||||
// cosine of angles between photons, from momentum conservation
|
||||
cos12=(r3*r3 - r1*r1 -r2*r2)/(2*r1*r2);
|
||||
cos13=(r2*r2 - r1*r1 -r3*r3)/(2*r1*r3);
|
||||
// request both cosines < 1.
|
||||
} while ( std::abs(cos12) > 1 || std::abs(cos13) > 1 );
|
||||
|
||||
theta12 = std::acos(cos12);
|
||||
theta13 = - std::acos(cos13);
|
||||
sin12 = std::sin(theta12);
|
||||
sin13 = std::sin(theta13);
|
||||
G4double cos23=cos12*cos13+sin12*sin13;
|
||||
|
||||
pdf = (1 - cos12)*(1 - cos12) + (1 - cos13)*(1 - cos13) + (1 - cos23)*(1 - cos23);
|
||||
} while ( pdf < ymax * rndmv1 );
|
||||
// END of Sampling
|
||||
|
||||
// photon directions in the decay plane, photon 1 along z, x perp to the plane.
|
||||
G4ThreeVector PhotonMomentum1(0., 0., 1.);
|
||||
G4ThreeVector PhotonMomentum2(0.,sin12,cos12);
|
||||
G4ThreeVector PhotonMomentum3(0.,sin13,cos13);
|
||||
|
||||
// First Gamma direction
|
||||
G4ThreeVector dir1 = G4RandomDirection();
|
||||
|
||||
PhotonMomentum1.rotateUz(dir1);
|
||||
PhotonMomentum2.rotateUz(dir1);
|
||||
PhotonMomentum3.rotateUz(dir1);
|
||||
|
||||
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum1,
|
||||
r1 * PositronMass);
|
||||
|
||||
//Random polarization
|
||||
G4double phi1 = CLHEP::twopi * G4UniformRand();
|
||||
G4ThreeVector pol1(std::cos(phi1),std::sin(phi1),0.0);
|
||||
pol1.rotateUz(PhotonMomentum1);
|
||||
aGamma1->SetPolarization(pol1);
|
||||
secParticles.push_back(aGamma1);
|
||||
|
||||
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum2,
|
||||
r2 * PositronMass);
|
||||
|
||||
G4double phi2 = CLHEP::twopi * G4UniformRand();
|
||||
G4ThreeVector pol2(std::cos(phi2),std::sin(phi2),0.0);
|
||||
pol2.rotateUz(PhotonMomentum2);
|
||||
aGamma2->SetPolarization(pol2);
|
||||
secParticles.push_back(aGamma2);
|
||||
|
||||
auto aGamma3 = new G4DynamicParticle(G4Gamma::Gamma(), PhotonMomentum3,
|
||||
r3 * PositronMass);
|
||||
|
||||
G4double phi3 = CLHEP::twopi * G4UniformRand();
|
||||
G4ThreeVector pol3(std::cos(phi3),std::sin(phi3),0.0);
|
||||
pol3.rotateUz(PhotonMomentum3);
|
||||
aGamma3->SetPolarization(pol3);
|
||||
secParticles.push_back(aGamma3);
|
||||
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4OrePowellAtRestModel::PrintGeneratorInformation() const
|
||||
{
|
||||
G4cout << "Orel Powell AtRest positron 3-gamma annihilation model" << G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// GEANT4 Class file
|
||||
//
|
||||
//
|
||||
// File name: G4SimplePositronAtRestModel
|
||||
//
|
||||
// Author: Vladimir Ivanchenko
|
||||
//
|
||||
// Creation date: 14 May 2024
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "G4SimplePositronAtRestModel.hh"
|
||||
#include "G4DynamicParticle.hh"
|
||||
#include "G4Material.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4Gamma.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4SimplePositronAtRestModel::G4SimplePositronAtRestModel()
|
||||
: G4VPositronAtRestModel("Simple")
|
||||
{}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4SimplePositronAtRestModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>& secParticles,
|
||||
G4double&, const G4Material*) const
|
||||
{
|
||||
G4ThreeVector dir1 = G4RandomDirection();
|
||||
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), dir1,
|
||||
CLHEP::electron_mass_c2);
|
||||
G4double phi = CLHEP::twopi * G4UniformRand();
|
||||
G4double cosphi = std::cos(phi);
|
||||
G4double sinphi = std::sin(phi);
|
||||
G4ThreeVector pol1(cosphi, sinphi, 0.0);
|
||||
pol1.rotateUz(dir1);
|
||||
aGamma1->SetPolarization(pol1);
|
||||
secParticles.push_back(aGamma1);
|
||||
|
||||
G4ThreeVector dir2 = -dir1;
|
||||
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), dir2,
|
||||
CLHEP::electron_mass_c2);
|
||||
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
|
||||
pol2.rotateUz(dir1);
|
||||
aGamma2->SetPolarization(pol2);
|
||||
secParticles.push_back(aGamma2);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4SimplePositronAtRestModel::PrintGeneratorInformation() const
|
||||
{
|
||||
G4cout << "\n" << G4endl;
|
||||
G4cout << "Simple AtRest positron 2-gamma annihilation model" << G4endl;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// GEANT4 Class file
|
||||
//
|
||||
//
|
||||
// File name: G4SimplePsAtRestModel
|
||||
//
|
||||
// Author: I.Semeniouk & D.Bernard
|
||||
//
|
||||
// Creation date: 04 Juin 2024
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "G4SimplePsAtRestModel.hh"
|
||||
#include "G4SimplePositronAtRestModel.hh"
|
||||
#include "G4OrePowellAtRestModel.hh"
|
||||
#include "G4DynamicParticle.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4EmParameters.hh"
|
||||
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4SimplePsAtRestModel::G4SimplePsAtRestModel()
|
||||
: G4VPositronAtRestModel("SimplePs")
|
||||
{
|
||||
f3gFranction = G4EmParameters::Instance()->OrtoPsFraction();
|
||||
model2g = new G4SimplePositronAtRestModel();
|
||||
model3g = new G4OrePowellAtRestModel();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4SimplePsAtRestModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>& secParticles,
|
||||
G4double& localEnergyDeposit, const G4Material* mat) const
|
||||
{
|
||||
// G4cout << "SampleSecondaries model " << GetName() << G4endl;
|
||||
// G4cout << "3 gamma fraction " << f3gFranction << G4endl;
|
||||
if ( G4UniformRand() > f3gFranction ) {
|
||||
model2g->SampleSecondaries(secParticles,localEnergyDeposit,mat);
|
||||
} else {
|
||||
model3g->SampleSecondaries(secParticles,localEnergyDeposit,mat);
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4SimplePsAtRestModel::PrintGeneratorInformation() const
|
||||
{
|
||||
G4cout << G4endl;
|
||||
model2g->PrintGeneratorInformation();
|
||||
model3g->PrintGeneratorInformation();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4SimplePsAtRestModel::~G4SimplePsAtRestModel()
|
||||
{
|
||||
delete model2g;
|
||||
delete model3g;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -124,7 +124,7 @@ G4UrbanMscModel::G4UrbanMscModel(const G4String& nam)
|
||||
G4UrbanMscModel::~G4UrbanMscModel()
|
||||
{
|
||||
if(isFirstInstance) {
|
||||
for(auto & ptr : msc) { delete ptr; }
|
||||
for(auto const & ptr : msc) { delete ptr; }
|
||||
msc.clear();
|
||||
}
|
||||
}
|
||||
@@ -504,8 +504,9 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
|
||||
|
||||
smallstep += 1.;
|
||||
insideskin = false;
|
||||
tgeom = geombig;
|
||||
|
||||
// initialisation at firs step and at the boundary
|
||||
// initialisation at first step and at the boundary
|
||||
if(firstStep || (stepStatus == fGeomBoundary))
|
||||
{
|
||||
rangeinit = currentRange;
|
||||
@@ -520,22 +521,17 @@ G4double G4UrbanMscModel::ComputeTruePathLengthLimit(
|
||||
<< " tlimitmin= " << tlimitmin << " geomlimit= "
|
||||
<< geomlimit <<G4endl;
|
||||
*/
|
||||
// constraint from the geometry
|
||||
|
||||
if((geomlimit < geombig) && (geomlimit > geommin))
|
||||
{
|
||||
// geomlimit is a geometrical step length
|
||||
// transform it to true path length (estimation)
|
||||
if(lambda0 > geomlimit) {
|
||||
geomlimit = -lambda0*G4Log(1.-geomlimit/lambda0)+tlimitmin;
|
||||
}
|
||||
tgeom = (stepStatus == fGeomBoundary)
|
||||
? geomlimit/facgeom : 2.*geomlimit/facgeom;
|
||||
}
|
||||
else
|
||||
{
|
||||
tgeom = geombig;
|
||||
}
|
||||
}
|
||||
// constraint from the geometry
|
||||
if((geomlimit < geombig) && (geomlimit > geommin))
|
||||
{
|
||||
// geomlimit is a geometrical step length
|
||||
// transform it to true path length (estimation)
|
||||
if(lambda0 > geomlimit) {
|
||||
geomlimit = -lambda0*G4Log(1.-geomlimit/lambda0)+tlimitmin;
|
||||
}
|
||||
tgeom = (stepStatus == fGeomBoundary) ? geomlimit/facgeom
|
||||
: facrange*rangeinit + stepmin;
|
||||
}
|
||||
|
||||
//step limit
|
||||
|
||||
@@ -83,14 +83,10 @@
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
using namespace std;
|
||||
|
||||
G4bool G4eeToTwoGammaModel::fSampleAtomicPDF = false;
|
||||
|
||||
G4eeToTwoGammaModel::G4eeToTwoGammaModel(const G4ParticleDefinition*,
|
||||
const G4String& nam)
|
||||
: G4VEmModel(nam),
|
||||
pi_rcl2(pi*classic_electr_radius*classic_electr_radius)
|
||||
pi_rcl2(CLHEP::pi*CLHEP::classic_electr_radius*CLHEP::classic_electr_radius)
|
||||
{
|
||||
theGamma = G4Gamma::Gamma();
|
||||
fParticleChange = nullptr;
|
||||
@@ -105,27 +101,7 @@ G4eeToTwoGammaModel::~G4eeToTwoGammaModel() = default;
|
||||
void G4eeToTwoGammaModel::Initialise(const G4ParticleDefinition*,
|
||||
const G4DataVector&)
|
||||
{
|
||||
if(IsMaster()) {
|
||||
G4int verbose = G4EmParameters::Instance()->Verbose();
|
||||
// redo initialisation for each new run
|
||||
fSampleAtomicPDF = false;
|
||||
const auto& materialTable = G4Material::GetMaterialTable();
|
||||
for (const auto& material: *materialTable) {
|
||||
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
|
||||
if (meanEnergyPerIonPair > 0.) {
|
||||
fSampleAtomicPDF = true;
|
||||
if(verbose > 0) {
|
||||
G4cout << "### G4eeToTwoGammaModel: for " << material->GetName() << " mean energy per ion pair is "
|
||||
<< meanEnergyPerIonPair/CLHEP::eV << " eV" << G4endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no materials have meanEnergyPerIonPair set. This is probably the usual
|
||||
// case, since most applications are not senstive to the slight
|
||||
// non-collinearity of gammas in eeToTwoGamma. Do not issue any warning.
|
||||
|
||||
if(fParticleChange) { return; }
|
||||
if (nullptr != fParticleChange) { return; }
|
||||
fParticleChange = GetParticleChangeForGamma();
|
||||
}
|
||||
|
||||
@@ -137,13 +113,13 @@ G4eeToTwoGammaModel::ComputeCrossSectionPerElectron(G4double kineticEnergy)
|
||||
// Calculates the cross section per electron of annihilation into two photons
|
||||
// from the Heilter formula.
|
||||
|
||||
G4double ekin = std::max(eV,kineticEnergy);
|
||||
G4double ekin = std::max(CLHEP::eV, kineticEnergy);
|
||||
|
||||
G4double tau = ekin/electron_mass_c2;
|
||||
G4double tau = ekin/CLHEP::electron_mass_c2;
|
||||
G4double gam = tau + 1.0;
|
||||
G4double gamma2= gam*gam;
|
||||
G4double bg2 = tau * (tau+2.0);
|
||||
G4double bg = sqrt(bg2);
|
||||
G4double bg = std::sqrt(bg2);
|
||||
|
||||
G4double cross = pi_rcl2*((gamma2+4*gam+1.)*G4Log(gam+bg) - (gam+3.)*bg)
|
||||
/ (bg2*(gam+1.));
|
||||
@@ -178,183 +154,46 @@ G4double G4eeToTwoGammaModel::CrossSectionPerVolume(
|
||||
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
|
||||
// Nature 4065 (1947) 435.
|
||||
|
||||
void G4eeToTwoGammaModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
|
||||
const G4MaterialCutsCouple* pCutsCouple,
|
||||
void G4eeToTwoGammaModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
|
||||
const G4MaterialCutsCouple*,
|
||||
const G4DynamicParticle* dp,
|
||||
G4double,
|
||||
G4double)
|
||||
{
|
||||
G4double posiKinEnergy = dp->GetKineticEnergy();
|
||||
G4DynamicParticle *aGamma1, *aGamma2;
|
||||
|
||||
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
|
||||
|
||||
// Case at rest
|
||||
if(posiKinEnergy == 0.0) {
|
||||
|
||||
const G4double eGamma = electron_mass_c2;
|
||||
|
||||
// In rest frame of positronium gammas are back to back
|
||||
const G4ThreeVector& dir1 = G4RandomDirection();
|
||||
const G4ThreeVector& dir2 = -dir1;
|
||||
aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(),dir1,eGamma);
|
||||
aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(),dir2,eGamma);
|
||||
|
||||
// In rest frame the gammas are polarised perpendicular to each other - see
|
||||
// Pryce and Ward, Nature No 4065 (1947) p.435.
|
||||
// Snyder et al, Physical Review 73 (1948) p.440.
|
||||
G4ThreeVector pol1 = (G4RandomDirection().cross(dir1)).unit();
|
||||
G4ThreeVector pol2 = (pol1.cross(dir2)).unit();
|
||||
|
||||
// But the positronium is moving...
|
||||
// A positron in matter slows down and combines with an atomic electron to
|
||||
// make a neutral “atom” called positronium, about half the size of a normal
|
||||
// atom. I expect that when the energy of the positron is small enough,
|
||||
// less than the binding energy of positronium (6.8 eV), it is
|
||||
// energetically favourable for an electron from the outer orbitals of a
|
||||
// nearby atom or molecule to transfer and bind to the positron, as in an
|
||||
// ionic bond, leaving behind a mildly ionised nearby atom/molecule. I
|
||||
// would expect the positronium to come away with a kinetic energy of a
|
||||
// few eV on average. In its para (spin 0) state it annihilates into two
|
||||
// photons, which in the rest frame of the positronium are collinear
|
||||
// (back-to-back) due to momentum conservation. Because of the motion of the
|
||||
// positronium, photons will be not quite back-to-back in the laboratory.
|
||||
|
||||
// The positroniuim acquires an energy of order its binding energy and
|
||||
// doesn't have time to thermalise. Nevertheless, here we approximate its
|
||||
// energy distribution by a Maxwell-Boltzman with mean energy <KE>. In terms
|
||||
// of a more familiar concept of temperature, and the law of equipartition
|
||||
// of energy of translational motion, <KE>=3kT/2. Each component of velocity
|
||||
// has a distribution exp(-mv^2/2kT), which is a Gaussian of mean zero
|
||||
// and variance kT/m=2<KE>/3m, where m is the positronium mass.
|
||||
|
||||
// We take <KE> = material->GetIonisation()->GetMeanEnergyPerIonPair().
|
||||
|
||||
if(fSampleAtomicPDF) {
|
||||
const G4Material* material = pCutsCouple->GetMaterial();
|
||||
const G4double meanEnergyPerIonPair = material->GetIonisation()->GetMeanEnergyPerIonPair();
|
||||
const G4double& meanKE = meanEnergyPerIonPair; // Just an alias
|
||||
if (meanKE > 0.) { // Positronium haas motion
|
||||
// Mass of positronium
|
||||
const G4double mass = 2.*electron_mass_c2;
|
||||
// Mean <KE>=3kT/2, as described above
|
||||
// const G4double T = 2.*meanKE/(3.*k_Boltzmann);
|
||||
// Component velocities: Gaussian, variance kT/m=2<KE>/3m.
|
||||
const G4double sigmav = std::sqrt(2.*meanKE/(3.*mass));
|
||||
// This is in units where c=1
|
||||
const G4double vx = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4double vy = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4double vz = G4RandGauss::shoot(0.,sigmav);
|
||||
const G4ThreeVector v(vx,vy,vz); // In unit where c=1
|
||||
const G4ThreeVector& beta = v; // so beta=v/c=v
|
||||
|
||||
aGamma1->Set4Momentum(aGamma1->Get4Momentum().boost(beta));
|
||||
aGamma2->Set4Momentum(aGamma2->Get4Momentum().boost(beta));
|
||||
|
||||
// Rotate polarisation vectors
|
||||
const G4ThreeVector& newDir1 = aGamma1->GetMomentumDirection();
|
||||
const G4ThreeVector& newDir2 = aGamma2->GetMomentumDirection();
|
||||
const G4ThreeVector& axis1 = dir1.cross(newDir1); // No need to be unit
|
||||
const G4ThreeVector& axis2 = dir2.cross(newDir2); // No need to be unit
|
||||
const G4double& angle1 = std::acos(dir1*newDir1);
|
||||
const G4double& angle2 = std::acos(dir2*newDir2);
|
||||
if (axis1 != G4ThreeVector()) pol1.rotate(axis1,angle1);
|
||||
if (axis2 != G4ThreeVector()) pol2.rotate(axis2,angle2);
|
||||
}
|
||||
}
|
||||
aGamma1->SetPolarization(pol1.x(),pol1.y(),pol1.z());
|
||||
aGamma2->SetPolarization(pol2.x(),pol2.y(),pol2.z());
|
||||
|
||||
} else { // Positron interacts in flight
|
||||
|
||||
G4ThreeVector posiDirection = dp->GetMomentumDirection();
|
||||
|
||||
G4double tau = posiKinEnergy/electron_mass_c2;
|
||||
G4double gam = tau + 1.0;
|
||||
G4double tau2 = tau + 2.0;
|
||||
G4double sqgrate = sqrt(tau/tau2)*0.5;
|
||||
G4double sqg2m1 = sqrt(tau*tau2);
|
||||
|
||||
// limits of the energy sampling
|
||||
G4double epsilmin = 0.5 - sqgrate;
|
||||
G4double epsilmax = 0.5 + sqgrate;
|
||||
G4double epsilqot = epsilmax/epsilmin;
|
||||
|
||||
//
|
||||
// sample the energy rate of the created gammas
|
||||
//
|
||||
G4double epsil, greject;
|
||||
|
||||
do {
|
||||
epsil = epsilmin*G4Exp(G4Log(epsilqot)*rndmEngine->flat());
|
||||
greject = 1. - epsil + (2.*gam*epsil-1.)/(epsil*tau2*tau2);
|
||||
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
|
||||
} while( greject < rndmEngine->flat());
|
||||
|
||||
//
|
||||
// scattered Gamma angles. ( Z - axis along the parent positron)
|
||||
//
|
||||
|
||||
G4double cost = (epsil*tau2-1.)/(epsil*sqg2m1);
|
||||
if(std::abs(cost) > 1.0) {
|
||||
G4cout << "### G4eeToTwoGammaModel WARNING cost= " << cost
|
||||
<< " positron Ekin(MeV)= " << posiKinEnergy
|
||||
<< " gamma epsil= " << epsil
|
||||
<< G4endl;
|
||||
if(cost > 1.0) cost = 1.0;
|
||||
else cost = -1.0;
|
||||
}
|
||||
G4double sint = sqrt((1.+cost)*(1.-cost));
|
||||
G4double phi = twopi * rndmEngine->flat();
|
||||
|
||||
//
|
||||
// kinematic of the created pair
|
||||
//
|
||||
|
||||
G4double totalEnergy = posiKinEnergy + 2.0*electron_mass_c2;
|
||||
G4double phot1Energy = epsil*totalEnergy;
|
||||
|
||||
G4ThreeVector phot1Direction(sint*cos(phi), sint*sin(phi), cost);
|
||||
phot1Direction.rotateUz(posiDirection);
|
||||
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
|
||||
phi = twopi * rndmEngine->flat();
|
||||
G4double cosphi = cos(phi);
|
||||
G4double sinphi = sin(phi);
|
||||
G4ThreeVector pol(cosphi, sinphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
|
||||
G4double phot2Energy =(1.-epsil)*totalEnergy;
|
||||
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
|
||||
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
|
||||
G4ThreeVector phot2Direction = dir.unit();
|
||||
|
||||
// create G4DynamicParticle object for the particle2
|
||||
aGamma2 = new G4DynamicParticle (theGamma, phot2Direction, phot2Energy);
|
||||
|
||||
//!!! likely problematic direction to be checked
|
||||
pol.set(-sinphi, cosphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
cost = pol*phot2Direction;
|
||||
pol -= cost*phot2Direction;
|
||||
pol = pol.unit();
|
||||
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
/*
|
||||
G4cout << "Annihilation on fly: e0= " << posiKinEnergy
|
||||
<< " m= " << electron_mass_c2
|
||||
<< " e1= " << phot1Energy
|
||||
<< " e2= " << phot2Energy << " dir= " << dir
|
||||
<< " -> " << phot1Direction << " "
|
||||
<< phot2Direction << G4endl;
|
||||
*/
|
||||
}
|
||||
|
||||
vdp->push_back(aGamma1);
|
||||
vdp->push_back(aGamma2);
|
||||
|
||||
// kill primary positron
|
||||
fParticleChange->SetProposedKineticEnergy(0.0);
|
||||
fParticleChange->ProposeTrackStatus(fStopAndKill);
|
||||
|
||||
// Case at rest not considered anymore inside this model
|
||||
G4LorentzVector lv(dp->GetMomentum(),
|
||||
dp->GetKineticEnergy() + 2*CLHEP::electron_mass_c2);
|
||||
G4double eGammaCMS = 0.5 * lv.mag();
|
||||
|
||||
G4ThreeVector dir1 = G4RandomDirection();
|
||||
G4double phi = CLHEP::twopi * G4UniformRand();
|
||||
G4double cosphi = std::cos(phi);
|
||||
G4double sinphi = std::sin(phi);
|
||||
G4ThreeVector pol1(cosphi, sinphi, 0.0);
|
||||
pol1.rotateUz(dir1);
|
||||
G4LorentzVector lv1(eGammaCMS*dir1, eGammaCMS);
|
||||
|
||||
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
|
||||
pol2.rotateUz(dir1);
|
||||
|
||||
// transformation to lab system
|
||||
lv1.boost(lv.boostVector());
|
||||
lv -= lv1;
|
||||
|
||||
//!!! boost of polarisation vector is not yet implemented
|
||||
|
||||
// use constructors optimal for massless particle
|
||||
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), lv1.vect());
|
||||
aGamma1->SetPolarization(pol1);
|
||||
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), lv.vect());
|
||||
aGamma2->SetPolarization(pol2);
|
||||
|
||||
vdp->push_back(aGamma1);
|
||||
vdp->push_back(aGamma2);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
@@ -54,12 +54,13 @@
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4MaterialCutsCouple.hh"
|
||||
#include "G4Gamma.hh"
|
||||
#include "G4Electron.hh"
|
||||
#include "G4Positron.hh"
|
||||
#include "G4eeToTwoGammaModel.hh"
|
||||
#include "G4EmBiasingManager.hh"
|
||||
#include "G4EntanglementAuxInfo.hh"
|
||||
#include "G4eplusAnnihilationEntanglementClipBoard.hh"
|
||||
#include "G4SimplePositronAtRestModel.hh"
|
||||
#include "G4AllisonPositronAtRestModel.hh"
|
||||
#include "G4EmParameters.hh"
|
||||
#include "G4PhysicsModelCatalog.hh"
|
||||
|
||||
@@ -68,12 +69,10 @@
|
||||
G4eplusAnnihilation::G4eplusAnnihilation(const G4String& name)
|
||||
: G4VEmProcess(name)
|
||||
{
|
||||
theGamma = G4Gamma::Gamma();
|
||||
theElectron = G4Electron::Electron();
|
||||
SetCrossSectionType(fEmDecreasing);
|
||||
SetBuildTableFlag(false);
|
||||
SetStartFromNullFlag(false);
|
||||
SetSecondaryParticle(theGamma);
|
||||
SetSecondaryParticle(G4Gamma::Gamma());
|
||||
SetProcessSubType(fAnnihilation);
|
||||
enableAtRestDoIt = true;
|
||||
mainSecondaries = 2;
|
||||
@@ -82,7 +81,10 @@ G4eplusAnnihilation::G4eplusAnnihilation(const G4String& name)
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4eplusAnnihilation::~G4eplusAnnihilation() = default;
|
||||
G4eplusAnnihilation::~G4eplusAnnihilation()
|
||||
{
|
||||
delete fAtRestModel;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
@@ -104,13 +106,28 @@ G4double G4eplusAnnihilation::AtRestGetPhysicalInteractionLength(
|
||||
|
||||
void G4eplusAnnihilation::InitialiseProcess(const G4ParticleDefinition*)
|
||||
{
|
||||
if(!isInitialised) {
|
||||
if (!isInitialised) {
|
||||
isInitialised = true;
|
||||
if(nullptr == EmModel(0)) { SetEmModel(new G4eeToTwoGammaModel()); }
|
||||
EmModel(0)->SetLowEnergyLimit(MinKinEnergy());
|
||||
EmModel(0)->SetHighEnergyLimit(MaxKinEnergy());
|
||||
AddEmModel(1, EmModel(0));
|
||||
}
|
||||
auto param = G4EmParameters::Instance();
|
||||
|
||||
// AtRest model should be chosen only once
|
||||
if (nullptr == fAtRestModel) {
|
||||
auto type = param->PositronAtRestModelType();
|
||||
if (type == fAllisonPositronium) {
|
||||
fAtRestModel = new G4AllisonPositronAtRestModel();
|
||||
} else {
|
||||
fAtRestModel = new G4SimplePositronAtRestModel();
|
||||
}
|
||||
}
|
||||
// Check that entanglement is switched on
|
||||
// It may be set by the UI command "/process/em/QuantumEntanglement true".
|
||||
fEntangled = param->QuantumEntanglement();
|
||||
fApplyCuts = param->ApplyCuts();
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -122,136 +139,96 @@ void G4eplusAnnihilation::StreamProcessInfo(std::ostream&) const
|
||||
|
||||
G4VParticleChange* G4eplusAnnihilation::AtRestDoIt(const G4Track& track,
|
||||
const G4Step& step)
|
||||
// Performs the e+ e- annihilation when both particles are assumed at rest.
|
||||
{
|
||||
// positron at rest should be killed
|
||||
fParticleChange.InitializeForPostStep(track);
|
||||
fParticleChange.SetProposedKineticEnergy(0.);
|
||||
fParticleChange.ProposeTrackStatus(fStopAndKill);
|
||||
|
||||
DefineMaterial(track.GetMaterialCutsCouple());
|
||||
G4int idx = (G4int)CurrentMaterialCutsCoupleIndex();
|
||||
G4double ene(0.0);
|
||||
G4VEmModel* model = SelectModel(ene, idx);
|
||||
auto couple = step.GetPreStepPoint()->GetMaterialCutsCouple();
|
||||
DefineMaterial(couple);
|
||||
|
||||
G4double gammaCut = GetGammaEnergyCut();
|
||||
|
||||
// define new weight for primary and secondaries
|
||||
G4double weight = fParticleChange.GetParentWeight();
|
||||
// apply cuts
|
||||
if (fApplyCuts && gammaCut > CLHEP::electron_mass_c2) {
|
||||
fParticleChange.ProposeLocalEnergyDeposit(2*CLHEP::electron_mass_c2);
|
||||
return &fParticleChange;
|
||||
}
|
||||
|
||||
// sample secondaries
|
||||
secParticles.clear();
|
||||
G4double gammaCut = GetGammaEnergyCut();
|
||||
model->SampleSecondaries(&secParticles, MaterialCutsCouple(),
|
||||
track.GetDynamicParticle(), gammaCut);
|
||||
|
||||
G4int num0 = (G4int)secParticles.size();
|
||||
G4double edep = 0.0;
|
||||
fAtRestModel->SampleSecondaries(secParticles, edep, couple->GetMaterial());
|
||||
|
||||
// define new weight for primary and secondaries
|
||||
G4double weight = fParticleChange.GetParentWeight();
|
||||
std::size_t num0 = secParticles.size();
|
||||
|
||||
// splitting or Russian roulette
|
||||
if(biasManager) {
|
||||
if(biasManager->SecondaryBiasingRegion(idx)) {
|
||||
if (nullptr != biasManager) {
|
||||
G4int idx = couple->GetIndex();
|
||||
if (biasManager->SecondaryBiasingRegion(idx) &&
|
||||
!biasManager->GetDirectionalSplitting()) {
|
||||
G4VEmModel* mod = nullptr;
|
||||
G4double eloss = 0.0;
|
||||
weight *= biasManager->ApplySecondaryBiasing(
|
||||
secParticles, track, model, &fParticleChange, eloss,
|
||||
idx, gammaCut, step.GetPostStepPoint()->GetSafety());
|
||||
if(eloss > 0.0) {
|
||||
eloss += fParticleChange.GetLocalEnergyDeposit();
|
||||
fParticleChange.ProposeLocalEnergyDeposit(eloss);
|
||||
}
|
||||
weight *= biasManager->ApplySecondaryBiasing(secParticles, track, mod,
|
||||
&fParticleChange, eloss,
|
||||
idx, gammaCut);
|
||||
edep += eloss;
|
||||
}
|
||||
}
|
||||
|
||||
// save secondaries
|
||||
G4int num = (G4int)secParticles.size();
|
||||
std::size_t num = secParticles.size();
|
||||
|
||||
// Check that entanglement is switched on... (the following flag is
|
||||
// set by /process/em/QuantumEntanglement).
|
||||
G4bool entangled = G4EmParameters::Instance()->QuantumEntanglement();
|
||||
// ...and that we have two gammas with both gammas' energies above
|
||||
// gammaCut (entanglement is only programmed for e+ e- -> gamma gamma).
|
||||
G4bool entangledgammagamma = false;
|
||||
if (entangled) {
|
||||
if (num == 2) {
|
||||
entangledgammagamma = true;
|
||||
for (const auto* p: secParticles) {
|
||||
if (p->GetDefinition() != theGamma ||
|
||||
p->GetKineticEnergy() < gammaCut) {
|
||||
entangledgammagamma = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare a shared pointer for psossible use below. If it is used, the
|
||||
// Prepare a shared pointer only for two first gamma. If it is used, the
|
||||
// shared pointer is copied into the tracks through G4EntanglementAuxInfo.
|
||||
// This ensures the clip board lasts until both tracks are destroyed.
|
||||
// It is assumed that 2 first secondary particles are the most energetic gamma
|
||||
std::shared_ptr<G4eplusAnnihilationEntanglementClipBoard> clipBoard;
|
||||
if (entangledgammagamma) {
|
||||
if (fEntangled && num >= 2) {
|
||||
clipBoard = std::make_shared<G4eplusAnnihilationEntanglementClipBoard>();
|
||||
clipBoard->SetParentParticleDefinition(track.GetDefinition());
|
||||
}
|
||||
|
||||
if(num > 0) {
|
||||
if (num > 0) {
|
||||
const G4double time = track.GetGlobalTime();
|
||||
const G4ThreeVector& pos = track.GetPosition();
|
||||
auto touch = track.GetTouchableHandle();
|
||||
for (std::size_t i=0; i<num; ++i) {
|
||||
G4DynamicParticle* dp = secParticles[i];
|
||||
G4Track* t = new G4Track(dp, time, pos);
|
||||
t->SetTouchableHandle(touch);
|
||||
if (fEntangled && i < 2) {
|
||||
// entangledgammagamma is only true when there are only two gammas
|
||||
// (See code above where entangledgammagamma is calculated.)
|
||||
if (i == 0) { // First gamma
|
||||
clipBoard->SetTrackA(t);
|
||||
} else if (i == 1) { // Second gamma
|
||||
clipBoard->SetTrackB(t);
|
||||
}
|
||||
t->SetAuxiliaryTrackInformation
|
||||
(fEntanglementModelID, new G4EntanglementAuxInfo(clipBoard));
|
||||
}
|
||||
if (nullptr != biasManager) {
|
||||
t->SetWeight(weight * biasManager->GetWeight((G4int)i));
|
||||
} else {
|
||||
t->SetWeight(weight);
|
||||
}
|
||||
pParticleChange->AddSecondary(t);
|
||||
|
||||
fParticleChange.SetNumberOfSecondaries(num);
|
||||
G4double edep = fParticleChange.GetLocalEnergyDeposit();
|
||||
G4double time = track.GetGlobalTime();
|
||||
|
||||
for (G4int i=0; i<num; ++i) {
|
||||
if (secParticles[i]) {
|
||||
G4DynamicParticle* dp = secParticles[i];
|
||||
const G4ParticleDefinition* p = dp->GetParticleDefinition();
|
||||
G4double e = dp->GetKineticEnergy();
|
||||
G4bool good = true;
|
||||
if(ApplyCuts()) {
|
||||
if (p == theGamma) {
|
||||
if (e < gammaCut) { good = false; }
|
||||
} else if (p == theElectron) {
|
||||
if (e < GetElectronEnergyCut()) { good = false; }
|
||||
}
|
||||
// added secondary if it is good
|
||||
}
|
||||
if (good) {
|
||||
G4Track* t = new G4Track(dp, time, track.GetPosition());
|
||||
t->SetTouchableHandle(track.GetTouchableHandle());
|
||||
if (entangledgammagamma) {
|
||||
// entangledgammagamma is only true when there are only two gammas
|
||||
// (See code above where entangledgammagamma is calculated.)
|
||||
if (i == 0) { // First gamma
|
||||
clipBoard->SetTrackA(t);
|
||||
} else if (i == 1) { // Second gamma
|
||||
clipBoard->SetTrackB(t);
|
||||
}
|
||||
t->SetAuxiliaryTrackInformation
|
||||
(fEntanglementModelID,new G4EntanglementAuxInfo(clipBoard));
|
||||
}
|
||||
if (biasManager) {
|
||||
t->SetWeight(weight * biasManager->GetWeight(i));
|
||||
} else {
|
||||
t->SetWeight(weight);
|
||||
}
|
||||
pParticleChange->AddSecondary(t);
|
||||
|
||||
// define type of secondary
|
||||
if(i < mainSecondaries) { t->SetCreatorModelID(secID); }
|
||||
else if(i < num0) {
|
||||
if(p == theGamma) {
|
||||
t->SetCreatorModelID(fluoID);
|
||||
} else {
|
||||
t->SetCreatorModelID(augerID);
|
||||
}
|
||||
} else {
|
||||
t->SetCreatorModelID(biasID);
|
||||
}
|
||||
/*
|
||||
G4cout << "Secondary(post step) has weight " << t->GetWeight()
|
||||
<< ", Ekin= " << t->GetKineticEnergy()/MeV << " MeV "
|
||||
<< GetProcessName() << " fluoID= " << fluoID
|
||||
<< " augerID= " << augerID <<G4endl;
|
||||
*/
|
||||
} else {
|
||||
delete dp;
|
||||
edep += e;
|
||||
}
|
||||
}
|
||||
// define type of secondary
|
||||
if (i < num0) {
|
||||
t->SetCreatorModelID(secID);
|
||||
}
|
||||
else {
|
||||
t->SetCreatorModelID(biasID);
|
||||
}
|
||||
}
|
||||
fParticleChange.ProposeLocalEnergyDeposit(edep);
|
||||
}
|
||||
fParticleChange.ProposeLocalEnergyDeposit(edep);
|
||||
return &fParticleChange;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
//
|
||||
// Creation date: 29.03.2018
|
||||
//
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "G4DataVector.hh"
|
||||
#include "G4PhysicsVector.hh"
|
||||
#include "G4PhysicsLogVector.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4ParticleChangeForGamma.hh"
|
||||
#include "G4Log.hh"
|
||||
@@ -60,64 +62,70 @@
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
using namespace std;
|
||||
|
||||
G4PhysicsVector* G4eplusTo2GammaOKVIModel::fCrossSection = nullptr;
|
||||
G4PhysicsVector* G4eplusTo2GammaOKVIModel::fCrossSection3G = nullptr;
|
||||
G4PhysicsVector* G4eplusTo2GammaOKVIModel::f3GProbability = nullptr;
|
||||
|
||||
G4eplusTo2GammaOKVIModel::G4eplusTo2GammaOKVIModel(const G4ParticleDefinition*,
|
||||
const G4String& nam)
|
||||
: G4VEmModel(nam),
|
||||
fDelta(0.001),
|
||||
fGammaTh(MeV)
|
||||
G4eplusTo2GammaOKVIModel::G4eplusTo2GammaOKVIModel()
|
||||
: G4VEmModel("eplus2ggOKVI"),
|
||||
fDeltaMin(0.001),
|
||||
fDelta(fDeltaMin),
|
||||
fGammaTh(CLHEP::MeV)
|
||||
{
|
||||
theGamma = G4Gamma::Gamma();
|
||||
fParticleChange = nullptr;
|
||||
fCuts = nullptr;
|
||||
f3GModel = new G4eplusTo3GammaOKVIModel();
|
||||
SetTripletModel(f3GModel);
|
||||
|
||||
// instantiate vectors once
|
||||
if (nullptr == fCrossSection) {
|
||||
G4double emin = 10*CLHEP::eV;
|
||||
G4double emax = 100*CLHEP::TeV;
|
||||
G4int nbins = 20*G4lrint(std::log10(emax/emin));
|
||||
fCrossSection = new G4PhysicsLogVector(emin, emax, nbins, true);
|
||||
f3GProbability = new G4PhysicsLogVector(emin, emax, nbins, true);
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
G4eplusTo2GammaOKVIModel::~G4eplusTo2GammaOKVIModel() = default;
|
||||
G4eplusTo2GammaOKVIModel::~G4eplusTo2GammaOKVIModel()
|
||||
{
|
||||
if (IsMaster()) {
|
||||
delete fCrossSection;
|
||||
delete f3GProbability;
|
||||
fCrossSection = nullptr;
|
||||
f3GProbability = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
void G4eplusTo2GammaOKVIModel::Initialise(const G4ParticleDefinition* p,
|
||||
const G4DataVector& cuts)
|
||||
{
|
||||
f3GModel->Initialise(p, cuts);
|
||||
fCuts = &cuts;
|
||||
fGammaTh = G4EmParameters::Instance()->LowestTripletEnergy();
|
||||
f3GModel->SetDelta(fDelta);
|
||||
|
||||
if(IsMaster()) {
|
||||
if(!fCrossSection) {
|
||||
G4double emin = 10*eV;
|
||||
G4double emax = 100*TeV;
|
||||
G4int nbins = 20*G4lrint(std::log10(emax/emin));
|
||||
fCrossSection = new G4PhysicsLogVector(emin, emax, nbins, true);
|
||||
fCrossSection3G = new G4PhysicsLogVector(emin, emax, nbins, true);
|
||||
f3GProbability = new G4PhysicsLogVector(emin, emax, nbins, true);
|
||||
for(G4int i=0; i<= nbins; ++i) {
|
||||
G4double e = fCrossSection->Energy(i);
|
||||
G4double cs2 = ComputeCrossSectionPerElectron(e);
|
||||
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(e);
|
||||
cs2 += cs3;
|
||||
fCrossSection->PutValue(i, cs2);
|
||||
fCrossSection3G->PutValue(i, cs3);
|
||||
f3GProbability->PutValue(i, cs3/cs2);
|
||||
}
|
||||
fCrossSection->FillSecondDerivatives();
|
||||
fCrossSection3G->FillSecondDerivatives();
|
||||
f3GProbability->FillSecondDerivatives();
|
||||
}
|
||||
}
|
||||
// here particle change is set for the triplet model
|
||||
if(fParticleChange) { return; }
|
||||
fParticleChange = GetParticleChangeForGamma();
|
||||
if (nullptr == fParticleChange) {
|
||||
fParticleChange = GetParticleChangeForGamma();
|
||||
}
|
||||
// initialialise 3-gamma model before new run
|
||||
f3GModel->Initialise(p, cuts);
|
||||
fGammaTh = G4EmParameters::Instance()->LowestTripletEnergy();
|
||||
|
||||
// initialise vectors
|
||||
if (IsMaster()) {
|
||||
std::size_t num = fCrossSection->GetVectorLength();
|
||||
for (std::size_t i=0; i<num; ++i) {
|
||||
G4double e = fCrossSection->Energy(i);
|
||||
G4double cs2 = ComputeCrossSectionPerElectron(e);
|
||||
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(e);
|
||||
cs2 += cs3;
|
||||
fCrossSection->PutValue(i, cs2);
|
||||
G4double y = (cs2 > 0.0) ? cs3/cs2 : 0.0;
|
||||
f3GProbability->PutValue(i, y);
|
||||
}
|
||||
fCrossSection->FillSecondDerivatives();
|
||||
f3GProbability->FillSecondDerivatives();
|
||||
}
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
@@ -129,16 +137,20 @@ G4eplusTo2GammaOKVIModel::ComputeCrossSectionPerElectron(G4double kinEnergy)
|
||||
// photons from the Heilter formula with the radiation correction to 3 gamma
|
||||
// annihilation channel. (A.A.) rho is changed
|
||||
|
||||
G4double ekin = std::max(eV,kinEnergy);
|
||||
G4double tau = ekin/electron_mass_c2;
|
||||
G4double ekin = std::max(CLHEP::eV, kinEnergy);
|
||||
G4double tau = ekin/CLHEP::electron_mass_c2;
|
||||
G4double gam = tau + 1.0;
|
||||
G4double gamma2 = gam*gam;
|
||||
G4double bg2 = tau * (tau+2.0);
|
||||
G4double bg = sqrt(bg2);
|
||||
G4double bg = std::sqrt(bg2);
|
||||
G4double rho = (gamma2+4.*gam+1.)*G4Log(gam+bg)/(gamma2-1.)
|
||||
- (gam+3.)/(sqrt(gam*gam - 1.));
|
||||
- (gam+3.)/(std::sqrt(gam*gam - 1.));
|
||||
G4double eGammaCMS = CLHEP::electron_mass_c2 * std::sqrt(0.5*(tau + 2.0));
|
||||
fDelta = std::max(fDeltaMin, fGammaTh/eGammaCMS);
|
||||
f3GModel->SetDelta(fDelta);
|
||||
|
||||
static const G4double pir2 = pi*classic_electr_radius*classic_electr_radius;
|
||||
static const G4double pir2 =
|
||||
CLHEP::pi*CLHEP::classic_electr_radius*CLHEP::classic_electr_radius;
|
||||
G4double cross = (pir2*rho + alpha_rcl2*2.*G4Log(fDelta)*rho*rho)/(gam+1.);
|
||||
|
||||
return cross;
|
||||
@@ -175,143 +187,54 @@ G4double G4eplusTo2GammaOKVIModel::CrossSectionPerVolume(
|
||||
// Polarisation of gamma according to M.H.L.Pryce and J.C.Ward,
|
||||
// Nature 4065 (1947) 435.
|
||||
|
||||
void
|
||||
G4eplusTo2GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
|
||||
const G4MaterialCutsCouple* mcc,
|
||||
const G4DynamicParticle* dp,
|
||||
G4double, G4double)
|
||||
void G4eplusTo2GammaOKVIModel::SampleSecondaries(
|
||||
std::vector<G4DynamicParticle*>* vdp,
|
||||
const G4MaterialCutsCouple* couple,
|
||||
const G4DynamicParticle* dp,
|
||||
G4double, G4double)
|
||||
{
|
||||
G4double posiKinEnergy = dp->GetKineticEnergy();
|
||||
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
|
||||
|
||||
if(rndmEngine->flat() < f3GProbability->Value(posiKinEnergy)) {
|
||||
G4double cutd = std::max(fGammaTh,(*fCuts)[mcc->GetIndex()])
|
||||
/(posiKinEnergy + electron_mass_c2);
|
||||
// check cut to avoid production of 3d gamma below
|
||||
if(cutd > fDelta) {
|
||||
G4double cs30 = fCrossSection3G->Value(posiKinEnergy);
|
||||
f3GModel->SetDelta(cutd);
|
||||
G4double cs3 = f3GModel->ComputeCrossSectionPerElectron(posiKinEnergy);
|
||||
if(rndmEngine->flat()*cs30 < cs3) {
|
||||
f3GModel->SampleSecondaries(vdp, mcc, dp);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
f3GModel->SampleSecondaries(vdp, mcc, dp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
G4DynamicParticle *aGamma1, *aGamma2;
|
||||
|
||||
// Case at rest
|
||||
if(posiKinEnergy == 0.0) {
|
||||
G4double cost = 2.*rndmEngine->flat()-1.;
|
||||
G4double sint = sqrt((1. - cost)*(1. + cost));
|
||||
G4double phi = twopi * rndmEngine->flat();
|
||||
G4ThreeVector dir(sint*cos(phi), sint*sin(phi), cost);
|
||||
phi = twopi * rndmEngine->flat();
|
||||
G4double cosphi = cos(phi);
|
||||
G4double sinphi = sin(phi);
|
||||
G4ThreeVector pol(cosphi, sinphi, 0.0);
|
||||
pol.rotateUz(dir);
|
||||
aGamma1 = new G4DynamicParticle(theGamma, dir, electron_mass_c2);
|
||||
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
aGamma2 = new G4DynamicParticle(theGamma,-dir, electron_mass_c2);
|
||||
pol.set(-sinphi, cosphi, 0.0);
|
||||
pol.rotateUz(dir);
|
||||
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
|
||||
} else {
|
||||
|
||||
G4ThreeVector posiDirection = dp->GetMomentumDirection();
|
||||
|
||||
G4double tau = posiKinEnergy/electron_mass_c2;
|
||||
G4double gam = tau + 1.0;
|
||||
G4double tau2 = tau + 2.0;
|
||||
G4double sqgrate = sqrt(tau/tau2)*0.5;
|
||||
G4double sqg2m1 = sqrt(tau*tau2);
|
||||
|
||||
// limits of the energy sampling
|
||||
G4double epsilmin = 0.5 - sqgrate;
|
||||
G4double epsilmax = 0.5 + sqgrate;
|
||||
G4double epsilqot = epsilmax/epsilmin;
|
||||
|
||||
//
|
||||
// sample the energy rate of the created gammas
|
||||
//
|
||||
G4double epsil, greject;
|
||||
|
||||
do {
|
||||
epsil = epsilmin*G4Exp(G4Log(epsilqot)*rndmEngine->flat());
|
||||
greject = 1. - epsil + (2.*gam*epsil-1.)/(epsil*tau2*tau2);
|
||||
// Loop checking, 03-Aug-2015, Vladimir Ivanchenko
|
||||
} while( greject < rndmEngine->flat());
|
||||
|
||||
//
|
||||
// scattered Gamma angles. ( Z - axis along the parent positron)
|
||||
//
|
||||
|
||||
G4double cost = (epsil*tau2-1.)/(epsil*sqg2m1);
|
||||
if(std::abs(cost) > 1.0) {
|
||||
G4cout << "### G4eplusTo2GammaOKVIModel WARNING cost= " << cost
|
||||
<< " positron Ekin(MeV)= " << posiKinEnergy
|
||||
<< " gamma epsil= " << epsil
|
||||
<< G4endl;
|
||||
if(cost > 1.0) cost = 1.0;
|
||||
else cost = -1.0;
|
||||
}
|
||||
G4double sint = sqrt((1.+cost)*(1.-cost));
|
||||
G4double phi = twopi * rndmEngine->flat();
|
||||
|
||||
//
|
||||
// kinematic of the created pair
|
||||
//
|
||||
|
||||
G4double TotalAvailableEnergy = posiKinEnergy + 2.0*electron_mass_c2;
|
||||
G4double phot1Energy = epsil*TotalAvailableEnergy;
|
||||
|
||||
G4ThreeVector phot1Direction(sint*cos(phi), sint*sin(phi), cost);
|
||||
phot1Direction.rotateUz(posiDirection);
|
||||
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
|
||||
phi = twopi * rndmEngine->flat();
|
||||
G4double cosphi = cos(phi);
|
||||
G4double sinphi = sin(phi);
|
||||
G4ThreeVector pol(cosphi, sinphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
|
||||
G4double phot2Energy =(1.-epsil)*TotalAvailableEnergy;
|
||||
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
|
||||
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
|
||||
G4ThreeVector phot2Direction = dir.unit();
|
||||
|
||||
// create G4DynamicParticle object for the particle2
|
||||
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
|
||||
|
||||
//!!! likely problematic direction to be checked
|
||||
pol.set(-sinphi, cosphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
cost = pol*phot2Direction;
|
||||
pol -= cost*phot2Direction;
|
||||
pol = pol.unit();
|
||||
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
}
|
||||
/*
|
||||
G4cout << "Annihilation in fly: e0= " << posiKinEnergy
|
||||
<< " m= " << electron_mass_c2
|
||||
<< " e1= " << phot1Energy
|
||||
<< " e2= " << phot2Energy << " dir= " << dir
|
||||
<< " -> " << phot1Direction << " "
|
||||
<< phot2Direction << G4endl;
|
||||
*/
|
||||
|
||||
vdp->push_back(aGamma1);
|
||||
vdp->push_back(aGamma2);
|
||||
|
||||
// kill primary positron
|
||||
fParticleChange->SetProposedKineticEnergy(0.0);
|
||||
fParticleChange->ProposeTrackStatus(fStopAndKill);
|
||||
|
||||
// Case at rest not considered anymore
|
||||
G4double posiKinEnergy = dp->GetKineticEnergy();
|
||||
G4LorentzVector lv(dp->GetMomentum(),
|
||||
posiKinEnergy + 2*CLHEP::electron_mass_c2);
|
||||
G4double eGammaCMS = 0.5 * lv.mag();
|
||||
|
||||
if (G4UniformRand() < f3GProbability->Value(posiKinEnergy)) {
|
||||
fDelta = std::max(fDeltaMin, fGammaTh/eGammaCMS);
|
||||
f3GModel->SetDelta(fDelta);
|
||||
f3GModel->SampleSecondaries(vdp, couple, dp);
|
||||
return;
|
||||
}
|
||||
|
||||
G4ThreeVector dir1 = G4RandomDirection();
|
||||
G4double phi = CLHEP::twopi * G4UniformRand();
|
||||
G4double cosphi = std::cos(phi);
|
||||
G4double sinphi = std::sin(phi);
|
||||
G4ThreeVector pol1(cosphi, sinphi, 0.0);
|
||||
pol1.rotateUz(dir1);
|
||||
G4LorentzVector lv1(eGammaCMS*dir1, eGammaCMS);
|
||||
|
||||
G4ThreeVector pol2(-sinphi, cosphi, 0.0);
|
||||
pol2.rotateUz(dir1);
|
||||
|
||||
// transformation to lab system
|
||||
lv1.boost(lv.boostVector());
|
||||
lv -= lv1;
|
||||
|
||||
//!!! boost of polarisation vector is not yet implemented
|
||||
|
||||
// use constructors optimal for massless particle
|
||||
auto aGamma1 = new G4DynamicParticle(G4Gamma::Gamma(), lv1.vect());
|
||||
aGamma1->SetPolarization(pol1);
|
||||
auto aGamma2 = new G4DynamicParticle(G4Gamma::Gamma(), lv.vect());
|
||||
aGamma2->SetPolarization(pol2);
|
||||
|
||||
vdp->push_back(aGamma1);
|
||||
vdp->push_back(aGamma2);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
@@ -62,7 +62,6 @@ G4eplusTo3GammaOKVIModel::G4eplusTo3GammaOKVIModel(const G4ParticleDefinition*,
|
||||
: G4VEmModel(nam), fDelta(0.001)
|
||||
{
|
||||
theGamma = G4Gamma::Gamma();
|
||||
fParticleChange = nullptr;
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
@@ -73,11 +72,7 @@ G4eplusTo3GammaOKVIModel::~G4eplusTo3GammaOKVIModel() = default;
|
||||
|
||||
void G4eplusTo3GammaOKVIModel::Initialise(const G4ParticleDefinition*,
|
||||
const G4DataVector&)
|
||||
{
|
||||
// here particle change is set for the triplet model
|
||||
if(fParticleChange) { return; }
|
||||
fParticleChange = GetParticleChangeForGamma();
|
||||
}
|
||||
{}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
|
||||
|
||||
@@ -183,8 +178,8 @@ G4eplusTo3GammaOKVIModel::ComputeCrossSectionPerElectron(G4double kinEnergy)
|
||||
// Calculates the cross section per electron of annihilation into 3 photons
|
||||
// from the Heilter formula.
|
||||
|
||||
G4double ekin = std::max(eV,kinEnergy);
|
||||
G4double tau = ekin/electron_mass_c2;
|
||||
G4double ekin = std::max(CLHEP::eV, kinEnergy);
|
||||
G4double tau = ekin/CLHEP::electron_mass_c2;
|
||||
G4double gam = tau + 1.0;
|
||||
G4double gamma2 = gam*gam;
|
||||
G4double bg2 = tau * (tau+2.0);
|
||||
@@ -204,10 +199,6 @@ G4double G4eplusTo3GammaOKVIModel::ComputeCrossSectionPerAtom(
|
||||
G4double kineticEnergy, G4double Z,
|
||||
G4double, G4double, G4double)
|
||||
{
|
||||
// Calculates the cross section per atom of annihilation into two photons
|
||||
|
||||
|
||||
|
||||
G4double cross = Z*ComputeCrossSectionPerElectron(kineticEnergy);
|
||||
return cross;
|
||||
}
|
||||
@@ -238,149 +229,78 @@ G4eplusTo3GammaOKVIModel::SampleSecondaries(vector<G4DynamicParticle*>* vdp,
|
||||
const G4DynamicParticle* dp,
|
||||
G4double, G4double)
|
||||
{
|
||||
|
||||
// let us perform sampling in C.M.S. reference frame of e- at rest and e+ on fly
|
||||
G4double posiKinEnergy = dp->GetKineticEnergy();
|
||||
G4DynamicParticle *aGamma1, *aGamma2;
|
||||
G4DynamicParticle* aGamma3 = nullptr;
|
||||
G4double border;
|
||||
G4LorentzVector lv(dp->GetMomentum(),
|
||||
posiKinEnergy + 2*CLHEP::electron_mass_c2);
|
||||
G4double eGammaCMS = 0.5 * lv.mag();
|
||||
|
||||
if(posiKinEnergy < 500*MeV) {
|
||||
border = 1. - (electron_mass_c2)/(2*(posiKinEnergy + electron_mass_c2));
|
||||
} else {
|
||||
border = 1. - (100*electron_mass_c2)/(2*(posiKinEnergy + electron_mass_c2));
|
||||
}
|
||||
border = std::min(border, 0.9999);
|
||||
// the limit value fDelta is defined by a class, which call this method
|
||||
// thickness of border defined by C.M.S. energy
|
||||
G4double border =
|
||||
1.0 - std::min(std::max(CLHEP::electron_mass_c2/eGammaCMS, fDelta), 0.1);
|
||||
|
||||
CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
|
||||
|
||||
// Case at rest
|
||||
if(posiKinEnergy == 0.0) {
|
||||
G4double cost = 2.*rndmEngine->flat()-1.;
|
||||
G4double sint = sqrt((1. - cost)*(1. + cost));
|
||||
G4double phi = twopi * rndmEngine->flat();
|
||||
G4ThreeVector dir(sint*cos(phi), sint*sin(phi), cost);
|
||||
phi = twopi * rndmEngine->flat();
|
||||
G4double cosphi = cos(phi);
|
||||
G4double sinphi = sin(phi);
|
||||
G4ThreeVector pol(cosphi, sinphi, 0.0);
|
||||
pol.rotateUz(dir);
|
||||
aGamma1 = new G4DynamicParticle(theGamma, dir, electron_mass_c2);
|
||||
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
aGamma2 = new G4DynamicParticle(theGamma,-dir, electron_mass_c2);
|
||||
pol.set(-sinphi, cosphi, 0.0);
|
||||
pol.rotateUz(dir);
|
||||
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
G4ThreeVector posiDirection = dp->GetMomentumDirection();
|
||||
|
||||
} else {
|
||||
|
||||
G4ThreeVector posiDirection = dp->GetMomentumDirection();
|
||||
|
||||
// (A.A.) LIMITS FOR 1st GAMMA
|
||||
G4double xmin = 0.01;
|
||||
G4double xmax = 0.667; // CHANGE to 3/2
|
||||
// (A.A.) LIMITS FOR 1st GAMMA
|
||||
G4double xmin = 0.01;
|
||||
G4double xmax = 0.667; // CHANGE to 3/2
|
||||
|
||||
G4double d1, d0, x1, x2, dmax, x2min;
|
||||
G4double d1, d0, x1, x2, dmax, x2min;
|
||||
|
||||
// (A.A.) sampling of x1 x2 x3 (whole cycle of rejection)
|
||||
do {
|
||||
x1 = 1/((1/xmin) - ((1/xmin)-(1/xmax))*rndmEngine->flat());
|
||||
dmax = ComputeFS(posiKinEnergy, x1,1.-x1,border);
|
||||
x2min = 1.-x1;
|
||||
x2 = 1 - rndmEngine->flat()*(1-x2min);
|
||||
d1 = dmax*rndmEngine->flat();
|
||||
d0 = ComputeFS(posiKinEnergy,x1,x2,2-x1-x2);
|
||||
}
|
||||
while(d0 < d1);
|
||||
|
||||
G4double x3 = 2 - x1 - x2;
|
||||
|
||||
//
|
||||
// angles between Gammas
|
||||
//
|
||||
|
||||
G4double psi13 = 2*asin(sqrt(std::abs((x1+x3-1)/(x1*x3))));
|
||||
G4double psi12 = 2*asin(sqrt(std::abs((x1+x2-1)/(x1*x2))));
|
||||
|
||||
// sin^t
|
||||
|
||||
//G4double phi = twopi * rndmEngine->flat();
|
||||
//G4double psi = acos(x3); // Angle of the plane
|
||||
|
||||
//
|
||||
// kinematic of the created pair
|
||||
//
|
||||
|
||||
G4double TotalAvailableEnergy = posiKinEnergy + 2.0*electron_mass_c2;
|
||||
|
||||
G4double phot1Energy = 0.5*x1*TotalAvailableEnergy;
|
||||
G4double phot2Energy = 0.5*x2*TotalAvailableEnergy;
|
||||
G4double phot3Energy = 0.5*x3*TotalAvailableEnergy;
|
||||
// (A.A.) sampling of x1 x2 x3 (whole cycle of rejection)
|
||||
do {
|
||||
x1 = 1./((1./xmin) - ((1./xmin)-(1./xmax))*rndmEngine->flat());
|
||||
dmax = ComputeFS(eGammaCMS, x1, 1.-x1, border);
|
||||
x2min = 1. - x1;
|
||||
x2 = 1 - rndmEngine->flat()*(1. - x2min);
|
||||
d1 = dmax*rndmEngine->flat();
|
||||
d0 = ComputeFS(eGammaCMS, x1, x2, 2.-x1-x2);
|
||||
}
|
||||
while(d0 < d1);
|
||||
|
||||
G4double x3 = 2 - x1 - x2;
|
||||
//
|
||||
// angles between Gammas
|
||||
//
|
||||
G4double psi13 = 2*std::asin(std::sqrt(std::abs((x1+x3-1.)/(x1*x3))));
|
||||
G4double psi12 = 2*std::asin(std::sqrt(std::abs((x1+x2-1.)/(x1*x2))));
|
||||
//
|
||||
// kinematic of the created pair
|
||||
//
|
||||
G4double phot1Energy = x1*eGammaCMS;
|
||||
G4double phot2Energy = x2*eGammaCMS;
|
||||
G4double phot3Energy = x3*eGammaCMS;
|
||||
|
||||
// DIRECTIONS
|
||||
// DIRECTIONS
|
||||
|
||||
// The azimuthal angles of ql and q3 with respect to some plane
|
||||
// through the beam axis are generated at random.
|
||||
// The azimuthal angles of q1 and q3 with respect to some plane
|
||||
// through the beam axis are generated at random.
|
||||
|
||||
G4ThreeVector phot1Direction(0, 0, 1);
|
||||
G4ThreeVector phot2Direction(0, sin(psi12), cos(psi12));
|
||||
G4ThreeVector phot3Direction(0, sin(psi13), cos(psi13));
|
||||
G4ThreeVector phot1Direction(0, 0, 1);
|
||||
G4ThreeVector phot2Direction(0, std::sin(psi12), std::cos(psi12));
|
||||
G4ThreeVector phot3Direction(0, std::sin(psi13), std::cos(psi13));
|
||||
|
||||
phot1Direction.rotateUz(posiDirection);
|
||||
phot2Direction.rotateUz(posiDirection);
|
||||
phot3Direction.rotateUz(posiDirection);
|
||||
G4LorentzVector lv1(phot1Energy*phot1Direction, phot1Energy);
|
||||
G4LorentzVector lv2(phot2Energy*phot2Direction, phot2Energy);
|
||||
G4LorentzVector lv3(phot3Energy*phot3Direction, phot3Energy);
|
||||
|
||||
aGamma1 = new G4DynamicParticle (theGamma,phot1Direction, phot1Energy);
|
||||
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
|
||||
aGamma3 = new G4DynamicParticle (theGamma,phot3Direction, phot3Energy);
|
||||
auto boostV = lv.boostVector();
|
||||
lv1.boost(boostV);
|
||||
lv2.boost(boostV);
|
||||
lv3.boost(boostV);
|
||||
|
||||
auto aGamma1 = new G4DynamicParticle (theGamma, lv1.vect());
|
||||
auto aGamma2 = new G4DynamicParticle (theGamma, lv2.vect());
|
||||
auto aGamma3 = new G4DynamicParticle (theGamma, lv3.vect());
|
||||
|
||||
//POLARIZATION - ???
|
||||
/*
|
||||
|
||||
|
||||
phi = twopi * rndmEngine->flat();
|
||||
G4double cosphi = cos(phi);
|
||||
G4double sinphi = sin(phi);
|
||||
G4ThreeVector pol(cosphi, sinphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
aGamma1->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
|
||||
G4double phot2Energy =(1.-epsil)*TotalAvailableEnergy;
|
||||
G4double posiP= sqrt(posiKinEnergy*(posiKinEnergy+2.*electron_mass_c2));
|
||||
G4ThreeVector dir = posiDirection*posiP - phot1Direction*phot1Energy;
|
||||
G4ThreeVector phot2Direction = dir.unit();
|
||||
|
||||
// create G4DynamicParticle object for the particle2
|
||||
aGamma2 = new G4DynamicParticle (theGamma,phot2Direction, phot2Energy);
|
||||
|
||||
//!!! likely problematic direction to be checked
|
||||
pol.set(-sinphi, cosphi, 0.0);
|
||||
pol.rotateUz(phot1Direction);
|
||||
cost = pol*phot2Direction;
|
||||
pol -= cost*phot2Direction;
|
||||
pol = pol.unit();
|
||||
aGamma2->SetPolarization(pol.x(),pol.y(),pol.z());
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
/*
|
||||
G4cout << "Annihilation in fly: e0= " << posiKinEnergy
|
||||
<< " m= " << electron_mass_c2
|
||||
<< " e1= " << phot1Energy
|
||||
<< " e2= " << phot2Energy << " dir= " << dir
|
||||
<< " -> " << phot1Direction << " "
|
||||
<< phot2Direction << G4endl;
|
||||
*/
|
||||
//!!! POLARIZATION - not yet implemented
|
||||
|
||||
vdp->push_back(aGamma1);
|
||||
vdp->push_back(aGamma2);
|
||||
if(aGamma3 != nullptr) { vdp->push_back(aGamma3); }
|
||||
|
||||
// kill primary positron
|
||||
fParticleChange->SetProposedKineticEnergy(0.0);
|
||||
fParticleChange->ProposeTrackStatus(fStopAndKill);
|
||||
vdp->push_back(aGamma3);
|
||||
}
|
||||
|
||||
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
|
||||
|
||||
Reference in New Issue
Block a user