ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4OpRayleigh.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4OpRayleigh.cc
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 //
30 // Optical Photon Rayleigh Scattering Class Implementation
32 //
33 // File: G4OpRayleigh.cc
34 // Description: Discrete Process -- Rayleigh scattering of optical
35 // photons
36 // Version: 1.0
37 // Created: 1996-05-31
38 // Author: Juliet Armstrong
39 // Updated: 2014-10-10 - This version calculates the Rayleigh scattering
40 // length for more materials than just Water (although the Water
41 // default is kept). To do this the user would need to specify the
42 // ISOTHERMAL_COMPRESSIBILITY as a material property and
43 // optionally an RS_SCALE_LENGTH (useful for testing). Code comes
44 // from Philip Graham (Queen Mary University of London).
45 // 2010-06-11 - Fix Bug 207; Thanks to Xin Qian
46 // (Kellogg Radiation Lab of Caltech)
47 // 2005-07-28 - add G4ProcessType to constructor
48 // 2001-10-18 by Peter Gumplinger
49 // eliminate unused variable warning on Linux (gcc-2.95.2)
50 // 2001-09-18 by mma
51 // >numOfMaterials=G4Material::GetNumberOfMaterials() in BuildPhy
52 // 2001-01-30 by Peter Gumplinger
53 // > allow for positiv and negative CosTheta and force the
54 // > new momentum direction to be in the same plane as the
55 // > new and old polarization vectors
56 // 2001-01-29 by Peter Gumplinger
57 // > fix calculation of SinTheta (from CosTheta)
58 // 1997-04-09 by Peter Gumplinger
59 // > new physics/tracking scheme
60 // mail: gum@triumf.ca
61 //
63 
64 #include "G4OpRayleigh.hh"
65 
66 #include "G4ios.hh"
67 #include "G4PhysicalConstants.hh"
68 #include "G4SystemOfUnits.hh"
69 #include "G4OpProcessSubType.hh"
70 
71 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
72 
74  : G4VDiscreteProcess(processName, type)
75 {
77 
78  thePhysicsTable = nullptr;
79 
80  if (verboseLevel > 0) {
81  G4cout << GetProcessName() << " is created " << G4endl;
82  }
83 }
84 
85 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
86 
88 {
89  if (thePhysicsTable) {
91  delete thePhysicsTable;
92  }
93 }
94 
95 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
96 
98 G4OpRayleigh::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
99 {
100  aParticleChange.Initialize(aTrack);
101 
102  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
103 
104  if (verboseLevel >0 ) {
105  G4cout << "Scattering Photon!" << G4endl;
106  G4cout << "Old Momentum Direction: "
107  << aParticle->GetMomentumDirection() << G4endl;
108  G4cout << "Old Polarization: "
109  << aParticle->GetPolarization() << G4endl;
110  }
111 
112  G4double cosTheta;
113  G4ThreeVector OldMomentumDirection, NewMomentumDirection;
114  G4ThreeVector OldPolarization, NewPolarization;
115 
116  G4double rand, constant;
117  G4double CosTheta, SinTheta, SinPhi, CosPhi, unit_x, unit_y, unit_z;
118 
119  do {
120  // Try to simulate the scattered photon momentum direction
121  // w.r.t. the initial photon momentum direction
122 
123  CosTheta = G4UniformRand();
124  SinTheta = std::sqrt(1.-CosTheta*CosTheta);
125  // consider for the angle 90-180 degrees
126  if (G4UniformRand() < 0.5) CosTheta = -CosTheta;
127 
128  // simulate the phi angle
129  rand = twopi*G4UniformRand();
130  SinPhi = std::sin(rand);
131  CosPhi = std::cos(rand);
132 
133  // start constructing the new momentum direction
134  unit_x = SinTheta * CosPhi;
135  unit_y = SinTheta * SinPhi;
136  unit_z = CosTheta;
137  NewMomentumDirection.set (unit_x,unit_y,unit_z);
138 
139  // Rotate the new momentum direction into global reference system
140  OldMomentumDirection = aParticle->GetMomentumDirection();
141  OldMomentumDirection = OldMomentumDirection.unit();
142  NewMomentumDirection.rotateUz(OldMomentumDirection);
143  NewMomentumDirection = NewMomentumDirection.unit();
144 
145  // calculate the new polarization direction
146  // The new polarization needs to be in the same plane as the new
147  // momentum direction and the old polarization direction
148  OldPolarization = aParticle->GetPolarization();
149  constant = -NewMomentumDirection.dot(OldPolarization);
150 
151  NewPolarization = OldPolarization + constant*NewMomentumDirection;
152  NewPolarization = NewPolarization.unit();
153 
154  // There is a corner case, where the Newmomentum direction
155  // is the same as oldpolariztion direction:
156  // random generate the azimuthal angle w.r.t. Newmomentum direction
157  if (NewPolarization.mag() == 0.) {
158  rand = G4UniformRand()*twopi;
159  NewPolarization.set(std::cos(rand),std::sin(rand),0.);
160  NewPolarization.rotateUz(NewMomentumDirection);
161  } else {
162  // There are two directions which are perpendicular
163  // to the new momentum direction
164  if (G4UniformRand() < 0.5) NewPolarization = -NewPolarization;
165  }
166 
167  // simulate according to the distribution cos^2(theta)
168  cosTheta = NewPolarization.dot(OldPolarization);
169  // Loop checking, 13-Aug-2015, Peter Gumplinger
170  } while (std::pow(cosTheta,2) < G4UniformRand());
171 
172  aParticleChange.ProposePolarization(NewPolarization);
173  aParticleChange.ProposeMomentumDirection(NewMomentumDirection);
174 
175  if (verboseLevel > 0) {
176  G4cout << "New Polarization: "
177  << NewPolarization << G4endl;
178  G4cout << "Polarization Change: "
179  << *(aParticleChange.GetPolarization()) << G4endl;
180  G4cout << "New Momentum Direction: "
181  << NewMomentumDirection << G4endl;
182  G4cout << "Momentum Change: "
183  << *(aParticleChange.GetMomentumDirection()) << G4endl;
184  }
185 
186  return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
187 }
188 
189 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
190 
192 {
193  if (thePhysicsTable) {
195  delete thePhysicsTable;
196  thePhysicsTable = nullptr;
197  }
198 
199  const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
200  const G4int numOfMaterials = G4Material::GetNumberOfMaterials();
201 
202  thePhysicsTable = new G4PhysicsTable(numOfMaterials);
203 
204  for (G4int iMaterial = 0; iMaterial < numOfMaterials; ++iMaterial)
205  {
206  G4Material* material = (*theMaterialTable)[iMaterial];
207  G4MaterialPropertiesTable* materialProperties =
208  material->GetMaterialPropertiesTable();
209  G4PhysicsOrderedFreeVector* rayleigh = nullptr;
210  if (materialProperties) {
211  rayleigh = materialProperties->GetProperty(kRAYLEIGH);
212  if (rayleigh == nullptr) rayleigh = CalculateRayleighMeanFreePaths(material);
213  }
214  thePhysicsTable->insertAt(iMaterial, rayleigh);
215  }
216 }
217 
218 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
219 
221  G4double ,
223 {
225  const G4double photonMomentum = particle->GetTotalMomentum();
226  const G4Material* material = aTrack.GetMaterial();
227 
228  G4PhysicsOrderedFreeVector* rayleigh =
229  static_cast<G4PhysicsOrderedFreeVector*>
230  ((*thePhysicsTable)(material->GetIndex()));
231 
232  G4double rsLength = DBL_MAX;
233  if (rayleigh) rsLength = rayleigh->Value(photonMomentum);
234  return rsLength;
235 }
236 
237 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
240 {
241  G4MaterialPropertiesTable* materialProperties =
242  material->GetMaterialPropertiesTable();
243 
244  // Retrieve the beta_T or isothermal compressibility value. For backwards
245  // compatibility use a constant if the material is "Water". If the material
246  // doesn't have an ISOTHERMAL_COMPRESSIBILITY constant then return
247  G4double betat;
248  if (material->GetName() == "Water") {
249  betat = 7.658e-23*m3/MeV;
250  }
251  else if (materialProperties->ConstPropertyExists("ISOTHERMAL_COMPRESSIBILITY")) {
252  betat = materialProperties->GetConstProperty(kISOTHERMAL_COMPRESSIBILITY);
253  }
254  else {
255  return nullptr;
256  }
257 
258  // If the material doesn't have a RINDEX property vector then return
259  G4MaterialPropertyVector* rIndex = materialProperties->GetProperty(kRINDEX);
260  if (rIndex == nullptr) return nullptr;
261 
262  // Retrieve the optional scale factor, (this just scales the scattering length
263  G4double scaleFactor = 1.0;
264  if (materialProperties->ConstPropertyExists("RS_SCALE_FACTOR")) {
265  scaleFactor = materialProperties->GetConstProperty(kRS_SCALE_FACTOR);
266  }
267 
268  // Retrieve the material temperature. For backwards compatibility use a
269  // constant if the material is "Water"
270  G4double temperature;
271  if (material->GetName() == "Water") {
272  temperature = 283.15*kelvin; // Temperature of water is 10 degrees celsius
273  }
274  else {
275  temperature = material->GetTemperature();
276  }
277 
278  G4PhysicsOrderedFreeVector* rayleighMeanFreePaths =
280  // This calculates the meanFreePath via the Einstein-Smoluchowski formula
281  const G4double c1 = scaleFactor * betat * temperature * k_Boltzmann /
282  ( 6.0 * pi );
283 
284  for (size_t uRIndex = 0; uRIndex < rIndex->GetVectorLength(); ++uRIndex)
285  {
286  const G4double energy = rIndex->Energy(uRIndex);
287  const G4double rIndexSquared = (*rIndex)[uRIndex] * (*rIndex)[uRIndex];
288  const G4double xlambda = h_Planck * c_light / energy;
289  const G4double c2 = std::pow(twopi/xlambda,4);
290  const G4double c3 =
291  std::pow(((rIndexSquared-1.0)*(rIndexSquared+2.0 )/3.0),2);
292 
293  const G4double meanFreePath = 1.0 / ( c1 * c2 * c3 );
294 
295  if( verboseLevel > 0) {
296  G4cout << energy << "MeV\t" << meanFreePath << "mm" << G4endl;
297  }
298 
299  rayleighMeanFreePaths->InsertValues(energy, meanFreePath);
300  }
301 
302  return rayleighMeanFreePaths;
303 }