ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4IonParametrisedLossModel.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4IonParametrisedLossModel.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 // ===========================================================================
28 // GEANT4 class source file
29 //
30 // Class: G4IonParametrisedLossModel
31 //
32 // Base class: G4VEmModel (utils)
33 //
34 // Author: Anton Lechner (Anton.Lechner@cern.ch)
35 //
36 // First implementation: 10. 11. 2008
37 //
38 // Modifications: 03. 02. 2009 - Bug fix iterators (AL)
39 // 11. 03. 2009 - Introduced new table handler(G4IonDEDXHandler)
40 // and modified method to add/remove tables
41 // (tables are now built in init. phase),
42 // Minor bug fix in ComputeDEDXPerVolume (AL)
43 // 11. 05. 2009 - Introduced scaling algorithm for heavier ions:
44 // G4IonDEDXScalingICRU73 (AL)
45 // 12. 11. 2009 - Moved from original ICRU 73 classes to new
46 // class (G4IonStoppingData), which is capable
47 // of reading stopping power data files stored
48 // in G4LEDATA (requires G4EMLOW6.8 or higher).
49 // Simultanesouly, the upper energy limit of
50 // ICRU 73 is increased to 1 GeV/nucleon.
51 // - Removed nuclear stopping from Corrections-
52 // AlongStep since dedicated process was created.
53 // - Added function for switching off scaling
54 // of heavy ions from ICRU 73 data
55 // - Minor fix in ComputeLossForStep function
56 // - Minor fix in ComputeDEDXPerVolume (AL)
57 // 23. 11. 2009 - Changed energy loss limit from 0.15 to 0.01
58 // to improve accuracy for large steps (AL)
59 // 24. 11. 2009 - Bug fix: Range calculation corrected if same
60 // materials appears with different cuts in diff.
61 // regions (added UpdateRangeCache function and
62 // modified BuildRangeVector, ComputeLossForStep
63 // functions accordingly, added new cache param.)
64 // - Removed GetRange function (AL)
65 // 04. 11. 2010 - Moved virtual methods to the source (VI)
66 //
67 //
68 // Class description:
69 // Model for computing the energy loss of ions by employing a
70 // parameterisation of dE/dx tables (by default ICRU 73 tables). For
71 // ion-material combinations and/or projectile energies not covered
72 // by this model, the G4BraggIonModel and G4BetheBloch models are
73 // employed.
74 //
75 // Comments:
76 //
77 // ===========================================================================
78 
79 
81 #include "G4PhysicalConstants.hh"
82 #include "G4SystemOfUnits.hh"
83 #include "G4LPhysicsFreeVector.hh"
84 #include "G4IonStoppingData.hh"
85 #include "G4VIonDEDXTable.hh"
88 #include "G4BraggIonModel.hh"
89 #include "G4BetheBlochModel.hh"
90 #include "G4ProductionCutsTable.hh"
92 #include "G4LossTableManager.hh"
93 #include "G4EmParameters.hh"
94 #include "G4GenericIon.hh"
95 #include "G4Electron.hh"
96 #include "G4DeltaAngle.hh"
97 #include "Randomize.hh"
98 #include "G4Exp.hh"
99 
100 //#define PRINT_TABLE_BUILT
101 
102 
103 // #########################################################################
104 
106  const G4ParticleDefinition*,
107  const G4String& nam)
108  : G4VEmModel(nam),
109  braggIonModel(0),
110  betheBlochModel(0),
111  nmbBins(90),
112  nmbSubBins(100),
113  particleChangeLoss(0),
114  corrFactor(1.0),
115  energyLossLimit(0.01),
116  cutEnergies(0),
117  isInitialised(false)
118 {
122 
123  // The Bragg ion and Bethe Bloch models are instantiated
126 
127  // The boundaries for the range tables are set
128  lowerEnergyEdgeIntegr = 0.025 * MeV;
130 
131  // Cache parameters are set
132  cacheParticle = 0;
133  cacheMass = 0;
134  cacheElecMassRatio = 0;
135  cacheChargeSquare = 0;
136 
137  // Cache parameters are set
138  rangeCacheParticle = 0;
142 
143  // Cache parameters are set
144  dedxCacheParticle = 0;
145  dedxCacheMaterial = 0;
146  dedxCacheEnergyCut = 0;
151 
152  // default generator
154 }
155 
156 // #########################################################################
157 
159 
160  // dE/dx table objects are deleted and the container is cleared
161  LossTableList::iterator iterTables = lossTableList.begin();
162  LossTableList::iterator iterTables_end = lossTableList.end();
163 
164  for(;iterTables != iterTables_end; ++iterTables) { delete *iterTables; }
165  lossTableList.clear();
166 
167  // range table
168  RangeEnergyTable::iterator itr = r.begin();
169  RangeEnergyTable::iterator itr_end = r.end();
170  for(;itr != itr_end; ++itr) { delete itr->second; }
171  r.clear();
172 
173  // inverse range
174  EnergyRangeTable::iterator ite = E.begin();
175  EnergyRangeTable::iterator ite_end = E.end();
176  for(;ite != ite_end; ++ite) { delete ite->second; }
177  E.clear();
178 
179 }
180 
181 // #########################################################################
182 
184  const G4ParticleDefinition*,
185  const G4MaterialCutsCouple* couple) {
186 
187  return couple->GetMaterial()->GetIonisation()->GetMeanExcitationEnergy();
188 }
189 
190 // #########################################################################
191 
194  G4double kineticEnergy) {
195 
196  // ############## Maximum energy of secondaries ##########################
197  // Function computes maximum energy of secondary electrons which are
198  // released by an ion
199  //
200  // See Geant4 physics reference manual (version 9.1), section 9.1.1
201  //
202  // Ref.: W.M. Yao et al, Jour. of Phys. G 33 (2006) 1.
203  // C.Caso et al. (Part. Data Group), Europ. Phys. Jour. C 3 1 (1998).
204  // B. Rossi, High energy particles, New York, NY: Prentice-Hall (1952).
205  //
206  // (Implementation adapted from G4BraggIonModel)
207 
208  if(particle != cacheParticle) UpdateCache(particle);
209 
210  G4double tau = kineticEnergy/cacheMass;
211  G4double tmax = 2.0 * electron_mass_c2 * tau * (tau + 2.) /
212  (1. + 2.0 * (tau + 1.) * cacheElecMassRatio +
214 
215  return tmax;
216 }
217 
218 // #########################################################################
219 
222  const G4Material* material,
223  G4double kineticEnergy) { // Kinetic energy
224 
225  G4double chargeSquareRatio = corrections ->
226  EffectiveChargeSquareRatio(particle,
227  material,
228  kineticEnergy);
229  corrFactor = chargeSquareRatio *
230  corrections -> EffectiveChargeCorrection(particle,
231  material,
232  kineticEnergy);
233  return corrFactor;
234 }
235 
236 // #########################################################################
237 
240  const G4Material* material,
241  G4double kineticEnergy) { // Kinetic energy
242 
243  return corrections -> GetParticleCharge(particle, material, kineticEnergy);
244 }
245 
246 // #########################################################################
247 
250  const G4DataVector& cuts) {
251 
252  // Cached parameters are reset
253  cacheParticle = 0;
254  cacheMass = 0;
255  cacheElecMassRatio = 0;
256  cacheChargeSquare = 0;
257 
258  // Cached parameters are reset
259  rangeCacheParticle = 0;
263 
264  // Cached parameters are reset
265  dedxCacheParticle = 0;
266  dedxCacheMaterial = 0;
267  dedxCacheEnergyCut = 0;
272 
273  // By default ICRU 73 stopping power tables are loaded:
274  if(!isInitialised) {
276  isInitialised = true;
277  AddDEDXTable("ICRU73",
278  new G4IonStoppingData("ion_stopping_data/icru",icru90),
279  new G4IonDEDXScalingICRU73());
280  }
281  // The cache of loss tables is cleared
282  LossTableList::iterator iterTables = lossTableList.begin();
283  LossTableList::iterator iterTables_end = lossTableList.end();
284 
285  for(;iterTables != iterTables_end; ++iterTables) {
286  (*iterTables) -> ClearCache();
287  }
288 
289  // Range vs energy and energy vs range vectors from previous runs are
290  // cleared
291  RangeEnergyTable::iterator iterRange = r.begin();
292  RangeEnergyTable::iterator iterRange_end = r.end();
293 
294  for(;iterRange != iterRange_end; ++iterRange) {
295  delete iterRange->second;
296  }
297  r.clear();
298 
299  EnergyRangeTable::iterator iterEnergy = E.begin();
300  EnergyRangeTable::iterator iterEnergy_end = E.end();
301 
302  for(;iterEnergy != iterEnergy_end; iterEnergy++) {
303  delete iterEnergy->second;
304  }
305  E.clear();
306 
307  // The cut energies
308  cutEnergies = cuts;
309 
310  // All dE/dx vectors are built
311  const G4ProductionCutsTable* coupleTable=
313  size_t nmbCouples = coupleTable->GetTableSize();
314 
315 #ifdef PRINT_TABLE_BUILT
316  G4cout << "G4IonParametrisedLossModel::Initialise():"
317  << " Building dE/dx vectors:"
318  << G4endl;
319 #endif
320 
321  for (size_t i = 0; i < nmbCouples; ++i) {
322 
323  const G4MaterialCutsCouple* couple = coupleTable->GetMaterialCutsCouple(i);
324  const G4Material* material = couple->GetMaterial();
325 
326  for(G4int atomicNumberIon = 3; atomicNumberIon < 102; ++atomicNumberIon) {
327 
328  LossTableList::iterator iter = lossTableList.begin();
329  LossTableList::iterator iter_end = lossTableList.end();
330 
331  for(;iter != iter_end; ++iter) {
332 
333  if(*iter == 0) {
334  G4cout << "G4IonParametrisedLossModel::Initialise():"
335  << " Skipping illegal table."
336  << G4endl;
337  }
338 
339  if((*iter)->BuildDEDXTable(atomicNumberIon, material)) {
340 
341 #ifdef PRINT_TABLE_BUILT
342  G4cout << " Atomic Number Ion = " << atomicNumberIon
343  << ", Material = " << material -> GetName()
344  << ", Table = " << (*iter) -> GetName()
345  << G4endl;
346 #endif
347  break;
348  }
349  }
350  }
351  }
352 
353  // The particle change object
354  if(! particleChangeLoss) {
358  }
359 
360  // The G4BraggIonModel and G4BetheBlochModel instances are initialised with
361  // the same settings as the current model:
362  braggIonModel -> Initialise(particle, cuts);
363  betheBlochModel -> Initialise(particle, cuts);
364 }
365 
366 // #########################################################################
367 
370  G4double kineticEnergy,
371  G4double atomicNumber,
372  G4double,
373  G4double cutEnergy,
374  G4double maxKinEnergy) {
375 
376  // ############## Cross section per atom ################################
377  // Function computes ionization cross section per atom
378  //
379  // See Geant4 physics reference manual (version 9.1), section 9.1.3
380  //
381  // Ref.: W.M. Yao et al, Jour. of Phys. G 33 (2006) 1.
382  // B. Rossi, High energy particles, New York, NY: Prentice-Hall (1952).
383  //
384  // (Implementation adapted from G4BraggIonModel)
385 
386  G4double crosssection = 0.0;
387  G4double tmax = MaxSecondaryEnergy(particle, kineticEnergy);
388  G4double maxEnergy = std::min(tmax, maxKinEnergy);
389 
390  if(cutEnergy < tmax) {
391 
392  G4double energy = kineticEnergy + cacheMass;
393  G4double betaSquared = kineticEnergy *
394  (energy + cacheMass) / (energy * energy);
395 
396  crosssection = 1.0 / cutEnergy - 1.0 / maxEnergy -
397  betaSquared * std::log(maxEnergy / cutEnergy) / tmax;
398 
399  crosssection *= twopi_mc2_rcl2 * cacheChargeSquare / betaSquared;
400  }
401 
402 #ifdef PRINT_DEBUG_CS
403  G4cout << "########################################################"
404  << G4endl
405  << "# G4IonParametrisedLossModel::ComputeCrossSectionPerAtom"
406  << G4endl
407  << "# particle =" << particle -> GetParticleName()
408  << G4endl
409  << "# cut(MeV) = " << cutEnergy/MeV
410  << G4endl;
411 
412  G4cout << "#"
413  << std::setw(13) << std::right << "E(MeV)"
414  << std::setw(14) << "CS(um)"
415  << std::setw(14) << "E_max_sec(MeV)"
416  << G4endl
417  << "# ------------------------------------------------------"
418  << G4endl;
419 
420  G4cout << std::setw(14) << std::right << kineticEnergy / MeV
421  << std::setw(14) << crosssection / (um * um)
422  << std::setw(14) << tmax / MeV
423  << G4endl;
424 #endif
425 
426  crosssection *= atomicNumber;
427 
428  return crosssection;
429 }
430 
431 // #########################################################################
432 
434  const G4Material* material,
436  G4double kineticEnergy,
437  G4double cutEnergy,
438  G4double maxEnergy) {
439 
440  G4double nbElecPerVolume = material -> GetTotNbOfElectPerVolume();
442  kineticEnergy,
443  nbElecPerVolume, 0,
444  cutEnergy,
445  maxEnergy);
446 
447  return cross;
448 }
449 
450 // #########################################################################
451 
453  const G4Material* material,
455  G4double kineticEnergy,
456  G4double cutEnergy) {
457 
458  // ############## dE/dx ##################################################
459  // Function computes dE/dx values, where following rules are adopted:
460  // A. If the ion-material pair is covered by any native ion data
461  // parameterisation, then:
462  // * This parameterization is used for energies below a given energy
463  // limit,
464  // * whereas above the limit the Bethe-Bloch model is applied, in
465  // combination with an effective charge estimate and high order
466  // correction terms.
467  // A smoothing procedure is applied to dE/dx values computed with
468  // the second approach. The smoothing factor is based on the dE/dx
469  // values of both approaches at the transition energy (high order
470  // correction terms are included in the calculation of the transition
471  // factor).
472  // B. If the particle is a generic ion, the BraggIon and Bethe-Bloch
473  // models are used and a smoothing procedure is applied to values
474  // obtained with the second approach.
475  // C. If the ion-material is not covered by any ion data parameterization
476  // then:
477  // * The BraggIon model is used for energies below a given energy
478  // limit,
479  // * whereas above the limit the Bethe-Bloch model is applied, in
480  // combination with an effective charge estimate and high order
481  // correction terms.
482  // Also in this case, a smoothing procedure is applied to dE/dx values
483  // computed with the second model.
484 
485  G4double dEdx = 0.0;
486  UpdateDEDXCache(particle, material, cutEnergy);
487 
488  LossTableList::iterator iter = dedxCacheIter;
489 
490  if(iter != lossTableList.end()) {
491 
492  G4double transitionEnergy = dedxCacheTransitionEnergy;
493 
494  if(transitionEnergy > kineticEnergy) {
495 
496  dEdx = (*iter) -> GetDEDX(particle, material, kineticEnergy);
497 
498  G4double dEdxDeltaRays = DeltaRayMeanEnergyTransferRate(material,
499  particle,
500  kineticEnergy,
501  cutEnergy);
502  dEdx -= dEdxDeltaRays;
503  }
504  else {
506 
507  G4double chargeSquare =
508  GetChargeSquareRatio(particle, material, kineticEnergy);
509 
510  G4double scaledKineticEnergy = kineticEnergy * massRatio;
511  G4double scaledTransitionEnergy = transitionEnergy * massRatio;
512 
513  G4double lowEnergyLimit = betheBlochModel -> LowEnergyLimit();
514 
515  if(scaledTransitionEnergy >= lowEnergyLimit) {
516 
518  material, genericIon,
519  scaledKineticEnergy, cutEnergy);
520 
521  dEdx *= chargeSquare;
522 
523  dEdx += corrections -> ComputeIonCorrections(particle,
524  material, kineticEnergy);
525 
526  G4double factor = 1.0 + dedxCacheTransitionFactor /
527  kineticEnergy;
528 
529  dEdx *= factor;
530  }
531  }
532  }
533  else {
534  G4double massRatio = 1.0;
535  G4double chargeSquare = 1.0;
536 
537  if(particle != genericIon) {
538 
539  chargeSquare = GetChargeSquareRatio(particle, material, kineticEnergy);
540  massRatio = genericIonPDGMass / particle -> GetPDGMass();
541  }
542 
543  G4double scaledKineticEnergy = kineticEnergy * massRatio;
544 
545  G4double lowEnergyLimit = betheBlochModel -> LowEnergyLimit();
546  if(scaledKineticEnergy < lowEnergyLimit) {
548  material, genericIon,
549  scaledKineticEnergy, cutEnergy);
550 
551  dEdx *= chargeSquare;
552  }
553  else {
554  G4double dEdxLimitParam = braggIonModel -> ComputeDEDXPerVolume(
555  material, genericIon,
556  lowEnergyLimit, cutEnergy);
557 
558  G4double dEdxLimitBetheBloch = betheBlochModel -> ComputeDEDXPerVolume(
559  material, genericIon,
560  lowEnergyLimit, cutEnergy);
561 
562  if(particle != genericIon) {
563  G4double chargeSquareLowEnergyLimit =
564  GetChargeSquareRatio(particle, material,
565  lowEnergyLimit / massRatio);
566 
567  dEdxLimitParam *= chargeSquareLowEnergyLimit;
568  dEdxLimitBetheBloch *= chargeSquareLowEnergyLimit;
569 
570  dEdxLimitBetheBloch +=
571  corrections -> ComputeIonCorrections(particle,
572  material, lowEnergyLimit / massRatio);
573  }
574 
575  G4double factor = (1.0 + (dEdxLimitParam/dEdxLimitBetheBloch - 1.0)
576  * lowEnergyLimit / scaledKineticEnergy);
577 
579  material, genericIon,
580  scaledKineticEnergy, cutEnergy);
581 
582  dEdx *= chargeSquare;
583 
584  if(particle != genericIon) {
585  dEdx += corrections -> ComputeIonCorrections(particle,
586  material, kineticEnergy);
587  }
588 
589  dEdx *= factor;
590  }
591 
592  }
593 
594  if (dEdx < 0.0) dEdx = 0.0;
595 
596  return dEdx;
597 }
598 
599 // #########################################################################
600 
602  const G4ParticleDefinition* particle, // Projectile (ion)
603  const G4Material* material, // Absorber material
604  G4double lowerBoundary, // Minimum energy per nucleon
605  G4double upperBoundary, // Maximum energy per nucleon
606  G4int numBins, // Number of bins
607  G4bool logScaleEnergy) { // Logarithmic scaling of energy
608 
609  G4double atomicMassNumber = particle -> GetAtomicMass();
610  G4double materialDensity = material -> GetDensity();
611 
612  G4cout << "# dE/dx table for " << particle -> GetParticleName()
613  << " in material " << material -> GetName()
614  << " of density " << materialDensity / g * cm3
615  << " g/cm3"
616  << G4endl
617  << "# Projectile mass number A1 = " << atomicMassNumber
618  << G4endl
619  << "# ------------------------------------------------------"
620  << G4endl;
621  G4cout << "#"
622  << std::setw(13) << std::right << "E"
623  << std::setw(14) << "E/A1"
624  << std::setw(14) << "dE/dx"
625  << std::setw(14) << "1/rho*dE/dx"
626  << G4endl;
627  G4cout << "#"
628  << std::setw(13) << std::right << "(MeV)"
629  << std::setw(14) << "(MeV)"
630  << std::setw(14) << "(MeV/cm)"
631  << std::setw(14) << "(MeV*cm2/mg)"
632  << G4endl
633  << "# ------------------------------------------------------"
634  << G4endl;
635 
636  G4double energyLowerBoundary = lowerBoundary * atomicMassNumber;
637  G4double energyUpperBoundary = upperBoundary * atomicMassNumber;
638 
639  if(logScaleEnergy) {
640 
641  energyLowerBoundary = std::log(energyLowerBoundary);
642  energyUpperBoundary = std::log(energyUpperBoundary);
643  }
644 
645  G4double deltaEnergy = (energyUpperBoundary - energyLowerBoundary) /
646  G4double(nmbBins);
647 
648  for(int i = 0; i < numBins + 1; i++) {
649 
650  G4double energy = energyLowerBoundary + i * deltaEnergy;
651  if(logScaleEnergy) energy = G4Exp(energy);
652 
653  G4double dedx = ComputeDEDXPerVolume(material, particle, energy, DBL_MAX);
654  G4cout.precision(6);
655  G4cout << std::setw(14) << std::right << energy / MeV
656  << std::setw(14) << energy / atomicMassNumber / MeV
657  << std::setw(14) << dedx / MeV * cm
658  << std::setw(14) << dedx / materialDensity / (MeV*cm2/(0.001*g))
659  << G4endl;
660  }
661 }
662 
663 // #########################################################################
664 
666  const G4ParticleDefinition* particle, // Projectile (ion)
667  const G4Material* material, // Absorber material
668  G4double lowerBoundary, // Minimum energy per nucleon
669  G4double upperBoundary, // Maximum energy per nucleon
670  G4int numBins, // Number of bins
671  G4bool logScaleEnergy) { // Logarithmic scaling of energy
672 
673  LossTableList::iterator iter = lossTableList.begin();
674  LossTableList::iterator iter_end = lossTableList.end();
675 
676  for(;iter != iter_end; iter++) {
677  G4bool isApplicable = (*iter) -> IsApplicable(particle, material);
678  if(isApplicable) {
679  (*iter) -> PrintDEDXTable(particle, material,
680  lowerBoundary, upperBoundary,
681  numBins,logScaleEnergy);
682  break;
683  }
684  }
685 }
686 
687 // #########################################################################
688 
690  std::vector<G4DynamicParticle*>* secondaries,
691  const G4MaterialCutsCouple* couple,
693  G4double cutKinEnergySec,
694  G4double userMaxKinEnergySec) {
695 
696 
697  // ############## Sampling of secondaries #################################
698  // The probability density function (pdf) of the kinetic energy T of a
699  // secondary electron may be written as:
700  // pdf(T) = f(T) * g(T)
701  // where
702  // f(T) = (Tmax - Tcut) / (Tmax * Tcut) * (1 / T^2)
703  // g(T) = 1 - beta^2 * T / Tmax
704  // where Tmax is the maximum kinetic energy of the secondary, Tcut
705  // is the lower energy cut and beta is the kinetic energy of the
706  // projectile.
707  //
708  // Sampling of the kinetic energy of a secondary electron:
709  // 1) T0 is sampled from f(T) using the cumulated distribution function
710  // F(T) = int_Tcut^T f(T')dT'
711  // 2) T is accepted or rejected by evaluating the rejection function g(T)
712  // at the sampled energy T0 against a randomly sampled value
713  //
714  //
715  // See Geant4 physics reference manual (version 9.1), section 9.1.4
716  //
717  //
718  // Reference pdf: W.M. Yao et al, Jour. of Phys. G 33 (2006) 1.
719  //
720  // (Implementation adapted from G4BraggIonModel)
721 
722  G4double rossiMaxKinEnergySec = MaxSecondaryKinEnergy(particle);
723  G4double maxKinEnergySec =
724  std::min(rossiMaxKinEnergySec, userMaxKinEnergySec);
725 
726  if(cutKinEnergySec >= maxKinEnergySec) return;
727 
728  G4double kineticEnergy = particle -> GetKineticEnergy();
729 
730  G4double energy = kineticEnergy + cacheMass;
731  G4double betaSquared = kineticEnergy * (energy + cacheMass)
732  / (energy * energy);
733 
734  G4double kinEnergySec;
735  G4double grej;
736 
737  do {
738 
739  // Sampling kinetic energy from f(T) (using F(T)):
740  G4double xi = G4UniformRand();
741  kinEnergySec = cutKinEnergySec * maxKinEnergySec /
742  (maxKinEnergySec * (1.0 - xi) + cutKinEnergySec * xi);
743 
744  // Deriving the value of the rejection function at the obtained kinetic
745  // energy:
746  grej = 1.0 - betaSquared * kinEnergySec / rossiMaxKinEnergySec;
747 
748  if(grej > 1.0) {
749  G4cout << "G4IonParametrisedLossModel::SampleSecondary Warning: "
750  << "Majorant 1.0 < "
751  << grej << " for e= " << kinEnergySec
752  << G4endl;
753  }
754 
755  } while( G4UniformRand() >= grej );
756 
757  const G4Material* mat = couple->GetMaterial();
759 
761 
762  G4DynamicParticle* delta = new G4DynamicParticle(electron,
763  GetAngularDistribution()->SampleDirection(particle, kinEnergySec,
764  Z, mat),
765  kinEnergySec);
766 
767 
768  secondaries->push_back(delta);
769 
770  // Change kinematics of primary particle
771  G4ThreeVector direction = particle ->GetMomentumDirection();
772  G4double totalMomentum = std::sqrt(kineticEnergy*(energy + cacheMass));
773 
774  G4ThreeVector finalP = totalMomentum*direction - delta->GetMomentum();
775  finalP = finalP.unit();
776 
777  kineticEnergy -= kinEnergySec;
778 
781 }
782 
783 // #########################################################################
784 
787  const G4MaterialCutsCouple* matCutsCouple) {
788 
789  // ############## Caching ##################################################
790  // If the ion-material-cut combination is covered by any native ion data
791  // parameterisation (for low energies), range vectors are computed
792 
793  if(particle == rangeCacheParticle &&
794  matCutsCouple == rangeCacheMatCutsCouple) {
795  }
796  else{
798  rangeCacheMatCutsCouple = matCutsCouple;
799 
800  const G4Material* material = matCutsCouple -> GetMaterial();
801  LossTableList::iterator iter = IsApplicable(particle, material);
802 
803  // If any table is applicable, the transition factor is computed:
804  if(iter != lossTableList.end()) {
805 
806  // Build range-energy and energy-range vectors if they don't exist
807  IonMatCouple ionMatCouple = std::make_pair(particle, matCutsCouple);
808  RangeEnergyTable::iterator iterRange = r.find(ionMatCouple);
809 
810  if(iterRange == r.end()) BuildRangeVector(particle, matCutsCouple);
811 
812  rangeCacheEnergyRange = E[ionMatCouple];
813  rangeCacheRangeEnergy = r[ionMatCouple];
814  }
815  else {
818  }
819  }
820 }
821 
822 // #########################################################################
823 
826  const G4Material* material,
827  G4double cutEnergy) {
828 
829  // ############## Caching ##################################################
830  // If the ion-material combination is covered by any native ion data
831  // parameterisation (for low energies), a transition factor is computed
832  // which is applied to Bethe-Bloch results at higher energies to
833  // guarantee a smooth transition.
834  // This factor only needs to be calculated for the first step an ion
835  // performs inside a certain material.
836 
837  if(particle == dedxCacheParticle &&
838  material == dedxCacheMaterial &&
839  cutEnergy == dedxCacheEnergyCut) {
840  }
841  else {
842 
845  dedxCacheEnergyCut = cutEnergy;
846 
847  G4double massRatio = genericIonPDGMass / particle -> GetPDGMass();
848  dedxCacheGenIonMassRatio = massRatio;
849 
850  LossTableList::iterator iter = IsApplicable(particle, material);
851  dedxCacheIter = iter;
852 
853  // If any table is applicable, the transition factor is computed:
854  if(iter != lossTableList.end()) {
855 
856  // Retrieving the transition energy from the parameterisation table
857  G4double transitionEnergy =
858  (*iter) -> GetUpperEnergyEdge(particle, material);
859  dedxCacheTransitionEnergy = transitionEnergy;
860 
861  // Computing dE/dx from low-energy parameterisation at
862  // transition energy
863  G4double dEdxParam = (*iter) -> GetDEDX(particle, material,
864  transitionEnergy);
865 
866  G4double dEdxDeltaRays = DeltaRayMeanEnergyTransferRate(material,
867  particle,
868  transitionEnergy,
869  cutEnergy);
870  dEdxParam -= dEdxDeltaRays;
871 
872  // Computing dE/dx from Bethe-Bloch formula at transition
873  // energy
874  G4double transitionChargeSquare =
875  GetChargeSquareRatio(particle, material, transitionEnergy);
876 
877  G4double scaledTransitionEnergy = transitionEnergy * massRatio;
878 
879  G4double dEdxBetheBloch =
881  material, genericIon,
882  scaledTransitionEnergy, cutEnergy);
883  dEdxBetheBloch *= transitionChargeSquare;
884 
885  // Additionally, high order corrections are added
886  dEdxBetheBloch +=
887  corrections -> ComputeIonCorrections(particle,
888  material, transitionEnergy);
889 
890  // Computing transition factor from both dE/dx values
892  (dEdxParam - dEdxBetheBloch)/dEdxBetheBloch
893  * transitionEnergy;
894  }
895  else {
896 
899  dedxCacheEnergyCut = cutEnergy;
900 
902  genericIonPDGMass / particle -> GetPDGMass();
903 
906  }
907  }
908 }
909 
910 // #########################################################################
911 
913  const G4MaterialCutsCouple* couple,
914  const G4DynamicParticle* dynamicParticle,
915  G4double& eloss,
916  G4double&,
917  G4double length) {
918 
919  // ############## Corrections for along step energy loss calculation ######
920  // The computed energy loss (due to electronic stopping) is overwritten
921  // by this function if an ion data parameterization is available for the
922  // current ion-material pair.
923  // No action on the energy loss (due to electronic stopping) is performed
924  // if no parameterization is available. In this case the original
925  // generic ion tables (in combination with the effective charge) are used
926  // in the along step DoIt function.
927  //
928  //
929  // (Implementation partly adapted from G4BraggIonModel/G4BetheBlochModel)
930 
931  const G4ParticleDefinition* particle = dynamicParticle -> GetDefinition();
932  const G4Material* material = couple -> GetMaterial();
933 
934  G4double kineticEnergy = dynamicParticle -> GetKineticEnergy();
935 
936  if(kineticEnergy == eloss) { return; }
937 
938  G4double cutEnergy = DBL_MAX;
939  size_t cutIndex = couple -> GetIndex();
940  cutEnergy = cutEnergies[cutIndex];
941 
942  UpdateDEDXCache(particle, material, cutEnergy);
943 
944  LossTableList::iterator iter = dedxCacheIter;
945 
946  // If parameterization for ions is available the electronic energy loss
947  // is overwritten
948  if(iter != lossTableList.end()) {
949 
950  // The energy loss is calculated using the ComputeDEDXPerVolume function
951  // and the step length (it is assumed that dE/dx does not change
952  // considerably along the step)
953  eloss =
954  length * ComputeDEDXPerVolume(material, particle,
955  kineticEnergy, cutEnergy);
956 
957 #ifdef PRINT_DEBUG
958  G4cout.precision(6);
959  G4cout << "########################################################"
960  << G4endl
961  << "# G4IonParametrisedLossModel::CorrectionsAlongStep"
962  << G4endl
963  << "# cut(MeV) = " << cutEnergy/MeV
964  << G4endl;
965 
966  G4cout << "#"
967  << std::setw(13) << std::right << "E(MeV)"
968  << std::setw(14) << "l(um)"
969  << std::setw(14) << "l*dE/dx(MeV)"
970  << std::setw(14) << "(l*dE/dx)/E"
971  << G4endl
972  << "# ------------------------------------------------------"
973  << G4endl;
974 
975  G4cout << std::setw(14) << std::right << kineticEnergy / MeV
976  << std::setw(14) << length / um
977  << std::setw(14) << eloss / MeV
978  << std::setw(14) << eloss / kineticEnergy * 100.0
979  << G4endl;
980 #endif
981 
982  // If the energy loss exceeds a certain fraction of the kinetic energy
983  // (the fraction is indicated by the parameter "energyLossLimit") then
984  // the range tables are used to derive a more accurate value of the
985  // energy loss
986  if(eloss > energyLossLimit * kineticEnergy) {
987 
988  eloss = ComputeLossForStep(couple, particle,
989  kineticEnergy,length);
990 
991 #ifdef PRINT_DEBUG
992  G4cout << "# Correction applied:"
993  << G4endl;
994 
995  G4cout << std::setw(14) << std::right << kineticEnergy / MeV
996  << std::setw(14) << length / um
997  << std::setw(14) << eloss / MeV
998  << std::setw(14) << eloss / kineticEnergy * 100.0
999  << G4endl;
1000 #endif
1001 
1002  }
1003  }
1004 
1005  // For all corrections below a kinetic energy between the Pre- and
1006  // Post-step energy values is used
1007  G4double energy = kineticEnergy - eloss * 0.5;
1008  if(energy < 0.0) energy = kineticEnergy * 0.5;
1009 
1010  G4double chargeSquareRatio = corrections ->
1011  EffectiveChargeSquareRatio(particle,
1012  material,
1013  energy);
1014  GetModelOfFluctuations() -> SetParticleAndCharge(particle,
1015  chargeSquareRatio);
1016 
1017  // A correction is applied considering the change of the effective charge
1018  // along the step (the parameter "corrFactor" refers to the effective
1019  // charge at the beginning of the step). Note: the correction is not
1020  // applied for energy loss values deriving directly from parameterized
1021  // ion stopping power tables
1022  G4double transitionEnergy = dedxCacheTransitionEnergy;
1023 
1024  if(iter != lossTableList.end() && transitionEnergy < kineticEnergy) {
1025  chargeSquareRatio *= corrections -> EffectiveChargeCorrection(particle,
1026  material,
1027  energy);
1028 
1029  G4double chargeSquareRatioCorr = chargeSquareRatio/corrFactor;
1030  eloss *= chargeSquareRatioCorr;
1031  }
1032  else if (iter == lossTableList.end()) {
1033 
1034  chargeSquareRatio *= corrections -> EffectiveChargeCorrection(particle,
1035  material,
1036  energy);
1037 
1038  G4double chargeSquareRatioCorr = chargeSquareRatio/corrFactor;
1039  eloss *= chargeSquareRatioCorr;
1040  }
1041 
1042  // Ion high order corrections are applied if the current model does not
1043  // overwrite the energy loss (i.e. when the effective charge approach is
1044  // used)
1045  if(iter == lossTableList.end()) {
1046 
1047  G4double scaledKineticEnergy = kineticEnergy * dedxCacheGenIonMassRatio;
1048  G4double lowEnergyLimit = betheBlochModel -> LowEnergyLimit();
1049 
1050  // Corrections are only applied in the Bethe-Bloch energy region
1051  if(scaledKineticEnergy > lowEnergyLimit)
1052  eloss += length *
1053  corrections -> IonHighOrderCorrections(particle, couple, energy);
1054  }
1055 }
1056 
1057 // #########################################################################
1058 
1061  const G4MaterialCutsCouple* matCutsCouple) {
1062 
1063  G4double cutEnergy = DBL_MAX;
1064  size_t cutIndex = matCutsCouple -> GetIndex();
1065  cutEnergy = cutEnergies[cutIndex];
1066 
1067  const G4Material* material = matCutsCouple -> GetMaterial();
1068 
1069  G4double massRatio = genericIonPDGMass / particle -> GetPDGMass();
1070 
1071  G4double lowerEnergy = lowerEnergyEdgeIntegr / massRatio;
1072  G4double upperEnergy = upperEnergyEdgeIntegr / massRatio;
1073 
1074  G4double logLowerEnergyEdge = std::log(lowerEnergy);
1075  G4double logUpperEnergyEdge = std::log(upperEnergy);
1076 
1077  G4double logDeltaEnergy = (logUpperEnergyEdge - logLowerEnergyEdge) /
1078  G4double(nmbBins);
1079 
1080  G4double logDeltaIntegr = logDeltaEnergy / G4double(nmbSubBins);
1081 
1082  G4LPhysicsFreeVector* energyRangeVector =
1084  lowerEnergy,
1085  upperEnergy);
1086 
1087  G4double dedxLow = ComputeDEDXPerVolume(material,
1088  particle,
1089  lowerEnergy,
1090  cutEnergy);
1091 
1092  G4double range = 2.0 * lowerEnergy / dedxLow;
1093 
1094  energyRangeVector -> PutValues(0, lowerEnergy, range);
1095 
1096  G4double logEnergy = std::log(lowerEnergy);
1097  for(size_t i = 1; i < nmbBins+1; i++) {
1098 
1099  G4double logEnergyIntegr = logEnergy;
1100 
1101  for(size_t j = 0; j < nmbSubBins; j++) {
1102 
1103  G4double binLowerBoundary = G4Exp(logEnergyIntegr);
1104  logEnergyIntegr += logDeltaIntegr;
1105 
1106  G4double binUpperBoundary = G4Exp(logEnergyIntegr);
1107  G4double deltaIntegr = binUpperBoundary - binLowerBoundary;
1108 
1109  G4double energyIntegr = binLowerBoundary + 0.5 * deltaIntegr;
1110 
1111  G4double dedxValue = ComputeDEDXPerVolume(material,
1112  particle,
1113  energyIntegr,
1114  cutEnergy);
1115 
1116  if(dedxValue > 0.0) range += deltaIntegr / dedxValue;
1117 
1118 #ifdef PRINT_DEBUG_DETAILS
1119  G4cout << " E = "<< energyIntegr/MeV
1120  << " MeV -> dE = " << deltaIntegr/MeV
1121  << " MeV -> dE/dx = " << dedxValue/MeV*mm
1122  << " MeV/mm -> dE/(dE/dx) = " << deltaIntegr /
1123  dedxValue / mm
1124  << " mm -> range = " << range / mm
1125  << " mm " << G4endl;
1126 #endif
1127  }
1128 
1129  logEnergy += logDeltaEnergy;
1130 
1131  G4double energy = G4Exp(logEnergy);
1132 
1133  energyRangeVector -> PutValues(i, energy, range);
1134 
1135 #ifdef PRINT_DEBUG_DETAILS
1136  G4cout << "G4IonParametrisedLossModel::BuildRangeVector() bin = "
1137  << i <<", E = "
1138  << energy / MeV << " MeV, R = "
1139  << range / mm << " mm"
1140  << G4endl;
1141 #endif
1142 
1143  }
1144  energyRangeVector -> SetSpline(true);
1145 
1146  G4double lowerRangeEdge =
1147  energyRangeVector -> Value(lowerEnergy);
1148  G4double upperRangeEdge =
1149  energyRangeVector -> Value(upperEnergy);
1150 
1151  G4LPhysicsFreeVector* rangeEnergyVector
1152  = new G4LPhysicsFreeVector(nmbBins+1,
1153  lowerRangeEdge,
1154  upperRangeEdge);
1155 
1156  for(size_t i = 0; i < nmbBins+1; i++) {
1157  G4double energy = energyRangeVector -> Energy(i);
1158  rangeEnergyVector ->
1159  PutValues(i, energyRangeVector -> Value(energy), energy);
1160  }
1161 
1162  rangeEnergyVector -> SetSpline(true);
1163 
1164 #ifdef PRINT_DEBUG_TABLES
1165  G4cout << *energyLossVector
1166  << *energyRangeVector
1167  << *rangeEnergyVector << G4endl;
1168 #endif
1169 
1170  IonMatCouple ionMatCouple = std::make_pair(particle, matCutsCouple);
1171 
1172  E[ionMatCouple] = energyRangeVector;
1173  r[ionMatCouple] = rangeEnergyVector;
1174 }
1175 
1176 // #########################################################################
1177 
1179  const G4MaterialCutsCouple* matCutsCouple,
1181  G4double kineticEnergy,
1182  G4double stepLength) {
1183 
1184  G4double loss = 0.0;
1185 
1186  UpdateRangeCache(particle, matCutsCouple);
1187 
1188  G4PhysicsVector* energyRange = rangeCacheEnergyRange;
1189  G4PhysicsVector* rangeEnergy = rangeCacheRangeEnergy;
1190 
1191  if(energyRange != 0 && rangeEnergy != 0) {
1192 
1193  G4double lowerEnEdge = energyRange -> Energy( 0 );
1194  G4double lowerRangeEdge = rangeEnergy -> Energy( 0 );
1195 
1196  // Computing range for pre-step kinetic energy:
1197  G4double range = energyRange -> Value(kineticEnergy);
1198 
1199  // Energy below vector boundary:
1200  if(kineticEnergy < lowerEnEdge) {
1201 
1202  range = energyRange -> Value(lowerEnEdge);
1203  range *= std::sqrt(kineticEnergy / lowerEnEdge);
1204  }
1205 
1206 #ifdef PRINT_DEBUG
1207  G4cout << "G4IonParametrisedLossModel::ComputeLossForStep() range = "
1208  << range / mm << " mm, step = " << stepLength / mm << " mm"
1209  << G4endl;
1210 #endif
1211 
1212  // Remaining range:
1213  G4double remRange = range - stepLength;
1214 
1215  // If range is smaller than step length, the loss is set to kinetic
1216  // energy
1217  if(remRange < 0.0) loss = kineticEnergy;
1218  else if(remRange < lowerRangeEdge) {
1219 
1220  G4double ratio = remRange / lowerRangeEdge;
1221  loss = kineticEnergy - ratio * ratio * lowerEnEdge;
1222  }
1223  else {
1224 
1225  G4double energy = rangeEnergy -> Value(range - stepLength);
1226  loss = kineticEnergy - energy;
1227  }
1228  }
1229 
1230  if(loss < 0.0) loss = 0.0;
1231 
1232  return loss;
1233 }
1234 
1235 // #########################################################################
1236 
1238  const G4String& nam,
1239  G4VIonDEDXTable* table,
1241 
1242  if(table == 0) {
1243  G4cout << "G4IonParametrisedLossModel::AddDEDXTable() Cannot "
1244  << " add table: Invalid pointer."
1245  << G4endl;
1246 
1247  return false;
1248  }
1249 
1250  // Checking uniqueness of name
1251  LossTableList::iterator iter = lossTableList.begin();
1252  LossTableList::iterator iter_end = lossTableList.end();
1253 
1254  for(;iter != iter_end; ++iter) {
1255  const G4String& tableName = (*iter)->GetName();
1256 
1257  if(tableName == nam) {
1258  G4cout << "G4IonParametrisedLossModel::AddDEDXTable() Cannot "
1259  << " add table: Name already exists."
1260  << G4endl;
1261 
1262  return false;
1263  }
1264  }
1265 
1266  G4VIonDEDXScalingAlgorithm* scalingAlgorithm = algorithm;
1267  if(scalingAlgorithm == 0)
1268  scalingAlgorithm = new G4VIonDEDXScalingAlgorithm;
1269 
1270  G4IonDEDXHandler* handler =
1271  new G4IonDEDXHandler(table, scalingAlgorithm, nam);
1272 
1273  lossTableList.push_front(handler);
1274 
1275  return true;
1276 }
1277 
1278 // #########################################################################
1279 
1281  const G4String& nam) {
1282 
1283  LossTableList::iterator iter = lossTableList.begin();
1284  LossTableList::iterator iter_end = lossTableList.end();
1285 
1286  for(;iter != iter_end; iter++) {
1287  G4String tableName = (*iter) -> GetName();
1288 
1289  if(tableName == nam) {
1290  delete (*iter);
1291 
1292  // Remove from table list
1293  lossTableList.erase(iter);
1294 
1295  // Range vs energy and energy vs range vectors are cleared
1296  RangeEnergyTable::iterator iterRange = r.begin();
1297  RangeEnergyTable::iterator iterRange_end = r.end();
1298 
1299  for(;iterRange != iterRange_end; iterRange++)
1300  delete iterRange -> second;
1301  r.clear();
1302 
1303  EnergyRangeTable::iterator iterEnergy = E.begin();
1304  EnergyRangeTable::iterator iterEnergy_end = E.end();
1305 
1306  for(;iterEnergy != iterEnergy_end; iterEnergy++)
1307  delete iterEnergy -> second;
1308  E.clear();
1309 
1310  return true;
1311  }
1312  }
1313 
1314  return false;
1315 }
1316 
1317 // #########################################################################
1318 /*
1319 void G4IonParametrisedLossModel::DeactivateICRU73Scaling() {
1320 
1321  RemoveDEDXTable("ICRU73");
1322  AddDEDXTable("ICRU73", new G4IonStoppingData("ion_stopping_data/icru73"));
1323 }
1324 */
1325 // #########################################################################