Geant4  10.02
G4GoudsmitSaundersonMscModel.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 // $Id: G4GoudsmitSaundersonMscModel.cc 93663 2015-10-28 09:50:49Z gcosmo $
27 //
28 // ----------------------------------------------------------------------------
29 //
30 // GEANT4 Class implementation file
31 //
32 // File name: G4GoudsmitSaundersonMscModel
33 //
34 // Author: Mihaly Novak / (Omrane Kadri)
35 //
36 // Creation date: 20.02.2009
37 //
38 // Modifications:
39 // 04.03.2009 V.Ivanchenko cleanup and format according to Geant4 EM style
40 // 12.05.2010 O.Kadri: adding Qn1 and Qn12 as private doubles
41 // 18.05.2015 M. Novak provide PRELIMINARY verison of the revised class
42 // This class has been revised and updated, new methods added.
43 // A new version of Kawrakow-Bielajew Goudsmit-Saunderson MSC model
44 // based on the screened Rutherford DCS for elastic scattering of
45 // electrons/positrons has been introduced[1,2]. The corresponding MSC
46 // angular distributions over a 2D parameter grid have been recomputed
47 // and the CDFs are now stored in a variable transformed (smooth) form[2,3]
48 // together with the corresponding rational interpolation parameters.
49 // These angular distributions are handled by the new
50 // G4GoudsmitSaundersonTable class that is responsible to sample if
51 // it was no, single, few or multiple scattering case and delivers the
52 // angular deflection (i.e. cos(theta) and sin(theta)).
53 // Two screening options are provided:
54 // - if fIsUsePWATotalXsecData=TRUE i.e. SetOptionPWAScreening(TRUE)
55 // was called before initialisation: screening parameter value A is
56 // determined such that the first transport coefficient G1(A)
57 // computed according to the screened Rutherford DCS for elastic
58 // scattering will reproduce the one computed from the PWA elastic
59 // and first transport mean free paths[4].
60 // - if fIsUsePWATotalXsecData=FALSE i.e. default value or
61 // SetOptionPWAScreening(FALSE) was called before initialisation:
62 // screening parameter value A is computed according to Moliere's
63 // formula (by using material dependent parameters \chi_cc2 and b_c
64 // precomputed for each material used at initialization in
65 // G4GoudsmitSaundersonTable) [3]
66 // Elastic and first trasport mean free paths are used consistently.
67 // The new version is self-consistent, several times faster, more
68 // robust and accurate compared to the earlier version.
69 // Spin effects as well as a more accurate energy loss correction and
70 // computations of Lewis moments will be implemented later on.
71 // 02.09.2015 M. Novak: first version of new step limit is provided.
72 // fUseSafetyPlus corresponds to Urban fUseSafety (default)
73 // fUseDistanceToBoundary corresponds to Urban fUseDistanceToBoundary
74 // fUseSafety corresponds to EGSnrc error-free stepping algorithm
75 // Range factor can be significantly higher at each case than in Urban.
76 //
77 // Class description:
78 // Kawrakow-Bielajew Goudsmit-Saunderson MSC model based on the screened
79 // Rutherford DCS for elastic scattering of electrons/positrons. Step limitation
80 // algorithm as well as true to geomerty and geometry to true step length
81 // computations are adopted from Urban model[5].
82 //
83 // References:
84 // [1] A.F.Bielajew, NIMB 111 (1996) 195-208
85 // [2] I.Kawrakow, A.F.Bielajew, NIMB 134(1998) 325-336
86 // [3] I.Kawrakow, E.Mainegra-Hing, D.W.O.Rogers, F.Tessier,B.R.B.Walters, NRCC
87 // Report PIRS-701 (2013)
88 // [4] F.Salvat, A.Jablonski, C.J. Powell, CPC 165(2005) 157-190
89 // [5] L.Urban, Preprint CERN-OPEN-2006-077 (2006)
90 //
91 // -----------------------------------------------------------------------------
92 
93 
95 
97 #include "G4PWATotalXsecTable.hh"
98 
99 #include "G4PhysicalConstants.hh"
100 #include "G4SystemOfUnits.hh"
101 
102 #include "G4ParticleChangeForMSC.hh"
103 #include "G4DynamicParticle.hh"
104 #include "G4Electron.hh"
105 #include "G4Positron.hh"
106 
107 #include "G4LossTableManager.hh"
108 #include "G4Track.hh"
109 #include "G4PhysicsTable.hh"
110 #include "Randomize.hh"
111 #include "G4Log.hh"
112 #include "G4Exp.hh"
113 #include "G4Pow.hh"
114 #include <fstream>
115 
118 
119 // set accurate energy loss and dispalcement sampling to be always on now
121 // set the usual optimization to be always active now
123 
126  : G4VMscModel(nam),lowKEnergy(0.1*keV),highKEnergy(1.*GeV) {
127  charge = 0;
129 
130  lambdalimit = 1.*mm ;
131  fr = 0.02 ;
132  rangeinit = 0.;
133  geombig = 1.e50*mm;
134  geomlimit = geombig;
135  tlimit = 1.e+10*mm;
136  presafety = 0.*mm;
137 
138  particle = 0;
140  firstStep = true;
141 
142  tlimitminfix2 = 1.*nm;
143  par1=par2=par3= 0.0;
144  tausmall = 1.e-16;
145  mass = electron_mass_c2;
146  taulim = 1.e-6;
147 
148  currentCouple = 0;
149  fParticleChange = 0;
150 
151  // by default Moliere screeing parameter will be used but it can be set to the
152  // PWA screening before calling the Initialise method
153  fIsUsePWATotalXsecData = false;
154 
155  //*****************
156  fLambda0 = 0.0; // elastic mean free path
157  fLambda1 = 0.0; // first transport mean free path
158  fScrA = 0.0; // screening parameter
159  fG1 = 0.0; // first transport coef.
160  //******************
161  fTheTrueStepLenght = 0.;
163  fTheZPathLenght = 0.;
164  fTheDisplacementVector.set(0.,0.,0.);
165  fTheNewDirection.set(0.,0.,1.);
166 
167  fIsEverythingWasDone = false;
168  fIsMultipleSacettring = false;
169  fIsSingleScattering = false;
170  fIsEndedUpOnBoundary = false;
171  fIsNoScatteringInMSC = false;
172  fIsNoDisplace = false;
173 
174  fZeff = 1.;
175 //+++++++++++++
176 
177  rndmEngineMod = G4Random::getTheEngine();
178 }
179 
182  if(IsMaster()){
183  if(fgGSTable){
184  delete fgGSTable;
185  fgGSTable = 0;
186  }
187  if(fgPWAXsecTable){
188  delete fgPWAXsecTable;
189  fgPWAXsecTable = 0;
190  }
191  }
192 }
193 
194 
197  const G4DataVector&){
198  //skindepth=skin*stepmin;
199  SetParticle(p);
201 
202  //
203  // -create static GoudsmitSaundersonTable and PWATotalXsecTable is necessary
204  //
205  if(IsMaster()) {
206 
207  // Could delete as well if they are exist but then the same data are reloaded
208  // in case of e+ for example.
209 /* if(fgGSTable) {
210  delete fgGSTable;
211  fgGSTable = 0;
212  }
213  if(fgPWAXsecTable) {
214  delete fgPWAXsecTable;
215  fgPWAXsecTable = 0;
216  }
217 */
218  if(!fgGSTable)
220 
221  // G4GSTable will be initialised (data are loaded) only if they are not there yet.
223 
225  if(!fgPWAXsecTable)
227 
228  // Makes sure that all (and only those) atomic PWA data are in memory that
229  // are in the current MaterilaTable.
231  }
232  }
233 }
234 
235 
237 // gives back the first transport mean free path in internal G4 units
238 G4double
240  G4double kineticEnergy) {
241  // kinetic energy is assumed to be in Geant4 internal energy unit which is MeV
242  G4double efEnergy = kineticEnergy;
243  if(efEnergy<lowKEnergy) efEnergy=lowKEnergy;
244  if(efEnergy>highKEnergy)efEnergy=highKEnergy;
245 
247  const G4Material* mat = currentCouple->GetMaterial();
248 
249  fLambda0 = 0.0; // elastic mean free path
250  fLambda1 = 0.0; // first transport mean free path
251  fScrA = 0.0; // screening parameter
252  fG1 = 0.0; // first transport coef.
253 
255  // use PWA total xsec data to determine screening and lambda0 lambda1
256  const G4ElementVector* theElementVector = mat->GetElementVector();
257  const G4double* theAtomNumDensityVector = mat->GetVecNbOfAtomsPerVolume();
258  G4int nelm = mat->GetNumberOfElements();
259 
260  int elowindx = fgPWAXsecTable->GetPWATotalXsecForZet( G4lrint((*theElementVector)[0]->GetZ()) )
261  ->GetPWATotalXsecEnergyBinIndex(efEnergy);
262  for(G4int i=0;i<nelm;i++){
263  int zet = G4lrint((*theElementVector)[i]->GetZ());
264  // total elastic scattering cross section in Geant4 internal length2 units
265  int indx = (G4int)(1.5 + charge*1.5); // specify that want to get the total elastic scattering xsection
266  double elxsec = (fgPWAXsecTable->GetPWATotalXsecForZet(zet))->GetInterpXsec(efEnergy,elowindx,indx);
267  // first transport cross section in Geant4 internal length2 units
268  indx = (G4int)(2.5 + charge*1.5); // specify that want to get the first tarnsport xsection
269  double t1xsec = (fgPWAXsecTable->GetPWATotalXsecForZet(zet))->GetInterpXsec(efEnergy,elowindx,indx);
270  fLambda0 += (theAtomNumDensityVector[i]*elxsec);
271  fLambda1 += (theAtomNumDensityVector[i]*t1xsec);
272  }
273  if(fLambda0>0.0) { fLambda0 =1./fLambda0; }
274  if(fLambda1>0.0) { fLambda1 =1./fLambda1; }
275 
276  // determine screening parameter such that it gives back PWA G1
277  fG1=0.0;
278  if(fLambda1>0.0) { fG1 = fLambda0/fLambda1; }
279 
281  } else {
282  // Get SCREENING FROM MOLIER
283  // total mometum square in Geant4 internal energy2 units which is MeV2
284 
285  // below 1 keV it can give bananas so prevet (1 keV)
286  if(efEnergy<0.001) efEnergy = 0.001;
287 
288  G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
289  G4double beta2 = pt2/(pt2+electron_mass_c2*electron_mass_c2);
290  G4int matindx = mat->GetIndex();
291  G4double bc = fgGSTable->GetMoliereBc(matindx);
292  fScrA = fgGSTable->GetMoliereXc2(matindx)/(4.0*pt2*bc);
293  // total elastic mean free path in Geant4 internal lenght units
294  fLambda0 = beta2/bc/(1.+fScrA);
295  fG1 = 2.0*fScrA*((1.0+fScrA)*G4Log(1.0/fScrA+1.0)-1.0);
297  }
298 
299  return fLambda1;
300 }
301 
303 G4double
305  G4double kineticEnergy) {
306  // kinetic energy is assumed to be in Geant4 internal energy unit which is MeV
307  G4double efEnergy = kineticEnergy;
308  if(efEnergy<lowKEnergy) efEnergy=lowKEnergy;
309  if(efEnergy>highKEnergy)efEnergy=highKEnergy;
310 
312  const G4Material* mat = currentCouple->GetMaterial();
313 
314  G4double lambda0 = 0.0; // elastc mean free path
315  G4double lambda1 = 0.0; // first transport mean free path
316  G4double scrA = 0.0; // screening parametr
317  G4double g1 = 0.0; // first transport mean free path
318 
320  // use PWA total xsec data to determine screening and lambda0 lambda1
321  const G4ElementVector* theElementVector = mat->GetElementVector();
322  const G4double* theAtomNumDensityVector = mat->GetVecNbOfAtomsPerVolume();
323  G4int nelm = mat->GetNumberOfElements();
324 
325  int elowindx = fgPWAXsecTable->GetPWATotalXsecForZet( G4lrint((*theElementVector)[0]->GetZ()) )
326  ->GetPWATotalXsecEnergyBinIndex(efEnergy);
327  for(G4int i=0;i<nelm;i++){
328  int zet = G4lrint((*theElementVector)[i]->GetZ());
329  // total elastic scattering cross section in Geant4 internal length2 units
330 // int indx = (G4int)(1.5 + charge*1.5); // specify that want to get the total elastic scattering xsection
331 // double elxsec = (fgPWAXsecTable->GetPWATotalXsecForZet(zet))->GetInterpXsec(efEnergy,elowindx,indx);
332  // first transport cross section in Geant4 internal length2 units
333  int indx = (G4int)(2.5 + charge*1.5); // specify that want to get the first tarnsport xsection
334  double t1xsec = (fgPWAXsecTable->GetPWATotalXsecForZet(zet))->GetInterpXsec(efEnergy,elowindx,indx);
335 // fLambda0 += (theAtomNumDensityVector[i]*elxsec);
336  lambda1 += (theAtomNumDensityVector[i]*t1xsec);
337  }
338 // if(fLambda0>0.0) { fLambda0 =1./fLambda0; }
339  if(lambda1>0.0) { lambda1 =1./lambda1; }
340 
341  } else {
342  // Get SCREENING FROM MOLIER
343  // total mometum square in Geant4 internal energy2 units which is MeV2
344 
345  // below 1 keV it can give bananas so prevet (1 keV)
346  if(efEnergy<0.001) efEnergy = 0.001;
347 
348  G4double pt2 = efEnergy*(efEnergy+2.0*electron_mass_c2);
349  G4double beta2 = pt2/(pt2+electron_mass_c2*electron_mass_c2);
350  G4int matindx = mat->GetIndex();
351  G4double bc = fgGSTable->GetMoliereBc(matindx);
352  scrA = fgGSTable->GetMoliereXc2(matindx)/(4.0*pt2*bc);
353  // total elastic mean free path in Geant4 internal lenght units
354  lambda0 = beta2/bc/(1.+scrA);
355  g1 = 2.0*scrA*((1.0+scrA)*G4Log(1.0/scrA+1.0)-1.0);
356  lambda1 = lambda0/g1;
357  }
358 
359  return lambda1;
360 }
361 
364 {
366  firstStep = true;
367 }
368 
369 
372  const G4Track& track,
373  G4double& currentMinimalStep){
374  // some constant
375  const G4double almostZero = 1.e-8;
376  const G4double almostOne = 1.-almostZero;
377  const G4double mlogAlmostZero = -1.*G4Log(almostZero);
378  const G4double onemExpmOne = 1.-G4Exp(-1.0);
379 
380  G4double skindepth = 0.;
381 
382  const G4DynamicParticle* dp = track.GetDynamicParticle();
383 
384  G4StepPoint* sp = track.GetStep()->GetPreStepPoint();
385  G4StepStatus stepStatus = sp->GetStepStatus();
391 
392 
393 
394  // *** Elastic and first transport mfp, fScrA and fG1 are also set in this !!!
396 
397  //
398  // Set initial values:
399  // : lengths are initialised to currentMinimalStep which is the true, minimum
400  // step length from all other physics
401  fTheTrueStepLenght = currentMinimalStep;
402  fTheTransportDistance = currentMinimalStep;
403  fTheZPathLenght = currentMinimalStep; // will need to be converted
404  fTheDisplacementVector.set(0.,0.,0.);
405  fTheNewDirection.set(0.,0.,1.);
406 
407  // Can everything be done in the step limit phase ?
408  fIsEverythingWasDone = false;
409  // Multiple scattering needs to be sample ?
410  fIsMultipleSacettring = false;
411  // Single scattering needs to be sample ?
412  fIsSingleScattering = false;
413  // Was zero deflection in multiple scattering sampling ?
414  fIsNoScatteringInMSC = false;
415  // Do not care about displacement in MSC sampling
416  // ( used only in the case of fgIsOptimizationOn = true)
417  fIsNoDisplace = false;
418 
419  // get pre-step point safety
420  presafety = sp->GetSafety();
421 
424  G4double distance = currentRange;
425  distance *= (1.20-fZeff*(1.62e-2-9.22e-5*fZeff));
426 
427  // In G4VMscModel there is a member G4MscStepLimitType steppingAlgoritm;
429  // Possible optimization : if the range is samller than the safety -> the
430  // particle will never leave this volume -> dispalcement and angular
431  // deflection as the effects of multiple elastic scattering can be skipped
432  // Only true->geometrical->true pathlength conversion is done based on mean
433  // values. In order to be able to do this, only the maximum geometrical step
434  // length will be checked.
435  // Important : this optimization can cause problems if one does scoring
436  // in a bigger volume since MSC won't be done deep inside the volume when
437  // range < safety so don't use optimized-mode in such case.
438  if( fgIsOptimizationOn && (distance < presafety) ) {
439  // Do path length conversion using the means and do NOT sample dispalcement.
440  // :: according to optimized-mode:
441  // restrict the true step length such that the corresponding
442  // transport length is not longer than the first transport mean free path:
443  // -this is important for the g->t conversion (i.e. fTheZPathLenght ->
444  // fTheTrueStepLenght) that will be invoked later based on the mean
445  // values. However, it leads to fTheTrueStepLenght >> lambda1 and
446  // the MSC model as condensed simulation model is valid about
447  // fTheTrueStepLenght ~ lambda1 that corresponds to <cos(theta)> ~ 1 rad
448  // in one sub-step if we divide the true step length into two parts when
449  // sampling the angular distribution.
452  // Indicate that we need to do MSC after transportation and no dispalcement.
453  fIsMultipleSacettring = true;
454  fIsNoDisplace = true;
455  } else {
456 
457 
460  } else {
463  }
464 
465  // Set limit from range factor even in non-optimized mode.
466  // Important: At lower energies the energy loss process continuous limit
467  // will converge to range.
468  // In this case, we will limit the step to 'facrange x range' as long
469  // as the range is higher than safety i.e. the particle can leave the
470  // current volume. One can completely eliminate this limit by setting
471  // 'facrange = 1.' .
472  if(currentRange > presafety)
474 
475  // Compute skin-depth; fLambda0(elastic-mfp) was already set in
476  // GetTransportMeanFreePath(...)
477  skindepth = skin*fLambda0;
478 
479  // Limit the true step -length to the first transport mean free path that
480  // is the limit of the MSC model. Note: if the true step lenght is about
481  // half transport mean free path i.e. t = 0.5 x lambda_1 the corresponding
482  // mean angular deflection <cos(\theta)> = exp(-t/lambda_1) -> \theta ~
483  // 0.919 radian (52.6 degree) that is the aplicability limit of any
484  // condensed history techniques. The result will be more and more
485  // questionable when condensed history techniques are applied for even
486  // longer true step lengts.
487 // if( (currentKinEnergy > 0.3) || !fgIsOptimizationOn)
489 
490  // Check if we are within skin depth to/from boundary or making a step
491  // that is shorter than skindepth distance => try single scattering::
492  // - if stepStatus is fGeomBoundary -> pre-step point is on boundary
493  // - in case of initStep pre-step point status is fUndefined:
494  // at the moment I always call the navigator CheckNextStep even from
495  // the WORLD that will set presafety; if presafety = 0 then we are on
496  // the boundary at initStep
497  // - if the currentMinimalStep is already shorter than skindepth we do
498  // single scattering. NOTICE: it has only efficieny reasons because
499  // the angular sampling is fine for any short steps but much faster to
500  // try single scattering in case of short steps.
501  if( (stepStatus == fGeomBoundary) || (presafety < skindepth) || (fTheTrueStepLenght < skindepth)){
502  //Try single scattering:
503  // - sample distance to next single scattering interaction
504  // - compare to current minimum length
505  // * if ss-length is the shorter:
506  // - set the step length to the ss-length
507  // - indicate that single scattering needs to be done
508  // * else : nothing to do
509  G4double sslimit = -1.*fLambda0*G4Log(G4UniformRand());
510  // compare to current minimum step length
511  if(sslimit < fTheTrueStepLenght) {
512  fTheTrueStepLenght = sslimit;
513  fIsSingleScattering = true;
514  // zPathLength = tPathLength
515  // single scattering needs to be done
516  } //else {
517  //- tPathLength = tPathLength
518  //- zPathLength = tPathLength
519  //-> nothing to do
520  //}
521 
522  // short step -> true step length equal to geometrical path length
524  //set taht everything is done in step-limit phase
525  fIsEverythingWasDone = true;
526  } else {
527  // Compare the true step length to presafty to see if we can do safe MSC step
528  // - if yes, then performe MSC here
529  // - if no, postpone MSC sampling after transportation
531  // => we can do safe MSC step because for sure we don't reach boundary
532  // do multiple scattering: MSC will give the corresponding transport
533  // length i.e. fTheZPathLenght (and new direction, displacement)
534  fIsMultipleSacettring = true;
535  //set taht everything was done in step-limit phase
536  fIsEverythingWasDone = true;
537  } else {
538  // => we cannot be sure at this point what will be the true step length
539  // because transportation can hit boundary. The two step limit version
540  // will be different but both case MSC will need to be done:
541  // before(fUseSafety) OR after(fUseDistanceToBoundary) transportation.
542  fIsMultipleSacettring = true;
543  // Important that fIsEverythingWasDone remains false here;
544 
545  // two versions will be different here
546  if(geomlimit > presafety) {
547  // => It can happen only if fUseDistanceToBoundary stepping is used
548  // - limit geomlimit to a geometrical value, that corresponds
549  // to the maximum true step length i.e. to lambda1
550  // - convert the limited geomlimit to true length
551  // - take minimum of this and the current minimal true step length
552 
553  // if geom limit is not huge(real distance to boundary) then shorten it by almost skindepth
554  // => we try to end up within the skindepth to the boundary and not on the boundary.
555  if( geomlimit < geombig )
556  geomlimit -= 0.999*skindepth;
557 
558  // Set a maximum geometrical limit: a straight line distance that
559  // corresponds to the maximal true step length i.e. lambda1 of
560  // the MSC model (it is set based on the mean value).
561  geomlimit = std::min(geomlimit, fLambda1*onemExpmOne);
562  // convert to true-one
565  } else {
566  // => It can happen only if geomlimit is the safety i.e. fUseSafety
567  // steppingAlgorithm.
568  // - if we are here, then presafety is for sure shorther than lambda1 so
569  // we don't need to restrict
570  // -limit the true step-length to presafety: for sure we can
571  // perform MSC before transportation.
572  fTheTrueStepLenght = presafety; // geomlimit = presafty
573  fIsEverythingWasDone = true;
574  }
575  }
576  }
577  }
578  } else {
579 
580  // This is the default stepping algorithm: the fastest but the least
581  // accurate that corresponds to fUseSafety in Urban model. Note, that GS
582  // model can handle any short steps so we do not need the minimum limits
583  if( stepStatus != fGeomBoundary ) {
585  }
586 
587  // Far from boundary-> in optimized mode do not sample dispalcement.
589 // fTheTrueStepLenght = std::min(fTheTrueStepLenght, fLambda1*mlogAlmostZero);
590 // fTheZPathLenght = fLambda1*(1.-G4Exp(-fTheTrueStepLenght/fLambda1));
591  fIsNoDisplace = true;
592  } else {
593  // Urban like
594  if(firstStep || (stepStatus == fGeomBoundary)) {
596  fr = facrange;
598  if(fLambda1 > lambdalimit) {
599  fr *= (0.75+0.25*fLambda1/lambdalimit);
600  }
601  }
602 
603  //step limit
605 
606  // first step randomization
607  if(firstStep || stepStatus == fGeomBoundary) {
609  } else {
611  }
612 
613  // Do not let the true step length to be longer than the one that has a
614  // corresponding geometrical length almost one first transport mean free
615  // path. It is important for the g->t conversion.
617  }
618 
619  // indicate that MSC needs to be done (always after transportation)
620  fIsMultipleSacettring = true;
621  }
622 
623  // unset first-step
624  firstStep =false;
625 
626  // performe single scattering, multiple scattering if this later can be done safely here
629  // sample single scattering
630  G4double cost,sint,cosPhi,sinPhi;
631  SingleScattering(cost, sint);
633  sinPhi = std::sin(phi);
634  cosPhi = std::cos(phi);
635  fTheNewDirection.set(sint*cosPhi,sint*sinPhi,cost);
636  } else if(fIsMultipleSacettring){
637  // sample multiple scattering
638  SampleMSC(); // fTheZPathLenght, fTheDisplacementVector and fTheNewDirection will be set
639  } // and if single scattering but it was longer => nothing to do
640  } //else { do nothing here but after transportation
641 
642  return ConvertTrueToGeom(fTheTrueStepLenght,currentMinimalStep);
643 }
644 
645 
648 {
649  //
650  // convert true ->geom
651  // It is called from the step limitation ComputeTruePathLengthLimit if
652  // !fIsEverythingWasDone but protect:
653  //
654  par1 = -1. ;
655  par2 = par3 = 0. ;
656 
657  // if fIsEverythingWasDone = TRUE => fTheZPathLenght is already set
658  // so return with the already known value
659  // Otherwise:
660  if(!fIsEverythingWasDone) {
661  // this correction needed to run MSC with eIoni and eBrem inactivated
662  // and makes no harm for a normal run
664 
665  // do the true -> geom transformation
667 
668  // z = t for very small true-path-length
670 
672 
673  if (tau <= tausmall) {
675  } else if (fTheTrueStepLenght < currentRange*dtrl) {
676  if(tau < taulim) fTheZPathLenght = fTheTrueStepLenght*(1.-0.5*tau) ;
677  else fTheZPathLenght = fLambda1*(1.-G4Exp(-tau));
679  par1 = 1./currentRange ; // alpha =1/range_init for Ekin<mass
680  par2 = 1./(par1*fLambda1) ; // 1/(alphaxlambda01)
681  par3 = 1.+par2 ; // 1+1/
683  fTheZPathLenght = 1./(par1*par3) * (1.-std::pow(1.-par1*fTheTrueStepLenght,par3));
684  } else {
685  fTheZPathLenght = 1./(par1*par3);
686  }
687 
688  } else {
692 
693  par1 = (fLambda1-lambda1)/(fLambda1*fTheTrueStepLenght); // alpha
694  par2 = 1./(par1*fLambda1);
695  par3 = 1.+par2 ;
696  G4Pow *g4pow = G4Pow::GetInstance();
697  fTheZPathLenght = 1./(par1*par3) * (1.-g4pow->powA(1.-par1*fTheTrueStepLenght,par3));
698  }
699 
701  }
702 
703  return fTheZPathLenght;
704 }
705 
708 {
709  // init
710  fIsEndedUpOnBoundary = false;
711 
712  // step defined other than transportation
713  if(geomStepLength == fTheZPathLenght) {
714  return fTheTrueStepLenght;
715  }
716 
717  // else ::
718  // - set the flag that transportation was the winer so DoNothin in DOIT !!
719  // - convert geom -> true by using the mean value
720  fIsEndedUpOnBoundary = true; // OR LAST STEP
721 
722  fTheZPathLenght = geomStepLength;
723 
724  // t = z for very small step
725  if(geomStepLength < tlimitminfix2) {
726  fTheTrueStepLenght = geomStepLength;
727  // recalculation
728  } else {
729  G4double tlength = geomStepLength;
730  if(geomStepLength > fLambda1*tausmall ) {
731  if(par1 < 0.) {
732  tlength = -fLambda1*G4Log(1.-geomStepLength/fLambda1) ;
733  } else {
734  if(par1*par3*geomStepLength < 1.) {
735  G4Pow *g4pow = G4Pow::GetInstance();
736  tlength = (1.-g4pow->powA( 1.-par1*par3*geomStepLength,1./par3))/par1;
737  } else {
738  tlength = currentRange;
739  }
740  }
741  if(tlength < geomStepLength) { tlength = geomStepLength; }
742  else if(tlength > fTheTrueStepLenght) { tlength = geomStepLength; }
743  }
744  fTheTrueStepLenght = tlength;
745  }
746  return fTheTrueStepLenght;
747 }
748 
752  G4double)
753 {
754 
755 
757  // transportation was the winer => do nothing
758  fTheDisplacementVector.set(0.,0.,0.);
759  return fTheDisplacementVector;
760  } else if(fIsEverythingWasDone) {
761  // everything was done in the step limit => rotate and return
762  // but do it only something happend in the MSC
763  if(!fIsNoScatteringInMSC) {
764  fTheNewDirection.rotateUz(oldDirection);
765  fTheDisplacementVector.rotateUz(oldDirection);
767  }
768  return fTheDisplacementVector;
769  }
770 
771  //else {
772  // MSC needs to be done here: cause we went further than safety but did not hit boundary
773  SampleMSC();
774  if(!fIsNoScatteringInMSC) {
775  fTheNewDirection.rotateUz(oldDirection);
776  fTheDisplacementVector.rotateUz(oldDirection);
778  }
779  return fTheDisplacementVector;
780 }
781 
782 
784  G4double rand1 = G4UniformRand();
785  // sampling 1-cos(theta)
786  G4double dum0 = 2.0*fScrA*rand1/(1.0 - rand1 + fScrA);
787  // add protections
788  if(dum0 < 0.0) dum0 = 0.0;
789  else if(dum0 > 2.0 ) dum0 = 2.0;
790  // compute cos(theta) and sin(theta)
791  cost = 1.0 - dum0;
792  sint = std::sqrt(dum0*(2.0 - dum0));
793 }
794 
795 
796 
799  fIsNoScatteringInMSC = false;
800  // kinetic energy is assumed to be in Geant4 internal energy unit which is MeV
801  G4double kineticEnergy = currentKinEnergy;
802 
804  // Energy loss correction: 2 version
805  G4double eloss = 0.0;
807  eloss = kineticEnergy -
809  } else {
810  eloss = fTheTrueStepLenght*GetDEDX(particle,kineticEnergy,currentCouple);
811  }
812 
813 
814  G4double tau = 0.;// = kineticEnergy/electron_mass_c2; // where kinEnergy is the mean kinetic energy
815  G4double tau2 = 0.;// = tau*tau;
816  G4double eps0 = 0.;// = eloss/kineticEnergy0; // energy loss fraction to the begin step energy
817  G4double epsm = 0.;// = eloss/kineticEnergy; // energy loss fraction to the mean step energy
818 
819 
820  // - init.
821  G4double efEnergy = kineticEnergy;
822  G4double efStep = fTheTrueStepLenght;
823 
824  if(fgIsUseAccurate) { // - use accurate energy loss correction
825  G4double kineticEnergy0 = kineticEnergy;
826  kineticEnergy -= 0.5*eloss; // mean energy along the full step
827 
828  // other parameters for energy loss corrections
829  tau = kineticEnergy/electron_mass_c2; // where kinEnergy is the mean kinetic energy
830  tau2 = tau*tau;
831  eps0 = eloss/kineticEnergy0; // energy loss fraction to the begin step energy
832  epsm = eloss/kineticEnergy; // energy loss fraction to the mean step energy
833 // efEnergy = kineticEnergy0 * (1.0 - epsm*(6.0+10.0*tau+5.0*tau2)/(24.0*tau2+72.0*tau+48.0));
834  efEnergy = kineticEnergy0 * ( 1.0 - 0.5*eps0 - eps0*eps0/(12.0*(2.0-eps0))* ( (5.*tau2 +10.*tau +6.)/( (tau+1.)*(tau+2.) ) ) );
835 
836  // the real efStep will be s*(1-efStep)
837  // G4double efStep = 0.166666*epsilon*epsilonp*(tau2*tau2+4.0*tau2*tau+7.0*tau2+6.0*tau+4.0)/((tau2+3.0*tau+2)2);
838 
839 // efStep = 0.166666*eps0*epsm*(4.0+tau*(6.0+tau*(7.0+tau*(4.0+tau))));
840 // efStep /= ((tau2+3.0*tau+2)*(tau2+3.0*tau+2));
841 // efStep = fTheTrueStepLenght*(1.0-efStep);
842  efStep = (1.-eps0*eps0/(3.*(2.-eps0))* (tau2*tau2 + 4.*tau2*tau + 7.*tau2 +6.*tau +4.)/( ((tau+1.)*(tau+2.))*((tau+1.)*(tau+2.)) ) );
843  efStep *=fTheTrueStepLenght;
844  } else { // - take only mean energy
845  kineticEnergy -= 0.5*eloss; // mean energy along the full step
846  efEnergy = kineticEnergy;
847  efStep = fTheTrueStepLenght;
848  }
850 
851 
853  // Compute elastic mfp, first transport mfp, screening parameter, and G1
855 
856  G4double lambdan=0.;
857 
858  if(fLambda0>0.0) { lambdan=efStep/fLambda0; }
859  if(lambdan<=1.0e-12) {
862  fIsNoScatteringInMSC = true;
863  return;
864  }
865 
866  G4double Qn1 = lambdan *fG1;//2.* lambdan *scrA*((1.+scrA)*log(1.+1./scrA)-1.);
867 
869  // Sample scattering angles
870  // new direction, relative to the orriginal one is in {us,vs,ws}
871  G4double cosTheta1 =1.0,sinTheta1 =0.0, cosTheta2 =1.0, sinTheta2 =0.0;
872  G4double cosPhi1=1.0,sinPhi1=0.0, cosPhi2 =1.0, sinPhi2 =0.0;
873  G4double us=0.0,vs=0.0,ws=1.0,x_coord=0.0,y_coord=0.0,z_coord=1.0;
874  G4double u2=0.0,v2=0.0;
875 
876  // if we are above the upper grid limit with lambdaxG1=true-length/first-trans-mfp
877  // => izotropic distribution: lambG1_max =7.992
878  if(0.5*Qn1 > 7.99){
879  cosTheta1 = 1.-2.*G4UniformRand();
880  sinTheta1 = std::sqrt((1.-cosTheta1)*(1.+cosTheta1));
882  sinPhi1 = std::sin(phi1);
883  cosPhi1 = std::cos(phi1);
884  us = sinTheta1*cosPhi1;
885  vs = sinTheta1*sinPhi1;
886  ws = cosTheta1;
887  } else {
888  // sample 2 scattering cost1, sint1, cost2 and sint2 for half path
889  fgGSTable->Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta1, sinTheta1);
890  fgGSTable->Sampling(0.5*lambdan, 0.5*Qn1, fScrA, cosTheta2, sinTheta2);
891  if(cosTheta1 + cosTheta2 == 2.) { // no scattering happened
894  fIsNoScatteringInMSC = true;
895  return;
896  }
897 
898  // sample 2 azimuthal angles
900  sinPhi1 = std::sin(phi1);
901  cosPhi1 = std::cos(phi1);
903  sinPhi2 = std::sin(phi2);
904  cosPhi2 = std::cos(phi2);
905 
906  // compute final direction realtive to z-dir
907  u2 = sinTheta2*cosPhi2;
908  v2 = sinTheta2*sinPhi2;
909  G4double u2p = cosTheta1*u2 + sinTheta1*cosTheta2;
910  us = u2p*cosPhi1 - v2*sinPhi1;
911  vs = u2p*sinPhi1 + v2*cosPhi1;
912  ws = cosTheta1*cosTheta2 - sinTheta1*u2;
913  }
914 
916  fTheNewDirection.set(us,vs,ws);
917 
918  // set the fTheZPathLenght if we don't sample displacement and
919  // we should do everything at the step-limit-phase before we return
922 
923  // in optimized-mode if the current-safety > current-range we do not use dispalcement
924  if(fIsNoDisplace)
925  return;
926 
928  // Compute final position
929  if(fgIsUseAccurate) {
930  // correction parameters
931 
932  G4double par =1.;
933  if(Qn1<1.0) par = 1.;
934  else if (Qn1<7.8) par = -0.031376*Qn1+1.01356;
935  else par = 0.76;
936 
937  //
938  // Compute elastic mfp, first transport mfp, screening parameter, and G1
939  // for the initial energy
941 
942  // Moments with energy loss correction
943  // --first the uncorrected (for energy loss) values of gamma, eta, a1=a2=0.5*(1-eta), delta
944  // gamma = G_2/G_1 based on G2 computed from A by using the Wentzel DCS form of G2
945  G4double loga = G4Log(1.0+1.0/fScrA);
946  G4double gamma = 6.0*fScrA*(1.0 + fScrA)*(loga*(1.0 + 2.0*fScrA) - 2.0)/fG1;
947  // sample eta from p(eta)=2*eta i.e. P(eta) = eta_square ;-> P(eta) = rand --> eta = sqrt(rand)
948  G4double rand1 = G4UniformRand();
949  G4double eta = std::sqrt(rand1);
950  G4double eta1 = 0.5*(1 - eta); // used more than once
951  // 0.5 +sqrt(6)/6 = 0.9082483;
952  // 1/(4*sqrt(6)) = 0.1020621;
953  // (4-sqrt(6)/(24*sqrt(6))) = 0.026374715
954  // delta = 0.9082483-(0.1020621-0.0263747*gamma)*Qn1 without energy loss cor.
955  Qn1=fTheTrueStepLenght/fLambda0*fG1; // without energy loss
956  G4double delta = 0.9082483-(0.1020621-0.0263747*gamma)*Qn1;
957 
958  // compute alpha1 and alpha2 for energy loss correction
959  G4double temp1 = 2.0 + tau;
960  G4double temp = (2.0+tau*temp1)/((tau+1.0)*temp1);
961  //Take logarithmic dependence
962  temp = temp - (tau+1.0)/((tau+2.0)*(loga*(1.0+fScrA)-1.0));
963  temp = temp * epsm;
964  temp1 = 1.0 - temp;
965  delta = delta + 0.40824829*(eps0*(tau+1.0)/((tau+2.0)*
966  (loga*(1.0+fScrA)-1.0)*(loga*(1.0+2.0*fScrA)-2.0)) - 0.25*temp*temp);
967  G4double b = eta*delta;
968  G4double c = eta*(1.0-delta);
969 
970  //Calculate transport direction cosines:
971  // ut,vt,wt is the final position divided by the true step length
972  G4double w1v2 = cosTheta1*v2;
973  G4double ut = b*sinTheta1*cosPhi1 + c*(cosPhi1*u2 - sinPhi1*w1v2) + eta1*us*temp1;
974  G4double vt = b*sinTheta1*sinPhi1 + c*(sinPhi1*u2 + cosPhi1*w1v2) + eta1*vs*temp1;
975  G4double wt = eta1*(1+temp) + b*cosTheta1 + c*cosTheta2 + eta1*ws*temp1;
976 
977  // long step correction
978  ut *=par;
979  vt *=par;
980  wt *=par;
981 
982  // final position relative to the pre-step point in the scattering frame
983  // ut = x_f/s so needs to multiply by s
984  x_coord = ut*fTheTrueStepLenght;
985  y_coord = vt*fTheTrueStepLenght;
986  z_coord = wt*fTheTrueStepLenght;
987 
989  // We sample in the step limit so set fTheZPathLenght = transportDistance
990  // and lateral displacement (x_coord,y_coord,z_coord-transportDistance)
991  //Calculate transport distance
992  G4double transportDistance = std::sqrt(x_coord*x_coord+y_coord*y_coord+z_coord*z_coord);
993  // protection
994  if(transportDistance>fTheTrueStepLenght)
995  transportDistance = fTheTrueStepLenght;
996  fTheZPathLenght = transportDistance;
997  }
998  // else:: we sample in the DoIt so
999  // the fTheZPathLenght was already set and was taken as transport along zet
1000  fTheDisplacementVector.set(x_coord,y_coord,z_coord-fTheZPathLenght);
1001  } else {
1002  // compute zz = <z>/tPathLength
1003  // s -> true-path-length
1004  // z -> geom-path-length:: when PRESTA is used z =(def.) <z>
1005  // r -> lateral displacement = s/2 sin(theta) => x_f = r cos(phi); y_f = r sin(phi)
1006  G4double zz = 0.0;
1008  // We sample in the step limit so set fTheZPathLenght = transportDistance
1009  // and lateral displacement (x_coord,y_coord,z_coord-transportDistance)
1010  if(Qn1<0.1) { // use 3-order Taylor approximation of (1-exp(-x))/x around x=0
1011  zz = 1.0 - Qn1*(0.5 - Qn1*(0.166666667 - 0.041666667*Qn1)); // 1/6 =0.166..7 ; 1/24=0.041..
1012  } else {
1013  zz = (1.-G4Exp(-Qn1))/Qn1;
1014  }
1015  } else {
1016  // we sample in the DoIt so
1017  // the fTheZPathLenght was already set and was taken as transport along zet
1019  }
1020 
1021  G4double rr = (1.-zz*zz)/(1.-ws*ws); // s^2 >= <z>^2+r^2 :: where r^2 = s^2/4 sin^2(theta)
1022  if(rr >= 0.25) rr = 0.25; // (1-<z>^2/s^2)/sin^2(theta) >= r^2/(s^2 sin^2(theta)) = 1/4 must hold
1023  G4double rperp = fTheTrueStepLenght*std::sqrt(rr); // this is r/sint
1024  x_coord = rperp*us;
1025  y_coord = rperp*vs;
1026  z_coord = zz*fTheTrueStepLenght;
1027 
1029  G4double transportDistance = std::sqrt(x_coord*x_coord + y_coord*y_coord + z_coord*z_coord);
1030  fTheZPathLenght = transportDistance;
1031  }
1032 
1033  fTheDisplacementVector.set(x_coord,y_coord,z_coord- fTheZPathLenght);
1034  }
1035 }
static G4Pow * GetInstance()
Definition: G4Pow.cc:55
G4GoudsmitSaundersonMscModel(const G4String &nam="GoudsmitSaunderson")
virtual G4double ComputeTrueStepLength(G4double geomStepLength)
G4double powA(G4double A, G4double y) const
Definition: G4Pow.hh:259
static G4LossTableManager * Instance()
G4double GetTotNbOfElectPerVolume() const
Definition: G4Material.hh:212
std::vector< G4Element * > G4ElementVector
G4double GetKineticEnergy() const
CLHEP::Hep3Vector G4ThreeVector
G4double dtrl
Definition: G4VMscModel.hh:181
Definition: G4Pow.hh:56
G4double GetTransportMeanFreePathOnly(const G4ParticleDefinition *, G4double)
const G4DynamicParticle * GetDynamicParticle() const
G4double facrange
Definition: G4VMscModel.hh:177
size_t GetIndex() const
Definition: G4Material.hh:262
static G4PWATotalXsecTable * fgPWAXsecTable
G4StepStatus GetStepStatus() const
G4double ConvertTrueToGeom(G4double &tLength, G4double &gLength)
Definition: G4VMscModel.hh:247
G4double skin
Definition: G4VMscModel.hh:180
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
const G4ParticleDefinition * particle
G4bool IsMaster() const
Definition: G4VEmModel.hh:718
G4ParticleDefinition * GetDefinition() const
const G4Step * GetStep() const
G4double ComputeSafety(const G4ThreeVector &position, G4double limit=DBL_MAX)
Definition: G4VMscModel.hh:239
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:190
int G4int
Definition: G4Types.hh:78
G4StepStatus
Definition: G4StepStatus.hh:49
G4int GetPWATotalXsecEnergyBinIndex(G4double energy) const
const G4PWATotalXsecZ * GetPWATotalXsecForZet(G4int Z) const
G4StepPoint * GetPreStepPoint() const
G4double GetEnergy(const G4ParticleDefinition *part, G4double range, const G4MaterialCutsCouple *couple)
Definition: G4VMscModel.hh:315
virtual G4double ComputeTruePathLengthLimit(const G4Track &track, G4double &currentMinimalStep)
const G4double * GetVecNbOfAtomsPerVolume() const
Definition: G4Material.hh:206
#define G4UniformRand()
Definition: Randomize.hh:97
void SingleScattering(G4double &cost, G4double &sint)
const G4ThreeVector & GetPosition() const
G4double GetRange(const G4ParticleDefinition *part, G4double kineticEnergy, const G4MaterialCutsCouple *couple)
Definition: G4VMscModel.hh:295
G4ParticleChangeForMSC * GetParticleChangeForMSC(const G4ParticleDefinition *p=0)
Definition: G4VMscModel.cc:90
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
bool G4bool
Definition: G4Types.hh:79
static const double nm
Definition: G4SIunits.hh:111
static const double twopi
Definition: G4SIunits.hh:75
static const double GeV
Definition: G4SIunits.hh:214
void Sampling(G4double, G4double, G4double, G4double &, G4double &)
static G4GoudsmitSaundersonTable * fgGSTable
G4double ComputeGeomLimit(const G4Track &, G4double &presafety, G4double limit)
Definition: G4VMscModel.hh:257
G4double G4Log(G4double x)
Definition: G4Log.hh:230
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:183
G4double GetTotNbOfAtomsPerVolume() const
Definition: G4Material.hh:209
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
G4double GetMoliereXc2(G4int matindx)
int G4lrint(double ad)
Definition: templates.hh:163
T max(const T t1, const T t2)
brief Return the largest of the two arguments
G4double facsafety
Definition: G4VMscModel.hh:179
void SetParticle(const G4ParticleDefinition *p)
G4double GetDEDX(const G4ParticleDefinition *part, G4double kineticEnergy, const G4MaterialCutsCouple *couple)
Definition: G4VMscModel.hh:280
void SetCurrentCouple(const G4MaterialCutsCouple *)
Definition: G4VEmModel.hh:445
G4double GetMoliereBc(G4int matindx)
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
G4double GetSafety() const
G4MscStepLimitType steppingAlgorithm
Definition: G4VMscModel.hh:187
size_t GetNumberOfElements() const
Definition: G4Material.hh:186
static const double keV
Definition: G4SIunits.hh:213
G4double GetTransportMeanFreePath(const G4ParticleDefinition *, G4double)
virtual G4ThreeVector & SampleScattering(const G4ThreeVector &, G4double safety)
double G4double
Definition: G4Types.hh:76
static const double mm
Definition: G4SIunits.hh:114
const G4MaterialCutsCouple * currentCouple
const G4Material * GetMaterial() const
virtual G4double ComputeGeomPathLength(G4double truePathLength)