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

In This Package:

NucUtil.cc

Go to the documentation of this file.
00001 #include "GenDecay/NucUtil.h"
00002 #include "GenDecay/NucState.h"
00003 #include "GenDecay/NucDecay.h"
00004 #include "GenDecay/Radiation.h"
00005 
00006 #include "CLHEP/Units/SystemOfUnits.h"
00007 
00008 #include <sstream>
00009 #include <more/phys/ens.h>
00010 
00011 using namespace GenDecay;
00012 using namespace std;
00013 using namespace more;
00014 using namespace more::phys;
00015 
00016 double GenDecay::more_to_clhep_time(double more_time)
00017 {
00018     return more_time * CLHEP::second / SI::s;
00019 }
00020 double GenDecay::more_to_clhep_energy(double more_energy)
00021 {
00022     return more_energy * CLHEP::MeV / SI::MeV;
00023 }
00024 
00025 template<typename T>
00026 bool operator==(confidence_interval<T> x, confidence_interval<T> y)
00027 {
00028     const double epsilon = 20*SI::eV;
00029     return (fabs(x.cent()-y.cent()) < epsilon);
00030     //&& (fabs(x.min()-y.min()) < epsilon)
00031     //&& (fabs(x.max()-y.max()) < epsilon);
00032 }
00033 template<typename T>
00034 bool operator!=(confidence_interval<T> x, confidence_interval<T> y)
00035 {
00036     return !(x==y);
00037 }
00038 
00039 typedef map<const phys::nucleus, ens::nucleus> NucNucMap_t;
00040 bool GenDecay::get_nucleus(const more::phys::nucleus& pn, more::phys::ens::nucleus& en)
00041 {
00042     static NucNucMap_t nucnuc;
00043 
00044     ens::nucleus out = nucnuc[pn];
00045     if (out.has_dataset()) {
00046         en = out;
00047         return true;
00048     }
00049 
00050     try {
00051         out = pn;
00052     }
00053     catch (std::runtime_error) {
00054         cerr << "Caught run time error when assigning nucleus: \"" << pn << "\"" << endl;
00055         cerr << "Is the fetcher used a few lines above the correct one?\n"
00056              << "Maybe you need to set MORE_PHYS_FETCHER to point to the fetcher script?\n";            
00057         return false;
00058     }
00059     en = out;
00060     nucnuc[pn] = out;
00061     return true;
00062 }
00063 
00064 // NucState factory.
00065 typedef map<phys::nucleus, vector<NucState*> > Nuc2state_t;
00066 Nuc2state_t gsNuc2state;
00067 
00068 
00069 NucState* GenDecay::get_state(const phys::nucleus& n, ens::confiv_t hl,
00070                               ens::confiv_t rel, int ref)
00071 {
00072     Nuc2state_t::iterator it = gsNuc2state.find(n);
00073 
00074     // No such nucleus seen yet
00075     if (it == gsNuc2state.end()) {
00076         vector<NucState*> vns;
00077         NucState* ns = new NucState(n,hl,rel,ref);
00078         vns.push_back(ns);
00079         gsNuc2state[n] = vns;
00080         
00081         //cerr << "get_state: Made first ever " << *ns << "(@" 
00082         //     << (void*)ns << ")" << endl;
00083         return ns;
00084     }
00085 
00086     // nucleus seen, check for specific NucState
00087     vector<NucState*>& vns = it->second;
00088     for (size_t ind=0; ind < vns.size(); ++ind) {
00089         if (vns[ind]->eref() != ref) {
00090             //cerr << "get_state: No match: " << vns[ind]->eref << " != " << ref 
00091             //     << endl;
00092             continue;
00093         }
00094         if (vns[ind]->erel() != rel) {
00095             //cerr << "get_state: No match: " << vns[ind]->erel / SI::keV 
00096             //     << " != " << rel / SI::keV << endl;
00097             continue;
00098         }
00099         // found it
00100         //cerr << "get_state: in slot " << ind << " found "
00101         //     << *vns[ind] << "(@" << (void*)vns[ind] << ")" << endl;
00102         return vns[ind];
00103     }
00104 
00105     // Specific state not yet seen, add it.
00106     NucState* ns = new NucState(n,hl,rel,ref);
00107     vns.push_back(ns);
00108     //cerr << "get_state: added new " << *ns << "(@" << (void*)ns << ")" << endl;
00109     return ns;
00110 }
00111 
00112 static
00113 void normalize_branching_fractions(NucState& state)
00114 {
00115     vector<NucDecay*>& decays = state.decays();
00116 
00117     // special case, stable or
00118     if (!decays.size()) return;
00119 
00120     // single decay branch
00121     if (decays.size() == 1) { 
00122         decays[0]->fraction = 1.0;
00123         return;
00124     }
00125 
00126     // Some decays have unknown (0) branching fraction, drop them.
00127     vector<NucDecay*> tmp;
00128     for (size_t dind=0; dind < decays.size(); ++dind) {
00129         if (decays[dind]->fraction > 0.0) {
00130             tmp.push_back(decays[dind]);
00131         }
00132     }
00133     decays = tmp;
00134     if (!decays.size()) return;
00135 
00136     if (decays.size() == 1) { 
00137         decays[0]->fraction = 1.0;
00138         return;
00139     }
00140 
00141     double mag = 0;
00142     for (size_t dind=0; dind < decays.size(); ++dind) {
00143         mag += decays[dind]->fraction;
00144     }
00145 
00146     if (mag == 0.0) {
00147         cerr << "Zero total decay fraction for: " << state 
00148              << " with " << state.ndecays() << " decays"
00149              << endl;
00150         return;
00151     }
00152     for (size_t dind=0; dind < decays.size(); ++dind) {
00153         decays[dind]->fraction /= mag;
00154     }
00155     //cerr << "Normalized daughters of " << state << " by " << mag << endl;
00156 }
00157 
00158 //typedef map<pair<NucState*,NucState*>,vector<NucDecay*>> NucDecayMap_t;
00159 static NucDecayMap_t gsNucDecays;
00160 const NucDecayMap_t& GenDecay::get_decays() { return gsNucDecays; }
00161 
00162 NucDecay* get_decay(NucState* mo, NucState* da, const string& typ, double q=0, double f=0);
00163 NucDecay* get_decay(NucState* mo, NucState* da, const string& typ, double q, double f)
00164 {
00165     pair<NucState*,NucState*> moda(mo,da);
00166 
00167     vector<NucDecay*> vec;
00168 
00169     NucDecayMap_t::iterator it = gsNucDecays.find(moda);
00170     if (it != gsNucDecays.end()) {
00171         vec = it->second;
00172     }
00173 
00174     for (size_t ind=0; ind<vec.size(); ++ind) {
00175         NucDecay* nd = vec[ind];
00176         if (nd->type == typ) return nd;
00177     }
00178 
00179     NucDecay* nd = new NucDecay(mo,da,typ,q,f);
00180     vec.push_back(nd);
00181     gsNucDecays[moda] = vec;
00182     return nd;
00183 }
00184 
00185 template<typename ItType>
00186 int count(ItType beg, ItType end)
00187 {
00188     int c = 0;
00189     for(; beg!=end; ++beg) ++c;
00190     return c;
00191 }
00192 
00193 void dump_radiation(const ens::rec_radiation& rad)
00194 {
00195     cerr << "\t\t\t";
00196 
00197     if (rad.is_alpha()) {
00198         ens::rec_alpha const* alpha = rad.to_alpha();
00199         cerr << " alpha:"
00200              << " energy=" << rad.E_minus_E_ref() / SI::keV
00201              << " ref=" << rad.i_E_ref()
00202              << " status=" << rad.status()
00203              << " I_alpha=" << alpha->I_alpha()
00204              << " hindrance=" << alpha->hindrance_factor();
00205     }
00206     else if (rad.is_gamma()) {
00207         ens::rec_gamma const* gamma = rad.to_gamma();
00208         cerr << " gamma:"
00209              << " energy=" << rad.E_minus_E_ref() / SI::keV
00210              << " ref=" << rad.i_E_ref()
00211              << " status=" << rad.status()
00212              << " r_mix=" << gamma->r_mix()
00213              << " I_gamma_rel=" << gamma->I_gamma_rel()
00214              << " alpha_tot()=" << gamma->alpha_tot()
00215              << " I_trans_rel=" << gamma->I_trans_rel();
00216     }
00217     else if (rad.is_beta_mi()) {
00218         ens::rec_beta_mi const* beta_mi = rad.to_beta_mi();
00219         cerr << " beta-:"
00220              << " energy=" << rad.E_minus_E_ref() / SI::keV
00221              << " ref=" << rad.i_E_ref()
00222              << " status=" << rad.status()
00223              << " I_beta_mi_rel=" << beta_mi->I_beta_mi_rel()
00224              << " log_ft=" << beta_mi->log_ft();
00225     }
00226     else if (rad.is_beta_pl()) {
00227         ens::rec_beta_pl const* beta_pl = rad.to_beta_pl();
00228         cerr << " beta+:"
00229              << " energy=" << rad.E_minus_E_ref() / SI::keV
00230              << " ref=" << rad.i_E_ref()
00231              << " status=" << rad.status()
00232              << " I_tot_rel=" << beta_pl->I_tot_rel()
00233              << " I_beta_pl_rel=" << beta_pl->I_beta_pl_rel()
00234              << " I_EC_rel=" << beta_pl->I_EC_rel()
00235              << " log_ft=" << beta_pl->log_ft();
00236     }
00237     else {
00238         cerr << "unknown radiation:";
00239         rad.dump(cerr);
00240     }
00241     cerr << endl;
00242 
00243 }
00244 
00245 void dump_level(const ens::rec_level& lev)
00246 {
00247     cerr << "\t\tenergy level = " << lev.E_minus_E_ref() / SI::keV
00248          << " ref=" << lev.i_E_ref()
00249          << " hl=" << lev.T_half()
00250          << " radiations:\n";
00251     for (ens::rec_level::radiation_iterator it_rad = lev.radiation_begin();
00252          it_rad != lev.radiation_end(); ++it_rad) {
00253         dump_radiation(*it_rad);
00254     }
00255 }
00256 
00257 double rad_mass(const ens::rec_radiation& rad)
00258 {
00259     if (rad.is_gamma()) return 0.0;
00260     if (rad.is_beta_mi() || rad.is_beta_pl()) return SI::E_e;
00261     if (rad.is_alpha()) return 2*(SI::E_p + SI::E_n);
00262     cerr << "Unknown radiation:\n";
00263     rad.dump(cerr);
00264     return 0.0;
00265 }
00266 double rad_fraction(const ens::rec_radiation& rad,
00267                     const ens::rec_norm* norm=0,
00268                     const string& idstr = "");
00269 double rad_fraction(const ens::rec_radiation& rad,
00270                     const ens::rec_norm* norm,
00271                     const string& idstr)
00272 {
00273     double fraction = 0;
00274 
00275     if (rad.is_alpha()) {
00276         ens::rec_alpha const* alpha = rad.to_alpha();
00277         if (alpha->I_alpha().is_known()) {
00278             fraction = alpha->I_alpha().cent();
00279         }
00280         //cerr << " I_alpha = " << fraction<< endl;
00281     }
00282     if (rad.is_gamma()) {
00283         ens::rec_gamma const* gamma = rad.to_gamma();
00284         if (gamma->I_gamma_rel().is_known()) {
00285             fraction = gamma->I_gamma_rel().cent();
00286             //cerr << " I_gamma_rel = " << fraction<< endl;
00287             if (norm && norm->mult_gamma_rel_branch().is_known()) {
00288                 fraction *= norm->mult_gamma_rel_branch().cent();
00289                 //cerr << "\twith gamma_rel_branch: " << fraction << endl;
00290             }
00291         }
00292         else if (gamma->I_trans_rel().is_known()) {
00293             fraction = gamma->I_trans_rel().cent();
00294             //cerr << " I_trans_rel = " << fraction<< endl;
00295             if (norm && norm->mult_trans_rel_branch().is_known()) {
00296                 fraction *= norm->mult_trans_rel_branch().cent();
00297                 //cerr << "\twith mult_trans_rel_branch: " << fraction << endl;
00298             }
00299         }
00300 
00301     }
00302     if (rad.is_beta_mi()) {
00303         ens::rec_beta_mi const* beta_mi = rad.to_beta_mi();
00304         if (beta_mi->I_beta_mi_rel().is_known()) {
00305             fraction = beta_mi->I_beta_mi_rel().cent();
00306         }
00307         if (norm && norm->mult_beta_rel_branch().is_known()) {
00308             fraction *= norm->mult_beta_rel_branch().cent();
00309         }
00310     }
00311     if (rad.is_beta_pl()) {
00312         ens::rec_beta_pl const* beta_pl = rad.to_beta_pl();
00313         if (idstr == "EC DECAY") {
00314             if (beta_pl->I_EC_rel().is_known()) {
00315                 fraction = beta_pl->I_EC_rel().cent();
00316             }
00317         }
00318         else {
00319             if (beta_pl->I_beta_pl_rel().is_known()) {
00320                 fraction = beta_pl->I_beta_pl_rel().cent();
00321             }
00322         }
00323         if (norm && norm->mult_beta_rel_branch().is_known()) {
00324             fraction *= norm->mult_beta_rel_branch().cent();
00325         }
00326     }
00327 
00328     if (norm && norm->mult_branch().is_known()) {
00329         if (norm->mult_branch().is_known()) {
00330             fraction *= norm->mult_branch().cent();
00331         }
00332     }
00333 
00334     return fraction;
00335 }
00336 
00337 
00338 void GenDecay::dump_dataset(const ens::dataset& ds)
00339 {
00340     cerr << ds.ident()->nucl() << " with\n"
00341          << "\t"<< count(ds.decay_info_begin(), ds.decay_info_end()) << " decay info\n"
00342          << "\t"<< count(ds.level_begin(), ds.level_end()) << " levels\n"
00343          << endl;    
00344 
00345     for (ens::dataset::decay_info_iterator it_dk = ds.decay_info_begin();
00346          it_dk != ds.decay_info_end(); ++it_dk) {
00347         
00348         if (it_dk->parent()) {
00349             cerr << "Decay parent:\n";
00350             it_dk->parent()->dump(cerr);
00351         }
00352         else { cerr << "No decay parent\n"; }
00353 
00354         if (it_dk->norm()) {
00355             cerr << "Decay norm:\n";
00356             it_dk->norm()->dump(cerr);
00357         }
00358         else { cerr << "No decay norm\n"; }
00359 
00360         if (it_dk->pnorm()) {
00361             cerr << "Decay pnorm:\n";
00362             it_dk->pnorm()->dump(cerr);
00363         }
00364         else { cerr << "No decay pnorm\n"; }
00365     }
00366 
00367     cerr << "Levels:\n";
00368     for (ens::dataset::level_iterator it_lev = ds.level_begin();
00369          it_lev != ds.level_end(); ++it_lev) {
00370         
00371         dump_level(*it_lev);
00372     }
00373 
00374 }
00375 
00376 ens::rec_norm const* get_norm(const ens::dataset& ds)
00377 {
00378     for (ens::dataset::decay_info_iterator 
00379              it_di = ds.decay_info_begin();
00380          it_di != ds.decay_info_end(); ++it_di) {
00381         ens::rec_norm const* n = it_di->norm();
00382         if (n) return n;
00383     }
00384     return 0;
00385 }
00386 
00387 ens::rec_parent const* from_parent(const ens::dataset& ds, NucState& parent)
00388 {
00389     //cerr << "Checking parentage in decay_info for: " << parent << endl;
00390     for (ens::dataset::decay_info_iterator 
00391              it_di = ds.decay_info_begin();
00392          it_di != ds.decay_info_end(); ++it_di) {
00393             
00394         ens::rec_parent const* candidate = it_di->parent();
00395 
00396         if (!candidate) {
00397             //cerr << "from_parent: no decay_info parent\n";
00398             continue;
00399         }
00400         if (candidate->nucl() != parent.nuc()) {
00401             //cerr << "from_parent: decay_info parent = " << candidate->nucl()
00402             //     << " != parent = " << parent.nuc() << endl;
00403             continue;
00404         }
00405         if (candidate->E_minus_E_ref() != parent.erel()) {
00406             //cerr << "from_parent: energies differ: " << candidate->E_minus_E_ref() 
00407             //     << " != " << parent.erel() << endl;
00408             continue;
00409         }
00410         if (candidate->i_E_ref() != parent.eref()) {
00411             //cerr << "from_parent: eref differ: " << candidate->i_E_ref()
00412             //     << " != " << parent.eref() << endl;
00413             continue;
00414         }
00415             
00416         return candidate;
00417     }
00418     return 0;
00419 }
00420 
00421 const ens::dataset& get_decay_dataset(NucState& parent, ens::nucleus& daughter,
00422                                       string idstr, 
00423                                       ens::rec_parent const*& rparent,
00424                                       ens::rec_norm const*& rnorm)
00425 {
00426     static ens::dataset bogus;
00427     rparent = 0;
00428 
00429     //cerr << "Checking for " << parent << " -> " << daughter << " via \"" << idstr << "\"\n";
00430 
00431     for (ens::nucleus::dataset_iterator it_ds
00432              = daughter.dataset_begin ();
00433          it_ds != daughter.dataset_end (); ++it_ds) {
00434         std::string idn = it_ds->ident()->dataset_id_string();
00435 
00436         //cerr << "idn: \"" << idn << "\" idstr: \"" << idstr << "\"\n";
00437         
00438         if (idn.find(idstr) == std::string::npos) {
00439             //cerr << "get_decay_dataset: idstr \"" << idstr << "\" not in \"" << idn << "\"\n";
00440             continue;
00441         }
00442         ens::rec_norm const* n = get_norm(*it_ds);
00443         if (n) rnorm = n;
00444         ens::rec_parent const* p = from_parent(*it_ds,parent);
00445         if (! p) continue;
00446         rparent = p;
00447         return *it_ds;
00448     }
00449     //cerr << "Failed to get decay dataset for " << parent << " -> " << daughter
00450     //     << " for \"" << idstr  << "\"\n";
00451     return bogus;
00452 }
00453 
00454 bool dk_dataset_ok(const ens::dataset& ds)
00455 {
00456     return ds.decay_info_begin() != ds.decay_info_end();
00457 }
00458 
00459 const ens::dataset& get_adopted_levels(ens::nucleus& nuc)
00460 {
00461     static ens::dataset bogus;
00462     ens::dataset const* ds = adopted_levels_dataset(nuc);
00463     if (ds) return *ds;
00464     return bogus;
00465 }
00466 
00467 bool al_dataset_ok(const ens::dataset& ds)
00468 {
00469     return ds.level_begin() != ds.level_end();
00470 }
00471 
00472 // Returns the best, closely matching level of the given erel/eref.
00473 // Candidate levels must pass a hard selection of 1keV difference or
00474 // be withing the errors given by erel.  If none is found with the
00475 // given eref and eref is non-zero, a second search will be done with
00476 // eref == 0.
00477 const ens::rec_level* get_level(const ens::dataset& ds, ens::confiv_t erel, int eref)
00478 {
00479     const double epsilon = 1*SI::keV;
00480     double min_dE = -1;
00481     const ens::rec_level* the_level = 0;
00482 
00483     ens::dataset::level_iterator it, done = ds.level_end();
00484     for (it = ds.level_begin(); it != done; ++it) {
00485 
00486         if (it->i_E_ref() != eref) continue;
00487 
00488         bool candidate = false;
00489 
00490         // level energy must be w/in errors of target
00491         double x = it->E_minus_E_ref().cent();
00492         if (erel.min() < x && x < erel.max()) candidate = true;
00493 
00494         // And must be w/in hard epsilon
00495         double dE = fabs(x-erel.cent());
00496         if (dE < epsilon) candidate = true;
00497 
00498         if (!candidate) continue;
00499 
00500         // Take closest, not first
00501         if (min_dE < 0 || dE < min_dE) {
00502             min_dE = dE;
00503             the_level = &(*it);
00504         }
00505     }
00506 
00507     if (the_level) return the_level;
00508 
00509     // See if daughter level exists with zero reference energy
00510     if (eref > 0) return get_level(ds,erel,0);
00511     return 0;
00512 }
00513 
00514 const ens::rec_level* get_closest_level(const ens::dataset& ds, ens::confiv_t erel, int eref)
00515 {
00516     double min_dE = -1;
00517     const ens::rec_level* the_level = 0;
00518     ens::dataset::level_iterator it, done = ds.level_end();
00519     for (it = ds.level_begin(); it != done; ++it) {
00520         if (it->i_E_ref() != eref) continue;
00521 
00522         double x = it->E_minus_E_ref().cent();
00523         double dE = fabs(x-erel.cent());
00524         if (min_dE < 0 || dE < min_dE) {
00525             min_dE = dE;
00526             the_level = &*it;
00527         }
00528     }
00529 
00530     const ens::rec_level* the_other_level = 0;
00531     if (eref > 0) {
00532         the_other_level = get_closest_level(ds,erel,0);
00533     }
00534 
00535     if (the_level && the_other_level) {
00536         double dE1 = fabs(the_level->E_minus_E_ref().cent() - erel.cent());
00537         double dE2 = fabs(the_other_level->E_minus_E_ref().cent() - erel.cent());
00538         if (dE1 < dE2) return the_level;
00539         return the_other_level;
00540     }
00541     if (!(the_level || the_other_level)) return 0;
00542     if (the_level) return the_level;
00543     return the_other_level;
00544 }
00545 
00546 bool is_only_gamma(const ens::rec_level& lev)
00547 {
00548     int non_gamma = 0;
00549 
00550     for (ens::rec_level::radiation_iterator it_rad = lev.radiation_begin();
00551          it_rad != lev.radiation_end(); ++it_rad) {
00552         if (! it_rad->is_gamma()) ++non_gamma;
00553     }
00554     return non_gamma == 0;
00555 }
00556 
00557 const ens::rec_radiation* get_non_gamma(const ens::rec_level& lev)
00558 {
00559     for (ens::rec_level::radiation_iterator it_rad = lev.radiation_begin();
00560          it_rad != lev.radiation_end(); ++it_rad) {
00561         if (! it_rad->is_gamma()) return &*it_rad;
00562     }
00563     return 0;    
00564 }
00565 
00566 int count_gammas(const ens::rec_level& lev)
00567 {
00568     int ngammas = 0;
00569     for (ens::rec_level::radiation_iterator it_rad = lev.radiation_begin();
00570          it_rad != lev.radiation_end(); ++it_rad) {
00571         if (it_rad->is_gamma()) {
00572             ++ngammas;
00573         }
00574     }
00575     return ngammas;
00576 }
00577 
00578 
00579 // get_daughters for beta+/-, EC and alpha.  beta+ and EC are considered the same
00580 vector<NucState*> get_daughters(NucState* mother, phys::nucleus daughter, string idstr)
00581 {
00582     vector<NucState*> ret;
00583     ens::nucleus candidate;
00584     if (!get_nucleus(daughter,candidate)) {
00585         cerr << "Failed to get nucleus for " << daughter << endl;
00586         return ret;
00587     }
00588 
00589     ens::rec_parent const* parent=0;
00590     ens::rec_norm const* norm=0;
00591     const ens::dataset& dk = get_decay_dataset(*mother,candidate,idstr,parent,norm);
00592     if (!dk_dataset_ok(dk)) {
00593         // can happen if there is no way to get there from here
00594         //cerr << "Failed to get okay data set for mother "
00595         //     << *mother << " and daughter " << candidate << endl;
00596         return ret;
00597     }
00598 
00599     const ens::dataset& al = get_adopted_levels(candidate);
00600     if (!al_dataset_ok(al)) {
00601         cerr << "Failed to get adopted levels for " << candidate << endl;
00602         return ret;
00603     }
00604 
00605     // cerr << "Searching for " << idstr <<" for "<<*mother<<":\n";
00606     //dump_dataset(dk);
00607 
00608     for (ens::dataset::level_iterator it_lev = dk.level_begin();
00609          it_lev != dk.level_end(); ++it_lev) {
00610         const ens::rec_level& dk_lev = *it_lev;
00611 
00612         //dump_level(dk_lev);
00613         // The decay info data set has levels that are not directly
00614         // reachable by alpha/beta but are entered through gamma
00615         // decay, skip them for now.
00616         const ens::rec_radiation* rad = get_non_gamma(dk_lev);
00617         if (!rad) {
00618             //cerr << "No non-gammas for level\n";
00619             continue;
00620         }
00621 
00622         // try to find energy
00623         double energy = 0;
00624         if (rad->E_minus_E_ref().is_known()) {
00625             energy = rad->E_minus_E_ref().cent();
00626         }
00627         else {
00628             energy = parent->QP().cent()         // available ground state energy
00629                 + parent->E_minus_E_ref().cent() // any excitation
00630                 - dk_lev.E_minus_E_ref().cent(); // less our energy
00631             if (idstr == "A DECAY") {
00632                 int A = mother->nuc().n_part();
00633                 double alpha_mod = (A-4.0)/A;
00634                 energy *= alpha_mod;
00635                 cerr << "Warning: alpha decay energy not found, calculate from Qvalue*"
00636                      << alpha_mod << " = " << energy << endl;
00637             }
00638         }
00639         if (energy <= 0.0) {
00640             cerr << "Got bogus energy for this decay, skipping:\n";
00641             cerr << "Radiation:\n";
00642             rad->dump(cerr);
00643             cerr << "Level:\n";
00644             dk_lev.dump(cerr);
00645             continue;
00646         }
00647 
00648         // try to find halflife
00649         ens::confiv_t halflife;
00650         if (dk_lev.T_half().is_known()) halflife = dk_lev.T_half();
00651         else {
00652             const ens::rec_level *al_lev = get_level(al,dk_lev.E_minus_E_ref(),
00653                                                      dk_lev.i_E_ref());
00654             if (!al_lev) {
00655                 cerr << "Failed to get al_lev for dk_level = ";
00656                 dump_level(dk_lev);
00657                 cerr << "\tfrom adopted level dataset:\n";
00658                 dump_dataset(al);
00659             }
00660             else if (al_lev->T_half().is_known()) 
00661                 halflife = al_lev->T_half();
00662         }
00663         
00664         // ENSDF conflats electron capture and positron emission.
00665         // Datasets can be found with either "EC DECAY" or "B+ DECAY"
00666         // labels and in both cases the radiation line has branching
00667         // fractions for both decays.  This is related to #339.
00668         vector<string> idstrs;
00669         if (idstr == "EC DECAY" || idstr == "B+ DECAY") {
00670             idstrs.push_back("EC DECAY");
00671             idstrs.push_back("B+ DECAY");
00672         }
00673         else {
00674             idstrs.push_back(idstr);
00675         }
00676 
00677         for (size_t ind=0; ind < idstrs.size(); ++ind) {
00678             double fraction = rad_fraction(*rad,norm,idstrs[ind]);
00679         
00680             //dump_level(dk_lev);
00681             NucState* child = get_state(daughter,halflife,
00682                                         dk_lev.E_minus_E_ref(),
00683                                         dk_lev.i_E_ref());
00684             NucDecay* decay = get_decay(mother,child,idstrs[ind],energy,fraction);
00685             //cerr << "Decay by " << idstrs[ind] << ": "
00686             //     << *mother << " -> " << *child << " by " << *decay << endl;
00687             decay = 0;
00688         
00689             ret.push_back(child);
00690         }
00691     }
00692 
00693     //dump_dataset(dk);
00694     //dump_dataset(al);
00695 
00696     return ret;
00697 }
00698 
00699 vector<NucState*> get_alpha_daughters(NucState* mother)
00700 {
00701     phys::nucleus daughter(mother->nuc().n_neut()-2,mother->nuc().n_prot()-2);
00702     return get_daughters(mother, daughter,"A DECAY");
00703 }
00704 vector<NucState*> get_betami_daughters(NucState* mother)
00705 {
00706     phys::nucleus daughter(mother->nuc().n_neut()-1,mother->nuc().n_prot()+1);
00707     return get_daughters(mother, daughter,"B- DECAY");
00708 }
00709 vector<NucState*> get_betapl_daughters(NucState* mother)
00710 {
00711     phys::nucleus daughter(mother->nuc().n_neut()+1,mother->nuc().n_prot()-1);
00712     return get_daughters(mother, daughter,"B+ DECAY");
00713 }
00714 vector<NucState*> get_ec_daughters(NucState* mother)
00715 {
00716     phys::nucleus daughter(mother->nuc().n_neut()+1,mother->nuc().n_prot()-1);
00717     return get_daughters(mother, daughter,"EC DECAY");
00718 }
00719 vector<NucState*> get_it_daughters(NucState* mother)
00720 {
00721     phys::nucleus daughter(mother->nuc());
00722 
00723     vector<NucState*> ret;
00724     ens::nucleus candidate;
00725     
00726     if (!get_nucleus(daughter,candidate)) return ret;
00727 
00728     string idstr = "IT DECAY";
00729 
00730     ens::rec_parent const* parent=0;
00731     ens::rec_norm const* norm=0;
00732     const ens::dataset& dk = get_decay_dataset(*mother,candidate,idstr,parent,norm);
00733     if (!dk_dataset_ok(dk)) return ret;
00734 
00735     const ens::dataset& al = get_adopted_levels(candidate);
00736     if (!al_dataset_ok(al)) return ret;
00737 
00738 
00739     const ens::rec_level *lev = get_level(dk,mother->erel(),mother->eref());
00740     if (!lev) {
00741         cerr << "Failed to get decay level for " << *mother << endl;
00742         return ret;
00743     }
00744 
00745     int ngamma = count_gammas(*lev);
00746     if (ngamma != 1) {
00747         cerr << "Too many gammas for an IT DECAY level, got: " << ngamma
00748              << " from decay of " << *mother << " -> " << candidate
00749              << endl;
00750         dump_level(*lev);
00751         return ret;
00752     }
00753 
00754     //cerr << "Found " << idstr <<" for "<<*mother<<":\n";
00755 
00756     const ens::rec_level *child_lev = get_level(al,mother->erel(),0);
00757     if (!child_lev) {
00758         cerr << "Failed to get child of IT DECAY of " << *mother << endl;
00759         dump_dataset(al);
00760         return ret;
00761     }
00762 
00763     const ens::rec_radiation& rad = *(lev->radiation_begin());
00764 
00765     // try to find energy
00766     double energy = 0;
00767     if (rad.E_minus_E_ref().is_known()) {
00768         energy = rad.E_minus_E_ref().cent();
00769     }
00770 
00771     // try to find halflife
00772     ens::confiv_t halflife;
00773     if (lev->T_half().is_known()) halflife = lev->T_half();
00774     else {
00775         const ens::rec_level *al_lev = get_level(al,lev->E_minus_E_ref(),
00776                                                  lev->i_E_ref());
00777         if (!al_lev) {
00778             cerr << "Failed to get al_lev for " 
00779                  << lev->E_minus_E_ref() / SI::keV
00780                  << " w.r.t. " << lev->i_E_ref() << endl;
00781         }
00782         else if (al_lev->T_half().is_known()) 
00783             halflife = al_lev->T_half();
00784     }
00785         
00786     double fraction = norm->mult_branch().cent();
00787 
00788     NucState* child = get_state(daughter,halflife,
00789                                 child_lev->E_minus_E_ref(),
00790                                 child_lev->i_E_ref());
00791     NucDecay* decay = get_decay(mother,child,idstr,energy,fraction);
00792     //cerr << "Decay: " << *mother << " -> " << *child << " by " << *decay << endl;
00793     decay = 0;                  // quell compiler warning
00794 
00795     ret.push_back(child);
00796     return ret;
00797 }
00798 
00799 vector<NucState*> get_gamma_daughters(NucState* mother)
00800 {
00801     phys::nucleus daughter(mother->nuc());
00802 
00803     vector<NucState*> ret;
00804     ens::nucleus candidate;
00805     if (!get_nucleus(daughter,candidate)) return ret;
00806 
00807     const ens::dataset& al = get_adopted_levels(candidate);
00808     if (!al_dataset_ok(al)) return ret;
00809 
00810     const ens::rec_level* lev = get_level(al,mother->erel(),mother->eref());
00811     if (!lev) {
00812         cerr << "Failed to get level for " << *mother << endl;
00813         return ret;
00814     }
00815 
00816     if (0 == count_gammas(*lev) and mother->erel().cent() > 0) {
00817         // Sometimes there are no gammas given in the dataset, what
00818         // can I say?
00819 
00820         //cerr << "No gammas in level " << *mother << endl;
00821         //dump_level(*lev);
00822         return ret;
00823     }
00824 
00825     //cerr << "GAMMA decay from " << *mother << endl;
00826 
00827     for (ens::rec_level::radiation_iterator it_rad = lev->radiation_begin();
00828          it_rad != lev->radiation_end(); ++it_rad) {
00829 
00830         if (! it_rad->is_gamma()) continue;
00831 
00832         ens::confiv_t halflife;
00833 
00834         double energy = it_rad->E_minus_E_ref().cent();
00835         double fraction = rad_fraction(*it_rad);
00836 
00837         // fixme, this is bogus if i_E_ref is non-zero
00838         ens::confiv_t erel = mother->erel() - it_rad->E_minus_E_ref();
00839         if (erel.cent() < 0) erel = ens::confiv_t(0.0,0);
00840 
00841         // First look in same X-excited state
00842         const ens::rec_level* daughter_lev = get_level(al,erel,mother->eref());
00843         if (!daughter_lev) {
00844             daughter_lev = get_closest_level(al,erel,mother->eref());
00845             double de = daughter_lev->E_minus_E_ref().cent();
00846             double diff = fabs(de-erel.cent())/erel.cent();
00847 
00848             if (daughter_lev) {
00849                 cerr << "Warning inexact match for daughter of "<<*mother<<" for gamma of "
00850                      << it_rad->E_minus_E_ref()/SI::keV
00851                      << "\twanted:"<<erel/SI::keV<<" got:"
00852                      << de/SI::keV<<" ["<<daughter_lev->i_E_ref()<<"] diff="<<diff*100<<"%\n";
00853             }
00854         }
00855         if (!daughter_lev) {
00856             cerr << "Failed to get daughter energy ("<<erel/SI::keV<<") level for gamma from "<<*mother<<":\n";
00857             dump_radiation(*it_rad);
00858             dump_dataset(al);
00859             continue;
00860         }
00861         halflife = daughter_lev->T_half();
00862 
00863         NucState* child = get_state(mother->nuc(),halflife,
00864                                     daughter_lev->E_minus_E_ref(),
00865                                     daughter_lev->i_E_ref());
00866         NucDecay* decay = get_decay(mother,child,"Gamma",energy,fraction);
00867         //cerr << "Decay: " << *mother << " -> " << *child << " by " << *decay << endl;
00868         decay = 0;  // quell compiler warning
00869 
00870         ret.push_back(child);
00871 
00872     }
00873     return ret;
00874 }
00875 
00876 typedef vector<NucState*> (*GetDaughterFunc)(NucState*);
00877 GetDaughterFunc get_xxx_daughters[] = {
00878     get_alpha_daughters,
00879     get_betami_daughters,
00880     get_betapl_daughters,
00881     get_ec_daughters,
00882     get_it_daughters,
00883     get_gamma_daughters,
00884     0
00885 };
00886 const char* decay_names[] = {
00887     "A DECAY",
00888     "B- DECAY",
00889     "B+ DECAY",
00890     "EC DECAY",
00891     "IT DECAY",
00892     "GAMMA DECAY",
00893     0
00894 };
00895 
00896 void GenDecay::chain(NucState* mother, int depth,
00897                      more::phys::nucleus stop_nuc)
00898 {
00899     // record if a NucState has been chained yet
00900     typedef map<NucState*,int> NucChained_t;
00901     static NucChained_t chained;
00902 
00903 
00904     if (!mother) {
00905         cerr << "ERROR: chain given null mother\n";
00906         return;
00907     }
00908 
00909     if (!depth) {
00910         //cerr << "Reached target depth with " << *mother << endl;
00911         return;
00912     }
00913     --depth;
00914 
00915     //cerr << "Mother nuc: " << mother->nuc()
00916     //     << " stop_nuc: " << stop_nuc << endl;
00917     if (mother->energy() == 0.0 && mother->eref() == 0 &&
00918         mother->nuc() == stop_nuc) 
00919     {
00920         cerr << "Reached ground state stop_nuc = " << stop_nuc << endl;
00921         return;
00922     }
00923 
00924     // Don't chain a state that has already been seen
00925     if (chained[mother]) return;
00926     chained[mother] = 1;
00927 
00928     //cerr << "Chaining " << *mother << "(@" << (void*)mother << ") at depth "<<depth<<"\n";
00929 
00930     // load mother
00931     ens::nucleus pnucl;
00932     if (!get_nucleus(mother->nuc(),pnucl)) {
00933         cerr << "Got run time error with " << mother->nuc() << endl;
00934     }
00935 
00936     vector<NucState*> daughters;
00937 
00938     // look for daughters
00939     for (int ind=0; get_xxx_daughters[ind]; ++ind) {
00940         vector<NucState*> ds = get_xxx_daughters[ind](mother);
00941 
00942         //cerr << *mother << " has " << ds.size() 
00943         //     << " daughters made by " << decay_names[ind] << endl;
00944 
00945         daughters.insert(daughters.end(),ds.begin(),ds.end());
00946     }
00947 
00948     normalize_branching_fractions(*mother);
00949     
00950     //cerr << *mother << " has these daughters:\n";
00951     //for (size_t ind=0; ind < daughters.size(); ++ind) {
00952     //    cerr << "\t" << *daughters[ind] << endl;
00953     //}
00954     for (size_t ind=0; ind < daughters.size(); ++ind) {
00955         for (size_t inuc=0; inuc < daughters.size(); ++inuc) {
00956             chain(daughters[inuc],depth,stop_nuc);
00957         }
00958     }
00959 
00960 }
00961 
00962 NucState* GenDecay::get_ground(std::string name)
00963 {
00964     istringstream iss(name);
00965     phys::nucleus nucl;
00966     iss >> nucl;
00967     return get_ground(nucl);
00968 }
00969 
00970 NucState* GenDecay::get_ground(phys::nucleus nucl)
00971 {
00972     ens::nucleus candidate;
00973     if (!get_nucleus(nucl,candidate)) {
00974         cerr << "get_ground: failed to get_nucleus for " << nucl << endl;
00975         return 0;
00976     }
00977     const ens::dataset& al = get_adopted_levels(candidate);
00978     if (!al_dataset_ok(al)) {
00979         cerr << "get_ground: adopted levels data set is not okay:\n";
00980         al.dump(cerr);
00981         return 0;
00982     }
00983 
00984     ens::confiv_t erel(0.0,0.0);
00985     const ens::rec_level* lev = get_level(al,erel,0);
00986     if (!lev) {
00987         cerr << "get_ground: failed to get ground energy level record for " << nucl << endl;
00988         return 0;
00989     }
00990 
00991     ens::confiv_t hl = lev->T_half();
00992     NucState* head = get_state(nucl,hl);
00993     return head;
00994 }
00995 
00996 const Radiation* GenDecay::decay_radiation(const NucDecay& dk)
00997 {
00998     static map<const NucDecay*, Radiation*> radCache;
00999 
01000     Radiation* rad = radCache[&dk];
01001     if (rad) return rad;
01002 
01003     int parentZ = dk.mother->nuc().n_prot();
01004     int parentA = dk.mother->nuc().n_part();
01005     if (dk.type == "A DECAY") {
01006         rad = new AlphaRadiation(dk.clhep_energy(), parentA);
01007     }
01008     if (dk.type == "Gamma") {
01009         rad = new GammaRadiation(dk.clhep_energy());
01010     }
01011     if (dk.type == "IT DECAY") {
01012         rad = new GammaRadiation(dk.clhep_energy());
01013     }
01014     if (dk.type == "B- DECAY") {
01015         rad = new BetaRadiation(dk.clhep_energy(), parentZ);
01016     }
01017     if (dk.type == "B+ DECAY") {
01018         rad = new BetaRadiation(dk.clhep_energy(), -1*parentZ);
01019     }
01020     if (dk.type == "EC DECAY") {
01021         rad = new ElectronCapture(dk.clhep_energy());
01022     }
01023 
01024     if (!rad) {
01025         cerr << "decay_radiation: failed to make radiation from \"" << dk << "\"\n";
01026         return 0;
01027     }
01028 
01029     radCache[&dk] = rad;    
01030     return rad;
01031 }
| 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