source: trunk/source/processes/electromagnetic/lowenergy/src/G4IonParametrisedLossModel.cc@ 1199

Last change on this file since 1199 was 1192, checked in by garnier, 16 years ago

update par rapport a CVS

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