Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4PhotoElectricAngularGeneratorPolarized.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27// -------------------------------------------------------------------
28//
29// GEANT4 Class file
30//
31//
32// File name: G4PhotoElectricAngularGeneratorPolarized
33//
34// Author: A. C. Farinha, L. Peralta, P. Rodrigues and A. Trindade
35//
36// Creation date:
37//
38// Modifications:
39// 10 January 2006
40// 06 May 2011, Replace FILE with std::ifstream
41//
42// Class Description:
43//
44// Concrete class for PhotoElectric Electron Angular Polarized Distribution Generation
45//
46// Class Description:
47// PhotoElectric Electron Angular Generator based on the general Gavrila photoelectron angular distribution.
48// Includes polarization effects for K and L1 atomic shells, according to Gavrila (1959, 1961).
49// For higher shells the L1 cross-section is used.
50//
51// The Gavrila photoelectron angular distribution is a complex function which can not be sampled using
52// the inverse-transform method (James 1980). Instead a more general approach based on the one already
53// used to sample bremsstrahlung 2BN cross section (G4Generator2BN, Peralta, 2005) was used.
54//
55// M. Gavrila, "Relativistic K-Shell Photoeffect", Phys. Rev. 113, 514-526 (1959)
56// M. Gavrila, "Relativistic L-Shell Photoeffect", Phys. Rev. 124, 1132-1141 (1961)
57// F. James, Rept. on Prog. in Phys. 43, 1145 (1980)
58// L. Peralta et al., "A new low-energy bremsstrahlung generator for GEANT4", Radiat. Prot. Dosimetry. 116, 59-64 (2005)
59//
60//
61// -------------------------------------------------------------------
62//
63//
64
67#include "G4RotationMatrix.hh"
68#include "Randomize.hh"
69#include "G4Exp.hh"
70
72 :G4VEmAngularDistribution("AngularGenSauterGavrilaPolarized")
73{
74 const G4int arrayDim = 980;
75
76 //minimum electron beta parameter allowed
77 betaArray[0] = 0.02;
78 //beta step
79 betaArray[1] = 0.001;
80 //maximum index array for a and c tables
81 betaArray[2] = arrayDim - 1;
82
83 // read Majorant Surface Parameters. This are required in order to generate
84 //Gavrila angular photoelectron distribution
85 for(G4int level = 0; level < 2; level++){
86 char nameChar0[100] = "ftab0.dat"; // K-shell Majorant Surface Parameters
87 char nameChar1[100] = "ftab1.dat"; // L-shell Majorant Surface Parameters
88
89 G4String filename;
90 if(level == 0) filename = nameChar0;
91 if(level == 1) filename = nameChar1;
92
93 const char* path = G4FindDataDir("G4LEDATA");
94 if (!path)
95 {
96 G4String excep = "G4EMDataSet - G4LEDATA environment variable not set";
97 G4Exception("G4PhotoElectricAngularGeneratorPolarized::G4PhotoElectricAngularGeneratorPolarized",
98 "em0006",FatalException,"G4LEDATA environment variable not set");
99 return;
100 }
101
102 G4String pathString(path);
103 G4String dirFile = pathString + "/photoelectric_angular/" + filename;
104 std::ifstream infile(dirFile);
105 if (!infile.is_open())
106 {
107 G4String excep = "data file: " + dirFile + " not found";
108 G4Exception("G4PhotoElectricAngularGeneratorPolarized::G4PhotoElectricAngularGeneratorPolarized",
109 "em0003",FatalException,excep);
110 return;
111 }
112
113 // Read parameters into tables. The parameters are function of incident electron
114 // energy and shell level
115 G4float aRead=0,cRead=0, beta=0;
116 for(G4int i=0 ; i<arrayDim ;++i){
117 infile >> beta >> aRead >> cRead;
118 aMajorantSurfaceParameterTable[i][level] = aRead;
119 cMajorantSurfaceParameterTable[i][level] = cRead;
120 }
121 infile.close();
122 }
123}
124
125//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
126
128{}
129
130//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
131
134 const G4DynamicParticle* dp,
135 G4double eKinEnergy,
136 G4int shellId,
137 const G4Material*)
138{
139 // (shellId == 0) - K-shell - Polarized model for K-shell
140 // (shellId > 0) - L1-shell - Polarized model for L1 and higher shells
141
142 // Calculate Lorentz term (gamma) and beta parameters
143 G4double gamma = 1 + eKinEnergy/electron_mass_c2;
144 G4double beta = std::sqrt((gamma - 1)*(gamma + 1))/gamma;
145
146 const G4ThreeVector& direction = dp->GetMomentumDirection();
147 const G4ThreeVector& polarization = dp->GetPolarization();
148
149 G4double theta, phi = 0;
150 // Majorant surface parameters
151 // function of the outgoing electron kinetic energy
152 G4double aBeta = 0;
153 G4double cBeta = 0;
154
155 // For the outgoing kinetic energy
156 // find the current majorant surface parameters
157 PhotoElectronGetMajorantSurfaceAandCParameters(shellId, beta, &aBeta, &cBeta);
158
159 // Generate pho and theta according to the shell level
160 // and beta parameter of the electron
161 PhotoElectronGeneratePhiAndTheta(shellId, beta, aBeta, cBeta, &phi, &theta);
162
163 // Determine the rotation matrix
164 const G4RotationMatrix rotation =
165 PhotoElectronRotationMatrix(direction, polarization);
166
167 // Compute final direction of the outgoing electron
168 fLocalDirection = PhotoElectronComputeFinalDirection(rotation, theta, phi);
169
170 return fLocalDirection;
171}
172
173//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
174
175void
176G4PhotoElectricAngularGeneratorPolarized::PhotoElectronGeneratePhiAndTheta(
177 G4int shellLevel, G4double beta, G4double aBeta, G4double cBeta,
178 G4double *pphi, G4double *ptheta) const
179{
180 G4double rand1, rand2, rand3 = 0;
181 G4double phi = 0;
182 G4double theta = 0;
183 G4double crossSectionValue = 0;
184 G4double crossSectionMajorantFunctionValue = 0;
185 G4double maxBeta = 0;
186
187 do {
188
189 rand1 = G4UniformRand();
190 rand2 = G4UniformRand();
191 rand3 = G4UniformRand();
192
193 phi=2*pi*rand1;
194
195 if(shellLevel == 0){
196 // Polarized Gavrila Cross-Section for K-shell (1959)
197 theta=std::sqrt(((G4Exp(rand2*std::log(1+cBeta*pi*pi)))-1)/cBeta);
198 crossSectionMajorantFunctionValue =
199 CrossSectionMajorantFunction(theta, cBeta);
200 crossSectionValue = DSigmaKshellGavrila1959(beta, theta, phi);
201 } else {
202 // Polarized Gavrila Cross-Section for other shells (L1-shell) (1961)
203 theta = std::sqrt(((G4Exp(rand2*std::log(1+cBeta*pi*pi)))-1)/cBeta);
204 crossSectionMajorantFunctionValue =
205 CrossSectionMajorantFunction(theta, cBeta);
206 crossSectionValue = DSigmaL1shellGavrila(beta, theta, phi);
207 }
208
209 maxBeta=rand3*aBeta*crossSectionMajorantFunctionValue;
210 if(crossSectionValue < 0.0) { crossSectionValue = maxBeta; }
211
212 } while(maxBeta > crossSectionValue || theta > CLHEP::pi);
213
214 *pphi = phi;
215 *ptheta = theta;
216}
217
218//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
219
221G4PhotoElectricAngularGeneratorPolarized::CrossSectionMajorantFunction(
222 G4double theta, G4double cBeta) const
223{
224 // Compute Majorant Function
225 G4double crossSectionMajorantFunctionValue = 0;
226 crossSectionMajorantFunctionValue = theta/(1+cBeta*theta*theta);
227 return crossSectionMajorantFunctionValue;
228}
229
230//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
231
233G4PhotoElectricAngularGeneratorPolarized::DSigmaKshellGavrila1959(
234 G4double beta, G4double theta, G4double phi) const
235{
236 //Double differential K shell cross-section (Gavrila 1959)
237
238 G4double beta2 = beta*beta;
239 G4double oneBeta2 = 1 - beta2;
240 G4double sqrtOneBeta2 = std::sqrt(oneBeta2);
241 G4double oneBeta2_to_3_2 = std::pow(oneBeta2,1.5);
242 G4double cosTheta = std::cos(theta);
243 G4double sinTheta2 = std::sin(theta)*std::sin(theta);
244 G4double cosPhi2 = std::cos(phi)*std::cos(phi);
245 G4double oneBetaCosTheta = 1-beta*cosTheta;
246 G4double dsigma = 0;
247 G4double firstTerm = 0;
248 G4double secondTerm = 0;
249
250 firstTerm = sinTheta2*cosPhi2/std::pow(oneBetaCosTheta,4)-(1 - sqrtOneBeta2)/(2*oneBeta2) *
251 (sinTheta2 * cosPhi2)/std::pow(oneBetaCosTheta,3) + (1-sqrtOneBeta2)*
252 (1-sqrtOneBeta2)/(4*oneBeta2_to_3_2) * sinTheta2/std::pow(oneBetaCosTheta,3);
253
254 secondTerm = std::sqrt(1 - sqrtOneBeta2)/(std::pow(2.,3.5)*beta2*std::pow(oneBetaCosTheta,2.5)) *
255 (4*beta2/sqrtOneBeta2 * sinTheta2*cosPhi2/oneBetaCosTheta + 4*beta/oneBeta2 * cosTheta * cosPhi2
256 - 4*(1-sqrtOneBeta2)/oneBeta2 *(1+cosPhi2) - beta2 * (1-sqrtOneBeta2)/oneBeta2 * sinTheta2/oneBetaCosTheta
257 + 4*beta2*(1-sqrtOneBeta2)/oneBeta2_to_3_2 - 4*beta*(1-sqrtOneBeta2)*(1-sqrtOneBeta2)/oneBeta2_to_3_2 * cosTheta)
258 + (1-sqrtOneBeta2)/(4*beta2*oneBetaCosTheta*oneBetaCosTheta) * (beta/oneBeta2 - 2/oneBeta2 * cosTheta * cosPhi2 +
259 (1-sqrtOneBeta2)/oneBeta2_to_3_2 * cosTheta - beta * (1-sqrtOneBeta2)/oneBeta2_to_3_2);
260
261 dsigma = ( firstTerm*(1-pi*fine_structure_const/beta) + secondTerm*(pi*fine_structure_const) )*std::sin(theta);
262
263 return dsigma;
264}
265
266//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
267
269G4PhotoElectricAngularGeneratorPolarized::DSigmaL1shellGavrila(
270 G4double beta, G4double theta, G4double phi) const
271{
272 //Double differential L1 shell cross-section (Gavrila 1961)
273 // 26Oct2022: included factor (1/8) in dsigma from eqn 20 of paper
274 G4double beta2 = beta*beta;
275 G4double oneBeta2 = 1-beta2;
276 G4double sqrtOneBeta2 = std::sqrt(oneBeta2);
277 G4double oneBeta2_to_3_2=std::pow(oneBeta2,1.5);
278 G4double cosTheta = std::cos(theta);
279 G4double sinTheta2 =std::sin(theta)*std::sin(theta);
280 G4double cosPhi2 = std::cos(phi)*std::cos(phi);
281 G4double oneBetaCosTheta = 1-beta*cosTheta;
282
283 G4double dsigma = 0;
284 G4double firstTerm = 0;
285 G4double secondTerm = 0;
286
287 firstTerm = sinTheta2*cosPhi2/std::pow(oneBetaCosTheta,4)-(1 - sqrtOneBeta2)/(2*oneBeta2)
288 * (sinTheta2 * cosPhi2)/std::pow(oneBetaCosTheta,3) + (1-sqrtOneBeta2)*
289 (1-sqrtOneBeta2)/(4*oneBeta2_to_3_2) * sinTheta2/std::pow(oneBetaCosTheta,3);
290
291 secondTerm = std::sqrt(1 - sqrtOneBeta2)/(std::pow(2.,3.5)*beta2*std::pow(oneBetaCosTheta,2.5)) *
292 (4*beta2/sqrtOneBeta2 * sinTheta2*cosPhi2/oneBetaCosTheta + 4*beta/oneBeta2 * cosTheta * cosPhi2
293 - 4*(1-sqrtOneBeta2)/oneBeta2 *(1+cosPhi2) - beta2 * (1-sqrtOneBeta2)/oneBeta2 * sinTheta2/oneBetaCosTheta
294 + 4*beta2*(1-sqrtOneBeta2)/oneBeta2_to_3_2 - 4*beta*(1-sqrtOneBeta2)*(1-sqrtOneBeta2)/oneBeta2_to_3_2 * cosTheta)
295 + (1-sqrtOneBeta2)/(4*beta2*oneBetaCosTheta*oneBetaCosTheta) * (beta/oneBeta2 - 2/oneBeta2 * cosTheta * cosPhi2 +
296 (1-sqrtOneBeta2)/oneBeta2_to_3_2*cosTheta - beta*(1-sqrtOneBeta2)/oneBeta2_to_3_2);
297
298 dsigma = ( firstTerm*(1-pi*fine_structure_const/beta) + secondTerm*(pi*fine_structure_const) )*std::sin(theta) / 8.;
299
300 return dsigma;
301}
302
303//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
304
306G4PhotoElectricAngularGeneratorPolarized::PhotoElectronRotationMatrix(
307 const G4ThreeVector& direction,
308 const G4ThreeVector& polarization)
309{
310 G4double mK = direction.mag();
311 G4double mS = polarization.mag();
312 G4ThreeVector polarization2 = polarization;
313 const G4double kTolerance = 1e-6;
314
315 if(!(polarization.isOrthogonal(direction,kTolerance)) || mS == 0){
316 G4ThreeVector d0 = direction.unit();
318 G4ThreeVector a0 = a1.unit();
319 G4double rand1 = G4UniformRand();
320 G4double angle = twopi*rand1;
321 G4ThreeVector b0 = d0.cross(a0);
323 c.setX(std::cos(angle)*(a0.x())+std::sin(angle)*b0.x());
324 c.setY(std::cos(angle)*(a0.y())+std::sin(angle)*b0.y());
325 c.setZ(std::cos(angle)*(a0.z())+std::sin(angle)*b0.z());
326 polarization2 = c.unit();
327 mS = polarization2.mag();
328 }else
329 {
330 if ( polarization.howOrthogonal(direction) != 0)
331 {
332 polarization2 = polarization
333 - polarization.dot(direction)/direction.dot(direction) * direction;
334 }
335 }
336
337 G4ThreeVector direction2 = direction/mK;
338 polarization2 = polarization2/mS;
339
340 G4ThreeVector y = direction2.cross(polarization2);
341
342 G4RotationMatrix R(polarization2,y,direction2);
343 return R;
344}
345
346//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
347
348void
349G4PhotoElectricAngularGeneratorPolarized::PhotoElectronGetMajorantSurfaceAandCParameters(G4int shellId, G4double beta, G4double *majorantSurfaceParameterA, G4double *majorantSurfaceParameterC) const
350{
351 // This member function finds for a given shell and beta value
352 // of the outgoing electron the correct Majorant Surface parameters
353 G4double aBeta,cBeta;
354 G4double bMin,bStep;
355 G4int indexMax;
356 G4int level = 0;
357 if(shellId > 0) { level = 1; }
358
359 bMin = betaArray[0];
360 bStep = betaArray[1];
361 indexMax = (G4int)betaArray[2];
362 const G4double kBias = 1e-9;
363
364 G4int k = (G4int)((beta-bMin+kBias)/bStep);
365
366 if(k < 0)
367 k = 0;
368 if(k > indexMax)
369 k = indexMax;
370
371 if(k == 0)
372 aBeta = std::max(aMajorantSurfaceParameterTable[k][level],aMajorantSurfaceParameterTable[k+1][level]);
373 else if(k==indexMax)
374 aBeta = std::max(aMajorantSurfaceParameterTable[k-1][level],aMajorantSurfaceParameterTable[k][level]);
375 else{
376 aBeta = std::max(aMajorantSurfaceParameterTable[k-1][level],aMajorantSurfaceParameterTable[k][level]);
377 aBeta = std::max(aBeta,aMajorantSurfaceParameterTable[k+1][level]);
378 }
379
380 if(k == 0)
381 cBeta = std::max(cMajorantSurfaceParameterTable[k][level],cMajorantSurfaceParameterTable[k+1][level]);
382 else if(k == indexMax)
383 cBeta = std::max(cMajorantSurfaceParameterTable[k-1][level],cMajorantSurfaceParameterTable[k][level]);
384 else{
385 cBeta = std::max(cMajorantSurfaceParameterTable[k-1][level],cMajorantSurfaceParameterTable[k][level]);
386 cBeta = std::max(cBeta,cMajorantSurfaceParameterTable[k+1][level]);
387 }
388
389 *majorantSurfaceParameterA = aBeta;
390 *majorantSurfaceParameterC = cBeta;
391}
392
393//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
394
395G4ThreeVector G4PhotoElectricAngularGeneratorPolarized::PhotoElectronComputeFinalDirection(const G4RotationMatrix& rotation, G4double theta, G4double phi) const
396{
397 //computes the photoelectron momentum unitary vector
398 G4double sint = std::sin(theta);
399 G4double px = std::cos(phi)*sint;
400 G4double py = std::sin(phi)*sint;
401 G4double pz = std::cos(theta);
402
403 G4ThreeVector samplingDirection(px,py,pz);
404
405 G4ThreeVector outgoingDirection = rotation*samplingDirection;
406 return outgoingDirection;
407}
408
409//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
410
412{
413 G4cout << "\n" << G4endl;
414 G4cout << "Polarized Photoelectric Angular Generator" << G4endl;
415 G4cout << "PhotoElectric Electron Angular Generator based on the general Gavrila photoelectron angular distribution" << G4endl;
416 G4cout << "Includes polarization effects for K and L1 atomic shells, according to Gavrilla (1959, 1961)." << G4endl;
417 G4cout << "For higher shells the L1 cross-section is used." << G4endl;
418 G4cout << "(see Physics Reference Manual) \n" << G4endl;
419}
420
421//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
422
425 const G4ThreeVector& a) const
426{
427 G4double dx = a.x();
428 G4double dy = a.y();
429 G4double dz = a.z();
430 G4double x = dx < 0.0 ? -dx : dx;
431 G4double y = dy < 0.0 ? -dy : dy;
432 G4double z = dz < 0.0 ? -dz : dz;
433 if (x < y) {
434 return x < z ? G4ThreeVector(-dy,dx,0) : G4ThreeVector(0,-dz,dy);
435 }else{
436 return y < z ? G4ThreeVector(dz,0,-dx) : G4ThreeVector(-dy,dx,0);
437 }
438}
const char * G4FindDataDir(const char *)
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
const G4double a0
CLHEP::Hep3Vector G4ThreeVector
float G4float
Definition: G4Types.hh:84
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
double z() const
Hep3Vector unit() const
double x() const
void setY(double)
double y() const
Hep3Vector cross(const Hep3Vector &) const
double dot(const Hep3Vector &) const
void setZ(double)
bool isOrthogonal(const Hep3Vector &v, double epsilon=tolerance) const
Definition: SpaceVector.cc:233
double mag() const
double howOrthogonal(const Hep3Vector &v) const
Definition: SpaceVector.cc:215
void setX(double)
const G4ThreeVector & GetMomentumDirection() const
const G4ThreeVector & GetPolarization() const
G4ThreeVector PerpendicularVector(const G4ThreeVector &a) const
G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double eKinEnergy, G4int shellId, const G4Material *mat=nullptr) override
const G4double pi