139 using namespace CLHEP;
141 const G4double G4RadioactiveDecay::levelTolerance =2.0*
keV;
146 isInitialised(false), forceDecayDirection(0.,0.,0.),
147 forceDecayHalfAngle(0.*deg), verboseLevel(0)
151 G4cout <<
"G4RadioactiveDecay constructor Name: ";
169 LoadedNuclei.clear();
174 theUserRadioactiveDataFiles.clear();
192 theRadioactivityTables.push_back(rTable);
199 halflifethreshold = -1.*
second;
202 isAllVolumesMode=
true;
209 delete theRadioactiveDecaymessenger;
217 if (((
const G4Ions*)(&aParticle))->GetExcitationEnergy() > 0.) {
return true;}
227 G4int A = ((
const G4Ions*) (&aParticle))->GetAtomicMass();
228 G4int Z = ((
const G4Ions*) (&aParticle))->GetAtomicNumber();
229 if (A > theNucleusLimits.
GetAMax() || A < theNucleusLimits.
GetAMin())
231 else if (Z > theNucleusLimits.
GetZMax() || Z < theNucleusLimits.
GetZMin())
242 return std::binary_search(LoadedNuclei.begin(),
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());
263 }
else if(i == theLogicalVolumes->size())
265 G4cerr <<
"SelectAVolume: "<<aVolume <<
" is not a valid logical volume name"<<
G4endl;
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;
286 G4cerr <<
" DeselectVolume:" << aVolume <<
" is not in the list"<<
G4endl;
290 G4cout <<
" DeselectVolume: " << aVolume <<
" is removed from list"<<
G4endl;
292 }
else if (i == theLogicalVolumes->size()) {
293 G4cerr <<
" DeselectVolume:" << aVolume
294 <<
"is not a valid logical volume name"<<
G4endl;
305 ValidVolumes.clear();
310 for (
size_t i = 0; i < theLogicalVolumes->size(); i++){
311 volume=(*theLogicalVolumes)[i];
312 ValidVolumes.push_back(volume->
GetName());
318 std::sort(ValidVolumes.begin(), ValidVolumes.end());
320 isAllVolumesMode=
true;
326 ValidVolumes.clear();
327 isAllVolumesMode=
false;
341 for (
size_t i = 0; i < theDecayRateTableVector.size(); i++) {
342 if (theDecayRateTableVector[i].GetIonName() == aParticleName)
356 for (
size_t i = 0; i < theDecayRateTableVector.size(); i++) {
357 if (theDecayRateTableVector[i].GetIonName() == aParticleName) {
358 theDecayRateVector = theDecayRateTableVector[i].GetItsRates();
363 G4cout <<
"The DecayRate Table for "
364 << aParticleName <<
" is selected." <<
G4endl;
373 long double taotime =0.L;
375 if ( t > SBin[NSourceBin]) {
379 while (t > SBin[nbin]) nbin++;
382 long double ltao = tao;
385 for (
G4int i = 0; i < nbin; i++)
387 taotime += (
long double)SProfile[i] * (std::exp(-(lt-(
long double)SBin[i+1])/ltao)-std::exp(-(lt-(
long double)SBin[i])/ltao));
390 taotime += (
long double)SProfile[nbin] * (1.L-std::exp(-(lt-(
long double)SBin[nbin])/ltao));
392 G4cout <<
" Tao time =: " <<taotime <<
" reset to zero!"<<
G4endl;
527 while ( DProfile[i] < rand) i++;
529 decaytime = DBin[i] + rand*(DBin[i+1]-DBin[i]);
541 while ( aDecayTime > DBin[i] ) i++;
567 G4cout <<
"G4RadioactiveDecay::GetMeanLifeTime() " <<
G4endl;
574 else if (theLife < 0.0) {meanlife =
DBL_MAX;}
575 else {meanlife = theLife;}
577 if (((
const G4Ions*)(theParticleDef))->GetExcitationEnergy() > 0. && meanlife ==
DBL_MAX) {meanlife = 0.;}
607 G4cout <<
"G4RadioactiveDecay::GetMeanFreePath() "<<
G4endl;
609 G4cout <<
"Mass:" << aMass/
GeV <<
"[GeV]";
618 }
else if (aCtau < 0.0) {
637 if ( rKineticEnergy > HighestValue) {
639 pathlength = ( rKineticEnergy + 1.0)* aCtau;
640 }
else if ( rKineticEnergy <
DBL_MIN ) {
644 G4cout <<
"G4Decay::GetMeanFreePath() !!particle stops!!";
658 G4cout <<
"mean free path: "<< pathlength/
m <<
"[m]" <<
G4endl;
673 isInitialised =
true;
694 G4int A = ((
const G4Ions*)(&theParentNucleus))->GetAtomicMass();
695 G4int Z = ((
const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
696 G4double E = ((
const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
702 if (!getenv(
"G4RADIOACTIVEDATA") ) {
703 G4cout <<
"Please setenv G4RADIOACTIVEDATA to point to the radioactive decay data files."
706 "Please setenv G4RADIOACTIVEDATA to point to the radioactive decay data files.");
708 G4String dirName = getenv(
"G4RADIOACTIVEDATA");
710 std::ostringstream os;
711 os <<dirName <<
"/z" <<Z <<
".a" <<A <<
'\0';
716 std::sort( LoadedNuclei.begin(), LoadedNuclei.end() );
719 std::ifstream DecaySchemeFile(file);
722 if (DecaySchemeFile) {
725 G4bool modeFirstRecord[7];
728 for (
G4int i = 0; i < nMode; i++) {
729 modeFirstRecord[i] =
true;
734 char inputChars[100]={
' '};
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);
753 if (inputChars[0] ==
'P') {
756 tmpStream >> recordType >> a >>
b;
757 if (found) {complete =
true;}
758 else {found = (std::abs(a*
keV - E) < levelTolerance);}
763 if (inputChars[0] ==
'W') {
768 G4cout <<
" Warning in G4RadioactiveDecay::LoadDecayTable " <<
G4endl;
774 tmpStream >> theDecayMode >> a >> b >> c >> betaType;
778 if (inputLine.length() < 80) betaType =
allowed;
782 switch (theDecayMode) {
788 (
const G4Ions*)& theParentNucleus, b);
789 anITChannel->
SetICM(applyICM);
790 anITChannel->
SetARM(applyARM);
792 theDecayTable->
Insert(anITChannel);
798 if (modeFirstRecord[1]) {
799 modeFirstRecord[1] =
false;
813 for (
G4int ptn = 0; ptn < npti; ptn++) {
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);
823 f *= corrections.
ShapeFactor(betaType, p, e0-e+1.);
830 b, c*
MeV, a*MeV, 0, FBeta, aRandomEnergy);
831 aBetaMinusChannel->
SetICM(applyICM);
832 aBetaMinusChannel->
SetARM(applyARM);
834 theDecayTable->
Insert(aBetaMinusChannel);
844 if (modeFirstRecord[2]) {
845 modeFirstRecord[2] =
false;
848 e0 = c*
MeV/0.511 - 2.;
861 for (
G4int ptn = 0; ptn < npti; ptn++) {
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);
871 f *= corrections.
ShapeFactor(betaType, p, e0-e+1.);
877 b, c*
MeV, a*MeV, 0, FBeta, aRandomEnergy);
878 aBetaPlusChannel->
SetICM(applyICM);
879 aBetaPlusChannel->
SetARM(applyARM);
881 theDecayTable->
Insert(aBetaPlusChannel);
891 if (modeFirstRecord[3]) {
892 modeFirstRecord[3] =
false;
899 aKECChannel->
SetICM(applyICM);
900 aKECChannel->
SetARM(applyARM);
902 theDecayTable->
Insert(aKECChannel);
909 if (modeFirstRecord[4]) {
910 modeFirstRecord[4] =
false;
916 aLECChannel->
SetICM(applyICM);
917 aLECChannel->
SetARM(applyARM);
919 theDecayTable->
Insert(aLECChannel);
926 if (modeFirstRecord[5]) {
927 modeFirstRecord[5] =
false;
934 aMECChannel->
SetICM(applyICM);
935 aMECChannel->
SetARM(applyARM);
937 theDecayTable->
Insert(aMECChannel);
945 if (modeFirstRecord[6]) {
946 modeFirstRecord[6] =
false;
953 anAlphaChannel->
SetICM(applyICM);
954 anAlphaChannel->
SetARM(applyARM);
956 theDecayTable->
Insert(anAlphaChannel);
967 G4Exception(
"G4RadioactiveDecay::LoadDecayTable()",
"HAD_RDM_000",
988 if (theDecayMode !=
IT) {
989 theBR = theChannel->
GetBR();
990 theChannel->
SetBR(theBR*modeTotalBR[theDecayMode]/modeSumBR[theDecayMode]);
994 DecaySchemeFile.close();
997 if (!found && E > 0.) {
1003 anITChannel->
SetICM(applyICM);
1004 anITChannel->
SetARM(applyARM);
1006 theDecayTable->
Insert(anITChannel);
1008 if (!theDecayTable) {
1013 G4cerr <<
"G4RadoactiveDecay::LoadDecayTable() : cannot find ion radioactive decay file " <<
G4endl;
1015 return theDecayTable;
1019 G4cout <<
"G4RadioactiveDecay::LoadDecayTable()" <<
G4endl;
1024 return theDecayTable;
1033 std::ifstream DecaySchemeFile(filename);
1034 if (DecaySchemeFile){
1036 theUserRadioactiveDataFiles[ID_ion]=filename;
1040 G4cout<<
"The file "<<filename<<
" does not exist!"<<
G4endl;
1049 G4int theG, std::vector<G4double> theRates,
1050 std::vector<G4double> theTaos)
1053 theDecayRate.
SetZ(theZ);
1054 theDecayRate.
SetA(theA);
1055 theDecayRate.
SetE(theE);
1058 theDecayRate.
SetTaos(theTaos);
1075 theDecayRateVector.clear();
1077 G4int nGeneration = 0;
1078 std::vector<G4double> rates;
1079 std::vector<G4double> taos;
1083 rates.push_back(-1.);
1086 G4int A = ((
const G4Ions*)(&theParentNucleus))->GetAtomicMass();
1087 G4int Z = ((
const G4Ions*)(&theParentNucleus))->GetAtomicNumber();
1088 G4double E = ((
const G4Ions*)(&theParentNucleus))->GetExcitationEnergy();
1090 if (tao < 0.) tao = 1
e-100;
1091 taos.push_back(tao);
1098 theDecayRateVector.push_back(theDecayRate);
1119 std::vector<G4double> TP;
1120 std::vector<G4double> RP;
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();
1144 G4cout <<
"G4RadioactiveDecay::AddDecayRateTable : "
1145 <<
" daughters of ("<< ZP <<
", "<<AP<<
", "
1147 <<
" are being calculated. "
1149 << nGeneration <<
G4endl;
1151 aParentNucleus = theIonTable->
GetIon(ZP,AP,EP);
1158 for (i=0; i< 7; i++) brs[i] = 0.0;
1163 for (i=0; i<aTempDecayTable->
entries(); i++) {
1169 AD = ((
const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
1170 ZD = ((
const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
1177 if (std::abs(daughterExcitation - level->
Energy()) < levelTolerance) {
1179 if (level->
HalfLife()*
ns >= halflifethreshold ){
1181 theDecayTable->
Insert(theChannel);
1184 brs[theDecayMode] += theChannel->
GetBR();
1188 brs[theDecayMode] += theChannel->
GetBR();
1192 brs[theDecayMode] += theChannel->
GetBR();
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++){
1207 (0, (
const G4Ions*) aParentNucleus, brs[0]);
1209 theDecayTable->
Insert(theITChannel);
1218 brs[1], 0.*
MeV, 0.*
MeV, 1,
false, 0);
1219 theDecayTable->
Insert(theBetaMinusChannel);
1229 brs[2], 0.*
MeV, 0.*
MeV, 1,
false, 0);
1230 theDecayTable->
Insert(theBetaPlusChannel);
1241 theDecayTable->
Insert(theAlphaChannel);
1252 for (i = 0; i < theDecayTable->
entries(); i++){
1255 theBR = theChannel->
GetBR();
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.);
1265 aParentNucleus != theDaughterNucleus) {
1267 if (!
IsLoaded(*theDaughterNucleus)){
1272 A = ((
const G4Ions*)(theDaughterNucleus))->GetAtomicMass();
1273 Z = ((
const G4Ions*)(theDaughterNucleus))->GetAtomicNumber();
1274 E = ((
const G4Ions*)(theDaughterNucleus))->GetExcitationEnergy();
1279 if (TaoPlus <= 0.) TaoPlus = 1
e-100;
1291 taos.push_back(TaoPlus);
1297 long double ta1,ta2;
1298 ta2 = (
long double)TaoPlus;
1299 for (k = 0; k < RP.size(); k++){
1300 ta1 = (
long double)TP[k];
1304 theRate = ta1/(ta1-ta2);}
1305 theRate = theRate * theBR * RP[k];
1306 rates.push_back(theRate);
1313 long double aRate, aRate1;
1315 for (k = 0; k < RP.size(); k++){
1316 ta1 = (
long double)TP[k];
1320 aRate = ta2/(ta1-ta2);}
1321 aRate = aRate * (
long double)(theBR * RP[k]);
1325 rates.push_back(theRate);
1327 theDecayRateVector.push_back(theDecayRate);
1337 if (nS == nT) stable =
true;
1353 theDecayRateTable.
SetItsRates(theDecayRateVector);
1358 theDecayRateTableVector.push_back(theDecayRateTable);
1373 ed <<
" Could not open file " << filename <<
G4endl;
1374 G4Exception(
"G4RadioactiveDecay::SetSourceTimeProfile()",
"HAD_RDM_001",
1380 while (infile >> bin >> flux ) {
1382 if (NSourceBin > 99) {
1383 G4Exception(
"G4RadioactiveDecay::SetSourceTimeProfile()",
"HAD_RDM_002",
1387 SBin[NSourceBin] = bin *
s;
1388 SProfile[NSourceBin] = flux;
1396 {
G4cout <<
" Source Timeprofile Nbin = " << NSourceBin <<
G4endl;}
1411 if (!infile)
G4Exception(
"G4RadioactiveDecay::SetDecayBias()",
"HAD_RDM_003",
1418 theRadioactivityTables.clear();
1421 while (infile >> bin >> flux ) {
1423 if (NDecayBin > 99) {
1424 G4Exception(
"G4RadioactiveDecay::SetDecayBias()",
"HAD_RDM_004",
1427 DBin[NDecayBin] = bin *
s;
1428 DProfile[NDecayBin] = flux;
1430 decayWindows[NDecayBin] = dWindows;
1433 theRadioactivityTables.push_back(rTable);
1437 for ( i = 1; i<= NDecayBin; i++) DProfile[i] += DProfile[i-1];
1438 for ( i = 0; i<= NDecayBin; i++) DProfile[i] /= DProfile[NDecayBin];
1446 {
G4cout <<
" Decay Bias Profile Nbin = " << NDecayBin <<
G4endl;}
1464 fParticleChangeForRadDecay.
Initialize(theTrack);
1472 if (!isAllVolumesMode){
1473 if (!std::binary_search(ValidVolumes.begin(), ValidVolumes.end(),
1477 G4cout <<
"G4RadioactiveDecay::DecayIt : "
1479 <<
" is not selected for the RDM"<<
G4endl;
1480 G4cout <<
" There are " << ValidVolumes.size() <<
" volumes" <<
G4endl;
1482 for (
size_t i = 0; i< ValidVolumes.size(); i++)
G4cout << ValidVolumes[i] << G4endl;
1492 return &fParticleChangeForRadDecay;
1504 G4cerr <<
"G4RadioactiveDecay::DecayIt : "
1506 <<
" is not a valid nucleus for the RDM"<<
G4endl;
1517 return &fParticleChangeForRadDecay;
1525 if (theDecayTable == 0 || theDecayTable->
entries() == 0) {
1531 G4cerr <<
"G4RadioactiveDecay::DecayIt : decay table not defined for ";
1541 return &fParticleChangeForRadDecay;
1563 if ( products->
entries() == 1) {
1568 return &fParticleChangeForRadDecay;
1593 if (temptime < 0.) temptime = 0.;
1594 finalGlobalTime += temptime;
1595 finalLocalTime += temptime;
1598 products->
Boost( ParentEnergy, ParentDirection);
1607 G4cout <<
"G4RadioactiveDecay::DecayIt : Decay vertex :";
1608 G4cout <<
" Time: " <<finalGlobalTime/
ns <<
"[ns]";
1613 G4cout <<
"G4Decay::DecayIt : decay products in Lab. Frame" <<
G4endl;
1618 for (index=0; index < numberOfSecondaries; index++) {
1620 finalGlobalTime, currentPosition);
1632 G4cout <<
"DecayIt: Variance Reduction version " <<
G4endl;
1648 std::vector<G4double> PT;
1649 std::vector<G4double> PR;
1651 long double decayRate;
1655 G4int numberOfSecondaries;
1656 G4int totalNumberOfSecondaries = 0;
1660 std::vector<G4DynamicParticle*> secondaryparticles;
1661 std::vector<G4double> pw;
1662 std::vector<G4double> ptime;
1667 for (
G4int n = 0;
n < NSplit;
n++) {
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;
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();
1703 for (j = 0; j < PT.size(); j++) {
1705 decayRate -= PR[j] * (
long double)taotime;
1718 theRadioactivityTables[decayWindows[nbin-1]]->AddIsotope(PZ,PA,PE,weight1*decayRate,theTrack.
GetWeight());
1729 parentNucleus = theIonTable->
GetIon(PZ,PA,PE);
1740 if (theDecayChannel == 0) {
1744 G4cerr <<
" G4RadioactiveDecay::DoIt : cannot determine decay channel ";
1745 G4cerr <<
" for this nucleus; decay as if no biasing active ";
1750 tempprods =
DoDecay(*parentNucleus);
1755 tempprods = theDecayChannel->DecayIt(tempmass);
1756 weight *= (theDecayChannel->GetBR())*(decayTable->
entries());
1759 tempprods =
DoDecay(*parentNucleus);
1763 numberOfSecondaries = tempprods->
entries();
1764 currentTime = finalGlobalTime + theDecayTime;
1765 for (index = 0; index < numberOfSecondaries; index++) {
1768 pw.push_back(weight);
1769 ptime.push_back(currentTime);
1770 secondaryparticles.push_back(asecondaryparticle);
1780 totalNumberOfSecondaries = pw.size();
1782 for (index=0; index < totalNumberOfSecondaries; index++) {
1784 ptime[index], currentPosition);
1804 return &fParticleChangeForRadDecay ;
1827 if (theDecayChannel == 0) {
1829 G4cerr <<
"G4RadioactiveDecay::DoIt : can not determine decay channel";
1836 G4cerr <<
"G4RadioactiveDecay::DoIt : selected decay channel addr:";
1841 products = theDecayChannel->
DecayIt(tempmass);
1853 if (origin == forceDecayDirection)
return;
1854 if (180.*
deg == forceDecayHalfAngle)
return;
1855 if (0 == products || 0 == products->
entries())
return;
1873 if (daughterType == electron || daughterType == positron ||
1874 daughterType == neutron || daughterType == gamma ||
1882 G4cout <<
"CollimateDecayProduct for daughter "
1895 if (origin == forceDecayDirection)
return origin;
1896 if (forceDecayHalfAngle == 180.*
deg)
return origin;
1901 if (forceDecayHalfAngle > 0.) {
1904 G4double cosMin = std::cos(forceDecayHalfAngle);
1913 G4cout <<
" ChooseCollimationDirection returns " << dir <<
G4endl;