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