Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4Radioactivation.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// File: G4Radioactivation.cc //
29// Author: D.H. Wright (SLAC) //
30// Date: 29 August 2017 //
31// Description: activation process derived from the original //
32// G4RadioactiveDecay of F. Lei and P.R. Truscott in which //
33// biasing and activation calculations are separated from the //
34// unbiased decay chain calculation performed in the base //
35// class. //
36// //
37////////////////////////////////////////////////////////////////////////////////
38
39#include "G4Radioactivation.hh"
41
42#include "G4SystemOfUnits.hh"
43#include "G4DynamicParticle.hh"
44#include "G4DecayProducts.hh"
45#include "G4DecayTable.hh"
47#include "G4ITDecay.hh"
48#include "G4BetaDecayType.hh"
49#include "G4BetaMinusDecay.hh"
50#include "G4BetaPlusDecay.hh"
51#include "G4ECDecay.hh"
52#include "G4AlphaDecay.hh"
53#include "G4TritonDecay.hh"
54#include "G4ProtonDecay.hh"
55#include "G4NeutronDecay.hh"
56#include "G4SFDecay.hh"
57#include "G4VDecayChannel.hh"
58#include "G4NuclearDecay.hh"
60#include "G4Fragment.hh"
61#include "G4Ions.hh"
62#include "G4IonTable.hh"
63#include "G4BetaDecayType.hh"
64#include "Randomize.hh"
66#include "G4NuclearLevelData.hh"
68#include "G4LevelManager.hh"
69#include "G4ThreeVector.hh"
70#include "G4Electron.hh"
71#include "G4Positron.hh"
72#include "G4Neutron.hh"
73#include "G4Gamma.hh"
74#include "G4Alpha.hh"
75#include "G4Triton.hh"
76#include "G4Proton.hh"
77
81#include "G4LossTableManager.hh"
85
86#include <vector>
87#include <sstream>
88#include <algorithm>
89#include <fstream>
90
91using namespace CLHEP;
92
94 : G4RadioactiveDecay(processName)
95{
96#ifdef G4VERBOSE
97 if (GetVerboseLevel() > 1) {
98 G4cout << "G4Radioactivation constructor: processName = " << processName
99 << G4endl;
100 }
101#endif
102
103// DHW SetProcessSubType(fRadioactiveDecay);
105
106 // Apply default values.
107 NSourceBin = 1;
108 SBin[0] = 0.* s;
109 SBin[1] = 1.* s; // Convert to ns
110 SProfile[0] = 1.;
111 SProfile[1] = 0.;
112 NDecayBin = 1;
113 DBin[0] = 0. * s ;
114 DBin[1] = 1. * s;
115 DProfile[0] = 1.;
116 DProfile[1] = 0.;
117 decayWindows[0] = 0;
119 theRadioactivityTables.push_back(rTable);
120 NSplit = 1;
121 AnalogueMC = true;
122 BRBias = true;
123 halflifethreshold = 1000.*nanosecond;
124}
125
126
127void G4Radioactivation::ProcessDescription(std::ostream& outFile) const
128{
129 outFile << "The G4Radioactivation process performs radioactive decay of\n"
130 << "nuclides (G4GenericIon) in biased mode which includes nucleus\n"
131 << "duplication, branching ratio biasing, source time convolution\n"
132 << "and detector time convolution. It is designed for use in\n"
133 << "activation physics.\n"
134 << "The required half-lives and decay schemes are retrieved from\n"
135 << "the RadioactiveDecay database which was derived from ENSDF.\n";
136}
137
138
140{
142}
143
145{
146 G4String key = aNucleus->GetParticleName();
147 DecayTableMap::iterator table_ptr = dkmap->find(key);
148
149 G4DecayTable* theDecayTable = 0;
150 if (table_ptr == dkmap->end() ) { // If table not there,
151 theDecayTable = LoadDecayTable(*aNucleus); // load from file and
152 if(theDecayTable) (*dkmap)[key] = theDecayTable; // store in library
153 } else {
154 theDecayTable = table_ptr->second;
155 }
156 return theDecayTable;
157}
158
159G4bool
161{
162 // Check whether the radioactive decay rates table for the ion has already
163 // been calculated.
164 G4String aParticleName = aParticle.GetParticleName();
165 for (std::size_t i = 0; i < theParentChainTable.size(); ++i) {
166 if (theParentChainTable[i].GetIonName() == aParticleName) return true;
167 }
168 return false;
169}
170
171
172void
174{
175 // Retrieve the decay rate table for the specified aParticle
176 G4String aParticleName = aParticle.GetParticleName();
177
178 for (std::size_t i = 0; i < theParentChainTable.size(); ++i) {
179 if (theParentChainTable[i].GetIonName() == aParticleName) {
180 theDecayRateVector = theParentChainTable[i].GetItsRates();
181 }
182 }
183#ifdef G4VERBOSE
184 if (GetVerboseLevel() > 1) {
185 G4cout << "The DecayRate Table for " << aParticleName << " is selected."
186 << G4endl;
187 }
188#endif
189}
190
191// ConvolveSourceTimeProfile performs the convolution of the source time profile
192// function with a single exponential characterized by a decay constant in the
193// decay chain. The time profile is treated as a step function so that the
194// convolution integral can be done bin-by-bin.
195// This implements Eq. 4.13 of DERA technical note, with SProfile[i] = F(t')
196
199{
200 G4double convolvedTime = 0.0;
201 G4int nbin;
202 if ( t > SBin[NSourceBin]) {
203 nbin = NSourceBin;
204 } else {
205 nbin = 0;
206
207 G4int loop = 0;
208 while (t > SBin[nbin]) { // Loop checking, 01.09.2015, D.Wright
209 loop++;
210 if (loop > 1000) {
211 G4Exception("G4Radioactivation::ConvolveSourceTimeProfile()",
212 "HAD_RDM_100", JustWarning, "While loop count exceeded");
213 break;
214 }
215 nbin++;
216 }
217 nbin--;
218 }
219
220 // Use expm1 wherever possible to avoid large cancellation errors in
221 // 1 - exp(x) for small x
222 G4double earg = 0.0;
223 if (nbin > 0) {
224 for (G4int i = 0; i < nbin; i++) {
225 earg = (SBin[i+1] - SBin[i])/tau;
226 if (earg < 100.) {
227 convolvedTime += SProfile[i] * std::exp((SBin[i] - t)/tau) *
228 std::expm1(earg);
229 } else {
230 convolvedTime += SProfile[i] *
231 (std::exp(-(t-SBin[i+1])/tau)-std::exp(-(t-SBin[i])/tau));
232 }
233 }
234 }
235 convolvedTime -= SProfile[nbin] * std::expm1((SBin[nbin] - t)/tau);
236 // tau divided out of final result to provide probability of decay in window
237
238 if (convolvedTime < 0.) {
239 G4cout << " Convolved time =: " << convolvedTime << " reset to zero! " << G4endl;
240 G4cout << " t = " << t << " tau = " << tau << G4endl;
241 G4cout << SBin[nbin] << " " << SBin[0] << G4endl;
242 convolvedTime = 0.;
243 }
244#ifdef G4VERBOSE
245 if (GetVerboseLevel() > 2)
246 G4cout << " Convolved time: " << convolvedTime << G4endl;
247#endif
248 return convolvedTime;
249}
250
251
252////////////////////////////////////////////////////////////////////////////////
253// //
254// GetDecayTime //
255// Randomly select a decay time for the decay process, following the //
256// supplied decay time bias scheme. //
257// //
258////////////////////////////////////////////////////////////////////////////////
259
261{
262 G4double decaytime = 0.;
263 G4double rand = G4UniformRand();
264 G4int i = 0;
265
266 G4int loop = 0;
267 while (DProfile[i] < rand) { /* Loop checking, 01.09.2015, D.Wright */
268 // Entries in DProfile[i] are all between 0 and 1 and arranged in inreaseing order
269 // Comparison with rand chooses which time bin to sample
270 i++;
271 loop++;
272 if (loop > 100000) {
273 G4Exception("G4Radioactivation::GetDecayTime()", "HAD_RDM_100",
274 JustWarning, "While loop count exceeded");
275 break;
276 }
277 }
278
279 rand = G4UniformRand();
280 decaytime = DBin[i] + rand*(DBin[i+1]-DBin[i]);
281#ifdef G4VERBOSE
282 if (GetVerboseLevel() > 2)
283 G4cout <<" Decay time: " <<decaytime/s <<"[s]" <<G4endl;
284#endif
285 return decaytime;
286}
287
288
290{
291 G4int i = 0;
292
293 G4int loop = 0;
294 while (aDecayTime > DBin[i] ) { /* Loop checking, 01.09.2015, D.Wright */
295 i++;
296 loop++;
297 if (loop > 100000) {
298 G4Exception("G4Radioactivation::GetDecayTimeBin()", "HAD_RDM_100",
299 JustWarning, "While loop count exceeded");
300 break;
301 }
302 }
303
304 return i;
305}
306
307////////////////////////////////////////////////////////////////////////////////
308// //
309// GetMeanLifeTime (required by the base class) //
310// //
311////////////////////////////////////////////////////////////////////////////////
312
315{
316 // For variance reduction time is set to 0 so as to force the particle
317 // to decay immediately.
318 // In analogue mode it returns the particle's mean-life.
319 G4double meanlife = 0.;
320 if (AnalogueMC) meanlife = G4RadioactiveDecay::GetMeanLifeTime(theTrack, 0);
321 return meanlife;
322}
323
324
325void
327 G4int theG, std::vector<G4double> theCoefficients,
328 std::vector<G4double> theTaos)
329// Why not make this a method of G4RadioactiveDecayRate? (e.g. SetParameters)
330{
331 //fill the decay rate vector
332 ratesToDaughter.SetZ(theZ);
333 ratesToDaughter.SetA(theA);
334 ratesToDaughter.SetE(theE);
335 ratesToDaughter.SetGeneration(theG);
336 ratesToDaughter.SetDecayRateC(theCoefficients);
337 ratesToDaughter.SetTaos(theTaos);
338}
339
340
342CalculateChainsFromParent(const G4ParticleDefinition& theParentNucleus)
343{
344 // Use extended Bateman equation to calculate the radioactivities of all
345 // progeny of theParentNucleus. The coefficients required to do this are
346 // calculated using the method of P. Truscott (Ph.D. thesis and
347 // DERA Technical Note DERA/CIS/CIS2/7/36/4/10) 11 January 2000.
348 // Coefficients are then added to the decay rate table vector
349
350 // Create and initialise variables used in the method.
351 theDecayRateVector.clear();
352
353 G4int nGeneration = 0;
354
355 std::vector<G4double> taos;
356
357 // Dimensionless A coefficients of Eqs. 4.24 and 4.25 of the TN
358 std::vector<G4double> Acoeffs;
359
360 // According to Eq. 4.26 the first coefficient (A_1:1) is -1
361 Acoeffs.push_back(-1.);
362
363 G4int A = ((const G4Ions*)(&theParentNucleus))->GetAtomicMass();
364 G4int Z = ((const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
365 G4double E = ((const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
366 G4double tao = theParentNucleus.GetPDGLifeTime();
367 if (tao < 0.) tao = 1e-100;
368 taos.push_back(tao);
369 G4int nEntry = 0;
370
371 // Fill the decay rate container (G4RadioactiveDecayRate) with the parent
372 // isotope data
373 SetDecayRate(Z,A,E,nGeneration,Acoeffs,taos); // Fill TP with parent lifetime
374
375 // store the decay rate in decay rate vector
376 theDecayRateVector.push_back(ratesToDaughter);
377 nEntry++;
378
379 // Now start treating the secondary generations.
380 G4bool stable = false;
381// G4int i;
382 G4int j;
383 G4VDecayChannel* theChannel = 0;
384 G4NuclearDecay* theNuclearDecayChannel = 0;
385
386 G4ITDecay* theITChannel = 0;
387 G4BetaMinusDecay* theBetaMinusChannel = 0;
388 G4BetaPlusDecay* theBetaPlusChannel = 0;
389 G4AlphaDecay* theAlphaChannel = 0;
390 G4ProtonDecay* theProtonChannel = 0;
391 G4TritonDecay* theTritonChannel = 0;
392 G4NeutronDecay* theNeutronChannel = 0;
393 G4SFDecay* theFissionChannel = 0;
394
395 G4RadioactiveDecayMode theDecayMode;
396 G4double theBR = 0.0;
397 G4int AP = 0;
398 G4int ZP = 0;
399 G4int AD = 0;
400 G4int ZD = 0;
401 G4double EP = 0.;
402 std::vector<G4double> TP;
403 std::vector<G4double> RP; // A coefficients of the previous generation
404 G4ParticleDefinition *theDaughterNucleus;
405 G4double daughterExcitation;
406 G4double nearestEnergy = 0.0;
407 G4int nearestLevelIndex = 0;
408 G4ParticleDefinition *aParentNucleus;
409 G4IonTable* theIonTable;
410 G4DecayTable* parentDecayTable;
411 G4double theRate;
412 G4double TaoPlus;
413 G4int nS = 0; // Running index of first decay in a given generation
414 G4int nT = nEntry; // Total number of decays accumulated over entire history
415 const G4int nMode = G4RadioactiveDecayModeSize;
416 G4double brs[nMode];
417 //
418 theIonTable =
420
421 G4int loop = 0;
422 while (!stable) { /* Loop checking, 01.09.2015, D.Wright */
423 loop++;
424 if (loop > 10000) {
425 G4Exception("G4Radioactivation::CalculateChainsFromParent()", "HAD_RDM_100",
426 JustWarning, "While loop count exceeded");
427 break;
428 }
429 nGeneration++;
430 for (j = nS; j < nT; j++) {
431 // First time through, get data for parent nuclide
432 ZP = theDecayRateVector[j].GetZ();
433 AP = theDecayRateVector[j].GetA();
434 EP = theDecayRateVector[j].GetE();
435 RP = theDecayRateVector[j].GetDecayRateC();
436 TP = theDecayRateVector[j].GetTaos();
437 if (GetVerboseLevel() > 1) {
438 G4cout << "G4RadioactiveDecay::CalculateChainsFromParent: daughters of ("
439 << ZP << ", " << AP << ", " << EP
440 << ") are being calculated, generation = " << nGeneration
441 << G4endl;
442 }
443// G4cout << " Taus = " << G4endl;
444// for (G4int ii = 0; ii < TP.size(); ii++) G4cout << TP[ii] << ", " ;
445// G4cout << G4endl;
446
447 aParentNucleus = theIonTable->GetIon(ZP,AP,EP);
448 parentDecayTable = GetDecayTable1(aParentNucleus);
449
450 G4DecayTable* summedDecayTable = new G4DecayTable();
451 // This instance of G4DecayTable is for accumulating BRs and decay
452 // channels. It will contain one decay channel per type of decay
453 // (alpha, beta, etc.); its branching ratio will be the sum of all
454 // branching ratios for that type of decay of the parent. If the
455 // halflife of a particular channel is longer than some threshold,
456 // that channel will be inserted specifically and its branching
457 // ratio will not be included in the above sums.
458 // This instance is not used to perform actual decays.
459
460 for (G4int k = 0; k < nMode; k++) brs[k] = 0.0;
461
462 // Go through the decay table and sum all channels having the same decay mode
463 for (G4int i = 0; i < parentDecayTable->entries(); i++) {
464 theChannel = parentDecayTable->GetDecayChannel(i);
465 theNuclearDecayChannel = static_cast<G4NuclearDecay*>(theChannel);
466 theDecayMode = theNuclearDecayChannel->GetDecayMode();
467 daughterExcitation = theNuclearDecayChannel->GetDaughterExcitation();
468 theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus() ;
469 AD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
470 ZD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
471 const G4LevelManager* levelManager =
473
474 // Check each nuclide to see if it is metastable (lifetime > 1 usec)
475 // If so, add it to the decay chain by inserting its decay channel in
476 // summedDecayTable. If not, just add its BR to sum for that decay mode.
477 if (levelManager->NumberOfTransitions() ) {
478 nearestEnergy = levelManager->NearestLevelEnergy(daughterExcitation);
479 if (std::abs(daughterExcitation - nearestEnergy) < levelTolerance) {
480 // Level half-life is in ns and the threshold is set to 1 micros
481 // by default, user can set it via the UI command
482 nearestLevelIndex = (G4int)levelManager->NearestLevelIndex(daughterExcitation);
483 if (levelManager->LifeTime(nearestLevelIndex)*ns >= halflifethreshold){
484 // save the metastable decay channel
485 summedDecayTable->Insert(theChannel);
486 } else {
487 brs[theDecayMode] += theChannel->GetBR();
488 }
489 } else {
490 brs[theDecayMode] += theChannel->GetBR();
491 }
492 } else {
493 brs[theDecayMode] += theChannel->GetBR();
494 }
495
496 } // Combine decay channels (loop i)
497
498 brs[BetaPlus] = brs[BetaPlus]+brs[KshellEC]+brs[LshellEC]+brs[MshellEC]+brs[NshellEC]; // Combine beta+ and EC
499 brs[KshellEC] = brs[LshellEC] = brs[MshellEC] = brs[NshellEC] = 0.0;
500 for (G4int i = 0; i < nMode; i++) { // loop over decay modes
501 if (brs[i] > 0.) {
502 switch (i) {
503 case IT:
504 // Decay mode is isomeric transition
505 theITChannel = new G4ITDecay(aParentNucleus, brs[IT], 0.0, 0.0,
507
508 summedDecayTable->Insert(theITChannel);
509 break;
510
511 case BetaMinus:
512 // Decay mode is beta-
513 theBetaMinusChannel = new G4BetaMinusDecay(aParentNucleus, brs[BetaMinus],
514 0.*MeV, 0.*MeV,
516 summedDecayTable->Insert(theBetaMinusChannel);
517 break;
518
519 case BetaPlus:
520 // Decay mode is beta+ + EC.
521 theBetaPlusChannel = new G4BetaPlusDecay(aParentNucleus, brs[BetaPlus],
522 0.*MeV, 0.*MeV,
524 summedDecayTable->Insert(theBetaPlusChannel);
525 break;
526
527 case Alpha:
528 // Decay mode is alpha.
529 theAlphaChannel = new G4AlphaDecay(aParentNucleus, brs[Alpha], 0.*MeV,
530 0.*MeV, noFloat);
531 summedDecayTable->Insert(theAlphaChannel);
532 break;
533
534 case Proton:
535 // Decay mode is proton.
536 theProtonChannel = new G4ProtonDecay(aParentNucleus, brs[Proton], 0.*MeV,
537 0.*MeV, noFloat);
538 summedDecayTable->Insert(theProtonChannel);
539 break;
540
541 case Neutron:
542 // Decay mode is neutron.
543 theNeutronChannel = new G4NeutronDecay(aParentNucleus, brs[Neutron], 0.*MeV,
544 0.*MeV, noFloat);
545 summedDecayTable->Insert(theNeutronChannel);
546 break;
547
548 case SpFission:
549 // Decay mode is spontaneous fission
550 theFissionChannel = new G4SFDecay(aParentNucleus, brs[SpFission], 0.*MeV,
551 0.*MeV, noFloat);
552 summedDecayTable->Insert(theFissionChannel);
553 break;
554
555 case BDProton:
556 // Not yet implemented
557 break;
558
559 case BDNeutron:
560 // Not yet implemented
561 break;
562
563 case Beta2Minus:
564 // Not yet implemented
565 break;
566
567 case Beta2Plus:
568 // Not yet implemented
569 break;
570
571 case Proton2:
572 // Not yet implemented
573 break;
574
575 case Neutron2:
576 // Not yet implemented
577 break;
578
579 case Triton:
580 // Decay mode is Triton.
581 theTritonChannel = new G4TritonDecay(aParentNucleus, brs[Triton], 0.*MeV,
582 0.*MeV, noFloat);
583 summedDecayTable->Insert(theTritonChannel);
584 break;
585
586 default:
587 break;
588 }
589 }
590 }
591
592 // loop over all branches in summedDecayTable
593 //
594 for (G4int i = 0; i < summedDecayTable->entries(); i++){
595 theChannel = summedDecayTable->GetDecayChannel(i);
596 theNuclearDecayChannel = static_cast<G4NuclearDecay*>(theChannel);
597 theBR = theChannel->GetBR();
598 theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus();
599
600 // First check if the decay of the original nucleus is an IT channel,
601 // if true create a new ground-state nucleus
602 if (theNuclearDecayChannel->GetDecayMode() == IT && nGeneration == 1) {
603
604 A = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
605 Z = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
606 theDaughterNucleus=theIonTable->GetIon(Z,A,0.);
607 }
608 if (IsApplicable(*theDaughterNucleus) && theBR > 0.0 &&
609 aParentNucleus != theDaughterNucleus) {
610 // need to make sure daughter has decay table
611 parentDecayTable = GetDecayTable1(theDaughterNucleus);
612 if (parentDecayTable->entries() ) {
613 A = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
614 Z = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
615 E = ((const G4Ions*)(theDaughterNucleus))->GetExcitationEnergy();
616
617 TaoPlus = theDaughterNucleus->GetPDGLifeTime();
618 if (TaoPlus <= 0.) TaoPlus = 1e-100;
619
620 // first set the taos, one simply need to add to the parent ones
621 taos.clear();
622 taos = TP; // load lifetimes of all previous generations
623 std::size_t k;
624 //check that TaoPlus differs from other taos from at least 1.e5 relative difference
625 //for (k = 0; k < TP.size(); k++){
626 //if (std::abs((TaoPlus-TP[k])/TP[k])<1.e-5 ) TaoPlus=1.00001*TP[k];
627 //}
628 taos.push_back(TaoPlus); // add daughter lifetime to list
629 // now calculate the coefficiencies
630 //
631 // they are in two parts, first the less than n ones
632 // Eq 4.24 of the TN
633 Acoeffs.clear();
634 long double ta1,ta2;
635 ta2 = (long double)TaoPlus;
636 for (k = 0; k < RP.size(); k++){
637 ta1 = (long double)TP[k]; // loop over lifetimes of all previous generations
638 if (ta1 == ta2) {
639 theRate = 1.e100;
640 } else {
641 theRate = ta1/(ta1-ta2);
642 }
643 theRate = theRate * theBR * RP[k];
644 Acoeffs.push_back(theRate);
645 }
646
647 // the second part: the n:n coefficiency
648 // Eq 4.25 of the TN. Note Yn+1 is zero apart from Y1 which is -1
649 // as treated at line 1013
650 theRate = 0.;
651 long double aRate, aRate1;
652 aRate1 = 0.L;
653 for (k = 0; k < RP.size(); k++){
654 ta1 = (long double)TP[k];
655 if (ta1 == ta2 ) {
656 aRate = 1.e100;
657 } else {
658 aRate = ta2/(ta1-ta2);
659 }
660 aRate = aRate * (long double)(theBR * RP[k]);
661 aRate1 += aRate;
662 }
663 theRate = -aRate1;
664 Acoeffs.push_back(theRate);
665 SetDecayRate (Z,A,E,nGeneration,Acoeffs,taos);
666 theDecayRateVector.push_back(ratesToDaughter);
667 nEntry++;
668 } // there are entries in the table
669 } // nuclide is OK to decay
670 } // end of loop (i) over decay table branches
671
672 delete summedDecayTable;
673
674 } // Getting contents of decay rate vector (end loop on j)
675 nS = nT;
676 nT = nEntry;
677 if (nS == nT) stable = true;
678 } // while nuclide is not stable
679
680 // end of while loop
681 // the calculation completed here
682
683
684 // fill the first part of the decay rate table
685 // which is the name of the original particle (isotope)
686 chainsFromParent.SetIonName(theParentNucleus.GetParticleName());
687
688 // now fill the decay table with the newly completed decay rate vector
689 chainsFromParent.SetItsRates(theDecayRateVector);
690
691 // finally add the decayratetable to the tablevector
692 theParentChainTable.push_back(chainsFromParent);
693}
694
695////////////////////////////////////////////////////////////////////////////////
696// //
697// SetSourceTimeProfile //
698// read in the source time profile function (histogram) //
699// //
700////////////////////////////////////////////////////////////////////////////////
701
703{
704 std::ifstream infile ( filename, std::ios::in );
705 if (!infile) {
707 ed << " Could not open file " << filename << G4endl;
708 G4Exception("G4Radioactivation::SetSourceTimeProfile()", "HAD_RDM_001",
709 FatalException, ed);
710 }
711
712 G4double bin, flux;
713 NSourceBin = -1;
714
715 G4int loop = 0;
716 while (infile >> bin >> flux) { /* Loop checking, 01.09.2015, D.Wright */
717 loop++;
718 if (loop > 10000) {
719 G4Exception("G4Radioactivation::SetSourceTimeProfile()", "HAD_RDM_100",
720 JustWarning, "While loop count exceeded");
721 break;
722 }
723
724 NSourceBin++;
725 if (NSourceBin > 99) {
726 G4Exception("G4Radioactivation::SetSourceTimeProfile()", "HAD_RDM_002",
727 FatalException, "Input source time file too big (>100 rows)");
728
729 } else {
730 SBin[NSourceBin] = bin * s; // Convert read-in time to ns
731 SProfile[NSourceBin] = flux; // Dimensionless
732 }
733 }
734
735 AnalogueMC = false;
736 infile.close();
737
738#ifdef G4VERBOSE
739 if (GetVerboseLevel() > 2)
740 G4cout <<" Source Timeprofile Nbin = " << NSourceBin <<G4endl;
741#endif
742}
743
744////////////////////////////////////////////////////////////////////////////////
745// //
746// SetDecayBiasProfile //
747// read in the decay bias scheme function (histogram) //
748// //
749////////////////////////////////////////////////////////////////////////////////
750
752{
753 std::ifstream infile(filename, std::ios::in);
754 if (!infile) G4Exception("G4Radioactivation::SetDecayBias()", "HAD_RDM_001",
755 FatalException, "Unable to open bias data file" );
756
757 G4double bin, flux;
758 G4int dWindows = 0;
759 G4int i ;
760
761 theRadioactivityTables.clear();
762
763 NDecayBin = -1;
764
765 G4int loop = 0;
766 while (infile >> bin >> flux ) { /* Loop checking, 01.09.2015, D.Wright */
767 NDecayBin++;
768 loop++;
769 if (loop > 10000) {
770 G4Exception("G4Radioactivation::SetDecayBias()", "HAD_RDM_100",
771 JustWarning, "While loop count exceeded");
772 break;
773 }
774
775 if (NDecayBin > 99) {
776 G4Exception("G4Radioactivation::SetDecayBias()", "HAD_RDM_002",
777 FatalException, "Input bias file too big (>100 rows)" );
778 } else {
779 DBin[NDecayBin] = bin * s; // Convert read-in time to ns
780 DProfile[NDecayBin] = flux; // Dimensionless
781 if (flux > 0.) {
782 decayWindows[NDecayBin] = dWindows;
783 dWindows++;
785 theRadioactivityTables.push_back(rTable);
786 }
787 }
788 }
789 for ( i = 1; i<= NDecayBin; i++) DProfile[i] += DProfile[i-1]; // Cumulative flux vs i
790 for ( i = 0; i<= NDecayBin; i++) DProfile[i] /= DProfile[NDecayBin];
791 // Normalize so entries increase from 0 to 1
792 // converted to accumulated probabilities
793
794 AnalogueMC = false;
795 infile.close();
796
797#ifdef G4VERBOSE
798 if (GetVerboseLevel() > 2)
799 G4cout <<" Decay Bias Profile Nbin = " << NDecayBin <<G4endl;
800#endif
801}
802
803////////////////////////////////////////////////////////////////////////////////
804// //
805// DecayIt //
806// //
807////////////////////////////////////////////////////////////////////////////////
808
811{
812 // Initialize G4ParticleChange object, get particle details and decay table
815 const G4DynamicParticle* theParticle = theTrack.GetDynamicParticle();
816 const G4ParticleDefinition* theParticleDef = theParticle->GetDefinition();
817
818 // First check whether RDM applies to the current logical volume
819 if (!isAllVolumesMode) {
820 if (!std::binary_search(ValidVolumes.begin(), ValidVolumes.end(),
821 theTrack.GetVolume()->GetLogicalVolume()->GetName())) {
822#ifdef G4VERBOSE
823 if (GetVerboseLevel()>0) {
824 G4cout <<"G4RadioactiveDecay::DecayIt : "
825 << theTrack.GetVolume()->GetLogicalVolume()->GetName()
826 << " is not selected for the RDM"<< G4endl;
827 G4cout << " There are " << ValidVolumes.size() << " volumes" << G4endl;
828 G4cout << " The Valid volumes are " << G4endl;
829 for (std::size_t i = 0; i< ValidVolumes.size(); ++i)
830 G4cout << ValidVolumes[i] << G4endl;
831 }
832#endif
834
835 // Kill the parent particle.
840 }
841 }
842
843 // Now check if particle is valid for RDM
844 if (!(IsApplicable(*theParticleDef) ) ) {
845 // Particle is not an ion or is outside the nucleuslimits for decay
846#ifdef G4VERBOSE
847 if (GetVerboseLevel() > 1) {
848 G4cout << "G4RadioactiveDecay::DecayIt : "
849 << theParticleDef->GetParticleName()
850 << " is not an ion or is outside (Z,A) limits set for the decay. "
851 << " Set particle change accordingly. "
852 << G4endl;
853 }
854#endif
856
857 // Kill the parent particle
862 }
863
864 G4DecayTable* theDecayTable = GetDecayTable1(theParticleDef);
865
866 if (theDecayTable == 0 || theDecayTable->entries() == 0) {
867 // No data in the decay table. Set particle change parameters
868 // to indicate this.
869#ifdef G4VERBOSE
870 if (GetVerboseLevel() > 1) {
871 G4cout << "G4RadioactiveDecay::DecayIt : "
872 << "decay table not defined for "
873 << theParticleDef->GetParticleName()
874 << ". Set particle change accordingly. "
875 << G4endl;
876 }
877#endif
879
880 // Kill the parent particle.
885
886 } else {
887 // Data found. Try to decay nucleus
888 if (AnalogueMC) {
890
891 } else {
892 // Proceed with decay using variance reduction
893 G4double energyDeposit = 0.0;
894 G4double finalGlobalTime = theTrack.GetGlobalTime();
895 G4double finalLocalTime = theTrack.GetLocalTime();
896 G4int index;
897 G4ThreeVector currentPosition;
898 currentPosition = theTrack.GetPosition();
899
900 G4IonTable* theIonTable;
901 G4ParticleDefinition* parentNucleus;
902
903 // Get decay chains for the given nuclide
904 if (!IsRateTableReady(*theParticleDef)) CalculateChainsFromParent(*theParticleDef);
905 GetChainsFromParent(*theParticleDef);
906
907 // Declare some of the variables required in the implementation
908 G4int PZ;
909 G4int PA;
910 G4double PE;
911 G4String keyName;
912 std::vector<G4double> PT;
913 std::vector<G4double> PR;
914 G4double taotime;
915 long double decayRate;
916
917 std::size_t i;
918 G4int numberOfSecondaries;
919 G4int totalNumberOfSecondaries = 0;
920 G4double currentTime = 0.;
921 G4int ndecaych;
922 G4DynamicParticle* asecondaryparticle;
923 std::vector<G4DynamicParticle*> secondaryparticles;
924 std::vector<G4double> pw;
925 std::vector<G4double> ptime;
926 pw.clear();
927 ptime.clear();
928
929 // Now apply the nucleus splitting
930 for (G4int n = 0; n < NSplit; n++) {
931 // Get the decay time following the decay probability function
932 // supplied by user
933 G4double theDecayTime = GetDecayTime();
934 G4int nbin = GetDecayTimeBin(theDecayTime);
935
936 // calculate the first part of the weight function
937 G4double weight1 = 1.;
938 if (nbin == 1) {
939 weight1 = 1./DProfile[nbin-1]
940 *(DBin[nbin]-DBin[nbin-1])/NSplit; // width of window in ns
941 } else if (nbin > 1) {
942 // Go from nbin to nbin-2 because flux entries in file alternate between 0 and 1
943 weight1 = 1./(DProfile[nbin]-DProfile[nbin-2])
944 *(DBin[nbin]-DBin[nbin-1])/NSplit;
945 // weight1 = (probability of choosing one of the bins)*(time width of bin)/NSplit
946 }
947 // it should be calculated in seconds
948 weight1 /= s ;
949
950 // loop over all the possible secondaries of the nucleus
951 // the first one is itself.
952 for (i = 0; i < theDecayRateVector.size(); i++) {
953 PZ = theDecayRateVector[i].GetZ();
954 PA = theDecayRateVector[i].GetA();
955 PE = theDecayRateVector[i].GetE();
956 PT = theDecayRateVector[i].GetTaos();
957 PR = theDecayRateVector[i].GetDecayRateC();
958
959 // The array of arrays theDecayRateVector contains all possible decay
960 // chains of a given parent nucleus (ZP,AP,EP) to a given descendant
961 // nuclide (Z,A,E).
962 //
963 // theDecayRateVector[0] contains the decay parameters of the parent
964 // nucleus
965 // PZ = ZP
966 // PA = AP
967 // PE = EP
968 // PT[] = {TP}
969 // PR[] = {RP}
970 //
971 // theDecayRateVector[1] contains the decay of the parent to the first
972 // generation daughter (Z1,A1,E1).
973 // PZ = Z1
974 // PA = A1
975 // PE = E1
976 // PT[] = {TP, T1}
977 // PR[] = {RP, R1}
978 //
979 // theDecayRateVector[2] contains the decay of the parent to the first
980 // generation daughter (Z1,A1,E1) and the decay of the first
981 // generation daughter to the second generation daughter (Z2,A2,E2).
982 // PZ = Z2
983 // PA = A2
984 // PE = E2
985 // PT[] = {TP, T1, T2}
986 // PR[] = {RP, R1, R2}
987 //
988 // theDecayRateVector[3] may contain a branch chain
989 // PZ = Z2a
990 // PA = A2a
991 // PE = E2a
992 // PT[] = {TP, T1, T2a}
993 // PR[] = {RP, R1, R2a}
994 //
995 // and so on.
996
997 // Calculate the decay rate of the isotope. decayRate is the
998 // radioactivity of isotope (PZ,PA,PE) at 'theDecayTime'
999 // it will be used to calculate the statistical weight of the
1000 // decay products of this isotope
1001
1002 // For each nuclide, calculate all the decay chains which can reach
1003 // the parent nuclide
1004 decayRate = 0.L;
1005 for (G4int j = 0; j < G4int(PT.size() ); j++) {
1006 taotime = ConvolveSourceTimeProfile(theDecayTime,PT[j]);
1007 decayRate -= PR[j] * (long double)taotime; // PRs are Acoeffs, taotime is inverse time
1008 // Eq.4.23 of of the TN
1009 // note the negative here is required as the rate in the
1010 // equation is defined to be negative,
1011 // i.e. decay away, but we need positive value here.
1012
1013 // G4cout << j << "\t"<< PT[j]/s << "\t" << PR[j] << "\t" << decayRate << G4endl;
1014 }
1015
1016 // At this point any negative decay rates are probably small enough
1017 // (order 10**-30) that negative values are likely due to cancellation
1018 // errors. Set them to zero.
1019 if (decayRate < 0.0) decayRate = 0.0;
1020
1021 // G4cout <<theDecayTime/s <<"\t"<<nbin<<G4endl;
1022 // G4cout << theTrack.GetWeight() <<"\t"<<weight1<<"\t"<<decayRate<< G4endl;
1023
1024 // Add isotope to the radioactivity tables
1025 // One table for each observation time window specified in
1026 // SetDecayBias(G4String filename)
1027
1028 theRadioactivityTables[decayWindows[nbin-1]]
1029 ->AddIsotope(PZ,PA,PE,weight1*decayRate,theTrack.GetWeight());
1030
1031 // Now calculate the statistical weight
1032 // One needs to fold the source bias function with the decaytime
1033 // also need to include the track weight! (F.Lei, 28/10/10)
1034 G4double weight = weight1*decayRate*theTrack.GetWeight();
1035
1036 // decay the isotope
1038 parentNucleus = theIonTable->GetIon(PZ,PA,PE);
1039
1040 // Create a temprary products buffer.
1041 // Its contents to be transfered to the products at the end of the loop
1042 G4DecayProducts* tempprods = 0;
1043
1044 // Decide whether to apply branching ratio bias or not
1045 if (BRBias) {
1046 G4DecayTable* decayTable = GetDecayTable1(parentNucleus);
1047 ndecaych = G4int(decayTable->entries()*G4UniformRand());
1048 G4VDecayChannel* theDecayChannel = decayTable->GetDecayChannel(ndecaych);
1049
1050 if (theDecayChannel == 0) {
1051 // Decay channel not found.
1052
1053 if (GetVerboseLevel() > 0) {
1054 G4cout << " G4RadioactiveDecay::DoIt : cannot determine decay channel ";
1055 G4cout << " for this nucleus; decay as if no biasing active. ";
1056 G4cout << G4endl;
1057 decayTable ->DumpInfo();
1058 }
1059
1060 tempprods = DoDecay(*parentNucleus); // DHW 6 Dec 2010 - do decay as if no biasing
1061 // to avoid deref of temppprods = 0
1062 } else {
1063 // A decay channel has been identified, so execute the DecayIt.
1064 G4double tempmass = parentNucleus->GetPDGMass();
1065 tempprods = theDecayChannel->DecayIt(tempmass);
1066 weight *= (theDecayChannel->GetBR())*(decayTable->entries());
1067 }
1068 } else {
1069 tempprods = DoDecay(*parentNucleus);
1070 }
1071
1072 // save the secondaries for buffers
1073 numberOfSecondaries = tempprods->entries();
1074 currentTime = finalGlobalTime + theDecayTime;
1075 for (index = 0; index < numberOfSecondaries; ++index) {
1076 asecondaryparticle = tempprods->PopProducts();
1077 if (asecondaryparticle->GetDefinition()->GetPDGStable() ) {
1078 pw.push_back(weight);
1079 ptime.push_back(currentTime);
1080 secondaryparticles.push_back(asecondaryparticle);
1081 }
1082 // Generate gammas and Xrays from excited nucleus, added by L.Desorgher
1083 else if (((const G4Ions*)(asecondaryparticle->GetDefinition()))
1084 ->GetExcitationEnergy() > 0. && weight > 0.) { //Compute the gamma
1085 G4ParticleDefinition* apartDef = asecondaryparticle->GetDefinition();
1086 AddDeexcitationSpectrumForBiasMode(apartDef,weight,currentTime,pw,
1087 ptime,secondaryparticles);
1088 }
1089 }
1090
1091 delete tempprods;
1092 } // end of i loop
1093 } // end of n loop
1094
1095 // now deal with the secondaries in the two stl containers
1096 // and submmit them back to the tracking manager
1097 totalNumberOfSecondaries = (G4int)pw.size();
1098 fParticleChangeForRadDecay.SetNumberOfSecondaries(totalNumberOfSecondaries);
1099 for (index=0; index < totalNumberOfSecondaries; ++index) {
1100 G4Track* secondary = new G4Track(secondaryparticles[index],
1101 ptime[index], currentPosition);
1102 secondary->SetGoodForTrackingFlag();
1103 secondary->SetTouchableHandle(theTrack.GetTouchableHandle());
1104 secondary->SetWeight(pw[index]);
1106 }
1107
1108 // Kill the parent particle
1112 // Reset NumberOfInteractionLengthLeft.
1114 } // end VR decay
1115
1117 } // end of data found branch
1118}
1119
1120
1121// Add gamma, X-ray, conversion and auger electrons for bias mode
1122void
1124 G4double weight,G4double currentTime,
1125 std::vector<double>& weights_v,
1126 std::vector<double>& times_v,
1127 std::vector<G4DynamicParticle*>& secondaries_v)
1128{
1129 G4double elevel=((const G4Ions*)(apartDef))->GetExcitationEnergy();
1130 G4double life_time=apartDef->GetPDGLifeTime();
1131 G4ITDecay* anITChannel = 0;
1132
1133 while (life_time < halflifethreshold && elevel > 0.) {
1134 anITChannel = new G4ITDecay(apartDef, 100., elevel, elevel, photonEvaporation);
1135 G4DecayProducts* pevap_products = anITChannel->DecayIt(0.);
1136 G4int nb_pevapSecondaries = pevap_products->entries();
1137
1138 G4DynamicParticle* a_pevap_secondary = 0;
1139 G4ParticleDefinition* secDef = 0;
1140 for (G4int ind = 0; ind < nb_pevapSecondaries; ind++) {
1141 a_pevap_secondary= pevap_products->PopProducts();
1142 secDef = a_pevap_secondary->GetDefinition();
1143
1144 if (secDef->GetBaryonNumber() > 4) {
1145 elevel = ((const G4Ions*)(secDef))->GetExcitationEnergy();
1146 life_time = secDef->GetPDGLifeTime();
1147 apartDef = secDef;
1148 if (secDef->GetPDGStable() ) {
1149 weights_v.push_back(weight);
1150 times_v.push_back(currentTime);
1151 secondaries_v.push_back(a_pevap_secondary);
1152 }
1153 } else {
1154 weights_v.push_back(weight);
1155 times_v.push_back(currentTime);
1156 secondaries_v.push_back(a_pevap_secondary);
1157 }
1158 }
1159
1160 delete anITChannel;
1161 delete pevap_products;
1162 }
1163}
1164
@ allowed
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
G4ForceCondition
#define noFloat
Definition: G4Ions.hh:112
G4RadioactiveDecayMode
@ G4RadioactiveDecayModeSize
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
const G4double A[17]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
G4int entries() const
G4DynamicParticle * PopProducts()
G4VDecayChannel * GetDecayChannel(G4int index) const
void Insert(G4VDecayChannel *aChannel)
Definition: G4DecayTable.cc:53
void DumpInfo() const
G4int entries() const
G4ParticleDefinition * GetDefinition() const
virtual G4DecayProducts * DecayIt(G4double)
Definition: G4ITDecay.cc:73
G4ParticleDefinition * GetIon(G4int Z, G4int A, G4int lvl=0)
Definition: G4IonTable.cc:522
Definition: G4Ions.hh:52
std::size_t NearestLevelIndex(const G4double energy, const std::size_t index=0) const
std::size_t NumberOfTransitions() const
G4double LifeTime(const std::size_t i) const
G4double NearestLevelEnergy(const G4double energy, const std::size_t index=0) const
const G4String & GetName() const
G4double GetDaughterExcitation()
G4ParticleDefinition * GetDaughterNucleus()
G4RadioactiveDecayMode GetDecayMode()
const G4LevelManager * GetLevelManager(G4int Z, G4int A)
static G4NuclearLevelData * GetInstance()
void Initialize(const G4Track &) final
G4bool GetPDGStable() const
G4double GetPDGLifeTime() const
const G4String & GetParticleName() const
G4IonTable * GetIonTable() const
static G4ParticleTable * GetParticleTable()
G4int GetDecayTimeBin(const G4double aDecayTime)
void AddDeexcitationSpectrumForBiasMode(G4ParticleDefinition *apartDef, G4double weight, G4double currenTime, std::vector< double > &weights_v, std::vector< double > &times_v, std::vector< G4DynamicParticle * > &secondaries_v)
void SetDecayBias(G4String filename)
G4bool IsRateTableReady(const G4ParticleDefinition &)
virtual void ProcessDescription(std::ostream &outFile) const
G4Radioactivation(const G4String &processName="Radioactivation")
G4VParticleChange * DecayIt(const G4Track &theTrack, const G4Step &theStep)
G4double ConvolveSourceTimeProfile(const G4double, const G4double)
void CalculateChainsFromParent(const G4ParticleDefinition &)
void SetDecayRate(G4int, G4int, G4double, G4int, std::vector< G4double >, std::vector< G4double >)
G4DecayTable * GetDecayTable1(const G4ParticleDefinition *)
void SetSourceTimeProfile(G4String filename)
void GetChainsFromParent(const G4ParticleDefinition &)
G4double GetMeanLifeTime(const G4Track &theTrack, G4ForceCondition *condition)
G4RadioactivationMessenger * theRadioactivationMessenger
void SetItsRates(G4RadioactiveDecayRates arate)
void SetTaos(std::vector< G4double > value)
void SetDecayRateC(std::vector< G4double > value)
void DecayAnalog(const G4Track &theTrack)
std::vector< G4String > ValidVolumes
G4DecayTable * LoadDecayTable(const G4ParticleDefinition &theParentNucleus)
G4double GetMeanLifeTime(const G4Track &theTrack, G4ForceCondition *condition)
G4DecayProducts * DoDecay(const G4ParticleDefinition &theParticleDef)
static const G4double levelTolerance
G4ParticleChangeForRadDecay fParticleChangeForRadDecay
G4int GetVerboseLevel() const
G4bool IsApplicable(const G4ParticleDefinition &)
G4PhotonEvaporation * photonEvaporation
Definition: G4Step.hh:62
G4VPhysicalVolume * GetVolume() const
G4double GetWeight() const
void SetWeight(G4double aValue)
const G4ThreeVector & GetPosition() const
void SetTouchableHandle(const G4TouchableHandle &apValue)
G4double GetGlobalTime() const
G4double GetLocalTime() const
const G4DynamicParticle * GetDynamicParticle() const
const G4TouchableHandle & GetTouchableHandle() const
void SetGoodForTrackingFlag(G4bool value=true)
G4double GetBR() const
virtual G4DecayProducts * DecayIt(G4double parentMass=-1.0)=0
void ProposeTrackStatus(G4TrackStatus status)
void ProposeWeight(G4double finalWeight)
void AddSecondary(G4Track *aSecondary)
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
void SetNumberOfSecondaries(G4int totSecondaries)
G4LogicalVolume * GetLogicalVolume() const
void ClearNumberOfInteractionLengthLeft()
Definition: G4VProcess.hh:428
Definition: DoubConv.h:17
#define ns(x)
Definition: xmltok.c:1649