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
00031
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
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
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
00082
00083 return ns;
00084 }
00085
00086
00087 vector<NucState*>& vns = it->second;
00088 for (size_t ind=0; ind < vns.size(); ++ind) {
00089 if (vns[ind]->eref() != ref) {
00090
00091
00092 continue;
00093 }
00094 if (vns[ind]->erel() != rel) {
00095
00096
00097 continue;
00098 }
00099
00100
00101
00102 return vns[ind];
00103 }
00104
00105
00106 NucState* ns = new NucState(n,hl,rel,ref);
00107 vns.push_back(ns);
00108
00109 return ns;
00110 }
00111
00112 static
00113 void normalize_branching_fractions(NucState& state)
00114 {
00115 vector<NucDecay*>& decays = state.decays();
00116
00117
00118 if (!decays.size()) return;
00119
00120
00121 if (decays.size() == 1) {
00122 decays[0]->fraction = 1.0;
00123 return;
00124 }
00125
00126
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
00156 }
00157
00158
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
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
00287 if (norm && norm->mult_gamma_rel_branch().is_known()) {
00288 fraction *= norm->mult_gamma_rel_branch().cent();
00289
00290 }
00291 }
00292 else if (gamma->I_trans_rel().is_known()) {
00293 fraction = gamma->I_trans_rel().cent();
00294
00295 if (norm && norm->mult_trans_rel_branch().is_known()) {
00296 fraction *= norm->mult_trans_rel_branch().cent();
00297
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
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
00398 continue;
00399 }
00400 if (candidate->nucl() != parent.nuc()) {
00401
00402
00403 continue;
00404 }
00405 if (candidate->E_minus_E_ref() != parent.erel()) {
00406
00407
00408 continue;
00409 }
00410 if (candidate->i_E_ref() != parent.eref()) {
00411
00412
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
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
00437
00438 if (idn.find(idstr) == std::string::npos) {
00439
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
00450
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
00473
00474
00475
00476
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
00491 double x = it->E_minus_E_ref().cent();
00492 if (erel.min() < x && x < erel.max()) candidate = true;
00493
00494
00495 double dE = fabs(x-erel.cent());
00496 if (dE < epsilon) candidate = true;
00497
00498 if (!candidate) continue;
00499
00500
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
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
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
00594
00595
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
00606
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
00613
00614
00615
00616 const ens::rec_radiation* rad = get_non_gamma(dk_lev);
00617 if (!rad) {
00618
00619 continue;
00620 }
00621
00622
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()
00629 + parent->E_minus_E_ref().cent()
00630 - dk_lev.E_minus_E_ref().cent();
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
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
00665
00666
00667
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
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
00686
00687 decay = 0;
00688
00689 ret.push_back(child);
00690 }
00691 }
00692
00693
00694
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
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
00766 double energy = 0;
00767 if (rad.E_minus_E_ref().is_known()) {
00768 energy = rad.E_minus_E_ref().cent();
00769 }
00770
00771
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
00793 decay = 0;
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
00818
00819
00820
00821
00822 return ret;
00823 }
00824
00825
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
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
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
00868 decay = 0;
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
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
00911 return;
00912 }
00913 --depth;
00914
00915
00916
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
00925 if (chained[mother]) return;
00926 chained[mother] = 1;
00927
00928
00929
00930
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
00939 for (int ind=0; get_xxx_daughters[ind]; ++ind) {
00940 vector<NucState*> ds = get_xxx_daughters[ind](mother);
00941
00942
00943
00944
00945 daughters.insert(daughters.end(),ds.begin(),ds.end());
00946 }
00947
00948 normalize_branching_fractions(*mother);
00949
00950
00951
00952
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 }