source: trunk/source/processes/hadronic/models/radioactive_decay/src/G4RadioactiveDecay.cc @ 1340

Last change on this file since 1340 was 1340, checked in by garnier, 14 years ago

update ti head

File size: 53.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// MODULE:              G4RadioactiveDecay.cc
29//
30// Author:              F Lei & P R Truscott
31// Organisation:        DERA UK
32// Customer:            ESA/ESTEC, NOORDWIJK
33// Contract:            12115/96/JG/NL Work Order No. 3
34//
35// Documentation avaialable at http://www.space.dera.gov.uk/space_env/rdm.html
36//   These include:
37//       User Requirement Document (URD)
38//       Software Specification Documents (SSD)
39//       Software User Manual (SUM)
40//       Technical Note (TN) on the physics and algorithms
41//
42//    The test and example programs are not included in the public release of
43//    G4 but they can be downloaded from
44//      http://www.space.qinetiq.com/space_env/rdm.html
45//
46// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47//
48// CHANGE HISTORY
49// --------------
50// 16 February 2006, V.Ivanchenko fix problem in IsApplicable connected with
51//            8.0 particle design
52// 18 October 2002, F. Lei
53//            in the case of beta decay, added a check of the end-energy
54//            to ensure it is > 0.
55//            ENSDF occationally have beta decay entries with zero energies
56//
57// 27 Sepetember 2001, F. Lei
58//            verboselevel(0) used in constructor
59//
60// 01 November 2000, F.Lei
61//            added " ee = e0 +1. ;" as line 763
62//            tagged as "radiative_decay-V02-00-02"             
63// 28 October 2000, F Lei
64//            added fast beta decay mode. Many files have been changed.
65//            tagged as "radiative_decay-V02-00-01"
66//
67// 25 October 2000, F Lei, DERA UK
68//            1) line 1185 added 'const' to work with tag "Track-V02-00-00"
69//            tagged as "radiative_decay-V02-00-00"
70// 14 April 2000, F Lei, DERA UK
71// 0.b.4 release. Changes are:
72//            1) Use PhotonEvaporation instead of DiscreteGammaDeexcitation
73//            2) VR: Significant efficiency improvement
74//
75// 29 February 2000, P R Truscott, DERA UK
76// 0.b.3 release.
77//
78// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79///////////////////////////////////////////////////////////////////////////////
80//
81#include "G4RadioactiveDecay.hh"
82#include "G4RadioactiveDecaymessenger.hh"
83
84#include "G4DynamicParticle.hh"
85#include "G4DecayProducts.hh"
86#include "G4DecayTable.hh"
87#include "G4PhysicsLogVector.hh"
88#include "G4ParticleChangeForRadDecay.hh"
89#include "G4ITDecayChannel.hh"
90#include "G4BetaMinusDecayChannel.hh"
91#include "G4BetaPlusDecayChannel.hh"
92#include "G4KshellECDecayChannel.hh"
93#include "G4LshellECDecayChannel.hh"
94#include "G4MshellECDecayChannel.hh"
95#include "G4AlphaDecayChannel.hh"
96#include "G4VDecayChannel.hh"
97#include "G4RadioactiveDecayMode.hh"
98#include "G4Ions.hh"
99#include "G4IonTable.hh"
100#include "G4RIsotopeTable.hh"
101#include "G4BetaFermiFunction.hh"
102#include "Randomize.hh"
103#include "G4LogicalVolumeStore.hh"
104#include "G4NuclearLevelManager.hh"
105#include "G4NuclearLevelStore.hh"
106
107#include "G4HadTmpUtil.hh"
108
109#include <vector>
110#include <sstream>
111#include <algorithm>
112#include <fstream>
113
114using namespace CLHEP;
115
116const G4double   G4RadioactiveDecay::levelTolerance =2.0*keV;
117
118///////////////////////////////////////////////////////////////////////////////
119//
120//
121// Constructor
122//
123G4RadioactiveDecay::G4RadioactiveDecay
124  (const G4String& processName)
125  :G4VRestDiscreteProcess(processName, fDecay), HighestBinValue(10.0),
126   LowestBinValue(1.0e-3), TotBin(200), verboseLevel(0)
127{
128#ifdef G4VERBOSE
129  if (GetVerboseLevel()>1) {
130    G4cout <<"G4RadioactiveDecay constructor    Name: ";
131    G4cout <<processName << G4endl;   }
132#endif
133
134  theRadioactiveDecaymessenger = new G4RadioactiveDecaymessenger(this);
135  theIsotopeTable              = new G4RIsotopeTable();
136  aPhysicsTable                = 0;
137  pParticleChange              = &fParticleChangeForRadDecay;
138 
139  //
140  // Now register the Isotopetable with G4IonTable.
141  //
142  G4IonTable *theIonTable =
143    (G4IonTable *)(G4ParticleTable::GetParticleTable()->GetIonTable());
144  G4VIsotopeTable *aVirtualTable = theIsotopeTable;
145  theIonTable->RegisterIsotopeTable(aVirtualTable);
146  //
147  //
148  // Reset the contents of the list of nuclei for which decay scheme data
149  // have been loaded.
150  //
151  LoadedNuclei.clear();
152  //
153  //
154  // Apply default values.
155  //
156  NSourceBin  = 1;
157  SBin[0]     = 0.* s;
158  SBin[1]     = 1e10 * s;
159  SProfile[0] = 1.;
160  SProfile[1] = 1.;
161  NDecayBin   = 1;
162  DBin[0]     = 9.9e9 * s ;
163  DBin[1]     = 1e10 * s;
164  DProfile[0] = 1.;
165  DProfile[1] = 0.;
166  NSplit      = 1;
167  AnalogueMC  = true ;
168  FBeta       = false ;
169  BRBias      = true ;
170  applyICM    = true ;
171  applyARM    = true ;
172  halflifethreshold = 0.*second;
173  //
174  // RDM applies to xall logical volumes as default
175  SelectAllVolumes();
176}
177////////////////////////////////////////////////////////////////////////////////
178//
179//
180// Destructor
181//
182G4RadioactiveDecay::~G4RadioactiveDecay()
183{
184  if (aPhysicsTable != 0)
185    {
186      aPhysicsTable->clearAndDestroy();
187      delete aPhysicsTable;
188    }
189  //  delete theIsotopeTable;
190  delete theRadioactiveDecaymessenger;
191}
192
193///////////////////////////////////////////////////////////////////////////////
194//
195//
196// IsApplicable
197//
198G4bool G4RadioactiveDecay::IsApplicable( const G4ParticleDefinition &
199  aParticle)
200{
201  //
202  //
203  // All particles, other than G4Ions, are rejected by default.
204  //
205  if (((const G4Ions*)(&aParticle))->GetExcitationEnergy() > 0.) {return true;}
206  if (aParticle.GetParticleName() == "GenericIon")      {return true;}
207  else if (!(aParticle.GetParticleType() == "nucleus") || aParticle.GetPDGLifeTime() < 0. ) {return false;}
208  //
209  //
210  // Determine whether the nuclide falls into the correct A and Z range.
211  //
212  G4int A = ((const G4Ions*) (&aParticle))->GetAtomicMass();
213  G4int Z = ((const G4Ions*) (&aParticle))->GetAtomicNumber();
214  if( A> theNucleusLimits.GetAMax() || A< theNucleusLimits.GetAMin())
215    {return false;}
216  else if( Z> theNucleusLimits.GetZMax() || Z< theNucleusLimits.GetZMin())
217    {return false;}
218  return true;
219}
220///////////////////////////////////////////////////////////////////////////////
221//
222//
223// IsLoaded
224//
225G4bool G4RadioactiveDecay::IsLoaded(const G4ParticleDefinition &
226  aParticle)
227{
228  //
229  //
230  // Check whether the radioactive decay data on the ion have already been
231  // loaded.
232  //
233  return std::binary_search(LoadedNuclei.begin(),
234                       LoadedNuclei.end(),
235                       aParticle.GetParticleName());
236}
237////////////////////////////////////////////////////////////////////////////////
238//
239//
240// SelectAVolume
241//
242void G4RadioactiveDecay::SelectAVolume(const G4String aVolume)
243{
244 
245  G4LogicalVolumeStore *theLogicalVolumes;
246  G4LogicalVolume *volume;
247  theLogicalVolumes=G4LogicalVolumeStore::GetInstance();
248  for (size_t i = 0; i < theLogicalVolumes->size(); i++){
249    volume=(*theLogicalVolumes)[i];
250    if (volume->GetName() == aVolume) {
251      ValidVolumes.push_back(aVolume);
252      std::sort(ValidVolumes.begin(), ValidVolumes.end());
253      // sort need for performing binary_search
254#ifdef G4VERBOSE
255      if (GetVerboseLevel()>0)
256        G4cout << " RDM Applies to : " << aVolume << G4endl; 
257#endif
258    }else if(i ==  theLogicalVolumes->size())
259      {
260        G4cerr << "SelectAVolume: "<<aVolume << " is not a valid logical volume name"<< G4endl; 
261      }
262  }
263}
264////////////////////////////////////////////////////////////////////////////////
265//
266//
267// DeSelectAVolume
268//
269void G4RadioactiveDecay::DeselectAVolume(const G4String aVolume)
270{
271  G4LogicalVolumeStore *theLogicalVolumes;
272  G4LogicalVolume *volume;
273  theLogicalVolumes=G4LogicalVolumeStore::GetInstance();
274  for (size_t i = 0; i < theLogicalVolumes->size(); i++){
275    volume=(*theLogicalVolumes)[i];
276    if (volume->GetName() == aVolume) {
277      std::vector<G4String>::iterator location;
278      location = std::find(ValidVolumes.begin(),ValidVolumes.end(),aVolume);
279      if (location != ValidVolumes.end()) {
280        ValidVolumes.erase(location);
281        std::sort(ValidVolumes.begin(), ValidVolumes.end());
282      }else{
283        G4cerr << " DeselectVolume:" << aVolume << " is not in the list"<< G4endl; 
284      }   
285#ifdef G4VERBOSE
286      if (GetVerboseLevel()>0)
287        G4cout << " DeselectVolume: " << aVolume << " is removed from list"<<G4endl; 
288#endif
289    }else if(i ==  theLogicalVolumes->size())
290      {
291        G4cerr << " DeselectVolume:" << aVolume << "is not a valid logical volume name"<< G4endl; 
292      }
293  }
294}
295////////////////////////////////////////////////////////////////////////////////
296//
297//
298// SelectAllVolumes
299//
300void G4RadioactiveDecay::SelectAllVolumes() 
301{
302  G4LogicalVolumeStore *theLogicalVolumes;
303  G4LogicalVolume *volume;
304  theLogicalVolumes=G4LogicalVolumeStore::GetInstance();
305  ValidVolumes.clear();
306#ifdef G4VERBOSE
307  if (GetVerboseLevel()>0)
308    G4cout << " RDM Applies to all Volumes"  << G4endl;
309#endif
310  for (size_t i = 0; i < theLogicalVolumes->size(); i++){
311    volume=(*theLogicalVolumes)[i];
312    ValidVolumes.push_back(volume->GetName());   
313#ifdef G4VERBOSE
314    if (GetVerboseLevel()>0)
315      G4cout << "         RDM Applies to Volume "  << volume->GetName() << G4endl;
316#endif
317  }
318  std::sort(ValidVolumes.begin(), ValidVolumes.end());
319  // sort needed in order to allow binary_search
320}
321////////////////////////////////////////////////////////////////////////////////
322//
323//
324// DeSelectAllVolumes
325//
326void G4RadioactiveDecay::DeselectAllVolumes() 
327{
328  ValidVolumes.clear();
329#ifdef G4VERBOSE
330  if (GetVerboseLevel()>0)
331    G4cout << " RDM removed from all volumes" << G4endl; 
332#endif
333 
334}
335
336///////////////////////////////////////////////////////////////////////////////
337//
338//
339// IsRateTableReady
340//
341G4bool G4RadioactiveDecay::IsRateTableReady(const G4ParticleDefinition &
342  aParticle)
343{
344  //
345  //
346  // Check whether the radioactive decay rates table on the ion has already
347  // been calculated.
348  //
349  G4String aParticleName = aParticle.GetParticleName();
350  for (size_t i = 0; i < theDecayRateTableVector.size(); i++)
351    {
352      if (theDecayRateTableVector[i].GetIonName() == aParticleName)
353        return true ;
354    }
355  return false;
356}
357////////////////////////////////////////////////////////////////////////////////
358//
359//
360// GetDecayRateTable
361//
362// retrieve the decayratetable for the specified aParticle
363//
364void G4RadioactiveDecay::GetDecayRateTable(const G4ParticleDefinition &
365  aParticle)
366{
367
368  G4String aParticleName = aParticle.GetParticleName();
369
370  for (size_t i = 0; i < theDecayRateTableVector.size(); i++)
371    {
372      if (theDecayRateTableVector[i].GetIonName() == aParticleName)
373        {
374          theDecayRateVector = theDecayRateTableVector[i].GetItsRates() ;
375        }
376    }
377#ifdef G4VERBOSE
378        if (GetVerboseLevel()>0)
379          {
380            G4cout <<"The DecayRate Table for "
381                   << aParticleName << " is selected." <<  G4endl;
382          }
383#endif
384}
385////////////////////////////////////////////////////////////////////////////////
386//
387//
388// GetTaoTime
389//
390// to perform the convilution of the sourcetimeprofile function with the
391// decay constants in the decay chain.
392//
393G4double G4RadioactiveDecay::GetTaoTime(G4double t, G4double tao)
394{
395  G4double taotime =0.;
396  G4int nbin;
397  if ( t > SBin[NSourceBin]) {
398    nbin  = NSourceBin;}
399  else {
400    nbin = 0;
401    while (t > SBin[nbin]) nbin++;
402    nbin--;}
403  if (nbin > 0) { 
404    for (G4int i = 0; i < nbin; i++) 
405      {
406        taotime += SProfile[i] * (std::exp(-(t-SBin[i+1])/tao)-std::exp(-(t-SBin[i])/tao));
407      }
408  }
409  taotime +=  SProfile[nbin] * (1-std::exp(-(t-SBin[nbin])/tao));
410#ifdef G4VERBOSE
411  if (GetVerboseLevel()>1)
412    {G4cout <<" Tao time: " <<taotime <<G4endl;}
413#endif
414  return  taotime ;
415}
416 
417////////////////////////////////////////////////////////////////////////////////
418//
419//
420// GetDecayTime
421//
422// Randomly select a decay time for the decay process, following the supplied
423// decay time bias scheme.
424//
425G4double G4RadioactiveDecay::GetDecayTime()
426{
427  G4double decaytime = 0.;
428  G4double rand = G4UniformRand();
429  G4int i = 0;
430  while ( DProfile[i] < rand) i++;
431  rand = G4UniformRand();
432  decaytime = DBin[i] + rand*(DBin[i+1]-DBin[i]);
433#ifdef G4VERBOSE
434  if (GetVerboseLevel()>1)
435    {G4cout <<" Decay time: " <<decaytime <<"[ns]" <<G4endl;}
436#endif
437  return  decaytime;       
438}
439
440////////////////////////////////////////////////////////////////////////////////
441//
442//
443// GetDecayTimeBin
444//
445//
446//
447G4int G4RadioactiveDecay::GetDecayTimeBin(const G4double aDecayTime)
448{
449  for (G4int i = 0; i < NDecayBin; i++) 
450    {
451      if ( aDecayTime > DBin[i]) return i+1;     
452    }
453  return  1;
454}
455////////////////////////////////////////////////////////////////////////////////
456//
457//
458// GetMeanLifeTime
459//
460// this is required by the base class
461//
462G4double G4RadioactiveDecay::GetMeanLifeTime(const G4Track& theTrack,
463                                             G4ForceCondition* )
464{
465  // For varience reduction implementation the time is set to 0 so as to
466  // force the particle to decay immediately.
467  // in analogueMC mode it return the particles meanlife.
468  //
469  G4double meanlife = 0.;
470  if (AnalogueMC) {
471    const G4DynamicParticle* theParticle = theTrack.GetDynamicParticle();
472    G4ParticleDefinition* theParticleDef = theParticle->GetDefinition();
473    G4double theLife = theParticleDef->GetPDGLifeTime();
474     
475#ifdef G4VERBOSE
476    if (GetVerboseLevel()>2)
477      {
478        G4cout <<"G4RadioactiveDecay::GetMeanLifeTime() " <<G4endl;
479        G4cout <<"KineticEnergy:" <<theParticle->GetKineticEnergy()/GeV <<"[GeV]";
480        G4cout <<"Mass:" <<theParticle->GetMass()/GeV <<"[GeV]"; 
481        G4cout <<"Life time: " <<theLife/ns <<"[ns]" << G4endl;
482      }
483#endif
484    if (theParticleDef->GetPDGStable()) {meanlife = DBL_MAX;}
485    else if (theLife < 0.0) {meanlife = DBL_MAX;}
486    else {meanlife = theLife;}
487  // set the meanlife to zero for excited istopes which is not in the RDM database
488    if (((const G4Ions*)(theParticleDef))->GetExcitationEnergy() > 0. && meanlife == DBL_MAX) {meanlife = 0.;}
489  }
490#ifdef G4VERBOSE
491  if (GetVerboseLevel()>1)
492    {G4cout <<"mean life time: " <<meanlife <<"[ns]" <<G4endl;}
493#endif
494 
495  return  meanlife;
496}
497////////////////////////////////////////////////////////////////////////////////
498//
499//
500// GetMeanFreePath
501//
502// it is of similar functions to GetMeanFreeTime
503//
504G4double G4RadioactiveDecay::GetMeanFreePath (const G4Track& aTrack,
505                                              G4double, G4ForceCondition*)
506{
507  // constants
508  G4bool isOutRange ;
509 
510  // get particle
511  const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
512 
513  // returns the mean free path in GEANT4 internal units
514  G4double pathlength;
515  G4ParticleDefinition* aParticleDef = aParticle->GetDefinition();
516  G4double aCtau = c_light * aParticleDef->GetPDGLifeTime();
517  G4double aMass = aParticle->GetMass();
518 
519#ifdef G4VERBOSE
520  if (GetVerboseLevel()>2) {
521    G4cout << "G4RadioactiveDecay::GetMeanFreePath() "<< G4endl;
522    G4cout << "KineticEnergy:" << aParticle->GetKineticEnergy()/GeV <<"[GeV]";
523    G4cout << "Mass:" << aMass/GeV <<"[GeV]";
524    G4cout << "c*Tau:" << aCtau/m <<"[m]" <<G4endl;
525  }
526#endif
527 
528  // check if the particle is stable?
529  if (aParticleDef->GetPDGStable()) {
530    pathlength = DBL_MAX;
531   
532  } else if (aCtau < 0.0) {
533    pathlength =  DBL_MAX;
534   
535    //check if the particle has very short life time ?
536  } else if (aCtau < DBL_MIN) {
537    pathlength =  DBL_MIN;
538   
539    //check if zero mass
540  } else if (aMass <  DBL_MIN)  {
541    pathlength =  DBL_MAX;
542#ifdef G4VERBOSE
543    if (GetVerboseLevel()>1) {
544      G4cerr << " Zero Mass particle " << G4endl;
545    }
546#endif
547   } else {
548     //calculate the mean free path
549     // by using normalized kinetic energy (= Ekin/mass)
550     G4double   rKineticEnergy = aParticle->GetKineticEnergy()/aMass;
551     if ( rKineticEnergy > HighestBinValue) {
552       // beta >> 1
553       pathlength = ( rKineticEnergy + 1.0)* aCtau;
554     } else if ( rKineticEnergy > LowestBinValue) {
555       // check if aPhysicsTable exists
556       if (aPhysicsTable == 0) BuildPhysicsTable(*aParticleDef);
557       // beta is in the range valid for PhysicsTable
558       pathlength = aCtau *
559         ((*aPhysicsTable)(0))-> GetValue(rKineticEnergy,isOutRange);
560     } else if ( rKineticEnergy < DBL_MIN ) {
561       // too slow particle
562#ifdef G4VERBOSE
563       if (GetVerboseLevel()>2) {
564         G4cout << "G4Decay::GetMeanFreePath()   !!particle stops!!";
565         G4cout << aParticleDef->GetParticleName() << G4endl;
566         G4cout << "KineticEnergy:" << aParticle->GetKineticEnergy()/GeV <<"[GeV]";
567       }
568#endif
569       pathlength = DBL_MIN;
570     } else {
571       // beta << 1
572       pathlength = (aParticle->GetTotalMomentum())/aMass*aCtau ;
573     }
574   }
575#ifdef G4VERBOSE
576   if (GetVerboseLevel()>1) {
577     G4cout << "mean free path: "<< pathlength/m << "[m]" << G4endl;
578   }
579#endif
580   return  pathlength;
581}
582////////////////////////////////////////////////////////////////////////////////
583//
584//
585//
586//
587void G4RadioactiveDecay::BuildPhysicsTable(const G4ParticleDefinition&)
588{
589  // if aPhysicsTableis has already been created, do nothing
590  if (aPhysicsTable != 0) return;
591
592  // create  aPhysicsTable
593  if (GetVerboseLevel()>1) G4cerr <<" G4Decay::BuildPhysicsTable() "<< G4endl;
594  aPhysicsTable = new G4PhysicsTable(1);
595
596  //create physics vector
597  G4PhysicsLogVector* aVector = new G4PhysicsLogVector(
598                                                       LowestBinValue,
599                                                       HighestBinValue,
600                                                       TotBin);
601
602  G4double beta, gammainv;
603  // fill physics Vector
604  G4int i;
605  for ( i = 0 ; i < TotBin ; i++ ) {
606      gammainv = 1.0/(aVector->GetLowEdgeEnergy(i) + 1.0);
607      beta  = std::sqrt((1.0 - gammainv)*(1.0 +gammainv));
608      aVector->PutValue(i, beta/gammainv);
609  }
610  aPhysicsTable->insert(aVector);
611}
612///////////////////////////////////////////////////////////////////////////////
613//
614// LoadDecayTable
615//
616//     To load the decay scheme from the Radioactivity database for
617//     theParentNucleus.
618//
619G4DecayTable *G4RadioactiveDecay::LoadDecayTable (G4ParticleDefinition &theParentNucleus)
620{
621  //
622  //
623  // Create and initialise variables used in the method.
624  //
625  G4DecayTable *theDecayTable = new G4DecayTable();
626  //
627  //
628  // Determine the filename of the file containing radioactive decay data.  Open
629  // it.
630  //
631  G4int A    = ((const G4Ions*)(&theParentNucleus))->GetAtomicMass();
632  G4int Z    = ((const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
633  G4double E = ((const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
634
635  if ( !getenv("G4RADIOACTIVEDATA") ) {
636    G4cout << "Please setenv G4RADIOACTIVEDATA to point to the radioactive decay data files." << G4endl;
637    throw G4HadronicException(__FILE__, __LINE__, 
638              "Please setenv G4RADIOACTIVEDATA to point to the radioactive decay data files.");
639  }
640  G4String dirName = getenv("G4RADIOACTIVEDATA");
641  LoadedNuclei.push_back(theParentNucleus.GetParticleName());
642  std::sort( LoadedNuclei.begin(), LoadedNuclei.end() );
643  // sort needed to allow binary_search
644
645  std::ostringstream os;
646  os <<dirName <<"/z" <<Z <<".a" <<A <<'\0';
647  G4String file = os.str();
648
649 
650  std::ifstream DecaySchemeFile(file);
651  G4bool found(false);
652  if (DecaySchemeFile) { 
653    //
654    //
655    // Initialise variables used for reading in radioactive decay data.
656    //
657    G4int    nMode = 7;
658    G4bool   modeFirstRecord[7];
659    G4double modeTotalBR[7];
660    G4double modeSumBR[7];
661    G4int i;
662    for (i=0; i<nMode; i++) {
663      modeFirstRecord[i] = true;
664      modeSumBR[i]       = 0.0;
665    }
666   
667    G4bool complete(false);
668    char inputChars[80]={' '};
669    G4String inputLine;
670    G4String recordType("");
671    G4RadioactiveDecayMode theDecayMode;
672    G4double a(0.0);
673    G4double b(0.0);
674    G4double c(0.0);
675    G4double n(1.0);
676    G4double e0;
677    //
678    //
679    // Go through each record in the data file until you identify the decay
680    // data relating to the nuclide of concern.
681    //
682    //  while (!complete && -DecaySchemeFile.getline(inputChars, 80).eof() != EOF)
683    while (!complete && !DecaySchemeFile.getline(inputChars, 80).eof()) {
684      inputLine = inputChars;
685      //    G4String::stripType stripend(1);
686      //    inputLine = inputLine.strip(stripend);
687      inputLine = inputLine.strip(1);
688      if (inputChars[0] != '#' && inputLine.length() != 0) {
689        std::istringstream tmpStream(inputLine);
690        if (inputChars[0] == 'P') {
691          //
692          //
693          // Nucleus is a parent type.  Check the excitation level to see if it matches
694          // that of theParentNucleus
695          //
696          tmpStream >>recordType >>a >>b;
697          if (found) {complete = true;}
698          else {found = (std::abs(a*keV - E)<levelTolerance);}
699        } else if (found) {
700          //
701          //
702          // The right part of the radioactive decay data file has been found.  Search
703          // through it to determine the mode of decay of the subsequent records.
704          //
705          if (inputChars[0] == 'W') {
706#ifdef G4VERBOSE
707            if (GetVerboseLevel()>0) {
708              // a comment line identified and print out the message
709              //
710              G4cout << " Warning in G4RadioactiveDecay::LoadDecayTable " << G4endl;
711              G4cout << "   In data file " << file << G4endl;
712              G4cout << "   " << inputLine << G4endl;
713            }
714#endif
715          }     
716          else {
717            tmpStream >>theDecayMode >>a >>b >>c;
718            a/=1000.;
719            c/=1000.;
720                 
721            //  cout<< "The decay mode is [LoadTable] "<<theDecayMode<<G4endl;
722                 
723            switch (theDecayMode) {
724            case IT:
725              {
726                //
727                //
728                // Decay mode is isomeric transition.
729                //
730                G4ITDecayChannel *anITChannel = new G4ITDecayChannel
731                  (GetVerboseLevel(), (const G4Ions*) &theParentNucleus, b);
732                anITChannel->SetICM(applyICM);
733                anITChannel->SetARM(applyARM);
734                anITChannel->SetHLThreshold(halflifethreshold);
735                theDecayTable->Insert(anITChannel);
736                break;
737              }
738            case BetaMinus:
739              {
740                //
741                //
742                // Decay mode is beta-.
743                //
744                if (modeFirstRecord[1])
745                  {modeFirstRecord[1] = false; modeTotalBR[1] = b;}
746                else {
747                  if (c > 0.) {
748                    // to work out the Fermi function normalization factor first
749                    G4BetaFermiFunction* aBetaFermiFunction = new G4BetaFermiFunction (A, (Z+1));
750                    e0 = c*MeV/0.511;
751                    n = aBetaFermiFunction->GetFFN(e0);
752                               
753                    // now to work out the histogram and initialise the random generator
754                    G4int npti = 100;                           
755                    G4double* pdf = new G4double[npti];
756                    G4int ptn;
757                    G4double g,e,ee,f;
758                    ee = e0+1.;
759                    for (ptn=0; ptn<npti; ptn++) {
760                      // e =e0*(ptn+1.)/102.;
761                      // bug fix (#662) (flei, 22/09/2004)
762                      e =e0*(ptn+0.5)/100.;
763                      g = e+1.;
764                      f = std::sqrt(g*g-1)*(ee-g)*(ee-g)*g;
765                      // Special treatment for K-40 (problem #1068) (flei,06/05/2010)
766                      if (theParentNucleus.GetParticleName() == "K40[0.0]") f *=
767                        (std::pow((g*g-1),3)+std::pow((ee-g),6)+7*(g*g-1)*std::pow((ee-g),2)*(g*g-1+std::pow((ee-g),2)));
768                      pdf[ptn] = f*aBetaFermiFunction->GetFF(e);
769                    }             
770                    RandGeneral* aRandomEnergy = new RandGeneral( pdf, npti); 
771                    G4BetaMinusDecayChannel *aBetaMinusChannel = new
772                      G4BetaMinusDecayChannel (GetVerboseLevel(), &theParentNucleus,
773                                               b, c*MeV, a*MeV, n, FBeta, aRandomEnergy);
774                    aBetaMinusChannel->SetICM(applyICM);
775                    aBetaMinusChannel->SetARM(applyARM);
776                    aBetaMinusChannel->SetHLThreshold(halflifethreshold);
777                    theDecayTable->Insert(aBetaMinusChannel);
778                    modeSumBR[1] += b;
779                    delete[] pdf;
780                    delete aBetaFermiFunction;
781                  }
782                }
783                break;
784              case BetaPlus:
785                //
786                //
787                // Decay mode is beta+.
788                //
789                if (modeFirstRecord[2])
790                  {modeFirstRecord[2] = false; modeTotalBR[2] = b;}
791                else {
792                  //  e0 = c*MeV/0.511;
793                  // bug fix (#662) (flei, 22/09/2004)
794                  // need to test e0 as there are some data files (e.g. z67.a162) which have entries for beta+
795                  // with Q < 2Me
796                  //
797                  e0 = c*MeV/0.511 -2.;
798                  if (e0 > 0.) {
799                    G4BetaFermiFunction* aBetaFermiFunction = new G4BetaFermiFunction (A, -(Z-1));
800                               
801                    n = aBetaFermiFunction->GetFFN(e0);
802                               
803                    // now to work out the histogram and initialise the random generator
804                    G4int npti = 100;                           
805                    G4double* pdf = new G4double[npti];
806                    G4int ptn;
807                    G4double g,e,ee,f;
808                    ee = e0+1.;
809                    for (ptn=0; ptn<npti; ptn++) {
810                      // e =e0*(ptn+1.)/102.;
811                      // bug fix (#662) (flei, 22/09/2004)
812                      e =e0*(ptn+0.5)/100.;
813                      g = e+1.;
814                      f = std::sqrt(g*g-1)*(ee-g)*(ee-g)*g;
815                      pdf[ptn] = f*aBetaFermiFunction->GetFF(e);
816                    }
817                    RandGeneral* aRandomEnergy = new RandGeneral( pdf, npti); 
818                    G4BetaPlusDecayChannel *aBetaPlusChannel = new 
819                      G4BetaPlusDecayChannel (GetVerboseLevel(), &theParentNucleus,
820                                              b, c*MeV, a*MeV, n, FBeta, aRandomEnergy);
821                    aBetaPlusChannel->SetICM(applyICM);
822                    aBetaPlusChannel->SetARM(applyARM);
823                    aBetaPlusChannel->SetHLThreshold(halflifethreshold);
824                    theDecayTable->Insert(aBetaPlusChannel);
825                    modeSumBR[2] += b;
826                               
827                    delete[] pdf;
828                    delete aBetaFermiFunction;       
829                  }
830                }
831                break;
832              case KshellEC:
833                //
834                //
835                // Decay mode is K-electron capture.
836                //
837                if (modeFirstRecord[3])
838                  {modeFirstRecord[3] = false; modeTotalBR[3] = b;}
839                else {
840                  G4KshellECDecayChannel *aKECChannel = new
841                    G4KshellECDecayChannel (GetVerboseLevel(), &theParentNucleus,
842                                            b, c*MeV, a*MeV);
843                  aKECChannel->SetICM(applyICM);
844                  aKECChannel->SetARM(applyARM);
845                  aKECChannel->SetHLThreshold(halflifethreshold);
846                  theDecayTable->Insert(aKECChannel);
847                  //delete aKECChannel;
848                  modeSumBR[3] += b;
849                }
850                break;
851              case LshellEC:
852                //
853                //
854                // Decay mode is L-electron capture.
855                //
856                if (modeFirstRecord[4])
857                  {modeFirstRecord[4] = false; modeTotalBR[4] = b;}
858                else {
859                  G4LshellECDecayChannel *aLECChannel = new
860                    G4LshellECDecayChannel (GetVerboseLevel(), &theParentNucleus,
861                                            b, c*MeV, a*MeV);
862                  aLECChannel->SetICM(applyICM);
863                  aLECChannel->SetARM(applyARM);
864                  aLECChannel->SetHLThreshold(halflifethreshold);
865                  theDecayTable->Insert(aLECChannel);
866                  //delete aLECChannel;
867                  modeSumBR[4] += b;
868                }
869                break;
870              case MshellEC:
871                //
872                //
873                // Decay mode is M-electron capture. In this implementation it is added to L-shell case
874                //
875                if (modeFirstRecord[5])
876                  {modeFirstRecord[5] = false; modeTotalBR[5] = b;}
877                else {
878                  G4MshellECDecayChannel *aMECChannel = new
879                    G4MshellECDecayChannel (GetVerboseLevel(), &theParentNucleus,
880                                            b, c*MeV, a*MeV);
881                  aMECChannel->SetICM(applyICM);
882                  aMECChannel->SetARM(applyARM);
883                  aMECChannel->SetHLThreshold(halflifethreshold);
884                  theDecayTable->Insert(aMECChannel);
885                  modeSumBR[5] += b;
886                }
887                break;
888              case Alpha:
889                //
890                //
891                // Decay mode is alpha.
892                //
893                if (modeFirstRecord[6])
894                  {modeFirstRecord[6] = false; modeTotalBR[6] = b;}
895                else {
896                  G4AlphaDecayChannel *anAlphaChannel = new
897                    G4AlphaDecayChannel (GetVerboseLevel(), &theParentNucleus,
898                                         b, c*MeV, a*MeV);
899                  anAlphaChannel->SetICM(applyICM);
900                  anAlphaChannel->SetARM(applyARM);
901                  anAlphaChannel->SetHLThreshold(halflifethreshold);
902                  theDecayTable->Insert(anAlphaChannel);
903                  //          delete anAlphaChannel;
904                  modeSumBR[6] += b;
905                }
906                break;
907              case ERROR:
908              default:
909                G4Exception("G4RadioactiveDecay::LoadDecayTable()", "601",
910                            FatalException, "Error in decay mode selection");
911               
912              }
913            }
914          }
915        }
916      }
917    }   
918    //
919    //
920    // Go through the decay table and make sure that the branching ratios are
921    // correctly normalised.
922    //
923    G4VDecayChannel       *theChannel             = 0;
924    G4NuclearDecayChannel *theNuclearDecayChannel = 0;
925    G4String mode                     = "";
926    G4int j                           = 0;
927    G4double theBR                    = 0.0;
928    for (i=0; i<theDecayTable->entries(); i++) {
929      theChannel             = theDecayTable->GetDecayChannel(i);
930      theNuclearDecayChannel = static_cast<G4NuclearDecayChannel *>(theChannel);
931      theDecayMode           = theNuclearDecayChannel->GetDecayMode();
932      j          = 0;
933      if (theDecayMode != IT) {
934        theBR = theChannel->GetBR();
935        theChannel->SetBR(theBR*modeTotalBR[theDecayMode]/modeSumBR[theDecayMode]);
936      }
937    } 
938  }             
939  DecaySchemeFile.close();             
940  if (!found && E > 0.) {
941    // cases where IT cascade for exited isotopes without entry in RDM database
942    // Decay mode is isomeric transition.
943    //
944    G4ITDecayChannel *anITChannel = new G4ITDecayChannel
945      (GetVerboseLevel(), (const G4Ions*) &theParentNucleus, 1);
946    anITChannel->SetICM(applyICM);
947    anITChannel->SetARM(applyARM);
948    anITChannel->SetHLThreshold(halflifethreshold);
949    theDecayTable->Insert(anITChannel);
950  } 
951  if (!theDecayTable) {
952    //
953    // There is no radioactive decay data for this nucleus.  Return a null
954    // decay table.
955    //
956    G4cerr <<"G4RadoactiveDecay::LoadDecayTable() : cannot find ion radioactive decay file " <<G4endl;
957    theDecayTable = 0;
958    return theDecayTable;
959  }     
960  if (theDecayTable && GetVerboseLevel()>1)
961    {
962      G4cout <<"G4RadioactiveDecay::LoadDecayTable()" << G4endl;
963      G4cout << "  No. of  entries: "<< theDecayTable->entries() <<G4endl;
964      theDecayTable ->DumpInfo();
965    }
966
967  return theDecayTable;
968}
969
970////////////////////////////////////////////////////////////////////////
971//
972//
973void G4RadioactiveDecay::SetDecayRate(G4int theZ, G4int theA, G4double theE, 
974                                       G4int theG, std::vector<G4double> theRates, 
975                                       std::vector<G4double> theTaos)
976{ 
977  //fill the decay rate vector
978  theDecayRate.SetZ(theZ);
979  theDecayRate.SetA(theA);
980  theDecayRate.SetE(theE);
981  theDecayRate.SetGeneration(theG);
982  theDecayRate.SetDecayRateC(theRates);
983  theDecayRate.SetTaos(theTaos);
984}
985//////////////////////////////////////////////////////////////////////////
986//
987//
988void G4RadioactiveDecay::AddDecayRateTable(const G4ParticleDefinition &theParentNucleus)
989{
990  // 1) To calculate all the coefficiecies required to derive the radioactivities for all
991  // progeny of theParentNucleus
992  //
993  // 2) Add the coefficiencies to the decay rate table vector
994  //
995 
996  //
997  // Create and initialise variables used in the method.
998  //
999
1000  theDecayRateVector.clear();
1001 
1002  G4int nGeneration = 0;
1003  std::vector<G4double> rates;
1004  std::vector<G4double> taos;
1005 
1006  // start rate is -1.
1007  rates.push_back(-1.);
1008  //
1009  //
1010  G4int A = ((const G4Ions*)(&theParentNucleus))->GetAtomicMass();
1011  G4int Z = ((const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
1012  G4double E = ((const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
1013  G4double tao = theParentNucleus.GetPDGLifeTime();
1014  taos.push_back(tao);
1015  G4int nEntry = 0;
1016 
1017  //fill the decay rate with the intial isotope data
1018  SetDecayRate(Z,A,E,nGeneration,rates,taos);
1019
1020  // store the decay rate in decay rate vector
1021  theDecayRateVector.push_back(theDecayRate);
1022  nEntry++;
1023
1024  // now start treating the sencondary generations..
1025
1026  G4bool stable = false;
1027  G4int i;
1028  G4int j;
1029  G4VDecayChannel       *theChannel             = 0;
1030  G4NuclearDecayChannel *theNuclearDecayChannel = 0;
1031  G4ITDecayChannel *theITChannel = 0;
1032  G4BetaMinusDecayChannel *theBetaMinusChannel = 0;
1033  G4BetaPlusDecayChannel *theBetaPlusChannel = 0;
1034  G4AlphaDecayChannel *theAlphaChannel = 0;
1035  G4RadioactiveDecayMode theDecayMode;
1036  //  G4NuclearLevelManager levelManager;
1037  //const G4NuclearLevel* level;
1038  G4double theBR = 0.0;
1039  G4int AP = 0;
1040  G4int ZP = 0;
1041  G4int AD = 0;
1042  G4int ZD = 0;
1043  G4double EP = 0.;
1044  std::vector<G4double> TP;
1045  std::vector<G4double> RP;
1046  G4ParticleDefinition *theDaughterNucleus;
1047  G4double daughterExcitation;
1048  G4ParticleDefinition *aParentNucleus;
1049  G4IonTable* theIonTable;
1050  G4DecayTable *aTempDecayTable;
1051  G4double theRate;
1052  G4double TaoPlus;
1053  G4int nS = 0;
1054  G4int nT = nEntry;
1055  G4double brs[7];
1056  //
1057  theIonTable = (G4IonTable *)(G4ParticleTable::GetParticleTable()->GetIonTable());
1058 
1059  while (!stable) {
1060    nGeneration++;
1061    for (j = nS; j< nT; j++) {
1062      ZP = theDecayRateVector[j].GetZ();
1063      AP = theDecayRateVector[j].GetA();
1064      EP = theDecayRateVector[j].GetE();
1065      RP = theDecayRateVector[j].GetDecayRateC();
1066      TP = theDecayRateVector[j].GetTaos();     
1067      if (GetVerboseLevel()>0){
1068        G4cout <<"G4RadioactiveDecay::AddDecayRateTable : "
1069               << " daughters of ("<< ZP <<", "<<AP<<", "
1070               << EP <<") "
1071               << " are being calculated. "       
1072               <<" generation = "
1073               << nGeneration << G4endl;
1074      }
1075      aParentNucleus = theIonTable->GetIon(ZP,AP,EP);
1076      if (!IsLoaded(*aParentNucleus)){
1077        aParentNucleus->SetDecayTable(LoadDecayTable(*aParentNucleus));
1078      }
1079      aTempDecayTable = aParentNucleus->GetDecayTable();
1080      //
1081      //
1082      // Go through the decay table and to combine the same decay channels
1083      //
1084      for (i=0; i< 7; i++) brs[i] = 0.0;
1085     
1086      G4DecayTable *theDecayTable = new G4DecayTable();
1087     
1088      for (i=0; i<aTempDecayTable->entries(); i++) {
1089        theChannel             = aTempDecayTable->GetDecayChannel(i);
1090        theNuclearDecayChannel = static_cast<G4NuclearDecayChannel *>(theChannel);
1091        theDecayMode           = theNuclearDecayChannel->GetDecayMode();
1092        daughterExcitation = theNuclearDecayChannel->GetDaughterExcitation ();
1093        theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus () ;
1094        AD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
1095        ZD = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber(); 
1096        G4NuclearLevelManager * levelManager = G4NuclearLevelStore::GetInstance()->GetManager (ZD, AD);
1097        if ( levelManager->NumberOfLevels() ) {
1098          const G4NuclearLevel* level = levelManager->NearestLevel (daughterExcitation);
1099
1100          if (std::abs(daughterExcitation - level->Energy()) < levelTolerance) {
1101           
1102            // Level hafe life is in ns and the gate as 1 micros by default
1103            if ( theDecayMode == 0 && level->HalfLife()*ns >= halflifethreshold ){   
1104              // some further though may needed here
1105              theDecayTable->Insert(theChannel);
1106            } 
1107            else{
1108              brs[theDecayMode] += theChannel->GetBR();
1109            }
1110          }
1111          else {
1112            brs[theDecayMode] += theChannel->GetBR();
1113          }
1114        }
1115        else{
1116          brs[theDecayMode] += theChannel->GetBR();
1117        }
1118      }     
1119      brs[2] = brs[2]+brs[3]+brs[4]+brs[5];
1120      brs[3] = brs[4] =brs[5] =  0.0;
1121      for (i= 0; i<7; i++){
1122        if (brs[i] > 0) {
1123          switch ( i ) {
1124          case 0:
1125            //
1126            //
1127            // Decay mode is isomeric transition.
1128            //
1129           
1130            theITChannel =  new G4ITDecayChannel
1131              (0, (const G4Ions*) aParentNucleus, brs[0]);
1132           
1133            theDecayTable->Insert(theITChannel);
1134            break;
1135           
1136          case 1:
1137            //
1138            //
1139            // Decay mode is beta-.
1140            //
1141            theBetaMinusChannel = new G4BetaMinusDecayChannel (0, aParentNucleus,
1142                                                               brs[1], 0.*MeV, 0.*MeV, 1, false, 0);
1143            theDecayTable->Insert(theBetaMinusChannel);
1144           
1145            break;
1146           
1147          case 2:
1148            //
1149            //
1150            // Decay mode is beta+ + EC.
1151            //
1152            theBetaPlusChannel = new G4BetaPlusDecayChannel (GetVerboseLevel(), aParentNucleus,
1153                                                             brs[2], 0.*MeV, 0.*MeV, 1, false, 0);
1154            theDecayTable->Insert(theBetaPlusChannel);
1155            break;                   
1156           
1157          case 6:
1158            //
1159            //
1160            // Decay mode is alpha.
1161            //
1162            theAlphaChannel = new G4AlphaDecayChannel (GetVerboseLevel(), aParentNucleus,
1163                                                       brs[6], 0.*MeV, 0.*MeV);
1164            theDecayTable->Insert(theAlphaChannel);
1165            break;
1166           
1167          default:
1168            break;
1169          }
1170        }
1171      }
1172       
1173      //
1174      // loop over all braches in theDecayTable
1175      //
1176      for ( i=0; i<theDecayTable->entries(); i++){
1177        theChannel             = theDecayTable->GetDecayChannel(i);
1178        theNuclearDecayChannel = static_cast<G4NuclearDecayChannel *>(theChannel);
1179        theBR = theChannel->GetBR();
1180        theDaughterNucleus = theNuclearDecayChannel->GetDaughterNucleus();
1181       
1182        //
1183        // now test if the daughterNucleus is a valid one
1184        //
1185        if (IsApplicable(*theDaughterNucleus) && theBR
1186            && aParentNucleus != theDaughterNucleus ) {
1187          // need to make sure daugher has decaytable
1188          if (!IsLoaded(*theDaughterNucleus)){
1189            theDaughterNucleus->SetDecayTable(LoadDecayTable(*theDaughterNucleus));
1190          }
1191          if (theDaughterNucleus->GetDecayTable()->entries() ) {
1192            //
1193            A = ((const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
1194            Z = ((const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
1195            E = ((const G4Ions*)(theDaughterNucleus))->GetExcitationEnergy();
1196         
1197            TaoPlus = theDaughterNucleus->GetPDGLifeTime();
1198            //          cout << TaoPlus <<G4endl;
1199            if (TaoPlus > 0.) {
1200              // first set the taos, one simply need to add to the parent ones
1201              taos.clear();
1202              taos = TP;
1203              taos.push_back(TaoPlus);
1204              // now calculate the coefficiencies
1205              //
1206              // they are in two parts, first the les than n ones
1207              rates.clear();
1208              size_t k;
1209              for (k = 0; k < RP.size(); k++){
1210                theRate = TP[k]/(TP[k]-TaoPlus) * theBR * RP[k];
1211                rates.push_back(theRate);
1212              }
1213              //
1214              // the sencond part: the n:n coefficiency
1215              theRate = 0.;
1216              for (k = 0; k < RP.size(); k++){
1217                theRate -=TaoPlus/(TP[k]-TaoPlus) * theBR * RP[k];
1218              }
1219              rates.push_back(theRate);               
1220              SetDecayRate (Z,A,E,nGeneration,rates,taos);
1221              theDecayRateVector.push_back(theDecayRate);
1222              nEntry++;
1223            } 
1224          }
1225        } 
1226        // end of testing daughter nucleus
1227      }
1228      // end of i loop( the branches)
1229    }
1230    //end of for j loop
1231    nS = nT;
1232    nT = nEntry;
1233    if (nS == nT) stable = true;
1234  }
1235 
1236  //end of while loop
1237  // the calculation completed here
1238 
1239 
1240  // fill the first part of the decay rate table
1241  // which is the name of the original particle (isotope)
1242  //
1243  theDecayRateTable.SetIonName(theParentNucleus.GetParticleName()); 
1244  //
1245  //
1246  // now fill the decay table with the newly completed decay rate vector
1247  //
1248 
1249  theDecayRateTable.SetItsRates(theDecayRateVector);
1250 
1251  //
1252  // finally add the decayratetable to the tablevector
1253  //
1254  theDecayRateTableVector.push_back(theDecayRateTable);
1255}
1256 
1257////////////////////////////////////////////////////////////////////////////////
1258//
1259//
1260// SetSourceTimeProfile
1261//
1262//  read in the source time profile function (histogram)
1263//
1264
1265void G4RadioactiveDecay::SetSourceTimeProfile(G4String filename)
1266{
1267  std::ifstream infile ( filename, std::ios::in );
1268  if ( !infile ) G4Exception(__FILE__, G4inttostring(__LINE__), FatalException,  "Unable to open source data file" );
1269 
1270  float bin, flux;
1271  NSourceBin = -1;
1272  while (infile >> bin >> flux ) {
1273    NSourceBin++;
1274    if (NSourceBin > 99)  G4Exception(__FILE__, G4inttostring(__LINE__), FatalException,  "input source data file too big (>100 rows)" );
1275    SBin[NSourceBin] = bin * s;
1276    SProfile[NSourceBin] = flux;
1277  }
1278  SetAnalogueMonteCarlo(0);
1279#ifdef G4VERBOSE
1280  if (GetVerboseLevel()>1)
1281    {G4cout <<" Source Timeprofile Nbin = " << NSourceBin <<G4endl;}
1282#endif
1283}
1284
1285////////////////////////////////////////////////////////////////////////////////
1286//
1287//
1288// SetDecayBiasProfile
1289//
1290// read in the decay bias scheme function (histogram)
1291//
1292void G4RadioactiveDecay::SetDecayBias(G4String filename)
1293{
1294  std::ifstream infile ( filename, std::ios::in);
1295  if ( !infile ) G4Exception(__FILE__, G4inttostring(__LINE__), FatalException,  "Unable to open bias data file" );
1296 
1297  float bin, flux;
1298  NDecayBin = -1;
1299  while (infile >> bin >> flux ) {
1300    NDecayBin++;
1301    if (NDecayBin > 99)  G4Exception(__FILE__, G4inttostring(__LINE__), FatalException,  "input bias data file too big (>100 rows)" );
1302    DBin[NDecayBin] = bin * s;
1303    DProfile[NDecayBin] = flux;
1304  }
1305  G4int i ;
1306  for ( i = 1; i<= NDecayBin; i++) DProfile[i] += DProfile[i-1];
1307  for ( i = 0; i<= NDecayBin; i++) DProfile[i] /= DProfile[NDecayBin];
1308  SetAnalogueMonteCarlo(0);
1309#ifdef G4VERBOSE
1310  if (GetVerboseLevel()>1)
1311    {G4cout <<" Decay Bias Profile  Nbin = " << NDecayBin <<G4endl;}
1312#endif
1313}
1314
1315////////////////////////////////////////////////////////////////////////////////
1316//
1317//
1318// DecayIt
1319//
1320G4VParticleChange* G4RadioactiveDecay::DecayIt(const G4Track& theTrack, const G4Step& )
1321{
1322  //
1323  // Initialize the G4ParticleChange object. Get the particle details and the
1324  // decay table.
1325  //
1326  fParticleChangeForRadDecay.Initialize(theTrack);
1327  const G4DynamicParticle* theParticle = theTrack.GetDynamicParticle();
1328  G4ParticleDefinition *theParticleDef = theParticle->GetDefinition();
1329
1330  // First check whether RDM applies to the current logical volume
1331  //
1332  if(!std::binary_search(ValidVolumes.begin(),
1333                    ValidVolumes.end(), 
1334                    theTrack.GetVolume()->GetLogicalVolume()->GetName()))
1335    {
1336#ifdef G4VERBOSE
1337      if (GetVerboseLevel()>0)
1338        {
1339          G4cout <<"G4RadioactiveDecay::DecayIt : "
1340                 << theTrack.GetVolume()->GetLogicalVolume()->GetName()
1341                 << " is not selected for the RDM"<< G4endl;
1342          G4cout << " There are " << ValidVolumes.size() << " volumes" << G4endl;
1343          G4cout << " The Valid volumes are " << G4endl;
1344          for (size_t i = 0; i< ValidVolumes.size(); i++)
1345            G4cout << ValidVolumes[i] << G4endl;
1346        }
1347#endif
1348      fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
1349      //
1350      //
1351      // Kill the parent particle.
1352      //
1353      fParticleChangeForRadDecay.ProposeTrackStatus( fStopAndKill ) ;
1354      fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
1355      ClearNumberOfInteractionLengthLeft();
1356      return &fParticleChangeForRadDecay;
1357    }
1358   
1359  // now check is the particle is valid for RDM
1360  //
1361  if (!(IsApplicable(*theParticleDef)))
1362    { 
1363      //
1364      // The particle is not a Ion or outside the nucleuslimits for decay
1365      //
1366#ifdef G4VERBOSE
1367      if (GetVerboseLevel()>0)
1368        {
1369          G4cerr <<"G4RadioactiveDecay::DecayIt : "
1370                 <<theParticleDef->GetParticleName() 
1371                 << " is not a valid nucleus for the RDM"<< G4endl;
1372        }
1373#endif
1374      fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
1375      //
1376      //
1377      // Kill the parent particle.
1378      //
1379      fParticleChangeForRadDecay.ProposeTrackStatus( fStopAndKill ) ;
1380      fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
1381      ClearNumberOfInteractionLengthLeft();
1382      return &fParticleChangeForRadDecay;
1383    }
1384 
1385  if (!IsLoaded(*theParticleDef))
1386    {
1387      theParticleDef->SetDecayTable(LoadDecayTable(*theParticleDef));
1388    }
1389  G4DecayTable *theDecayTable = theParticleDef->GetDecayTable();
1390 
1391  if  (theDecayTable == 0 || theDecayTable->entries() == 0 )
1392    {
1393      //
1394      //
1395      // There are no data in the decay table.  Set the particle change parameters
1396      // to indicate this.
1397      //
1398#ifdef G4VERBOSE
1399      if (GetVerboseLevel()>0)
1400        {
1401          G4cerr <<"G4RadioactiveDecay::DecayIt : decay table not defined  for ";
1402          G4cerr <<theParticleDef->GetParticleName() <<G4endl;
1403        }
1404#endif
1405      fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
1406      //
1407      //
1408      // Kill the parent particle.
1409      //
1410      fParticleChangeForRadDecay.ProposeTrackStatus( fStopAndKill ) ;
1411      fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
1412      ClearNumberOfInteractionLengthLeft();
1413      return &fParticleChangeForRadDecay;
1414    }
1415  else 
1416    { 
1417      //
1418      // now try to  decay it
1419      //
1420      G4double energyDeposit = 0.0;
1421      G4double finalGlobalTime = theTrack.GetGlobalTime();
1422      G4int index;
1423      G4ThreeVector currentPosition;
1424      currentPosition = theTrack.GetPosition();
1425     
1426      // check whether use Analogue or VR implementation
1427      //
1428      if (AnalogueMC){
1429        //
1430        // Aanalogue MC
1431#ifdef G4VERBOSE
1432        if (GetVerboseLevel()>0)
1433          {
1434            G4cout <<"DecayIt:  Analogue MC version " << G4endl;
1435          }
1436#endif
1437        //
1438        G4DecayProducts *products = DoDecay(*theParticleDef);
1439        //
1440        // check if the product is the same as input and kill the track if necessary to prevent infinite loop
1441        // (11/05/10, F.Lei)
1442        //
1443        if ( products->entries() == 1) {
1444          fParticleChangeForRadDecay.SetNumberOfSecondaries(0);
1445          fParticleChangeForRadDecay.ProposeTrackStatus( fStopAndKill ) ;
1446          fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(0.0);
1447          ClearNumberOfInteractionLengthLeft();
1448          return &fParticleChangeForRadDecay;
1449        }       
1450        //
1451        // Get parent particle information and boost the decay products to the
1452        // laboratory frame based on this information.
1453        //
1454        G4double ParentEnergy = theParticle->GetTotalEnergy();
1455        G4ThreeVector ParentDirection(theParticle->GetMomentumDirection());
1456       
1457        if (theTrack.GetTrackStatus() == fStopButAlive )
1458          {
1459            //
1460            //
1461            // The particle is decayed at rest.
1462            //
1463            // since the time is still for rest particle in G4 we need to add the additional
1464            // time lapsed between the particle come to rest and the actual decay. This time
1465            // is simply sampled with the mean-life of the particle.
1466            // but we need to protect the case PDGTime < 0. (F.Lei 11/05/10)
1467            G4double temptime =  -std::log( G4UniformRand()) * theParticleDef->GetPDGLifeTime();
1468            if (temptime <0.) temptime =0.; 
1469            finalGlobalTime += temptime ;
1470            energyDeposit += theParticle->GetKineticEnergy();
1471          }
1472        else
1473          {
1474            //
1475            //
1476            // The particle is decayed in flight (PostStep case).
1477            //
1478            products->Boost( ParentEnergy, ParentDirection);
1479          }
1480        //
1481        //
1482        // Add products in theParticleChangeForRadDecay.
1483        //
1484        G4int numberOfSecondaries = products->entries();
1485        fParticleChangeForRadDecay.SetNumberOfSecondaries(numberOfSecondaries);
1486#ifdef G4VERBOSE
1487        if (GetVerboseLevel()>1) {
1488          G4cout <<"G4RadioactiveDecay::DecayIt : Decay vertex :";
1489          G4cout <<" Time: " <<finalGlobalTime/ns <<"[ns]";
1490          G4cout <<" X:" <<(theTrack.GetPosition()).x() /cm <<"[cm]";
1491          G4cout <<" Y:" <<(theTrack.GetPosition()).y() /cm <<"[cm]";
1492          G4cout <<" Z:" <<(theTrack.GetPosition()).z() /cm <<"[cm]";
1493          G4cout <<G4endl;
1494          G4cout <<"G4Decay::DecayIt  : decay products in Lab. Frame" <<G4endl;
1495          products->DumpInfo();
1496        }
1497#endif
1498        for (index=0; index < numberOfSecondaries; index++) 
1499          {
1500            G4Track* secondary = new G4Track
1501              (products->PopProducts(), finalGlobalTime, currentPosition);
1502            secondary->SetGoodForTrackingFlag();
1503                        secondary->SetTouchableHandle(theTrack.GetTouchableHandle());
1504            fParticleChangeForRadDecay.AddSecondary(secondary);
1505          }
1506        delete products;
1507        //
1508        // end of analogue MC algarithm
1509        //
1510      }
1511      else {
1512        //
1513        // Varaice Reduction Method
1514        //
1515#ifdef G4VERBOSE
1516        if (GetVerboseLevel()>0)
1517          {
1518            G4cout <<"DecayIt:  Variance Reduction version " << G4endl;
1519          }
1520#endif
1521        if (!IsRateTableReady(*theParticleDef)) {
1522          // if the decayrates are not ready, calculate them and
1523          // add to the rate table vector
1524          AddDecayRateTable(*theParticleDef);
1525        }
1526        //retrieve the rates
1527        GetDecayRateTable(*theParticleDef);
1528        //
1529        // declare some of the variables required in the implementation
1530        //
1531        G4ParticleDefinition* parentNucleus;
1532        G4IonTable *theIonTable;
1533        G4int PZ;
1534        G4int PA;
1535        G4double PE;
1536        std::vector<G4double> PT;
1537        std::vector<G4double> PR;
1538        G4double taotime;
1539        G4double decayRate;
1540       
1541        size_t i;
1542        size_t j;
1543        G4int numberOfSecondaries;
1544        G4int totalNumberOfSecondaries = 0;
1545        G4double currentTime = 0.;
1546        G4int ndecaych;
1547        G4DynamicParticle* asecondaryparticle;
1548        //      G4DecayProducts* products = 0;
1549        std::vector<G4DynamicParticle*> secondaryparticles;
1550        std::vector<G4double> pw;
1551        std::vector<G4double> ptime;
1552        pw.clear();
1553        ptime.clear();
1554        //now apply the nucleus splitting
1555        //
1556        //
1557        for (G4int n = 0; n < NSplit; n++)
1558          {
1559            /*
1560            //
1561            // Get the decay time following the decay probability function
1562            // suppllied by user
1563            //
1564            G4double theDecayTime = GetDecayTime();
1565           
1566            G4int nbin = GetDecayTimeBin(theDecayTime);
1567           
1568            // claculate the first part of the weight function
1569           
1570            G4double weight1 =1./DProfile[nbin-1]
1571              *(DBin[nbin]-DBin[nbin-1])
1572              /NSplit;
1573            if (nbin > 1) {
1574               weight1 = 1./(DProfile[nbin]-DProfile[nbin-2])
1575                 *(DBin[nbin]-DBin[nbin-1])
1576                 /NSplit;}
1577            // it should be calculated in seconds
1578            weight1 /= s ;
1579            */
1580            //
1581            // loop over all the possible secondaries of the nucleus
1582            // the first one is itself.
1583            //
1584            for ( i = 0; i<theDecayRateVector.size(); i++){
1585              PZ = theDecayRateVector[i].GetZ();
1586              PA = theDecayRateVector[i].GetA();
1587              PE = theDecayRateVector[i].GetE();
1588              PT = theDecayRateVector[i].GetTaos();
1589              PR = theDecayRateVector[i].GetDecayRateC();
1590
1591              //
1592              // Get the decay time following the decay probability function
1593              // suppllied by user
1594              //
1595              G4double theDecayTime = GetDecayTime();
1596             
1597              G4int nbin = GetDecayTimeBin(theDecayTime);
1598             
1599              // claculate the first part of the weight function
1600             
1601              G4double weight1 =1./DProfile[nbin-1] 
1602                *(DBin[nbin]-DBin[nbin-1])
1603                /NSplit;
1604              if (nbin > 1) {
1605                weight1 = 1./(DProfile[nbin]-DProfile[nbin-2])
1606                  *(DBin[nbin]-DBin[nbin-1])
1607                  /NSplit;}
1608              // it should be calculated in seconds
1609              weight1 /= s ;
1610             
1611              // a temprary products buffer and its contents is transfered to
1612              // the products at the end of the loop
1613              //
1614              G4DecayProducts *tempprods = 0;
1615             
1616              // calculate the decay rate of the isotope
1617              // one need to fold the the source bias function with the decaytime
1618              //
1619              decayRate = 0.;
1620              for ( j = 0; j < PT.size(); j++){
1621                taotime = GetTaoTime(theDecayTime,PT[j]);
1622                decayRate -= PR[j] * taotime;
1623              }
1624             
1625              // decayRatehe radioactivity of isotope (PZ,PA,PE) at the
1626              // time 'theDecayTime'
1627              // it will be used to calculate the statistical weight of the
1628              // decay products of this isotope
1629             
1630             
1631              //
1632              // now calculate the statistical weight
1633              //
1634             
1635              G4double weight = weight1*decayRate; 
1636              // decay the isotope
1637              theIonTable = (G4IonTable *)(G4ParticleTable::GetParticleTable()->GetIonTable());
1638              parentNucleus = theIonTable->GetIon(PZ,PA,PE);
1639             
1640              // decide whther to apply branching ratio bias or not
1641              //
1642              if (BRBias){
1643                G4DecayTable *theDecayTable = parentNucleus->GetDecayTable();
1644                ndecaych = G4int(theDecayTable->entries()*G4UniformRand());
1645                G4VDecayChannel *theDecayChannel = theDecayTable->GetDecayChannel(ndecaych);
1646                if (theDecayChannel == 0)
1647                  {
1648                    // Decay channel not found.
1649#ifdef G4VERBOSE
1650                    if (GetVerboseLevel()>0)
1651                      {
1652                        G4cerr <<"G4RadioactiveDecay::DoIt : can not determine decay channel";
1653                        G4cerr <<G4endl;
1654                        theDecayTable ->DumpInfo();
1655                      }
1656#endif
1657                  }
1658                else
1659                  {
1660                    // A decay channel has been identified, so execute the DecayIt.
1661                    G4double tempmass = parentNucleus->GetPDGMass();     
1662                    tempprods = theDecayChannel->DecayIt(tempmass);
1663                    weight *= (theDecayChannel->GetBR())*(theDecayTable->entries());
1664                  }
1665              }
1666              else {
1667                tempprods = DoDecay(*parentNucleus);
1668              }
1669              //
1670              // save the secondaries for buffers
1671              //
1672              numberOfSecondaries = tempprods->entries();
1673              currentTime = finalGlobalTime + theDecayTime;
1674              for (index=0; index < numberOfSecondaries; index++) 
1675                {
1676                  asecondaryparticle = tempprods->PopProducts();
1677                  if (asecondaryparticle->GetDefinition()->GetBaryonNumber() < 5){
1678                    pw.push_back(weight);
1679                    ptime.push_back(currentTime);
1680                    secondaryparticles.push_back(asecondaryparticle);
1681                  }
1682                }
1683              //
1684              delete tempprods;
1685             
1686              //end of i loop
1687            }
1688           
1689            // end of n loop
1690          } 
1691        // now deal with the secondaries in the two stl containers
1692        // and submmit them back to the tracking manager
1693        //
1694        totalNumberOfSecondaries = pw.size();
1695        fParticleChangeForRadDecay.SetNumberOfSecondaries(totalNumberOfSecondaries);
1696        for (index=0; index < totalNumberOfSecondaries; index++) 
1697          { 
1698            G4Track* secondary = new G4Track(
1699                                             secondaryparticles[index], ptime[index], currentPosition);
1700            secondary->SetGoodForTrackingFlag();           
1701                        secondary->SetTouchableHandle(theTrack.GetTouchableHandle());
1702            secondary->SetWeight(pw[index]);       
1703            fParticleChangeForRadDecay.AddSecondary(secondary); 
1704          }
1705        //
1706        // make sure the original track is set to stop and its kinematic energy collected
1707        //
1708        //theTrack.SetTrackStatus(fStopButAlive);
1709        //energyDeposit += theParticle->GetKineticEnergy();
1710       
1711      }
1712   
1713      //
1714      // Kill the parent particle.
1715      //
1716      fParticleChangeForRadDecay.ProposeTrackStatus( fStopAndKill ) ;
1717      fParticleChangeForRadDecay.ProposeLocalEnergyDeposit(energyDeposit);
1718      //
1719      fParticleChangeForRadDecay.ProposeGlobalTime( finalGlobalTime );
1720      //
1721      // Reset NumberOfInteractionLengthLeft.
1722      //
1723      ClearNumberOfInteractionLengthLeft();
1724     
1725      return &fParticleChangeForRadDecay ;
1726    }
1727} 
1728
1729////////////////////////////////////////////////////////////////////////////////
1730//
1731//
1732// DoDecay
1733//
1734G4DecayProducts* G4RadioactiveDecay::DoDecay(  G4ParticleDefinition& theParticleDef )
1735{
1736  G4DecayProducts *products = 0;
1737  //
1738  //
1739  // follow the decaytable and generate the secondaries...
1740  //
1741  //
1742#ifdef G4VERBOSE
1743  if (GetVerboseLevel()>0)
1744    {
1745      G4cout<<"Begin of DoDecay..."<<G4endl;
1746    }
1747#endif
1748  G4DecayTable *theDecayTable = theParticleDef.GetDecayTable();
1749  //
1750  // Choose a decay channel.
1751  //
1752#ifdef G4VERBOSE
1753  if (GetVerboseLevel()>0)
1754    {
1755      G4cout <<"Selecte a channel..."<<G4endl;
1756    }
1757#endif
1758  G4VDecayChannel *theDecayChannel = theDecayTable->SelectADecayChannel();
1759  if (theDecayChannel == 0)
1760    {
1761      // Decay channel not found.
1762      //
1763      G4cerr <<"G4RadioactiveDecay::DoIt : can not determine decay channel";
1764      G4cerr <<G4endl;
1765      theDecayTable ->DumpInfo();
1766    }
1767      else
1768    {
1769      //
1770      // A decay channel has been identified, so execute the DecayIt.
1771      //
1772#ifdef G4VERBOSE
1773      if (GetVerboseLevel()>1)
1774        {
1775          G4cerr <<"G4RadioactiveDecay::DoIt : selected decay channel  addr:";
1776          G4cerr <<theDecayChannel <<G4endl;
1777        }
1778#endif
1779     
1780      G4double tempmass = theParticleDef.GetPDGMass();
1781      //
1782     
1783      products = theDecayChannel->DecayIt(tempmass);
1784     
1785    }
1786  return products;
1787
1788}
1789
1790
1791
1792
1793
1794
1795
1796
1797
Note: See TracBrowser for help on using the repository browser.