Geant4 Cross Reference

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