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