Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4OpRayleigh.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 // $Id$
28 //
29 //
31 // Optical Photon Rayleigh Scattering Class Implementation
33 //
34 // File: G4OpRayleigh.cc
35 // Description: Discrete Process -- Rayleigh scattering of optical
36 // photons
37 // Version: 1.0
38 // Created: 1996-05-31
39 // Author: Juliet Armstrong
40 // Updated: 2010-06-11 - Fix Bug 207; Thanks to Xin Qian
41 // (Kellogg Radiation Lab of Caltech)
42 // 2005-07-28 - add G4ProcessType to constructor
43 // 2001-10-18 by Peter Gumplinger
44 // eliminate unused variable warning on Linux (gcc-2.95.2)
45 // 2001-09-18 by mma
46 // >numOfMaterials=G4Material::GetNumberOfMaterials() in BuildPhy
47 // 2001-01-30 by Peter Gumplinger
48 // > allow for positiv and negative CosTheta and force the
49 // > new momentum direction to be in the same plane as the
50 // > new and old polarization vectors
51 // 2001-01-29 by Peter Gumplinger
52 // > fix calculation of SinTheta (from CosTheta)
53 // 1997-04-09 by Peter Gumplinger
54 // > new physics/tracking scheme
55 // mail: gum@triumf.ca
56 //
58 
59 #include "G4OpRayleigh.hh"
60 
61 #include "G4ios.hh"
62 #include "G4PhysicalConstants.hh"
63 #include "G4SystemOfUnits.hh"
64 #include "G4OpProcessSubType.hh"
65 
67 // Class Implementation
69 
71  // Operators
73 
74 // G4OpRayleigh::operator=(const G4OpRayleigh &right)
75 // {
76 // }
77 
79  // Constructors
81 
83  : G4VDiscreteProcess(processName, type)
84 {
86 
87  thePhysicsTable = 0;
88 
89  DefaultWater = false;
90 
91  if (verboseLevel>0) {
92  G4cout << GetProcessName() << " is created " << G4endl;
93  }
94 
95  BuildThePhysicsTable();
96 }
97 
98 // G4OpRayleigh::G4OpRayleigh(const G4OpRayleigh &right)
99 // {
100 // }
101 
103  // Destructors
105 
107 {
108  if (thePhysicsTable!= 0) {
110  delete thePhysicsTable;
111  }
112 }
113 
115  // Methods
117 
118 // PostStepDoIt
119 // -------------
120 //
122 G4OpRayleigh::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
123 {
124  aParticleChange.Initialize(aTrack);
125 
126  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
127 
128  if (verboseLevel>0) {
129  G4cout << "Scattering Photon!" << G4endl;
130  G4cout << "Old Momentum Direction: "
131  << aParticle->GetMomentumDirection() << G4endl;
132  G4cout << "Old Polarization: "
133  << aParticle->GetPolarization() << G4endl;
134  }
135 
136  G4double cosTheta;
137  G4ThreeVector OldMomentumDirection, NewMomentumDirection;
138  G4ThreeVector OldPolarization, NewPolarization;
139 
140  do {
141  // Try to simulate the scattered photon momentum direction
142  // w.r.t. the initial photon momentum direction
143 
144  G4double CosTheta = G4UniformRand();
145  G4double SinTheta = std::sqrt(1.-CosTheta*CosTheta);
146  // consider for the angle 90-180 degrees
147  if (G4UniformRand() < 0.5) CosTheta = -CosTheta;
148 
149  // simulate the phi angle
150  G4double rand = twopi*G4UniformRand();
151  G4double SinPhi = std::sin(rand);
152  G4double CosPhi = std::cos(rand);
153 
154  // start constructing the new momentum direction
155  G4double unit_x = SinTheta * CosPhi;
156  G4double unit_y = SinTheta * SinPhi;
157  G4double unit_z = CosTheta;
158  NewMomentumDirection.set (unit_x,unit_y,unit_z);
159 
160  // Rotate the new momentum direction into global reference system
161  OldMomentumDirection = aParticle->GetMomentumDirection();
162  OldMomentumDirection = OldMomentumDirection.unit();
163  NewMomentumDirection.rotateUz(OldMomentumDirection);
164  NewMomentumDirection = NewMomentumDirection.unit();
165 
166  // calculate the new polarization direction
167  // The new polarization needs to be in the same plane as the new
168  // momentum direction and the old polarization direction
169  OldPolarization = aParticle->GetPolarization();
170  G4double constant = -1./NewMomentumDirection.dot(OldPolarization);
171 
172  NewPolarization = NewMomentumDirection + constant*OldPolarization;
173  NewPolarization = NewPolarization.unit();
174 
175  // There is a corner case, where the Newmomentum direction
176  // is the same as oldpolariztion direction:
177  // random generate the azimuthal angle w.r.t. Newmomentum direction
178  if (NewPolarization.mag() == 0.) {
179  rand = G4UniformRand()*twopi;
180  NewPolarization.set(std::cos(rand),std::sin(rand),0.);
181  NewPolarization.rotateUz(NewMomentumDirection);
182  } else {
183  // There are two directions which are perpendicular
184  // to the new momentum direction
185  if (G4UniformRand() < 0.5) NewPolarization = -NewPolarization;
186  }
187 
188  // simulate according to the distribution cos^2(theta)
189  cosTheta = NewPolarization.dot(OldPolarization);
190  } while (std::pow(cosTheta,2) < G4UniformRand());
191 
192  aParticleChange.ProposePolarization(NewPolarization);
193  aParticleChange.ProposeMomentumDirection(NewMomentumDirection);
194 
195  if (verboseLevel>0) {
196  G4cout << "New Polarization: "
197  << NewPolarization << G4endl;
198  G4cout << "Polarization Change: "
199  << *(aParticleChange.GetPolarization()) << G4endl;
200  G4cout << "New Momentum Direction: "
201  << NewMomentumDirection << G4endl;
202  G4cout << "Momentum Change: "
203  << *(aParticleChange.GetMomentumDirection()) << G4endl;
204  }
205 
206  return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
207 }
208 
209 // BuildThePhysicsTable for the Rayleigh Scattering process
210 // --------------------------------------------------------
211 //
212 void G4OpRayleigh::BuildThePhysicsTable()
213 {
214 // Builds a table of scattering lengths for each material
215 
216  if (thePhysicsTable) return;
217 
218  const G4MaterialTable* theMaterialTable=
220  G4int numOfMaterials = G4Material::GetNumberOfMaterials();
221 
222  // create a new physics table
223 
224  thePhysicsTable = new G4PhysicsTable(numOfMaterials);
225 
226  // loop for materials
227 
228  for (G4int i=0 ; i < numOfMaterials; i++)
229  {
230  G4PhysicsOrderedFreeVector* ScatteringLengths = NULL;
231 
232  G4MaterialPropertiesTable *aMaterialPropertiesTable =
233  (*theMaterialTable)[i]->GetMaterialPropertiesTable();
234 
235  if(aMaterialPropertiesTable){
236 
237  G4MaterialPropertyVector* AttenuationLengthVector =
238  aMaterialPropertiesTable->GetProperty("RAYLEIGH");
239 
240  if(!AttenuationLengthVector){
241 
242  if ((*theMaterialTable)[i]->GetName() == "Water")
243  {
244  // Call utility routine to Generate
245  // Rayleigh Scattering Lengths
246 
247  DefaultWater = true;
248 
249  ScatteringLengths =
250  RayleighAttenuationLengthGenerator(aMaterialPropertiesTable);
251  }
252  }
253  }
254 
255  thePhysicsTable->insertAt(i,ScatteringLengths);
256  }
257 }
258 
259 // GetMeanFreePath()
260 // -----------------
261 //
263  G4double ,
265 {
266  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
267  const G4Material* aMaterial = aTrack.GetMaterial();
268 
269  G4double thePhotonEnergy = aParticle->GetTotalEnergy();
270 
271  G4double AttenuationLength = DBL_MAX;
272 
273  if (aMaterial->GetName() == "Water" && DefaultWater){
274 
275  G4bool isOutRange;
276 
277  AttenuationLength =
278  (*thePhysicsTable)(aMaterial->GetIndex())->
279  GetValue(thePhotonEnergy, isOutRange);
280  }
281  else {
282 
283  G4MaterialPropertiesTable* aMaterialPropertyTable =
284  aMaterial->GetMaterialPropertiesTable();
285 
286  if(aMaterialPropertyTable){
287  G4MaterialPropertyVector* AttenuationLengthVector =
288  aMaterialPropertyTable->GetProperty("RAYLEIGH");
289  if(AttenuationLengthVector){
290  AttenuationLength = AttenuationLengthVector ->
291  Value(thePhotonEnergy);
292  }
293  else{
294 // G4cout << "No Rayleigh scattering length specified" << G4endl;
295  }
296  }
297  else{
298 // G4cout << "No Rayleigh scattering length specified" << G4endl;
299  }
300  }
301 
302  return AttenuationLength;
303 }
304 
305 // RayleighAttenuationLengthGenerator()
306 // ------------------------------------
307 // Private method to compute Rayleigh Scattering Lengths (for water)
308 //
310 G4OpRayleigh::RayleighAttenuationLengthGenerator(G4MaterialPropertiesTable *aMPT)
311 {
312  // Physical Constants
313 
314  // isothermal compressibility of water
315  G4double betat = 7.658e-23*m3/MeV;
316 
317  // K Boltzman
318  G4double kboltz = 8.61739e-11*MeV/kelvin;
319 
320  // Temperature of water is 10 degrees celsius
321  // conversion to kelvin:
322  // TCelsius = TKelvin - 273.15 => 273.15 + 10 = 283.15
323  G4double temp = 283.15*kelvin;
324 
325  // Retrieve vectors for refraction index
326  // and photon energy from the material properties table
327 
328  G4MaterialPropertyVector* Rindex = aMPT->GetProperty("RINDEX");
329 
330  G4double refsq;
331  G4double e;
332  G4double xlambda;
333  G4double c1, c2, c3, c4;
334  G4double Dist;
335  G4double refraction_index;
336 
337  G4PhysicsOrderedFreeVector *RayleighScatteringLengths =
339 
340  if (Rindex ) {
341 
342  for (size_t i = 0; i < Rindex->GetVectorLength(); i++) {
343 
344  e = Rindex->Energy(i);
345 
346  refraction_index = (*Rindex)[i];
347 
348  refsq = refraction_index*refraction_index;
349  xlambda = h_Planck*c_light/e;
350 
351  if (verboseLevel>0) {
352  G4cout << Rindex->Energy(i) << " MeV\t";
353  G4cout << xlambda << " mm\t";
354  }
355 
356  c1 = 1 / (6.0 * pi);
357  c2 = std::pow((2.0 * pi / xlambda), 4);
358  c3 = std::pow( ( (refsq - 1.0) * (refsq + 2.0) / 3.0 ), 2);
359  c4 = betat * temp * kboltz;
360 
361  Dist = 1.0 / (c1*c2*c3*c4);
362 
363  if (verboseLevel>0) {
364  G4cout << Dist << " mm" << G4endl;
365  }
366  RayleighScatteringLengths->
367  InsertValues(Rindex->Energy(i), Dist);
368  }
369 
370  }
371 
372  return RayleighScatteringLengths;
373 }