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