Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4hRDEnergyLoss.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 // -----------------------------------------------------------
30 // GEANT 4 class implementation file
31 //
32 // History: based on object model of
33 // 2nd December 1995, G.Cosmo
34 // ---------- G4hEnergyLoss physics process -----------
35 // by Laszlo Urban, 30 May 1997
36 //
37 // **************************************************************
38 // It is the first implementation of the NEW UNIFIED ENERGY LOSS PROCESS.
39 // It calculates the energy loss of charged hadrons.
40 // **************************************************************
41 //
42 // 7/10/98 bug fixes + some cleanup , L.Urban
43 // 22/10/98 cleanup , L.Urban
44 // 07/12/98 works for ions as well+ bug corrected, L.Urban
45 // 02/02/99 several bugs fixed, L.Urban
46 // 31/03/00 rename to lowenergy as G4hRDEnergyLoss.cc V.Ivanchenko
47 // 05/11/00 new method to calculate particle ranges
48 // 10/05/01 V.Ivanchenko Clean up againist Linux compilation with -Wall
49 // 23/11/01 V.Ivanchenko Move static member-functions from header to source
50 // 28/10/02 V.Ivanchenko Optimal binning for dE/dx
51 // 21/01/03 V.Ivanchenko Cut per region
52 // 23/01/03 V.Ivanchenko Fix in table build
53 
54 // 31 Jul 2008 MGP Short term supply of energy loss of hadrons through clone of
55 // former G4hLowEnergyLoss (with some initial cleaning)
56 // To be replaced by reworked class to deal with condensed/discrete
57 // issues properly
58 
59 // 25 Nov 2010 MGP Added some protections for FPE (mostly division by 0)
60 // The whole energy loss domain would profit from a design iteration
61 
62 // 20 Jun 2011 MGP Corrected some compilation warnings. The whole class will be heavily refactored anyway.
63 
64 // --------------------------------------------------------------
65 
66 #include "G4hRDEnergyLoss.hh"
67 #include "G4PhysicalConstants.hh"
68 #include "G4SystemOfUnits.hh"
69 #include "G4EnergyLossTables.hh"
70 #include "G4Poisson.hh"
71 #include "G4ProductionCutsTable.hh"
72 
73 
74 // Initialisation of static members ******************************************
75 // contributing processes : ion.loss ->NumberOfProcesses is initialized
76 // to 1 . YOU DO NOT HAVE TO CHANGE this variable for a 'normal' run.
77 // You have to change NumberOfProcesses
78 // if you invent a new process contributing to the cont. energy loss,
79 // NumberOfProcesses should be 2 in this case,
80 // or for debugging purposes.
81 // The NumberOfProcesses data member can be changed using the (public static)
82 // functions Get/Set/Plus/MinusNumberOfProcesses (see G4hRDEnergyLoss.hh)
83 
84 
85 // The following vectors have a fixed dimension this means that if they are
86 // filled in with more than 100 elements will corrupt the memory.
87 G4int G4hRDEnergyLoss::NumberOfProcesses = 1 ;
88 
89 G4int G4hRDEnergyLoss::CounterOfProcess = 0 ;
90 G4PhysicsTable** G4hRDEnergyLoss::RecorderOfProcess =
91  new G4PhysicsTable*[100] ;
92 
95  new G4PhysicsTable*[100] ;
96 
99  new G4PhysicsTable*[100] ;
100 
111 
112 G4PhysicsTable* G4hRDEnergyLoss::thepRangeCoeffATable = 0 ;
113 G4PhysicsTable* G4hRDEnergyLoss::thepRangeCoeffBTable = 0 ;
114 G4PhysicsTable* G4hRDEnergyLoss::thepRangeCoeffCTable = 0 ;
115 G4PhysicsTable* G4hRDEnergyLoss::thepbarRangeCoeffATable = 0 ;
116 G4PhysicsTable* G4hRDEnergyLoss::thepbarRangeCoeffBTable = 0 ;
117 G4PhysicsTable* G4hRDEnergyLoss::thepbarRangeCoeffCTable = 0 ;
118 
119 G4PhysicsTable* G4hRDEnergyLoss::theDEDXTable = 0 ;
120 G4PhysicsTable* G4hRDEnergyLoss::theRangeTable = 0 ;
121 G4PhysicsTable* G4hRDEnergyLoss::theInverseRangeTable = 0 ;
122 G4PhysicsTable* G4hRDEnergyLoss::theLabTimeTable = 0 ;
123 G4PhysicsTable* G4hRDEnergyLoss::theProperTimeTable = 0 ;
124 
125 G4PhysicsTable* G4hRDEnergyLoss::theRangeCoeffATable = 0 ;
126 G4PhysicsTable* G4hRDEnergyLoss::theRangeCoeffBTable = 0 ;
127 G4PhysicsTable* G4hRDEnergyLoss::theRangeCoeffCTable = 0 ;
128 
129 //const G4Proton* G4hRDEnergyLoss::theProton=G4Proton::Proton() ;
130 //const G4AntiProton* G4hRDEnergyLoss::theAntiProton=G4AntiProton::AntiProton() ;
131 
135 
136 G4double G4hRDEnergyLoss::Mass,
137  G4hRDEnergyLoss::taulow,
138  G4hRDEnergyLoss::tauhigh,
139  G4hRDEnergyLoss::ltaulow,
140  G4hRDEnergyLoss::ltauhigh;
141 
144 
145 G4double G4hRDEnergyLoss::c1lim = dRoverRange ;
146 G4double G4hRDEnergyLoss::c2lim = 2.*(1.-dRoverRange)*finalRange ;
147 G4double G4hRDEnergyLoss::c3lim = -(1.-dRoverRange)*finalRange*finalRange;
148 
150 
153 
158 
159 //--------------------------------------------------------------------------------
160 
161 // constructor and destructor
162 
164  : G4VContinuousDiscreteProcess (processName),
165  MaxExcitationNumber (1.e6),
166  probLimFluct (0.01),
167  nmaxDirectFluct (100),
168  nmaxCont1(4),
169  nmaxCont2(16),
170  theLossTable(0),
171  linLossLimit(0.05),
172  MinKineticEnergy(0.0)
173 {;}
174 
175 //--------------------------------------------------------------------------------
176 
178 {
179  if(theLossTable) {
181  delete theLossTable;
182  }
183 }
184 
185 //--------------------------------------------------------------------------------
186 
188 {
189  return NumberOfProcesses;
190 }
191 
192 //--------------------------------------------------------------------------------
193 
195 {
196  NumberOfProcesses=number;
197 }
198 
199 //--------------------------------------------------------------------------------
200 
202 {
203  NumberOfProcesses++;
204 }
205 
206 //--------------------------------------------------------------------------------
207 
209 {
210  NumberOfProcesses--;
211 }
212 
213 //--------------------------------------------------------------------------------
214 
216 {
217  dRoverRange = value;
218 }
219 
220 //--------------------------------------------------------------------------------
221 
223 {
225 }
226 
227 //--------------------------------------------------------------------------------
228 
230 {
232 }
233 
234 //--------------------------------------------------------------------------------
235 
237 {
238  dRoverRange = c1;
239  finalRange = c2;
243 }
244 
245 //--------------------------------------------------------------------------------
246 
248  const G4ParticleDefinition& aParticleType)
249 {
250  // calculate data members TotBin,LOGRTable,RTable first
251 
252  const G4ProductionCutsTable* theCoupleTable=
254  size_t numOfCouples = theCoupleTable->GetTableSize();
255 
256  // create/fill proton or antiproton tables depending on the charge
257  Charge = aParticleType.GetPDGCharge()/eplus;
258  ParticleMass = aParticleType.GetPDGMass() ;
259 
260  if (Charge>0.) {theDEDXTable= theDEDXpTable;}
261  else {theDEDXTable= theDEDXpbarTable;}
262 
263  if( ((Charge>0.) && (theDEDXTable==0)) ||
264  ((Charge<0.) && (theDEDXTable==0))
265  )
266  {
267 
268  // Build energy loss table as a sum of the energy loss due to the
269  // different processes.
270  if( Charge >0.)
271  {
272  RecorderOfProcess=RecorderOfpProcess;
273  CounterOfProcess=CounterOfpProcess;
274 
275  if(CounterOfProcess == NumberOfProcesses)
276  {
277  if(theDEDXpTable)
279  delete theDEDXpTable; }
280  theDEDXpTable = new G4PhysicsTable(numOfCouples);
281  theDEDXTable = theDEDXpTable;
282  }
283  }
284  else
285  {
286  RecorderOfProcess=RecorderOfpbarProcess;
287  CounterOfProcess=CounterOfpbarProcess;
288 
289  if(CounterOfProcess == NumberOfProcesses)
290  {
291  if(theDEDXpbarTable)
293  delete theDEDXpbarTable; }
294  theDEDXpbarTable = new G4PhysicsTable(numOfCouples);
295  theDEDXTable = theDEDXpbarTable;
296  }
297  }
298 
299  if(CounterOfProcess == NumberOfProcesses)
300  {
301  // loop for materials
302  G4double LowEdgeEnergy , Value ;
303  G4bool isOutRange ;
304  G4PhysicsTable* pointer ;
305 
306  for (size_t J=0; J<numOfCouples; J++)
307  {
308  // create physics vector and fill it
309  G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
311 
312  // loop for the kinetic energy
313  for (G4int i=0; i<TotBin; i++)
314  {
315  LowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
316  Value = 0. ;
317 
318  // loop for the contributing processes
319  for (G4int process=0; process < NumberOfProcesses; process++)
320  {
321  pointer= RecorderOfProcess[process];
322  Value += (*pointer)[J]->
323  GetValue(LowEdgeEnergy,isOutRange) ;
324  }
325 
326  aVector->PutValue(i,Value) ;
327  }
328 
329  theDEDXTable->insert(aVector) ;
330  }
331 
332  // reset counter to zero ..................
333  if( Charge >0.)
335  else
337 
338  // Build range table
339  BuildRangeTable( aParticleType);
340 
341  // Build lab/proper time tables
342  BuildTimeTables( aParticleType) ;
343 
344  // Build coeff tables for the energy loss calculation
345  BuildRangeCoeffATable( aParticleType);
346  BuildRangeCoeffBTable( aParticleType);
347  BuildRangeCoeffCTable( aParticleType);
348 
349  // invert the range table
350 
351  BuildInverseRangeTable(aParticleType);
352  }
353  }
354  // make the energy loss and the range table available
355 
356  G4EnergyLossTables::Register(&aParticleType,
357  (Charge>0)?
359  (Charge>0)?
361  (Charge>0)?
363  (Charge>0)?
365  (Charge>0)?
368  proton_mass_c2/aParticleType.GetPDGMass(),
369  TotBin);
370 
371 }
372 
373 //--------------------------------------------------------------------------------
374 
375 void G4hRDEnergyLoss::BuildRangeTable(
376  const G4ParticleDefinition& aParticleType)
377 // Build range table from the energy loss table
378 {
379  Mass = aParticleType.GetPDGMass();
380 
381  const G4ProductionCutsTable* theCoupleTable=
383  size_t numOfCouples = theCoupleTable->GetTableSize();
384 
385  if( Charge >0.)
386  {
387  if(theRangepTable)
389  delete theRangepTable; }
390  theRangepTable = new G4PhysicsTable(numOfCouples);
391  theRangeTable = theRangepTable ;
392  }
393  else
394  {
397  delete theRangepbarTable; }
398  theRangepbarTable = new G4PhysicsTable(numOfCouples);
399  theRangeTable = theRangepbarTable ;
400  }
401 
402  // loop for materials
403 
404  for (size_t J=0; J<numOfCouples; J++)
405  {
406  G4PhysicsLogVector* aVector;
409 
410  BuildRangeVector(J, aVector);
411  theRangeTable->insert(aVector);
412  }
413 }
414 
415 //--------------------------------------------------------------------------------
416 
417 void G4hRDEnergyLoss::BuildTimeTables(
418  const G4ParticleDefinition& aParticleType)
419 {
420 
421  const G4ProductionCutsTable* theCoupleTable=
423  size_t numOfCouples = theCoupleTable->GetTableSize();
424 
425  if(&aParticleType == G4Proton::Proton())
426  {
427  if(theLabTimepTable)
429  delete theLabTimepTable; }
430  theLabTimepTable = new G4PhysicsTable(numOfCouples);
431  theLabTimeTable = theLabTimepTable ;
432 
435  delete theProperTimepTable; }
436  theProperTimepTable = new G4PhysicsTable(numOfCouples);
437  theProperTimeTable = theProperTimepTable ;
438  }
439 
440  if(&aParticleType == G4AntiProton::AntiProton())
441  {
444  delete theLabTimepbarTable; }
445  theLabTimepbarTable = new G4PhysicsTable(numOfCouples);
446  theLabTimeTable = theLabTimepbarTable ;
447 
450  delete theProperTimepbarTable; }
451  theProperTimepbarTable = new G4PhysicsTable(numOfCouples);
452  theProperTimeTable = theProperTimepbarTable ;
453  }
454 
455  for (size_t J=0; J<numOfCouples; J++)
456  {
457  G4PhysicsLogVector* aVector;
458  G4PhysicsLogVector* bVector;
459 
462 
463  BuildLabTimeVector(J, aVector);
464  theLabTimeTable->insert(aVector);
465 
468 
469  BuildProperTimeVector(J, bVector);
470  theProperTimeTable->insert(bVector);
471  }
472 }
473 
474 //--------------------------------------------------------------------------------
475 
476 void G4hRDEnergyLoss::BuildRangeVector(G4int materialIndex,
477  G4PhysicsLogVector* rangeVector)
478 // create range vector for a material
479 {
480  G4bool isOut;
481  G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
482  G4double energy1 = rangeVector->GetLowEdgeEnergy(0);
483  G4double dedx = physicsVector->GetValue(energy1,isOut);
484  G4double range = 0.5*energy1/dedx;
485  rangeVector->PutValue(0,range);
486  G4int n = 100;
487  G4double del = 1.0/(G4double)n ;
488 
489  for (G4int j=1; j<TotBin; j++) {
490 
491  G4double energy2 = rangeVector->GetLowEdgeEnergy(j);
492  G4double de = (energy2 - energy1) * del ;
493  G4double dedx1 = dedx ;
494 
495  for (G4int i=1; i<n; i++) {
496  G4double energy = energy1 + i*de ;
497  G4double dedx2 = physicsVector->GetValue(energy,isOut);
498  range += 0.5*de*(1.0/dedx1 + 1.0/dedx2);
499  dedx1 = dedx2;
500  }
501  rangeVector->PutValue(j,range);
502  dedx = dedx1 ;
503  energy1 = energy2 ;
504  }
505 }
506 
507 //--------------------------------------------------------------------------------
508 
509 void G4hRDEnergyLoss::BuildLabTimeVector(G4int materialIndex,
510  G4PhysicsLogVector* timeVector)
511 // create lab time vector for a material
512 {
513 
514  G4int nbin=100;
515  G4bool isOut;
516  G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ;
517  //G4double losslim,clim,taulim,timelim,ltaulim,ltaumax,
518  G4double losslim,clim,taulim,timelim,
519  LowEdgeEnergy,tau,Value ;
520 
521  G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
522 
523  // low energy part first...
524  losslim = physicsVector->GetValue(tlim,isOut);
525  taulim=tlim/ParticleMass ;
526  clim=std::sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar) ;
527  //ltaulim = std::log(taulim);
528  //ltaumax = std::log(HighestKineticEnergy/ParticleMass) ;
529 
530  G4int i=-1;
531  G4double oldValue = 0. ;
532  G4double tauold ;
533  do
534  {
535  i += 1 ;
536  LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i);
537  tau = LowEdgeEnergy/ParticleMass ;
538  if ( tau <= taulim )
539  {
540  Value = clim*std::exp(ppar*std::log(tau/taulim)) ;
541  }
542  else
543  {
544  timelim=clim ;
545  ltaulow = std::log(taulim);
546  ltauhigh = std::log(tau);
547  Value = timelim+LabTimeIntLog(physicsVector,nbin);
548  }
549  timeVector->PutValue(i,Value);
550  oldValue = Value ;
551  tauold = tau ;
552  } while (tau<=taulim) ;
553 
554  i += 1 ;
555  for (G4int j=i; j<TotBin; j++)
556  {
557  LowEdgeEnergy = timeVector->GetLowEdgeEnergy(j);
558  tau = LowEdgeEnergy/ParticleMass ;
559  ltaulow = std::log(tauold);
560  ltauhigh = std::log(tau);
561  Value = oldValue+LabTimeIntLog(physicsVector,nbin);
562  timeVector->PutValue(j,Value);
563  oldValue = Value ;
564  tauold = tau ;
565  }
566 }
567 
568 //--------------------------------------------------------------------------------
569 
570 void G4hRDEnergyLoss::BuildProperTimeVector(G4int materialIndex,
571  G4PhysicsLogVector* timeVector)
572 // create proper time vector for a material
573 {
574  G4int nbin=100;
575  G4bool isOut;
576  G4double tlim=5.*keV,parlowen=0.4,ppar=0.5-parlowen ;
577  //G4double losslim,clim,taulim,timelim,ltaulim,ltaumax,
578  G4double losslim,clim,taulim,timelim,
579  LowEdgeEnergy,tau,Value ;
580 
581  G4PhysicsVector* physicsVector= (*theDEDXTable)[materialIndex];
582 
583  // low energy part first...
584  losslim = physicsVector->GetValue(tlim,isOut);
585  taulim=tlim/ParticleMass ;
586  clim=std::sqrt(ParticleMass*tlim/2.)/(c_light*losslim*ppar) ;
587  //ltaulim = std::log(taulim);
588  //ltaumax = std::log(HighestKineticEnergy/ParticleMass) ;
589 
590  G4int i=-1;
591  G4double oldValue = 0. ;
592  G4double tauold ;
593  do
594  {
595  i += 1 ;
596  LowEdgeEnergy = timeVector->GetLowEdgeEnergy(i);
597  tau = LowEdgeEnergy/ParticleMass ;
598  if ( tau <= taulim )
599  {
600  Value = clim*std::exp(ppar*std::log(tau/taulim)) ;
601  }
602  else
603  {
604  timelim=clim ;
605  ltaulow = std::log(taulim);
606  ltauhigh = std::log(tau);
607  Value = timelim+ProperTimeIntLog(physicsVector,nbin);
608  }
609  timeVector->PutValue(i,Value);
610  oldValue = Value ;
611  tauold = tau ;
612  } while (tau<=taulim) ;
613 
614  i += 1 ;
615  for (G4int j=i; j<TotBin; j++)
616  {
617  LowEdgeEnergy = timeVector->GetLowEdgeEnergy(j);
618  tau = LowEdgeEnergy/ParticleMass ;
619  ltaulow = std::log(tauold);
620  ltauhigh = std::log(tau);
621  Value = oldValue+ProperTimeIntLog(physicsVector,nbin);
622  timeVector->PutValue(j,Value);
623  oldValue = Value ;
624  tauold = tau ;
625  }
626 }
627 
628 //--------------------------------------------------------------------------------
629 
630 G4double G4hRDEnergyLoss::RangeIntLin(G4PhysicsVector* physicsVector,
631  G4int nbin)
632 // num. integration, linear binning
633 {
634  G4double dtau,Value,taui,ti,lossi,ci;
635  G4bool isOut;
636  dtau = (tauhigh-taulow)/nbin;
637  Value = 0.;
638 
639  for (G4int i=0; i<=nbin; i++)
640  {
641  taui = taulow + dtau*i ;
642  ti = Mass*taui;
643  lossi = physicsVector->GetValue(ti,isOut);
644  if(i==0)
645  ci=0.5;
646  else
647  {
648  if(i<nbin)
649  ci=1.;
650  else
651  ci=0.5;
652  }
653  Value += ci/lossi;
654  }
655  Value *= Mass*dtau;
656  return Value;
657 }
658 
659 //--------------------------------------------------------------------------------
660 
661 G4double G4hRDEnergyLoss::RangeIntLog(G4PhysicsVector* physicsVector,
662  G4int nbin)
663 // num. integration, logarithmic binning
664 {
665  G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
666  G4bool isOut;
667  ltt = ltauhigh-ltaulow;
668  dltau = ltt/nbin;
669  Value = 0.;
670 
671  for (G4int i=0; i<=nbin; i++)
672  {
673  ui = ltaulow+dltau*i;
674  taui = std::exp(ui);
675  ti = Mass*taui;
676  lossi = physicsVector->GetValue(ti,isOut);
677  if(i==0)
678  ci=0.5;
679  else
680  {
681  if(i<nbin)
682  ci=1.;
683  else
684  ci=0.5;
685  }
686  Value += ci*taui/lossi;
687  }
688  Value *= Mass*dltau;
689  return Value;
690 }
691 
692 //--------------------------------------------------------------------------------
693 
694 G4double G4hRDEnergyLoss::LabTimeIntLog(G4PhysicsVector* physicsVector,
695  G4int nbin)
696 // num. integration, logarithmic binning
697 {
698  G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
699  G4bool isOut;
700  ltt = ltauhigh-ltaulow;
701  dltau = ltt/nbin;
702  Value = 0.;
703 
704  for (G4int i=0; i<=nbin; i++)
705  {
706  ui = ltaulow+dltau*i;
707  taui = std::exp(ui);
708  ti = ParticleMass*taui;
709  lossi = physicsVector->GetValue(ti,isOut);
710  if(i==0)
711  ci=0.5;
712  else
713  {
714  if(i<nbin)
715  ci=1.;
716  else
717  ci=0.5;
718  }
719  Value += ci*taui*(ti+ParticleMass)/(std::sqrt(ti*(ti+2.*ParticleMass))*lossi);
720  }
721  Value *= ParticleMass*dltau/c_light;
722  return Value;
723 }
724 
725 //--------------------------------------------------------------------------------
726 
727 G4double G4hRDEnergyLoss::ProperTimeIntLog(G4PhysicsVector* physicsVector,
728  G4int nbin)
729 // num. integration, logarithmic binning
730 {
731  G4double ltt,dltau,Value,ui,taui,ti,lossi,ci;
732  G4bool isOut;
733  ltt = ltauhigh-ltaulow;
734  dltau = ltt/nbin;
735  Value = 0.;
736 
737  for (G4int i=0; i<=nbin; i++)
738  {
739  ui = ltaulow+dltau*i;
740  taui = std::exp(ui);
741  ti = ParticleMass*taui;
742  lossi = physicsVector->GetValue(ti,isOut);
743  if(i==0)
744  ci=0.5;
745  else
746  {
747  if(i<nbin)
748  ci=1.;
749  else
750  ci=0.5;
751  }
752  Value += ci*taui*ParticleMass/(std::sqrt(ti*(ti+2.*ParticleMass))*lossi);
753  }
754  Value *= ParticleMass*dltau/c_light;
755  return Value;
756 }
757 
758 //--------------------------------------------------------------------------------
759 
760 void G4hRDEnergyLoss::BuildRangeCoeffATable(
761  const G4ParticleDefinition& )
762 // Build tables of coefficients for the energy loss calculation
763 // create table for coefficients "A"
764 {
765 
767 
768  if(Charge>0.)
769  {
770  if(thepRangeCoeffATable)
771  { thepRangeCoeffATable->clearAndDestroy();
772  delete thepRangeCoeffATable; }
773  thepRangeCoeffATable = new G4PhysicsTable(numOfCouples);
774  theRangeCoeffATable = thepRangeCoeffATable ;
775  theRangeTable = theRangepTable ;
776  }
777  else
778  {
779  if(thepbarRangeCoeffATable)
780  { thepbarRangeCoeffATable->clearAndDestroy();
781  delete thepbarRangeCoeffATable; }
782  thepbarRangeCoeffATable = new G4PhysicsTable(numOfCouples);
783  theRangeCoeffATable = thepbarRangeCoeffATable ;
784  theRangeTable = theRangepbarTable ;
785  }
786 
787  G4double R2 = RTable*RTable ;
788  G4double R1 = RTable+1.;
789  G4double w = R1*(RTable-1.)*(RTable-1.);
790  G4double w1 = RTable/w , w2 = -RTable*R1/w , w3 = R2/w ;
791  G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
792  G4bool isOut;
793 
794  // loop for materials
795  for (G4int J=0; J<numOfCouples; J++)
796  {
797  G4int binmax=TotBin ;
798  G4PhysicsLinearVector* aVector =
799  new G4PhysicsLinearVector(0.,binmax, TotBin);
800  Ti = LowestKineticEnergy ;
801  if (Ti < DBL_MIN) Ti = 1.e-8;
802  G4PhysicsVector* rangeVector= (*theRangeTable)[J];
803 
804  for ( G4int i=0; i<TotBin; i++)
805  {
806  Ri = rangeVector->GetValue(Ti,isOut) ;
807  if (Ti < DBL_MIN) Ti = 1.e-8;
808  if ( i==0 )
809  Rim = 0. ;
810  else
811  {
812  // ---- MGP ---- Modified to avoid a floating point exception
813  // The correction is just a temporary patch, the whole class should be redesigned
814  // Original: Tim = Ti/RTable results in 0./0.
815  if (RTable != 0.)
816  {
817  Tim = Ti/RTable ;
818  }
819  else
820  {
821  Tim = 0.;
822  }
823  Rim = rangeVector->GetValue(Tim,isOut);
824  }
825  if ( i==(TotBin-1))
826  Rip = Ri ;
827  else
828  {
829  Tip = Ti*RTable ;
830  Rip = rangeVector->GetValue(Tip,isOut);
831  }
832  Value = (w1*Rip + w2*Ri + w3*Rim)/(Ti*Ti) ;
833 
834  aVector->PutValue(i,Value);
835  Ti = RTable*Ti ;
836  }
837 
838  theRangeCoeffATable->insert(aVector);
839  }
840 }
841 
842 //--------------------------------------------------------------------------------
843 
844 void G4hRDEnergyLoss::BuildRangeCoeffBTable(
845  const G4ParticleDefinition& )
846 // Build tables of coefficients for the energy loss calculation
847 // create table for coefficients "B"
848 {
849 
851 
852  if(Charge>0.)
853  {
854  if(thepRangeCoeffBTable)
855  { thepRangeCoeffBTable->clearAndDestroy();
856  delete thepRangeCoeffBTable; }
857  thepRangeCoeffBTable = new G4PhysicsTable(numOfCouples);
858  theRangeCoeffBTable = thepRangeCoeffBTable ;
859  theRangeTable = theRangepTable ;
860  }
861  else
862  {
863  if(thepbarRangeCoeffBTable)
864  { thepbarRangeCoeffBTable->clearAndDestroy();
865  delete thepbarRangeCoeffBTable; }
866  thepbarRangeCoeffBTable = new G4PhysicsTable(numOfCouples);
867  theRangeCoeffBTable = thepbarRangeCoeffBTable ;
868  theRangeTable = theRangepbarTable ;
869  }
870 
871  G4double R2 = RTable*RTable ;
872  G4double R1 = RTable+1.;
873  G4double w = R1*(RTable-1.)*(RTable-1.);
874  if (w < DBL_MIN) w = DBL_MIN;
875  G4double w1 = -R1/w , w2 = R1*(R2+1.)/w , w3 = -R2*R1/w ;
876  G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
877  G4bool isOut;
878 
879  // loop for materials
880  for (G4int J=0; J<numOfCouples; J++)
881  {
882  G4int binmax=TotBin ;
883  G4PhysicsLinearVector* aVector =
884  new G4PhysicsLinearVector(0.,binmax, TotBin);
885  Ti = LowestKineticEnergy ;
886  if (Ti < DBL_MIN) Ti = 1.e-8;
887  G4PhysicsVector* rangeVector= (*theRangeTable)[J];
888 
889  for ( G4int i=0; i<TotBin; i++)
890  {
891  Ri = rangeVector->GetValue(Ti,isOut) ;
892  if (Ti < DBL_MIN) Ti = 1.e-8;
893  if ( i==0 )
894  Rim = 0. ;
895  else
896  {
897  if (RTable < DBL_MIN) RTable = DBL_MIN;
898  Tim = Ti/RTable ;
899  Rim = rangeVector->GetValue(Tim,isOut);
900  }
901  if ( i==(TotBin-1))
902  Rip = Ri ;
903  else
904  {
905  Tip = Ti*RTable ;
906  Rip = rangeVector->GetValue(Tip,isOut);
907  }
908  if (Ti < DBL_MIN) Ti = DBL_MIN;
909  Value = (w1*Rip + w2*Ri + w3*Rim)/Ti;
910 
911  aVector->PutValue(i,Value);
912  Ti = RTable*Ti ;
913  }
914  theRangeCoeffBTable->insert(aVector);
915  }
916 }
917 
918 //--------------------------------------------------------------------------------
919 
920 void G4hRDEnergyLoss::BuildRangeCoeffCTable(
921  const G4ParticleDefinition& )
922 // Build tables of coefficients for the energy loss calculation
923 // create table for coefficients "C"
924 {
925 
927 
928  if(Charge>0.)
929  {
930  if(thepRangeCoeffCTable)
931  { thepRangeCoeffCTable->clearAndDestroy();
932  delete thepRangeCoeffCTable; }
933  thepRangeCoeffCTable = new G4PhysicsTable(numOfCouples);
934  theRangeCoeffCTable = thepRangeCoeffCTable ;
935  theRangeTable = theRangepTable ;
936  }
937  else
938  {
939  if(thepbarRangeCoeffCTable)
940  { thepbarRangeCoeffCTable->clearAndDestroy();
941  delete thepbarRangeCoeffCTable; }
942  thepbarRangeCoeffCTable = new G4PhysicsTable(numOfCouples);
943  theRangeCoeffCTable = thepbarRangeCoeffCTable ;
944  theRangeTable = theRangepbarTable ;
945  }
946 
947  G4double R2 = RTable*RTable ;
948  G4double R1 = RTable+1.;
949  G4double w = R1*(RTable-1.)*(RTable-1.);
950  G4double w1 = 1./w , w2 = -RTable*R1/w , w3 = RTable*R2/w ;
951  G4double Ti , Tim , Tip , Ri , Rim , Rip , Value ;
952  G4bool isOut;
953 
954  // loop for materials
955  for (G4int J=0; J<numOfCouples; J++)
956  {
957  G4int binmax=TotBin ;
958  G4PhysicsLinearVector* aVector =
959  new G4PhysicsLinearVector(0.,binmax, TotBin);
960  Ti = LowestKineticEnergy ;
961  G4PhysicsVector* rangeVector= (*theRangeTable)[J];
962 
963  for ( G4int i=0; i<TotBin; i++)
964  {
965  Ri = rangeVector->GetValue(Ti,isOut) ;
966  if ( i==0 )
967  Rim = 0. ;
968  else
969  {
970  Tim = Ti/RTable ;
971  Rim = rangeVector->GetValue(Tim,isOut);
972  }
973  if ( i==(TotBin-1))
974  Rip = Ri ;
975  else
976  {
977  Tip = Ti*RTable ;
978  Rip = rangeVector->GetValue(Tip,isOut);
979  }
980  Value = w1*Rip + w2*Ri + w3*Rim ;
981 
982  aVector->PutValue(i,Value);
983  Ti = RTable*Ti ;
984  }
985  theRangeCoeffCTable->insert(aVector);
986  }
987 }
988 
989 //--------------------------------------------------------------------------------
990 
991 void G4hRDEnergyLoss::BuildInverseRangeTable(
992  const G4ParticleDefinition& aParticleType)
993 // Build inverse table of the range table
994 {
995  G4bool b;
996 
997  const G4ProductionCutsTable* theCoupleTable=
999  size_t numOfCouples = theCoupleTable->GetTableSize();
1000 
1001  if(&aParticleType == G4Proton::Proton())
1002  {
1005  delete theInverseRangepTable; }
1006  theInverseRangepTable = new G4PhysicsTable(numOfCouples);
1007  theInverseRangeTable = theInverseRangepTable ;
1008  theRangeTable = theRangepTable ;
1009  theDEDXTable = theDEDXpTable ;
1010  theRangeCoeffATable = thepRangeCoeffATable ;
1011  theRangeCoeffBTable = thepRangeCoeffBTable ;
1012  theRangeCoeffCTable = thepRangeCoeffCTable ;
1013  }
1014 
1015  if(&aParticleType == G4AntiProton::AntiProton())
1016  {
1019  delete theInverseRangepbarTable; }
1020  theInverseRangepbarTable = new G4PhysicsTable(numOfCouples);
1021  theInverseRangeTable = theInverseRangepbarTable ;
1022  theRangeTable = theRangepbarTable ;
1023  theDEDXTable = theDEDXpbarTable ;
1024  theRangeCoeffATable = thepbarRangeCoeffATable ;
1025  theRangeCoeffBTable = thepbarRangeCoeffBTable ;
1026  theRangeCoeffCTable = thepbarRangeCoeffCTable ;
1027  }
1028 
1029  // loop for materials
1030  for (size_t i=0; i<numOfCouples; i++)
1031  {
1032 
1033  G4PhysicsVector* pv = (*theRangeTable)[i];
1034  size_t nbins = pv->GetVectorLength();
1035  G4double elow = pv->GetLowEdgeEnergy(0);
1036  G4double ehigh = pv->GetLowEdgeEnergy(nbins-1);
1037  G4double rlow = pv->GetValue(elow, b);
1038  G4double rhigh = pv->GetValue(ehigh, b);
1039 
1040  if (rlow <DBL_MIN) rlow = 1.e-8;
1041  if (rhigh > 1.e16) rhigh = 1.e16;
1042  if (rhigh < 1.e-8) rhigh =1.e-8;
1043  G4double tmpTrick = rhigh/rlow;
1044 
1045  //std::cout << nbins << ", elow " << elow << ", ehigh " << ehigh
1046  // << ", rlow " << rlow << ", rhigh " << rhigh << ", trick " << tmpTrick << std::endl;
1047 
1048  if (tmpTrick <= 0. || tmpTrick < DBL_MIN) tmpTrick = 1.e-8;
1049  if (tmpTrick > 1.e16) tmpTrick = 1.e16;
1050 
1051  rhigh *= std::exp(std::log(tmpTrick)/((G4double)(nbins-1)));
1052 
1053  G4PhysicsLogVector* v = new G4PhysicsLogVector(rlow, rhigh, nbins);
1054 
1055  v->PutValue(0,elow);
1056  G4double energy1 = elow;
1057  G4double range1 = rlow;
1058  G4double energy2 = elow;
1059  G4double range2 = rlow;
1060  size_t ilow = 0;
1061  size_t ihigh;
1062 
1063  for (size_t j=1; j<nbins; j++) {
1064 
1065  G4double range = v->GetLowEdgeEnergy(j);
1066 
1067  for (ihigh=ilow+1; ihigh<nbins; ihigh++) {
1068  energy2 = pv->GetLowEdgeEnergy(ihigh);
1069  range2 = pv->GetValue(energy2, b);
1070  if(range2 >= range || ihigh == nbins-1) {
1071  ilow = ihigh - 1;
1072  energy1 = pv->GetLowEdgeEnergy(ilow);
1073  range1 = pv->GetValue(energy1, b);
1074  break;
1075  }
1076  }
1077 
1078  G4double e = std::log(energy1) + std::log(energy2/energy1)*std::log(range/range1)/std::log(range2/range1);
1079 
1080  v->PutValue(j,std::exp(e));
1081  }
1082  theInverseRangeTable->insert(v);
1083 
1084  }
1085 }
1086 
1087 //--------------------------------------------------------------------------------
1088 
1089 void G4hRDEnergyLoss::InvertRangeVector(G4int materialIndex,
1090  G4PhysicsLogVector* aVector)
1091 // invert range vector for a material
1092 {
1093  G4double LowEdgeRange,A,B,C,discr,KineticEnergy ;
1095  G4double rangebin = 0.0 ;
1096  G4int binnumber = -1 ;
1097  G4bool isOut ;
1098 
1099 
1100  //loop for range values
1101  for( G4int i=0; i<TotBin; i++)
1102  {
1103  LowEdgeRange = aVector->GetLowEdgeEnergy(i) ; //i.e. GetLowEdgeValue(i)
1104 
1105  if( rangebin < LowEdgeRange )
1106  {
1107  do
1108  {
1109  binnumber += 1 ;
1110  Tbin *= RTable ;
1111  rangebin = (*theRangeTable)(materialIndex)->GetValue(Tbin,isOut) ;
1112  }
1113  while ((rangebin < LowEdgeRange) && (binnumber < TotBin )) ;
1114  }
1115 
1116  if(binnumber == 0)
1117  KineticEnergy = LowestKineticEnergy ;
1118  else if(binnumber == TotBin-1)
1119  KineticEnergy = HighestKineticEnergy ;
1120  else
1121  {
1122  A = (*(*theRangeCoeffATable)(materialIndex))(binnumber-1) ;
1123  B = (*(*theRangeCoeffBTable)(materialIndex))(binnumber-1) ;
1124  C = (*(*theRangeCoeffCTable)(materialIndex))(binnumber-1) ;
1125  if(A==0.)
1126  KineticEnergy = (LowEdgeRange -C )/B ;
1127  else
1128  {
1129  discr = B*B - 4.*A*(C-LowEdgeRange);
1130  discr = discr>0. ? std::sqrt(discr) : 0.;
1131  KineticEnergy = 0.5*(discr-B)/A ;
1132  }
1133  }
1134 
1135  aVector->PutValue(i,KineticEnergy) ;
1136  }
1137 }
1138 
1139 //------------------------------------------------------------------------------
1140 
1142 {
1143  G4bool wasModified = false;
1144  const G4ProductionCutsTable* theCoupleTable=
1146  size_t numOfCouples = theCoupleTable->GetTableSize();
1147 
1148  for (size_t j=0; j<numOfCouples; j++){
1149  if (theCoupleTable->GetMaterialCutsCouple(j)->IsRecalcNeeded()) {
1150  wasModified = true;
1151  break;
1152  }
1153  }
1154  return wasModified;
1155 }
1156 
1157 //-----------------------------------------------------------------------
1158 //--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1159 
1160 //G4bool G4hRDEnergyLoss::IsApplicable(const G4ParticleDefinition&
1161 // particle)
1162 //{
1163 // return((particle.GetPDGCharge()!= 0.) && (particle.GetLeptonNumber() == 0));
1164 //}
1165 
1166 //G4double G4hRDEnergyLoss::GetContinuousStepLimit(
1167 // const G4Track& track,
1168 // G4double,
1169 // G4double currentMinimumStep,
1170 // G4double&)
1171 //{
1172 //
1173 // G4double Step =
1174 // GetConstraints(track.GetDynamicParticle(),track.GetMaterial()) ;
1175 //
1176 // if((Step>0.0)&&(Step<currentMinimumStep))
1177 // currentMinimumStep = Step ;
1178 //
1179 // return Step ;
1180 //}