| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

DecayRates.cc

Go to the documentation of this file.
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 // Return a randomly chosen decay.  
00038 GenDecay::NucDecay* DecayRates::decay() 
00039 {
00040     // Initially the m_meanDecayTimes for mothers are assuming they
00041     // are decayed in isolation.  Since they all produces decays
00042     // together with total rate equal to the sum of their individual
00043     // ones we must use their individual rates to choose a decay and
00044     // replace "their" mean decay time with the total one so that
00045     // their chosen times are set correctly.  W/out this one gets N
00046     // times too much time covered where N is ~number of uncorrelated
00047     // branches (=N for full SE).  More in trac ticket #315.
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 // Visit each possible decay in the chain.  save uncorrelated mothers
00079 // mean decay time of each decay of which the mother has some
00080 // abundance.
00081 bool GenDecay::DecayRates::visit(GenDecay::NucState* mother, GenDecay::NucState* daughter, 
00082                                  GenDecay::NucDecay* decay) 
00083 {
00084     // don't bother visiting a decay that has a mother already seen
00085     if (find(m_mothers.begin(),m_mothers.end(),mother) != m_mothers.end()) 
00086         return true;
00087 
00088     //cerr << "DecayRates::visit: visiting " 
00089     //     << mother->nuc() << " -> " << daughter->nuc() << " "
00090     //     << *decay << endl;
00091 
00092     // First time through we have mother of whole chain so can take
00093     // her abundance as the one to use for secular equilibrium
00094     if (!m_mothers.size()) {  
00095         // mother of chain is of course an uncorrelated mother.
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     // For decays that are considered instantaneous, set their decay
00113     // time to exactly zero.  (assumes epsilon < correlation time)
00114     if (mother->lifetime() < m_epsilonTime) {
00115         m_meanDecayTimes[mother] = 0;
00116         return true;
00117     }
00118 
00119     // What is left is either a "fast" correlated decay or a "slow"
00120     // uncorrelated one.  In either case we find a decay rate based on
00121     // an abundance.
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     // Check if mother is correlated or not
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     // All decays from this mother have a mean decay time which is the
00148     // mother's lifetime per her abundance.
00149     m_meanDecayTimes[mother] = meanDecayTime;
00150 
00151     return true;
00152 }
00153 
00154 /*
00155   For the given decay, pick a time for it to occur.  
00156 
00157   If the daughter is unstable with a correlated lifetime decay her and
00158   recuse.
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()) {     // not the mother of the chain
00173 
00174         // check if this decay is considered correlated
00175         if (decay->mother->lifetime() > m_correlationTime) {
00176             return;    // uncorelated decay, stop descent
00177         }
00178 
00179         // got a specific decay, use specific branch lifetime
00180         meanDecayTime = decay->mother->lifetime() / decay->fraction;
00181         
00182         //cerr << "Daughter ";
00183     }
00184     else {                      // this is the mother of the chain
00185         // got a general decay, use abundance based lifetime
00186         meanDecayTime = m_meanDecayTimes[decay->mother];
00187 
00188         //cerr << "Mother:  ";
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     // cerr << "now="<<now << " meanDecayTime=" << meanDecayTime 
00198     //      << " decay=" << *decay << " mother=" << *(decay->mother) 
00199     //      << " daughter=" << *(decay->daughter)
00200     //      << endl;
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); // recurse on chosen daughter decay
00208 }
00209 
00210 
00211 
00212 NucDecay* DecayRates::decay_state(NucState* nuc)
00213 {
00214     // Now, pick which daughter to follow
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         // Pick daughter
00224         total_fraction += dk->fraction;
00225         if (total_fraction > target) {
00226             //cerr << "Choose decay " << *dk << " at total_fraction = " << total_fraction
00227             //     << " and target fraction at " << target << endl;
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 }
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Mon Apr 11 21:01:08 2011 for GenDecay by doxygen 1.4.7