00001 #include "GenDecay/DecayRates.h"
00002 #include "GenDecay/NucState.h"
00003 #include "GenDecay/NucDecay.h"
00004 #include "GenDecay/NucUtil.h"
00005
00006 #include "GaudiKernel/GaudiException.h"
00007
00008 #include <algorithm>
00009
00010 using namespace GenDecay;
00011 using namespace std;
00012
00013 using namespace more;
00014 using namespace more::phys;
00015
00016 DecayRates::DecayRates(const map<phys::nucleus,double>& abundance,
00017 bool secularEquilibrium, double corrTime, double epsTime,
00018 IRndmGenSvc *rgs)
00019 : NucVisitor()
00020 , m_abundance(abundance)
00021 , m_secEq(secularEquilibrium)
00022 , m_correlationTime(corrTime)
00023 , m_epsilonTime(epsTime)
00024 , m_secEqRate(0.0)
00025 {
00026 StatusCode sc = m_uni.initialize(rgs, Rndm::Flat(0,1));
00027 if (sc.isFailure()) {
00028 throw GaudiException("Failed to initialize uniform random numbers",
00029 "GtDecayerator::DecayRates",StatusCode::FAILURE);
00030 }
00031 }
00032
00033 DecayRates::~DecayRates()
00034 {
00035 }
00036
00037
00038 GenDecay::NucDecay* DecayRates::decay()
00039 {
00040
00041
00042
00043
00044
00045
00046
00047
00048 if (!m_motherBranching.size()) {
00049 for (size_t ind=0; ind<m_mothers.size(); ++ind) {
00050 NucState* mom = m_mothers[ind];
00051 double rate = 1.0/m_meanDecayTimes[mom];
00052 m_motherBranching.push_back(rate);
00053 m_meanDecayTimes[mom] = 1.0/m_totalDecayRate;
00054 }
00055 }
00056
00057 double target = m_uni() * m_totalDecayRate;
00058 double arrow = 0.0;
00059 NucState* mother = 0;
00060 for (size_t ind=0; ind<m_mothers.size(); ++ind) {
00061 NucState* mom = m_mothers[ind];
00062 arrow += m_motherBranching[ind];
00063 if (arrow > target) {
00064 mother = mom;
00065 break;
00066 }
00067 }
00068 if (!mother) {
00069 cerr << "DecayRates::decay() failed to find mother to decay out of " << m_mothers.size()
00070 << " with target = " << target << " and total = " << m_totalDecayRate
00071 << endl;
00072 throw GaudiException("Failed to find mother to decay, this should not happen",
00073 "GtDecayerator::DecayRates",StatusCode::FAILURE);
00074 }
00075 return decay_state(mother);
00076 }
00077
00078
00079
00080
00081 bool GenDecay::DecayRates::visit(GenDecay::NucState* mother, GenDecay::NucState* daughter,
00082 GenDecay::NucDecay* decay)
00083 {
00084
00085 if (find(m_mothers.begin(),m_mothers.end(),mother) != m_mothers.end())
00086 return true;
00087
00088
00089
00090
00091
00092
00093
00094 if (!m_mothers.size()) {
00095
00096 m_mothers.push_back(mother);
00097 m_totalDecayRate = 0.0;
00098 double abundance = m_abundance[mother->nuc()];
00099 if (abundance == 0.0) {
00100 stringstream err;
00101 err << "DecayRates::visit: no abundance set for chain's mother nuclide: "
00102 << mother->nuc();
00103 throw GaudiException(err.str(),"GtDecayerator::DecayRates",StatusCode::FAILURE);
00104 }
00105 double rate = abundance / mother->lifetime();
00106 if (m_secEq) m_secEqRate = rate;
00107 m_meanDecayTimes[mother] = 1.0/rate;
00108 m_totalDecayRate += rate;
00109 return true;
00110 }
00111
00112
00113
00114 if (mother->lifetime() < m_epsilonTime) {
00115 m_meanDecayTimes[mother] = 0;
00116 return true;
00117 }
00118
00119
00120
00121
00122
00123 double meanDecayTime = 0;
00124 double abundance = m_abundance[mother->nuc()];
00125
00126 if (abundance > 0.0) {
00127 meanDecayTime = mother->lifetime() / abundance;
00128 }
00129 else if (m_secEq) {
00130 meanDecayTime = 1/m_secEqRate;
00131 }
00132 else {
00133 cerr << "Warning: No abundance for " << mother->nuc()
00134 << " via " << *decay
00135 << ", and no seqular equlibrium, this decay won't be allowed to happen\n";
00136 return true;
00137 }
00138
00139
00140 if (mother->lifetime() > m_correlationTime) {
00141 if (find(m_mothers.begin(),m_mothers.end(),mother) == m_mothers.end()) {
00142 m_mothers.push_back(mother);
00143 m_totalDecayRate += 1.0/meanDecayTime;
00144 }
00145 }
00146
00147
00148
00149 m_meanDecayTimes[mother] = meanDecayTime;
00150
00151 return true;
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161 GenDecay::DecayRates::DecayValues_t GenDecay::DecayRates::decayTimes(NucDecay* decay)
00162 {
00163 DecayValues_t decayTime;
00164 get_decay_times(decay,decayTime,0.0);
00165 return decayTime;
00166 }
00167
00168 void DecayRates::get_decay_times(NucDecay* decay, DecayRates::DecayValues_t& decayTime, double now)
00169 {
00170 double meanDecayTime = 0.0;
00171
00172 if (decayTime.size()) {
00173
00174
00175 if (decay->mother->lifetime() > m_correlationTime) {
00176 return;
00177 }
00178
00179
00180 meanDecayTime = decay->mother->lifetime() / decay->fraction;
00181
00182
00183 }
00184 else {
00185
00186 meanDecayTime = m_meanDecayTimes[decay->mother];
00187
00188
00189 }
00190
00191 double dt = 0.0;
00192 if (meanDecayTime > 0.0) {
00193 dt = (-1.0 * log(m_uni())) * meanDecayTime;
00194 }
00195 now += dt;
00196
00197
00198
00199
00200
00201
00202 decayTime.push_back(DecayValuePair_t(decay, now));
00203
00204 NucDecay* the_decay = decay_state(decay->daughter);
00205 if (!the_decay) { return; }
00206
00207 get_decay_times(the_decay,decayTime,now);
00208 }
00209
00210
00211
00212 NucDecay* DecayRates::decay_state(NucState* nuc)
00213 {
00214
00215 vector<NucDecay*>& decays = nuc->decays();
00216 if (!decays.size()) return 0;
00217
00218 double total_fraction = 0, target = m_uni();
00219
00220 for (size_t ind=0; ind < decays.size(); ++ind) {
00221 NucDecay* dk = decays[ind];
00222
00223
00224 total_fraction += dk->fraction;
00225 if (total_fraction > target) {
00226
00227
00228 return dk;
00229 }
00230 }
00231
00232 cerr << "Failed to choose a decay for " << *nuc
00233 << " target fraction = " << target << ", total fraction at end = " << total_fraction
00234 << " Precision error?\n";
00235 return 0;
00236 }