Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/examples/advanced/eRosita/physics/src/G4RDVeLowEnergyLoss.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // --------------------------------------------------------------
 30 //  GEANT 4 class implementation file
 31 //
 32 //  History: first implementation, based on object model of
 33 //  2nd December 1995, G.Cosmo
 34 // --------------------------------------------------------------
 35 //
 36 // Modifications:
 37 // 20/09/00 update fluctuations V.Ivanchenko
 38 // 22/11/00 minor fix in fluctuations V.Ivanchenko
 39 // 10/05/01  V.Ivanchenko Clean up againist Linux compilation with -Wall
 40 // 22/05/01  V.Ivanchenko Update range calculation
 41 // 23/11/01  V.Ivanchenko Move static member-functions from header to source
 42 // 22/01/03  V.Ivanchenko Cut per region
 43 // 11/02/03  V.Ivanchenko Add limits to fluctuations
 44 // 24/04/03  V.Ivanchenko Fix the problem of table size
 45 //
 46 // --------------------------------------------------------------
 47 
 48 #include "G4RDVeLowEnergyLoss.hh"
 49 #include "G4PhysicalConstants.hh"
 50 #include "G4SystemOfUnits.hh"
 51 #include "G4ProductionCutsTable.hh"
 52 
 53 G4double     G4RDVeLowEnergyLoss::ParticleMass ;
 54 G4double     G4RDVeLowEnergyLoss::taulow       ;
 55 G4double     G4RDVeLowEnergyLoss::tauhigh      ;
 56 G4double     G4RDVeLowEnergyLoss::ltaulow       ;
 57 G4double     G4RDVeLowEnergyLoss::ltauhigh      ;
 58 
 59 
 60 G4bool       G4RDVeLowEnergyLoss::rndmStepFlag   = false;
 61 G4bool       G4RDVeLowEnergyLoss::EnlossFlucFlag = true;
 62 G4double     G4RDVeLowEnergyLoss::dRoverRange    = 20*perCent;
 63 G4double     G4RDVeLowEnergyLoss::finalRange     = 200*micrometer;
 64 G4double     G4RDVeLowEnergyLoss::c1lim = dRoverRange ;
 65 G4double     G4RDVeLowEnergyLoss::c2lim = 2.*(1.-dRoverRange)*finalRange ;
 66 G4double     G4RDVeLowEnergyLoss::c3lim = -(1.-dRoverRange)*finalRange*finalRange;
 67 
 68 
 69 //
 70 
 71 G4RDVeLowEnergyLoss::G4RDVeLowEnergyLoss()
 72                    :G4VContinuousDiscreteProcess("No Name Loss Process"),
 73      lastMaterial(0),
 74      nmaxCont1(4),
 75      nmaxCont2(16)
 76 {
 77   G4Exception("G4RDVeLowEnergyLoss::G4RDVeLowEnergyLoss()", "InvalidCall",
 78               FatalException, "Default constructor is called!");
 79 }
 80 
 81 //
 82 
 83 G4RDVeLowEnergyLoss::G4RDVeLowEnergyLoss(const G4String& aName, G4ProcessType aType)
 84                   : G4VContinuousDiscreteProcess(aName, aType),
 85      lastMaterial(0),
 86      nmaxCont1(4),
 87      nmaxCont2(16)
 88 {
 89 }
 90 
 91 //
 92 
 93 G4RDVeLowEnergyLoss::~G4RDVeLowEnergyLoss()
 94 {
 95 }
 96 
 97 //
 98 
 99 G4RDVeLowEnergyLoss::G4RDVeLowEnergyLoss(G4RDVeLowEnergyLoss& right)
100                   : G4VContinuousDiscreteProcess(right),
101      lastMaterial(0),
102      nmaxCont1(4),
103      nmaxCont2(16)
104 {
105 }
106 
107 void G4RDVeLowEnergyLoss::SetRndmStep(G4bool value)
108 {
109    rndmStepFlag   = value;
110 }
111 
112 void G4RDVeLowEnergyLoss::SetEnlossFluc(G4bool value)
113 {
114    EnlossFlucFlag = value;
115 }
116 
117 void G4RDVeLowEnergyLoss::SetStepFunction (G4double c1, G4double c2)
118 {
119    dRoverRange = c1;
120    finalRange = c2;
121    c1lim=dRoverRange;
122    c2lim=2.*(1-dRoverRange)*finalRange;
123    c3lim=-(1.-dRoverRange)*finalRange*finalRange;
124 }
125 
126 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildRangeTable(G4PhysicsTable* theDEDXTable,
127                G4PhysicsTable* theRangeTable,
128                G4double lowestKineticEnergy,
129                G4double highestKineticEnergy,
130                G4int TotBin)
131 // Build range table from the energy loss table
132 {
133 
134    G4int numOfCouples = theDEDXTable->length();
135 
136    if(theRangeTable)
137    { theRangeTable->clearAndDestroy();
138      delete theRangeTable; }
139    theRangeTable = new G4PhysicsTable(numOfCouples);
140 
141    // loop for materials
142 
143    for (G4int J=0;  J<numOfCouples; J++)
144    {
145      G4PhysicsLogVector* aVector;
146      aVector = new G4PhysicsLogVector(lowestKineticEnergy,
147                               highestKineticEnergy,TotBin);
148      BuildRangeVector(theDEDXTable,lowestKineticEnergy,highestKineticEnergy,
149                       TotBin,J,aVector);
150      theRangeTable->insert(aVector);
151    }
152    return theRangeTable ;
153 }
154 
155 //
156 
157 void G4RDVeLowEnergyLoss::BuildRangeVector(G4PhysicsTable* theDEDXTable,
158                                          G4double lowestKineticEnergy,
159                                          G4double,
160                                          G4int TotBin,
161                                          G4int materialIndex,
162                                          G4PhysicsLogVector* rangeVector)
163 
164 //  create range vector for a material
165 {
166   G4bool isOut;
167   G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
168   G4double energy1 = lowestKineticEnergy;
169   G4double dedx    = physicsVector->GetValue(energy1,isOut);
170   G4double range   = 0.5*energy1/dedx;
171   rangeVector->PutValue(0,range);
172   G4int n = 100;
173   G4double del = 1.0/(G4double)n ;
174 
175   for (G4int j=1; j<TotBin; j++) {
176 
177     G4double energy2 = rangeVector->GetLowEdgeEnergy(j);
178     G4double de = (energy2 - energy1) * del ;
179     G4double dedx1 = dedx ;
180 
181     for (G4int i=1; i<n; i++) {
182       G4double energy = energy1 + i*de ;
183       G4double dedx2  = physicsVector->GetValue(energy,isOut);
184       range  += 0.5*de*(1.0/dedx1 + 1.0/dedx2);
185       dedx1   = dedx2;
186     }
187     rangeVector->PutValue(j,range);
188     dedx = dedx1 ;
189     energy1 = energy2 ;
190   }
191 }
192 
193 //
194 
195 G4double G4RDVeLowEnergyLoss::RangeIntLin(G4PhysicsVector* physicsVector,
196           G4int nbin)
197 //  num. integration, linear binning
198 {
199   G4double dtau,Value,taui,ti,lossi,ci;
200   G4bool isOut;
201   dtau = (tauhigh-taulow)/nbin;
202   Value = 0.;
203 
204   for (G4int i=0; i<=nbin; i++)
205   {
206     taui = taulow + dtau*i ;
207     ti = ParticleMass*taui;
208     lossi = physicsVector->GetValue(ti,isOut);
209     if(i==0)
210       ci=0.5;
211     else
212     {
213       if(i<nbin)
214         ci=1.;
215       else
216         ci=0.5;
217     }
218     Value += ci/lossi;
219   }
220   Value *= ParticleMass*dtau;
221   return Value;
222 }
223 
224 //
225 
226 G4double G4RDVeLowEnergyLoss::RangeIntLog(G4PhysicsVector* physicsVector,
227           G4int nbin)
228 //  num. integration, logarithmic binning
229 {
230   G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
231   G4bool isOut;
232   ltt = ltauhigh-ltaulow;
233   dltau = ltt/nbin;
234   Value = 0.;
235 
236   for (G4int i=0; i<=nbin; i++)
237   {
238     ui = ltaulow+dltau*i;
239     taui = std::exp(ui);
240     ti = ParticleMass*taui;
241     lossi = physicsVector->GetValue(ti,isOut);
242     if(i==0)
243       ci=0.5;
244     else
245     {
246       if(i<nbin)
247         ci=1.;
248       else
249         ci=0.5;
250     }
251     Value += ci*taui/lossi;
252   }
253   Value *= ParticleMass*dltau;
254   return Value;
255 }
256 
257 
258 //
259 
260 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildLabTimeTable(G4PhysicsTable* theDEDXTable,
261                  G4PhysicsTable* theLabTimeTable,
262                  G4double lowestKineticEnergy,
263                  G4double highestKineticEnergy,G4int TotBin)
264 
265 {
266 
267   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
268 
269   if(theLabTimeTable)
270   { theLabTimeTable->clearAndDestroy();
271     delete theLabTimeTable; }
272   theLabTimeTable = new G4PhysicsTable(numOfCouples);
273 
274 
275   for (G4int J=0;  J<numOfCouples; J++)
276   {
277     G4PhysicsLogVector* aVector;
278 
279     aVector = new G4PhysicsLogVector(lowestKineticEnergy,
280                             highestKineticEnergy,TotBin);
281 
282     BuildLabTimeVector(theDEDXTable,
283               lowestKineticEnergy,highestKineticEnergy,TotBin,J,aVector);
284     theLabTimeTable->insert(aVector);
285 
286 
287   }
288   return theLabTimeTable ;
289 }
290 
291 //    
292 
293 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildProperTimeTable(G4PhysicsTable* theDEDXTable,
294               G4PhysicsTable* theProperTimeTable,
295               G4double lowestKineticEnergy,
296               G4double highestKineticEnergy,G4int TotBin)
297                             
298 {
299 
300   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
301  
302   if(theProperTimeTable)
303   { theProperTimeTable->clearAndDestroy();
304     delete theProperTimeTable; }
305   theProperTimeTable = new G4PhysicsTable(numOfCouples);
306 
307 
308   for (G4int J=0;  J<numOfCouples; J++)
309   {
310     G4PhysicsLogVector* aVector;
311 
312     aVector = new G4PhysicsLogVector(lowestKineticEnergy,
313                             highestKineticEnergy,TotBin);
314 
315     BuildProperTimeVector(theDEDXTable,
316               lowestKineticEnergy,highestKineticEnergy,TotBin,J,aVector);
317     theProperTimeTable->insert(aVector);
318 
319 
320   }
321   return theProperTimeTable ;
322 }
323 
324 //    
325 
326 void G4RDVeLowEnergyLoss::BuildLabTimeVector(G4PhysicsTable* theDEDXTable,
327              G4double, // lowestKineticEnergy,
328              G4double, // highestKineticEnergy,
329                                            G4int TotBin,
330              G4int materialIndex, G4PhysicsLogVector* timeVector)
331 //  create lab time vector for a material
332 {
333 
334   G4int nbin=100;
335   G4bool isOut;
336   G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ;
337   G4double losslim,clim,taulim,timelim,
338            LowEdgeEnergy,tau,Value ;
339 
340   G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
341 
342   // low energy part first...
343   losslim = physicsVector->GetValue(tlim,isOut);
344   taulim=tlim/ParticleMass ;
345   clim=std::sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar) ;
346 
347   G4int i=-1;
348   G4double oldValue = 0. ;
349   G4double tauold ;
350   do
351   {
352     i += 1 ;
353     LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i);
354     tau = LowEdgeEnergy/ParticleMass ;
355     if ( tau <= taulim )
356     {
357       Value = clim*std::exp(ppar*std::log(tau/taulim)) ;
358     }
359     else
360     {
361       timelim=clim ;
362       ltaulow = std::log(taulim);
363       ltauhigh = std::log(tau);
364       Value = timelim+LabTimeIntLog(physicsVector,nbin);
365     }
366     timeVector->PutValue(i,Value);
367     oldValue = Value ;
368     tauold = tau ;
369   } while (tau<=taulim) ;
370   i += 1 ;
371   for (G4int j=i; j<TotBin; j++)
372   {
373     LowEdgeEnergy = timeVector->GetLowEdgeEnergy(j);
374     tau = LowEdgeEnergy/ParticleMass ;
375     ltaulow = std::log(tauold);
376     ltauhigh = std::log(tau);
377     Value = oldValue+LabTimeIntLog(physicsVector,nbin);
378     timeVector->PutValue(j,Value);
379     oldValue = Value ;
380     tauold = tau ;
381   }
382 }
383 
384 //    
385 
386 void G4RDVeLowEnergyLoss::BuildProperTimeVector(G4PhysicsTable* theDEDXTable,
387                 G4double, // lowestKineticEnergy,
388                 G4double, // highestKineticEnergy,
389                                               G4int TotBin,
390                 G4int materialIndex, G4PhysicsLogVector* timeVector)
391 //  create proper time vector for a material
392 {
393   G4int nbin=100;
394   G4bool isOut;
395   G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ;
396   G4double losslim,clim,taulim,timelim,
397            LowEdgeEnergy,tau,Value ;
398 
399   G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
400   //const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
401 
402   // low energy part first...
403   losslim = physicsVector->GetValue(tlim,isOut);
404   taulim=tlim/ParticleMass ;
405   clim=std::sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar) ;
406 
407   G4int i=-1;
408   G4double oldValue = 0. ;
409   G4double tauold ;
410   do
411   {
412     i += 1 ;
413     LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i);
414     tau = LowEdgeEnergy/ParticleMass ;
415     if ( tau <= taulim )
416     {
417       Value = clim*std::exp(ppar*std::log(tau/taulim)) ;
418     }
419     else
420     {
421       timelim=clim ;
422       ltaulow = std::log(taulim);
423       ltauhigh = std::log(tau);
424       Value = timelim+ProperTimeIntLog(physicsVector,nbin);
425     }
426     timeVector->PutValue(i,Value);
427     oldValue = Value ;
428     tauold = tau ;
429   } while (tau<=taulim) ;
430   i += 1 ;
431   for (G4int j=i; j<TotBin; j++)
432   {
433     LowEdgeEnergy = timeVector->GetLowEdgeEnergy(j);
434     tau = LowEdgeEnergy/ParticleMass ;
435     ltaulow = std::log(tauold);
436     ltauhigh = std::log(tau);
437     Value = oldValue+ProperTimeIntLog(physicsVector,nbin);
438     timeVector->PutValue(j,Value);
439     oldValue = Value ;
440     tauold = tau ;
441   }
442 }
443 
444 //    
445 
446 G4double G4RDVeLowEnergyLoss::LabTimeIntLog(G4PhysicsVector* physicsVector,
447             G4int nbin)
448 //  num. integration, logarithmic binning
449 {
450   G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
451   G4bool isOut;
452   ltt = ltauhigh-ltaulow;
453   dltau = ltt/nbin;
454   Value = 0.;
455 
456   for (G4int i=0; i<=nbin; i++)
457   {
458     ui = ltaulow+dltau*i;
459     taui = std::exp(ui);
460     ti = ParticleMass*taui;
461     lossi = physicsVector->GetValue(ti,isOut);
462     if(i==0)
463       ci=0.5;
464     else
465     {
466       if(i<nbin)
467         ci=1.;
468       else
469         ci=0.5;
470     }
471     Value += ci*taui*(ti+ParticleMass)/(std::sqrt(ti*(ti+2.*ParticleMass))*lossi);
472   }
473   Value *= ParticleMass*dltau/c_light;
474   return Value;
475 }
476 
477 //    
478 
479 G4double G4RDVeLowEnergyLoss::ProperTimeIntLog(G4PhysicsVector* physicsVector,
480                G4int nbin)
481 //  num. integration, logarithmic binning
482 {
483   G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
484   G4bool isOut;
485   ltt = ltauhigh-ltaulow;
486   dltau = ltt/nbin;
487   Value = 0.;
488 
489   for (G4int i=0; i<=nbin; i++)
490   {
491     ui = ltaulow+dltau*i;
492     taui = std::exp(ui);
493     ti = ParticleMass*taui;
494     lossi = physicsVector->GetValue(ti,isOut);
495     if(i==0)
496       ci=0.5;
497     else
498     {
499       if(i<nbin)
500         ci=1.;
501       else
502         ci=0.5;
503     }
504     Value += ci*taui*ParticleMass/(std::sqrt(ti*(ti+2.*ParticleMass))*lossi);
505   }
506   Value *= ParticleMass*dltau/c_light;
507   return Value;
508 }
509 
510 //    
511 
512 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildInverseRangeTable(G4PhysicsTable* theRangeTable,
513                 G4PhysicsTable*,
514                 G4PhysicsTable*,
515                 G4PhysicsTable*,
516                 G4PhysicsTable* theInverseRangeTable,
517                 G4double, // lowestKineticEnergy,
518                 G4double, // highestKineticEnergy
519                 G4int )   // nbins
520 // Build inverse table of the range table
521 {
522   G4bool b;
523 
524   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
525 
526     if(theInverseRangeTable)
527     { theInverseRangeTable->clearAndDestroy();
528       delete theInverseRangeTable; }
529     theInverseRangeTable = new G4PhysicsTable(numOfCouples);
530 
531   // loop for materials
532   for (G4int i=0;  i<numOfCouples; i++)
533   {
534 
535     G4PhysicsVector* pv = (*theRangeTable)[i];
536     size_t nbins   = pv->GetVectorLength();
537     G4double elow  = pv->GetLowEdgeEnergy(0);
538     G4double ehigh = pv->GetLowEdgeEnergy(nbins-1);
539     G4double rlow  = pv->GetValue(elow, b);
540     G4double rhigh = pv->GetValue(ehigh, b);
541 
542     rhigh *= std::exp(std::log(rhigh/rlow)/((G4double)(nbins-1)));
543 
544     G4PhysicsLogVector* v = new G4PhysicsLogVector(rlow, rhigh, nbins);
545 
546     v->PutValue(0,elow);
547     G4double energy1 = elow;
548     G4double range1  = rlow;
549     G4double energy2 = elow;
550     G4double range2  = rlow;
551     size_t ilow      = 0;
552     size_t ihigh;
553 
554     for (size_t j=1; j<nbins; j++) {
555 
556       G4double range = v->GetLowEdgeEnergy(j);
557 
558       for (ihigh=ilow+1; ihigh<nbins; ihigh++) {
559         energy2 = pv->GetLowEdgeEnergy(ihigh);
560         range2  = pv->GetValue(energy2, b);
561         if(range2 >= range || ihigh == nbins-1) {
562           ilow = ihigh - 1;
563           energy1 = pv->GetLowEdgeEnergy(ilow);
564           range1  = pv->GetValue(energy1, b); 
565           break;
566   }
567       }
568 
569       G4double e = std::log(energy1) + std::log(energy2/energy1)*std::log(range/range1)/std::log(range2/range1);
570 
571       v->PutValue(j,std::exp(e));
572     }
573     theInverseRangeTable->insert(v);
574 
575   }
576   return theInverseRangeTable ;
577 }
578 
579 //    
580 
581 void G4RDVeLowEnergyLoss::InvertRangeVector(G4PhysicsTable* theRangeTable,
582             G4PhysicsTable* theRangeCoeffATable,
583             G4PhysicsTable* theRangeCoeffBTable,
584             G4PhysicsTable* theRangeCoeffCTable,
585             G4double lowestKineticEnergy,
586             G4double highestKineticEnergy, G4int TotBin,
587             G4int  materialIndex, G4PhysicsLogVector* aVector)
588 //  invert range vector for a material
589 {
590   G4double LowEdgeRange,A,B,C,discr,KineticEnergy ;
591   G4double RTable = std::exp(std::log(highestKineticEnergy/lowestKineticEnergy)/TotBin) ;
592   G4double Tbin = lowestKineticEnergy/RTable ;
593   G4double rangebin = 0.0 ;
594   G4int binnumber = -1 ;
595   G4bool isOut ;
596 
597   //loop for range values
598   for( G4int i=0; i<TotBin; i++)
599   {
600     LowEdgeRange = aVector->GetLowEdgeEnergy(i) ;  //i.e. GetLowEdgeValue(i)
601     if( rangebin < LowEdgeRange )
602     {
603       do
604       {
605         binnumber += 1 ;
606         Tbin *= RTable ;
607         rangebin = (*theRangeTable)(materialIndex)->GetValue(Tbin,isOut) ;
608       }
609       while ((rangebin < LowEdgeRange) && (binnumber < TotBin )) ;
610     }
611 
612     if(binnumber == 0)
613       KineticEnergy = lowestKineticEnergy ;
614     else if(binnumber == TotBin-1)
615       KineticEnergy = highestKineticEnergy ;
616     else
617     {
618       A = (*(*theRangeCoeffATable)(materialIndex))(binnumber-1) ;
619       B = (*(*theRangeCoeffBTable)(materialIndex))(binnumber-1) ;
620       C = (*(*theRangeCoeffCTable)(materialIndex))(binnumber-1) ;
621       if(A==0.)
622          KineticEnergy = (LowEdgeRange -C )/B ;
623       else
624       {
625          discr = B*B - 4.*A*(C-LowEdgeRange);
626          discr = discr>0. ? std::sqrt(discr) : 0.;
627          KineticEnergy = 0.5*(discr-B)/A ;
628       }
629     }
630 
631     aVector->PutValue(i,KineticEnergy) ;
632   }
633 }
634 
635 //    
636 
637 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildRangeCoeffATable(G4PhysicsTable* theRangeTable,
638                G4PhysicsTable* theRangeCoeffATable,
639                G4double lowestKineticEnergy,
640                G4double highestKineticEnergy, G4int TotBin)
641 // Build tables of coefficients for the energy loss calculation
642 //  create table for coefficients "A"
643 {
644 
645   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
646 
647   if(theRangeCoeffATable)
648   { theRangeCoeffATable->clearAndDestroy();
649     delete theRangeCoeffATable; }
650   theRangeCoeffATable = new G4PhysicsTable(numOfCouples);
651 
652   G4double RTable = std::exp(std::log(highestKineticEnergy/lowestKineticEnergy)/TotBin) ;
653   G4double R2 = RTable*RTable ;
654   G4double R1 = RTable+1.;
655   G4double w = R1*(RTable-1.)*(RTable-1.);
656   G4double w1 = RTable/w , w2 = -RTable*R1/w , w3 = R2/w ;
657   G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
658   G4bool isOut;
659 
660   //  loop for materials
661   for (G4int J=0; J<numOfCouples; J++)
662   {
663     G4int binmax=TotBin ;
664     G4PhysicsLinearVector* aVector =
665                            new G4PhysicsLinearVector(0.,binmax, TotBin);
666     Ti = lowestKineticEnergy ;
667     G4PhysicsVector* rangeVector= (*theRangeTable)[J];
668 
669     for ( G4int i=0; i<TotBin; i++)
670     {
671       Ri = rangeVector->GetValue(Ti,isOut) ;
672       if ( i==0 )
673         Rim = 0. ;
674       else
675       {
676         Tim = Ti/RTable ;
677         Rim = rangeVector->GetValue(Tim,isOut);
678       }
679       if ( i==(TotBin-1))
680         Rip = Ri ;
681       else
682       {
683         Tip = Ti*RTable ;
684         Rip = rangeVector->GetValue(Tip,isOut);
685       }
686       Value = (w1*Rip + w2*Ri + w3*Rim)/(Ti*Ti) ;
687 
688       aVector->PutValue(i,Value);
689       Ti = RTable*Ti ;
690     }
691  
692     theRangeCoeffATable->insert(aVector);
693   }
694   return theRangeCoeffATable ;
695 }
696 
697 //    
698   
699 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildRangeCoeffBTable(G4PhysicsTable* theRangeTable,
700                G4PhysicsTable* theRangeCoeffBTable,
701                G4double lowestKineticEnergy,
702                G4double highestKineticEnergy, G4int TotBin)
703 // Build tables of coefficients for the energy loss calculation
704 //  create table for coefficients "B"
705 {
706 
707   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
708 
709   if(theRangeCoeffBTable)
710   { theRangeCoeffBTable->clearAndDestroy();
711     delete theRangeCoeffBTable; }
712   theRangeCoeffBTable = new G4PhysicsTable(numOfCouples);
713 
714   G4double RTable = std::exp(std::log(highestKineticEnergy/lowestKineticEnergy)/TotBin) ;
715   G4double R2 = RTable*RTable ;
716   G4double R1 = RTable+1.;
717   G4double w = R1*(RTable-1.)*(RTable-1.);
718   G4double w1 = -R1/w , w2 = R1*(R2+1.)/w , w3 = -R2*R1/w ;
719   G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
720   G4bool isOut;
721 
722   //  loop for materials
723   for (G4int J=0; J<numOfCouples; J++)
724   {
725     G4int binmax=TotBin ;
726     G4PhysicsLinearVector* aVector =
727                         new G4PhysicsLinearVector(0.,binmax, TotBin);
728     Ti = lowestKineticEnergy ;
729     G4PhysicsVector* rangeVector= (*theRangeTable)[J];
730   
731     for ( G4int i=0; i<TotBin; i++)
732     {
733       Ri = rangeVector->GetValue(Ti,isOut) ;
734       if ( i==0 )
735          Rim = 0. ;
736       else
737       {
738         Tim = Ti/RTable ;
739         Rim = rangeVector->GetValue(Tim,isOut);
740       }
741       if ( i==(TotBin-1))
742         Rip = Ri ;
743       else
744       {
745         Tip = Ti*RTable ;
746         Rip = rangeVector->GetValue(Tip,isOut);
747       }
748       Value = (w1*Rip + w2*Ri + w3*Rim)/Ti;
749 
750       aVector->PutValue(i,Value);
751       Ti = RTable*Ti ;
752     }
753     theRangeCoeffBTable->insert(aVector);
754   }
755   return theRangeCoeffBTable ;
756 }
757 
758 //    
759 
760 G4PhysicsTable* G4RDVeLowEnergyLoss::BuildRangeCoeffCTable(G4PhysicsTable* theRangeTable,
761                G4PhysicsTable* theRangeCoeffCTable,
762                G4double lowestKineticEnergy,
763                G4double highestKineticEnergy, G4int TotBin)
764 // Build tables of coefficients for the energy loss calculation
765 //  create table for coefficients "C"
766 {
767 
768   G4int numOfCouples = G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize();
769 
770   if(theRangeCoeffCTable)
771   { theRangeCoeffCTable->clearAndDestroy();
772     delete theRangeCoeffCTable; }
773   theRangeCoeffCTable = new G4PhysicsTable(numOfCouples);
774 
775   G4double RTable = std::exp(std::log(highestKineticEnergy/lowestKineticEnergy)/TotBin) ;
776   G4double R2 = RTable*RTable ;
777   G4double R1 = RTable+1.;
778   G4double w = R1*(RTable-1.)*(RTable-1.);
779   G4double w1 = 1./w , w2 = -RTable*R1/w , w3 = RTable*R2/w ;
780   G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
781   G4bool isOut;
782 
783   //  loop for materials
784   for (G4int J=0; J<numOfCouples; J++)
785   {
786     G4int binmax=TotBin ;
787     G4PhysicsLinearVector* aVector =
788                       new G4PhysicsLinearVector(0.,binmax, TotBin);
789     Ti = lowestKineticEnergy ;
790     G4PhysicsVector* rangeVector= (*theRangeTable)[J];
791   
792     for ( G4int i=0; i<TotBin; i++)
793     {
794       Ri = rangeVector->GetValue(Ti,isOut) ;
795       if ( i==0 )
796         Rim = 0. ;
797       else
798       {
799         Tim = Ti/RTable ;
800         Rim = rangeVector->GetValue(Tim,isOut);
801       }
802       if ( i==(TotBin-1))
803         Rip = Ri ;
804       else
805       {
806         Tip = Ti*RTable ;
807         Rip = rangeVector->GetValue(Tip,isOut);
808       }
809       Value = w1*Rip + w2*Ri + w3*Rim ;
810 
811       aVector->PutValue(i,Value);
812       Ti = RTable*Ti ;
813     }
814     theRangeCoeffCTable->insert(aVector);
815   }
816   return theRangeCoeffCTable ;
817 }
818 
819 //    
820 
821 G4double G4RDVeLowEnergyLoss::GetLossWithFluct(const G4DynamicParticle* aParticle,
822                                              const G4MaterialCutsCouple* couple,
823                G4double MeanLoss,
824                G4double step)
825 //  calculate actual loss from the mean loss
826 //  The model used to get the fluctuation is essentially the same as in Glandz in Geant3.
827 {
828    static const G4double minLoss = 1.*eV ;
829    static const G4double probLim = 0.01 ;
830    static const G4double sumaLim = -std::log(probLim) ;
831    static const G4double alim=10.;
832    static const G4double kappa = 10. ;
833    static const G4double factor = twopi_mc2_rcl2 ;
834   const G4Material* aMaterial = couple->GetMaterial();
835 
836   // check if the material has changed ( cache mechanism)
837 
838   if (aMaterial != lastMaterial)
839     {
840       lastMaterial = aMaterial;
841       imat         = couple->GetIndex();
842       f1Fluct      = aMaterial->GetIonisation()->GetF1fluct();
843       f2Fluct      = aMaterial->GetIonisation()->GetF2fluct();
844       e1Fluct      = aMaterial->GetIonisation()->GetEnergy1fluct();
845       e2Fluct      = aMaterial->GetIonisation()->GetEnergy2fluct();
846       e1LogFluct   = aMaterial->GetIonisation()->GetLogEnergy1fluct();
847       e2LogFluct   = aMaterial->GetIonisation()->GetLogEnergy2fluct();
848       rateFluct    = aMaterial->GetIonisation()->GetRateionexcfluct();
849       ipotFluct    = aMaterial->GetIonisation()->GetMeanExcitationEnergy();
850       ipotLogFluct = aMaterial->GetIonisation()->GetLogMeanExcEnergy();
851     }
852   G4double threshold,w1,w2,C,
853            beta2,suma,e0,loss,lossc,w;
854   G4double a1,a2,a3;
855   G4int p1,p2,p3;
856   G4int nb;
857   G4double Corrfac, na,alfa,rfac,namean,sa,alfa1,ea,sea;
858   //  G4double dp1;
859   G4double dp3;
860   G4double siga ;
861 
862   // shortcut for very very small loss
863   if(MeanLoss < minLoss) return MeanLoss ;
864 
865   // get particle data
866   G4double Tkin   = aParticle->GetKineticEnergy();
867 
868   //  G4cout << "MGP -- Fluc Tkin " << Tkin/keV << " keV "  << " MeanLoss = " << MeanLoss/keV << G4endl;
869 
870   threshold = (*((G4ProductionCutsTable::GetProductionCutsTable())
871                 ->GetEnergyCutsVector(1)))[imat];
872   G4double rmass = electron_mass_c2/ParticleMass;
873   G4double tau   = Tkin/ParticleMass, tau1 = tau+1., tau2 = tau*(tau+2.);
874   G4double Tm    = 2.*electron_mass_c2*tau2/(1.+2.*tau1*rmass+rmass*rmass);
875 
876   // G4cout << "MGP Particle mass " << ParticleMass/MeV << " Tm " << Tm << G4endl;
877 
878   if(Tm > threshold) Tm = threshold;
879   beta2 = tau2/(tau1*tau1);
880 
881   // Gaussian fluctuation ?
882   if(MeanLoss >= kappa*Tm || MeanLoss <= kappa*ipotFluct)
883   {
884     G4double electronDensity = aMaterial->GetElectronDensity() ;
885     siga = std::sqrt(Tm*(1.0-0.5*beta2)*step*
886                 factor*electronDensity/beta2) ;
887     do {
888       loss = G4RandGauss::shoot(MeanLoss,siga) ;
889     } while (loss < 0. || loss > 2.0*MeanLoss);
890     return loss ;
891   }
892 
893   w1 = Tm/ipotFluct;
894   w2 = std::log(2.*electron_mass_c2*tau2);
895 
896   C = MeanLoss*(1.-rateFluct)/(w2-ipotLogFluct-beta2);
897 
898   a1 = C*f1Fluct*(w2-e1LogFluct-beta2)/e1Fluct;
899   a2 = C*f2Fluct*(w2-e2LogFluct-beta2)/e2Fluct;
900   a3 = rateFluct*MeanLoss*(Tm-ipotFluct)/(ipotFluct*Tm*std::log(w1));
901 
902   suma = a1+a2+a3;
903 
904   loss = 0. ;
905 
906   if(suma < sumaLim)             // very small Step
907     {
908       e0 = aMaterial->GetIonisation()->GetEnergy0fluct();
909       // G4cout << "MGP e0 = " << e0/keV << G4endl;
910 
911       if(Tm == ipotFluct)
912   {
913     a3 = MeanLoss/e0;
914 
915     if(a3>alim)
916       {
917         siga=std::sqrt(a3) ;
918         p3 = std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
919       }
920     else p3 = G4Poisson(a3);
921 
922     loss = p3*e0 ;
923 
924     if(p3 > 0) loss += (1.-2.*G4UniformRand())*e0 ;
925     // G4cout << "MGP very small step " << loss/keV << G4endl;
926   }
927       else
928   {
929     //    G4cout << "MGP old Tm = " << Tm << " " << ipotFluct << " " << e0 << G4endl;
930     Tm = Tm-ipotFluct+e0 ;
931 
932     // MGP ---- workaround to avoid log argument<0, TO BE CHECKED
933     if (Tm <= 0.)
934       {
935         loss = MeanLoss;
936         p3 = 0;
937         // G4cout << "MGP correction loss = MeanLoss " << loss/keV << G4endl;
938       }
939     else
940       {
941         a3 = MeanLoss*(Tm-e0)/(Tm*e0*std::log(Tm/e0));
942 
943         // G4cout << "MGP new Tm = " << Tm << " " << ipotFluct << " " << e0 << " a3= " << a3 << G4endl;
944         
945         if(a3>alim)
946     {
947       siga=std::sqrt(a3) ;
948       p3 = std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
949     }
950         else
951     p3 = G4Poisson(a3);
952         //G4cout << "MGP p3 " << p3 << G4endl;
953 
954       }
955         
956     if(p3 > 0)
957       {
958         w = (Tm-e0)/Tm ;
959         if(p3 > nmaxCont2)
960     {
961       // G4cout << "MGP dp3 " << dp3 << " p3 " << p3 << " " << nmaxCont2 << G4endl;
962       dp3 = G4double(p3) ;
963       Corrfac = dp3/G4double(nmaxCont2) ;
964       p3 = nmaxCont2 ;
965     }
966         else
967     Corrfac = 1. ;
968         
969         for(G4int i=0; i<p3; i++) loss += 1./(1.-w*G4UniformRand()) ;
970         loss *= e0*Corrfac ; 
971         // G4cout << "MGP Corrfac = " << Corrfac << " e0 = " << e0/keV << " loss = " << loss/keV << G4endl;
972       }        
973   }
974     }
975 
976   else                              // not so small Step
977     {
978       // excitation type 1
979       if(a1>alim)
980       {
981         siga=std::sqrt(a1) ;
982         p1 = std::max(0,int(G4RandGauss::shoot(a1,siga)+0.5));
983       }
984       else
985        p1 = G4Poisson(a1);
986 
987       // excitation type 2
988       if(a2>alim)
989       {
990         siga=std::sqrt(a2) ;
991         p2 = std::max(0,int(G4RandGauss::shoot(a2,siga)+0.5));
992       }
993       else
994         p2 = G4Poisson(a2);
995 
996       loss = p1*e1Fluct+p2*e2Fluct;
997  
998       // smearing to avoid unphysical peaks
999       if(p2 > 0)
1000         loss += (1.-2.*G4UniformRand())*e2Fluct;
1001       else if (loss>0.)
1002         loss += (1.-2.*G4UniformRand())*e1Fluct;   
1003       
1004       // ionisation .......................................
1005       if(a3 > 0.)
1006   {
1007     if(a3>alim)
1008       {
1009         siga=std::sqrt(a3) ;
1010         p3 = std::max(0,int(G4RandGauss::shoot(a3,siga)+0.5));
1011       }
1012     else
1013       p3 = G4Poisson(a3);
1014     
1015     lossc = 0.;
1016     if(p3 > 0)
1017       {
1018         na = 0.; 
1019         alfa = 1.;
1020         if (p3 > nmaxCont2)
1021     {
1022       dp3        = G4double(p3);
1023       rfac       = dp3/(G4double(nmaxCont2)+dp3);
1024       namean     = G4double(p3)*rfac;
1025       sa         = G4double(nmaxCont1)*rfac;
1026       na         = G4RandGauss::shoot(namean,sa);
1027       if (na > 0.)
1028         {
1029           alfa   = w1*G4double(nmaxCont2+p3)/(w1*G4double(nmaxCont2)+G4double(p3));
1030           alfa1  = alfa*std::log(alfa)/(alfa-1.);
1031           ea     = na*ipotFluct*alfa1;
1032           sea    = ipotFluct*std::sqrt(na*(alfa-alfa1*alfa1));
1033           lossc += G4RandGauss::shoot(ea,sea);
1034         }
1035     }
1036         
1037         nb = G4int(G4double(p3)-na);
1038         if (nb > 0)
1039     {
1040       w2 = alfa*ipotFluct;
1041       w  = (Tm-w2)/Tm;      
1042       for (G4int k=0; k<nb; k++) lossc += w2/(1.-w*G4UniformRand());
1043     }
1044       }        
1045     
1046     loss += lossc;  
1047   }
1048     } 
1049   
1050   return loss ;
1051 }
1052 
1053 //    
1054    
1055