BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSComptonScatteringEngine.cc
1# /*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2024.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSComptonScatteringEngine.hh"
20
21#include "globals.hh"
22#include "G4Electron.hh"
23#include "G4Proton.hh"
24#include "G4RandomDirection.hh"
25#include "Randomize.hh"
26
27#include "CLHEP/Units/PhysicalConstants.h"
28#include "CLHEP/Units/SystemOfUnits.h"
29#include <cmath>
30
31BDSComptonScatteringEngine::BDSComptonScatteringEngine():
32 particleMass(0),
33 particleRadius(0),
34 partID(0)
35{;}
36
37BDSComptonScatteringEngine::~BDSComptonScatteringEngine()
38{;}
39
40void BDSComptonScatteringEngine::SetParticle(G4int partIDIn)
41{
42 partID = partIDIn;
43 if (std::abs(partID) == 11)
44 {particleMass = G4Electron::ElectronDefinition()->GetPDGMass();}
45 else if (partID == 2212)
46 {particleMass = G4Proton::ProtonDefinition()->GetPDGMass();}
47 // else particle mass just left as whatever it was before?
48 particleRadius = (CLHEP::e_squared) / (4 * CLHEP::pi * CLHEP::epsilon0 * particleMass);
49}
50
51
52G4double BDSComptonScatteringEngine::CrossSection(G4double photonEnergyIn, G4int partIn)
53{
54 SetParticle(partIn);
55 G4double e1 = photonEnergyIn / particleMass;
56
57 G4double crossSectionThomson = (8.0/3.0)*CLHEP::pi*particleRadius*particleRadius;
58
59 G4double p1 = ((1 + e1) / std::pow(e1,3)) * ( 2*e1 * (1 + e1) / (1 + 2*e1) - std::log(1 + 2*e1));
60 G4double p2 = (1. / (2*e1)) * std::log(1 + 2*e1);
61 G4double p3 = (1 + 3*e1) / std::pow((1 + 2*e1), 2);
62 G4double ratio = 0.75*(p1 + p2 - p3);
63 G4double crossSection = crossSectionThomson*ratio;
64
65 return crossSection;
66}
67
68void BDSComptonScatteringEngine::PerformCompton(const G4ThreeVector& boost,G4int partIn)
69{
70 SetParticle(partIn);
71 G4double theta = MCMCTheta();
72 G4double scatteredGammaEnergy = ScatteredEnergy(theta);
73 G4double phi = MCPhi(theta,scatteredGammaEnergy);
74 G4ThreeVector scatteredGammaUnitVector(std::sin(theta)*std::cos(phi), std::sin(theta)*std::sin(phi), std::cos(theta));
75 if(incomingGamma.x()<=1e9&&incomingGamma.y()<=1e9)
76 {
77 scatteredGammaUnitVector.rotate(0,CLHEP::pi,0);
78 }
79 else
80 {
81 G4RotationMatrix* rot = CalculateRotation();
82 scatteredGammaUnitVector.transform(*rot);
83 }
84 scatteredGamma.setVect(scatteredGammaUnitVector * scatteredGammaEnergy);
85 scatteredGamma.setE(scatteredGammaEnergy);
86 G4ThreeVector scatteredElectronVector(incomingGamma.vect()-scatteredGamma.vect());
87 scatteredElectron.setE(incomingGamma.e()+incomingElectron.e()-scatteredGammaEnergy);
88 scatteredElectron.setVect(scatteredElectronVector);
89 scatteredElectron.boost(boost);
90 scatteredGamma.boost(boost);
91}
92
93G4double BDSComptonScatteringEngine::MCMCTheta()
94{
95 G4double theta = std::acos(1-2*G4UniformRand());
96 G4double KNTheta = KleinNishinaDifferential(theta);
97 G4double KNMax = KleinNishinaDifferential(0);
98 G4double KNRandom = G4UniformRand()*KNMax;
99
100 return KNTheta > KNRandom ? theta : MCMCTheta();
101}
102
103G4double BDSComptonScatteringEngine::KleinNishinaDifferential(G4double theta)
104{
105 G4double E0 = incomingGamma.e();
106 G4double Ep = E0 / (1.0+(E0/particleMass) * (1.0-std::cos(theta)) );
107 return 0.5 * particleRadius * particleRadius * (Ep/E0) * (Ep/E0) * ((Ep/E0)+(E0/Ep)-std::sin(theta)*std::sin(theta));
108}
109
110
111G4RotationMatrix* BDSComptonScatteringEngine::CalculateRotation()
112{
113 G4ThreeVector theoryIncomingPhoton (0,0,1);
114 G4ThreeVector crossProduct = theoryIncomingPhoton.cross(incomingGamma.vect().unit());
115 G4double dotProduct = theoryIncomingPhoton.dot(incomingGamma.vect().unit());
116 G4double multiplier = 1.0/(1.0+dotProduct);
117 G4RotationMatrix* identity = new G4RotationMatrix;
118 G4ThreeVector vrow1 (1, -1*crossProduct.z(),crossProduct.y());
119 G4ThreeVector vrow2 (crossProduct.z(),1,-1.0*crossProduct.x());
120 G4ThreeVector vrow3 (-1.0*crossProduct.y(), crossProduct.x(),1);
121 G4ThreeVector v2row1 (multiplier*(-crossProduct.y()*crossProduct.y()-crossProduct.z()*crossProduct.z()), multiplier*crossProduct.x()*crossProduct.y(),multiplier*crossProduct.x()*crossProduct.z());
122 G4ThreeVector v2row2 (multiplier*crossProduct.x()*crossProduct.y(),multiplier*(-crossProduct.x()*crossProduct.x()-crossProduct.z()*crossProduct.z()),multiplier*crossProduct.y()*crossProduct.z());
123 G4ThreeVector v2row3 (multiplier*crossProduct.x()*crossProduct.z(), multiplier*crossProduct.y()*crossProduct.z(),multiplier*(-crossProduct.x()*crossProduct.x()-crossProduct.y()*crossProduct.y()));
124 identity->setRows(vrow1+v2row1,vrow2+v2row2,vrow3+v2row3);
125 return identity;
126}
127G4double BDSComptonScatteringEngine::ScatteredEnergy(G4double theta)
128{
129 return incomingGamma.e()/(1+(incomingGamma.e()/particleMass)*(1-std::cos(theta)));
130}
131
132G4double BDSComptonScatteringEngine::MCPhi(G4double theta, G4double scatteredEnergy)
133{
134 G4double maxPhiVal = PolarizationCrossSectionMaxPhi(theta,scatteredEnergy);
135 G4double maxCrossSec1 = PolarizationCrossSectionPhi(theta, maxPhiVal,scatteredEnergy);
136 G4double maxCrossSec2 = PolarizationCrossSectionPhi(theta, maxPhiVal+CLHEP::pi,scatteredEnergy);
137 G4double maxCrossSec;
138 if(maxCrossSec1>=maxCrossSec2)
139 {maxCrossSec=maxCrossSec1;}
140 else
141 {maxCrossSec=maxCrossSec2;}
142 G4double phi = CLHEP::twopi*G4UniformRand();
143 G4double randCrossSecPhi = PolarizationCrossSectionPhi(theta, phi, scatteredEnergy);
144 G4double randCrossSec = maxCrossSec*G4UniformRand();
145 return randCrossSecPhi > randCrossSec ? phi : MCPhi(theta, scatteredEnergy);
146}
147
148G4double BDSComptonScatteringEngine::PolarizationCrossSectionPhi(G4double theta, G4double phi, G4double Ep)
149{
150 G4double E0=incomingGamma.e();
151 G4double constants = ((particleRadius*particleRadius)/2.0)*(Ep/E0)*(Ep/E0);
152 G4double first = 1.0+std::cos(theta)*std::cos(theta)+(E0-Ep)*(1.0-std::cos(theta));
153 G4double second = std::sin(theta)*std::sin(theta)*(incomingGammaPolarization.p1()*std::cos(phi)+incomingGammaPolarization.p2()*std::sin(phi));
154 G4double third = -1.0*incomingGammaPolarization.p3()*(1.0-std::cos(theta))*
155 (Ep*std::sin(theta)*(incomingElectronPolarization.p1()*std::cos(phi)+incomingElectronPolarization.p2()*std::sin(phi))
156 +incomingElectronPolarization.p3()*std::cos(theta)*(E0+Ep));
157 return constants*(first+second+third);
158
159}
160
161G4double BDSComptonScatteringEngine::PolarizationCrossSectionMaxPhi(G4double theta ,G4double Ep)
162{
163 G4double numer = -incomingGammaPolarization.p3()*(1.0-std::cos(theta))*Ep*std::sin(theta)*incomingElectronPolarization.p2() -
164 std::sin(theta)*std::sin(theta)*incomingGammaPolarization.p2();
165 G4double denom = std::sin(theta)*std::sin(theta)*incomingGammaPolarization.p1()+
166 incomingGammaPolarization.p3()*(1.0-std::cos(theta))*Ep*std::sin(theta)*incomingElectronPolarization.p1();
167 G4double phiVal = std::atan(numer/denom);
168 if (phiVal<0)
169 {phiVal+=CLHEP::pi;}
170 if (numer ==0)
171 {return 0;}
172 if (denom ==0)
173 {return 0;}
174 else
175 {return phiVal;}
176}
177
178
179