3#if __cplusplus >= 201703L
18float TGamma::fTextSize = 0.020;
19float TLevel::fTextSize = 0.025;
21std::vector<TLevelScheme*> TLevelScheme::fLevelSchemes;
23TGamma::TGamma(TLevelScheme* levelScheme, std::string label,
const double& br,
const double& ts)
24 : fBranchingRatio(br), fTransitionStrength(ts), fLabelText(std::move(label)), fLevelScheme(levelScheme)
26 fLabelText.insert(0, 1,
' ');
30TGamma::TGamma(
const TGamma& rhs)
33 if(fDebug || rhs.fDebug) {
34 std::cout << __PRETTY_FUNCTION__ <<
": copying gamma \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
38 fEnergy = rhs.fEnergy;
39 fEnergyUncertainty = rhs.fEnergyUncertainty;
40 fUseTransitionStrength = rhs.fUseTransitionStrength;
41 fScalingGain = rhs.fScalingGain;
42 fScalingOffset = rhs.fScalingOffset;
43 fBranchingRatio = rhs.fBranchingRatio;
44 fBranchingRatioUncertainty = rhs.fBranchingRatioUncertainty;
45 fBranchingRatioPercent = rhs.fBranchingRatioPercent;
46 fBranchingRatioPercentUncertainty = rhs.fBranchingRatioPercentUncertainty;
47 fTransitionStrength = rhs.fTransitionStrength;
48 fTransitionStrengthUncertainty = rhs.fTransitionStrengthUncertainty;
49 fLabelText = rhs.fLabelText;
51 fLevelScheme = rhs.fLevelScheme;
52 fInitialEnergy = rhs.fInitialEnergy;
53 fFinalEnergy = rhs.fFinalEnergy;
56TGamma& TGamma::operator=(
const TGamma& rhs)
58 if(fDebug || rhs.fDebug) {
59 std::cout << __PRETTY_FUNCTION__ <<
": copying gamma \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
64 fEnergy = rhs.fEnergy;
65 fEnergyUncertainty = rhs.fEnergyUncertainty;
66 fUseTransitionStrength = rhs.fUseTransitionStrength;
67 fScalingGain = rhs.fScalingGain;
68 fScalingOffset = rhs.fScalingOffset;
69 fBranchingRatio = rhs.fBranchingRatio;
70 fBranchingRatioUncertainty = rhs.fBranchingRatioUncertainty;
71 fBranchingRatioPercent = rhs.fBranchingRatioPercent;
72 fBranchingRatioPercentUncertainty = rhs.fBranchingRatioPercentUncertainty;
73 fTransitionStrength = rhs.fTransitionStrength;
74 fTransitionStrengthUncertainty = rhs.fTransitionStrengthUncertainty;
75 fLabelText = rhs.fLabelText;
77 fLevelScheme = rhs.fLevelScheme;
78 fInitialEnergy = rhs.fInitialEnergy;
79 fFinalEnergy = rhs.fFinalEnergy;
85void TGamma::UpdateWidth()
87 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
88 auto arrowsize =
static_cast<Width_t
>((fUseTransitionStrength ? fTransitionStrength : fBranchingRatio) * fScalingGain + fScalingOffset);
89 SetLineWidth(arrowsize);
92void TGamma::UpdateLabel()
94 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
95 if(fLabel !=
nullptr) {
96 fLabel->SetText(fLabel->GetX(), fLabel->GetY(), fLabelText.c_str());
100void TGamma::Draw(
const double& x1,
const double& y1,
const double& x2,
const double& y2)
109 if(fLabel ==
nullptr) {
110 fLabel =
new TLatex((x1 + x2) / 2., (y1 + y2) / 2., fLabelText.c_str());
112 fLabel->SetText((x1 + x2) / 2., (y1 + y2) / 2., fLabelText.c_str());
114 fLabel->SetTextColor(GetLineColor());
115 fLabel->SetTextAlign(12);
116 fLabel->SetTextFont(42);
117 fLabel->SetTextSize(fTextSize);
119 if(fDebug) { Print(); }
122void TGamma::Print(Option_t*)
const
125 std::cout <<
"Gamma with energy " << fEnergy <<
" +- " << fEnergyUncertainty <<
" (from " << fInitialEnergy <<
" to " << fFinalEnergy <<
") " << (fUseTransitionStrength ?
"using" :
"not using") <<
" transition strength " << fTransitionStrength <<
", branching " << fBranchingRatio <<
" = " << 100. * fBranchingRatioPercent <<
"%, scaling gain " << fScalingGain <<
", scaling offset " << fScalingOffset <<
", arrow size " << GetArrowSize() <<
", line color " << GetLineColor() <<
", line width " << GetLineWidth() << std::endl;
128std::map<double, double> TGamma::CoincidentGammas()
131 if(fLevelScheme ==
nullptr) {
132 std::cerr <<
"Parent level scheme not set, can't find coincident gamma rays" << std::endl;
136 std::cout <<
"Looking for coincident gammas for gamma of " << fEnergy <<
" kev from level at " << fInitialEnergy <<
" keV to level at " << fFinalEnergy <<
" keV" << std::endl;
138 fLevelScheme->ResetGammaMap();
139 auto result = fLevelScheme->FeedingGammas(fInitialEnergy, fBranchingRatioPercent);
141 std::cout <<
"Got " << result.size() <<
" gammas feeding level at " << fInitialEnergy << std::endl;
143 if(fFinalEnergy > 0) {
144 auto draining = fLevelScheme->DrainingGammas(fFinalEnergy);
146 std::cout <<
"Plus " << draining.size() <<
" gammas draining level at " << fFinalEnergy << std::endl;
148 for(
auto& [energy, factor] : draining) {
149 result[energy] += factor;
153 std::cout <<
"Got " << result.size() <<
" coincident gammas:";
154 for(
auto& element : result) {
155 std::cout <<
" " << element.first <<
" (" << element.second <<
"%)";
157 std::cout << std::endl;
163void TGamma::PrintCoincidentGammas()
165 auto map = CoincidentGammas();
166 std::cout << map.size() <<
" coincident gammas for gamma " << fEnergy <<
" +- " << fEnergyUncertainty <<
" (" << fInitialEnergy <<
" to " << fFinalEnergy <<
"):";
167 for(
auto gamma : map) {
168 std::cout <<
" " << gamma.first <<
" (" << gamma.second <<
"%)";
170 std::cout << std::endl;
173std::vector<std::tuple<double, std::vector<double>>> TGamma::ParallelGammas()
177 if(fLevelScheme ==
nullptr) {
178 std::cerr <<
"Parent level scheme not set, can't find parallel gamma rays" << std::endl;
182 std::cout <<
"Looking for parallel gammas for gamma of " << fEnergy <<
" kev from level at " << fInitialEnergy <<
" keV to level at " << fFinalEnergy <<
" keV" << std::endl;
184 auto result = fLevelScheme->ParallelGammas(fInitialEnergy, fFinalEnergy);
185 auto last = std::remove_if(result.begin(), result.end(), [](std::tuple<
double, std::vector<double>> x) { return std::get<1>(x).size() < 2; });
187 std::cout <<
"Removing " << std::distance(last, result.end()) <<
" paths, keeping " << std::distance(result.begin(), last) << std::endl;
189 result.erase(last, result.end());
206void TGamma::PrintParallelGammas()
208 auto vec = ParallelGammas();
209 std::cout << vec.size() <<
" parallel paths for gamma " << fEnergy <<
" +- " << fEnergyUncertainty <<
" (" << fInitialEnergy <<
" to " << fFinalEnergy <<
"):" << std::endl;
210 for(
auto& element : vec) {
211 std::cout << std::get<0>(element) <<
":";
212 double totalEnergy = 0.;
213 for(
auto& energy : std::get<1>(element)) {
214 std::cout <<
" " << energy;
215 totalEnergy += energy;
217 std::cout <<
" (" << totalEnergy <<
")" << std::endl;
221TLevel::TLevel(TLevelScheme* levelScheme,
const double& energy,
const std::string& label)
223 if(fDebug && levelScheme ==
nullptr) {
224 std::cout <<
"Warning, nullptr provided to new band \"" << label <<
"\" for parent level scheme, some functions might no be available" << std::endl;
226 fLevelScheme = levelScheme;
231TLevel::TLevel(
const TLevel& rhs)
234 if(fDebug || rhs.fDebug) {
235 std::cout << __PRETTY_FUNCTION__ <<
": copying level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
239 fEnergy = rhs.fEnergy;
240 fEnergyUncertainty = rhs.fEnergyUncertainty;
242 fGammas = rhs.fGammas;
243 fNofFeeding = rhs.fNofFeeding;
244 fLevelScheme = rhs.fLevelScheme;
245 fLevelLabel = rhs.fLevelLabel;
246 fEnergyLabel = rhs.fEnergyLabel;
247 fOffset = rhs.fOffset;
249 std::cout << __PRETTY_FUNCTION__ <<
": copied level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
256 std::cout <<
"Deleting level \"" << fLabel <<
"\" at " << fEnergy <<
" keV (" <<
this <<
")" << std::endl;
260TLevel& TLevel::operator=(
const TLevel& rhs)
262 if(fDebug || rhs.fDebug) {
263 std::cout << __PRETTY_FUNCTION__ <<
": copying level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
267 TPolyLine::operator=(rhs);
269 fEnergy = rhs.fEnergy;
271 fGammas = rhs.fGammas;
272 fNofFeeding = rhs.fNofFeeding;
273 fLevelScheme = rhs.fLevelScheme;
274 fLevelLabel = rhs.fLevelLabel;
275 fEnergyLabel = rhs.fEnergyLabel;
276 fOffset = rhs.fOffset;
278 std::cout << __PRETTY_FUNCTION__ <<
": copied level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
285TGamma* TLevel::AddGamma(
const double levelEnergy,
const char* label,
double br,
double ts)
290 return AddGamma(levelEnergy, 0., label, br, ts);
293TGamma* TLevel::AddGamma(
const double levelEnergy,
const double energyUncertainty,
const char* label,
double br,
double ts)
298 auto* level = fLevelScheme->FindLevel(levelEnergy, energyUncertainty);
299 if(level ==
nullptr) {
300 std::cerr <<
DRED <<
"Failed to find level at " << levelEnergy <<
" keV, can't add gamma!" <<
RESET_COLOR << std::endl;
305 if(fGammas.count(level->Energy()) == 1) {
307 std::cout <<
"Already found gamma ray from ";
309 std::cout <<
" to " << levelEnergy <<
"/" << level->Energy() <<
" keV";
316 fGammas.emplace(std::piecewise_construct, std::forward_as_tuple(level->Energy()), std::forward_as_tuple(fLevelScheme, label, br, ts));
317 fGammas[level->Energy()].Debug(fDebug);
318 fGammas[level->Energy()].Energy(Energy() - levelEnergy);
319 fGammas[level->Energy()].EnergyUncertainty(energyUncertainty);
320 fGammas[level->Energy()].InitialEnergy(fEnergy);
321 fGammas[level->Energy()].FinalEnergy(level->Energy());
324 double sum = std::accumulate(fGammas.begin(), fGammas.end(), 0., [](
double r, std::pair<const double, TGamma>& g) { r += g.second.BranchingRatio(); return r; });
325 for(
auto& [en, gamma] : fGammas) {
326 gamma.BranchingRatioPercent(gamma.BranchingRatio() / sum);
327 gamma.BranchingRatioPercentUncertainty(gamma.BranchingRatioUncertainty() / sum);
330 if(fDebug) { Print(); }
332 fLevelScheme->Refresh();
334 return &(fGammas[level->Energy()]);
337void TLevel::MoveToBand(
const char* val)
339 if(fLevelScheme ==
nullptr) {
340 std::cerr << __PRETTY_FUNCTION__ <<
": Parent level scheme pointer not set!" << std::endl;
344 std::cout <<
"Trying to move level " <<
this <<
" at " << Energy() <<
" keV to band \"" << val <<
"\" using " << fLevelScheme << std::endl;
346 fLevelScheme->MoveToBand(val,
this);
349std::pair<double, double> TLevel::GetMinMaxGamma()
const
351 if(fGammas.empty()) {
return std::make_pair(-1., -1.); }
352 auto result = std::make_pair(fGammas.begin()->second.Width(), fGammas.begin()->second.Width());
353 for(
const auto& [energy, gamma] : fGammas) {
354 if(gamma.Width() < result.first) { result.first = gamma.Width(); }
355 if(gamma.Width() > result.second) { result.second = gamma.Width(); }
361void TLevel::Draw(
const double& left,
const double& right)
363 std::vector<double> x;
364 std::vector<double> y;
366 double tickLength = (fOffset == 0. ? 0. : 10.);
370 y.push_back(fEnergy + fOffset);
371 x.push_back(left + tickLength);
372 y.push_back(fEnergy + fOffset);
373 x.push_back(left + tickLength + std::fabs(fOffset) / 2.);
374 y.push_back(fEnergy);
375 if(fDebug) { std::cout <<
"Non-zero offset " << fOffset <<
" => left line " << left <<
", " << fEnergy + fOffset <<
" via " << left + tickLength <<
", " << fEnergy + fOffset <<
" to " << left + tickLength + std::fabs(fOffset) / 2. <<
", " << fEnergy << std::endl; }
377 x.push_back(left + tickLength + std::fabs(fOffset) / 2.);
378 y.push_back(fEnergy);
379 x.push_back(right - tickLength - std::fabs(fOffset) / 2.);
380 y.push_back(fEnergy);
382 x.push_back(right - tickLength - std::fabs(fOffset) / 2.);
383 y.push_back(fEnergy);
384 x.push_back(right - tickLength);
385 y.push_back(fEnergy + fOffset);
387 y.push_back(fEnergy + fOffset);
388 if(fDebug) { std::cout <<
"Non-zero offset " << fOffset <<
" => right line " << right - tickLength - std::fabs(fOffset) / 2. <<
", " << fEnergy <<
" via " << right - tickLength <<
", " << fEnergy + fOffset <<
" to " << right <<
", " << fEnergy + fOffset << std::endl; }
390 SetPolyLine(x.size(), x.data(), y.data());
392 if(fDebug) { std::cout <<
"Drew TPolyLine using x " << left <<
"-" << right <<
" and y " << fEnergy <<
" with a width of " << GetLineWidth() <<
" and offset " << fOffset << std::endl; }
395double TLevel::DrawLabel(
const double& pos)
397 if(fLevelLabel ==
nullptr) {
398 fLevelLabel =
new TLatex(pos, fEnergy + fOffset, fLabel.c_str());
400 fLevelLabel->SetText(pos, fEnergy + fOffset, fLabel.c_str());
402 fLevelLabel->SetTextColor(GetLineColor());
403 fLevelLabel->SetTextAlign(12);
404 fLevelLabel->SetTextFont(42);
405 fLevelLabel->SetTextSize(fTextSize);
407 return fLevelLabel->GetXsize();
410double TLevel::DrawEnergy(
const double& pos)
412 if(fEnergyLabel ==
nullptr) {
413 fEnergyLabel =
new TLatex(pos, fEnergy + fOffset, Form(
"%.0f keV", fEnergy));
415 fEnergyLabel->SetText(pos, fEnergy + fOffset, Form(
"%.0f keV", fEnergy));
417 fEnergyLabel->SetTextColor(GetLineColor());
418 fEnergyLabel->SetTextAlign(32);
419 fEnergyLabel->SetTextFont(42);
420 fEnergyLabel->SetTextSize(fTextSize);
421 fEnergyLabel->Draw();
422 return fEnergyLabel->GetXsize();
425void TLevel::Print(Option_t*)
const
427 std::cout <<
"Level \"" << fLabel <<
"\" (" <<
this <<
") at " << fEnergy <<
" keV has " << fGammas.size() <<
" draining gammas and " << fNofFeeding <<
" feeding gammas, debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
429 for(
const auto& [level, gamma] : fGammas) {
430 std::cout <<
"gamma to level " << level <<
" \"" << gamma.LabelText() <<
"\"" << std::endl;
435TBand::TBand(TLevelScheme* levelScheme,
const std::string& label)
437 if(levelScheme ==
nullptr) {
438 std::cout <<
"Warning, nullptr provided to new band \"" << label <<
"\" for parent level scheme, some functions might no be available" << std::endl;
440 fLevelScheme = levelScheme;
441 SetLabel(label.c_str());
446TBand::TBand(
const TBand& rhs)
449 if(fDebug || rhs.fDebug) {
450 std::cout << __PRETTY_FUNCTION__ <<
": copying band \"" << rhs.GetLabel() <<
"\" to \"" << GetLabel() <<
"\" (" << &rhs <<
" to " << this <<
"), " << rhs.fLevels.size() <<
" level(s) to " << fLevels.size() <<
" level(s)" << std::endl;
454 fLevels = rhs.fLevels;
455 fLevelScheme = rhs.fLevelScheme;
457 if(fDebug || rhs.fDebug) {
458 std::cout << __PRETTY_FUNCTION__ <<
": copied band \"" << rhs.GetLabel() <<
"\" to \"" << GetLabel() <<
"\" (" << &rhs <<
" to " << this <<
"), " << rhs.fLevels.size() <<
" level(s) to " << fLevels.size() <<
" level(s)" << std::endl;
462TBand& TBand::operator=(
const TBand& rhs)
465 TPaveLabel::operator=(rhs);
466 if(fDebug || rhs.fDebug) {
467 std::cout << __PRETTY_FUNCTION__ <<
": copying band \"" << rhs.GetLabel() <<
"\" to \"" << GetLabel() <<
"\" (" << &rhs <<
" to " <<
this <<
"), " << rhs.fLevels.size() <<
" level(s) to " << fLevels.size() <<
" level(s)" << std::endl;
470 fLevels = rhs.fLevels;
471 fLevelScheme = rhs.fLevelScheme;
472 if(fDebug || rhs.fDebug) {
473 std::cout << __PRETTY_FUNCTION__ <<
": copied band \"" << rhs.GetLabel() <<
"\" to \"" << GetLabel() <<
"\" (" << &rhs <<
" to " <<
this <<
"), " << rhs.fLevels.size() <<
" level(s) to " << fLevels.size() <<
" level(s)" << std::endl;
480TLevel* TBand::GetLevel(
double energy)
483 if(fLevels.count(energy) == 0) {
484 std::cout <<
this <<
": failed to find level with " << energy <<
" keV" << std::endl;
489 std::cout <<
this <<
": found ";
490 fLevels.find(energy)->second.Print();
491 std::cout <<
"energy " << energy <<
" - " << &(fLevels.find(energy)->second) << std::endl;
493 return &(fLevels.find(energy)->second);
496TLevel* TBand::FindLevel(
double energy,
double energyUncertainty)
500 auto low = fLevels.lower_bound(energy - energyUncertainty);
501 auto high = fLevels.upper_bound(energy + energyUncertainty);
503 std::cout <<
this <<
": failed to find level with " << energy <<
" +- " << energyUncertainty <<
" keV" << std::endl;
507 if(std::distance(low, high) == 1) {
509 std::cout <<
this <<
": found ";
511 std::cout <<
"energy " << energy <<
" +- " << energyUncertainty <<
" - " << &(low->second) << std::endl;
513 return &(low->second);
516 double en = low->first;
517 TLevel* level = &(low->second);
518 for(
auto& it = ++low; it != high; ++it) {
519 if(std::fabs(energy - en) > std::fabs(energy - it->first)) {
521 level = &(it->second);
525 std::cout <<
this <<
": found " << std::distance(low, high) <<
" levels, closest is";
527 std::cout <<
"energy " << energy <<
" +- " << energyUncertainty <<
" - " << level << std::endl;
532std::pair<double, double> TBand::GetMinMaxGamma()
const
534 if(fLevels.empty()) {
throw std::runtime_error(
"Trying to get min/max gamma width from empty band"); }
535 auto result = fLevels.begin()->second.GetMinMaxGamma();
536 for(
const auto& [energy, level] : fLevels) {
537 auto [min, max] = level.GetMinMaxGamma();
538 if(min < result.first) { result.first = min; }
539 if(max > result.second) { result.second = max; }
545TLevel* TBand::AddLevel(
const double energy,
const std::string& label)
552 std::cout << __PRETTY_FUNCTION__ <<
" - " <<
this <<
": Trying to add new level \"" << label <<
"\" at " << energy <<
" keV to " << std::flush;
555 auto [newLevel, success] = fLevels.emplace(std::piecewise_construct, std::forward_as_tuple(energy), std::forward_as_tuple(fLevelScheme, energy, label));
557 std::cerr <<
DRED <<
"Failed to add new level \"" << label <<
"\" at " << energy <<
" keV to " <<
RESET_COLOR;
561 newLevel->second.Debug(fDebug);
563 std::cout <<
this <<
": adding new level \"" << label <<
"\" at " << energy <<
" keV " << (success ?
"was a success" :
"failed") <<
" now got " << fLevels.size() <<
"/" << NofLevels() <<
" levels, debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
565 std::cout <<
"New level: ";
566 newLevel->second.Print();
571 fLevelScheme->Refresh();
573 return &(newLevel->second);
576void TBand::AddLevel(TLevel* level)
579 std::cout << __PRETTY_FUNCTION__ <<
" - " <<
this <<
" - \"" << GetLabel() <<
"\": Trying to add new level \"" << level->Label() <<
"\" at " << level->Energy() <<
" keV" << std::endl;
581 auto [iterator, success] = fLevels.insert(std::pair{level->Energy(), *level});
583 std::cout <<
"Failed to insert level at " << level->Energy() <<
" into ";
586 std::cout <<
"Successfully added new level \"" << level->Label() <<
"\" at " << level->Energy() <<
" keV" << std::endl;
591void TBand::RemoveLevel(TLevel* level)
594 auto nofRemoved = fLevels.erase(level->Energy());
596 std::cout <<
"\"" << GetLabel() <<
"\": Removed " << nofRemoved <<
" levels" << std::endl;
601double TBand::Width(
double distance)
const
603 size_t nofGammas = 0.;
605 std::cout <<
" (" << GetLabel() <<
" - " << fLevels.size() <<
": ";
607 for(
const auto& level : fLevels) {
608 nofGammas += level.second.NofDrainingGammas() + 1;
610 std::cout <<
" " << nofGammas <<
" ";
613 if(nofGammas == 0) { nofGammas = 1; }
616 std::cout <<
"=> width " <<
static_cast<double>(nofGammas) * distance <<
") ";
619 return static_cast<double>(nofGammas) * distance;
622void TBand::Print(Option_t*)
const
624 std::cout <<
this <<
": band \"" << GetLabel() <<
"\" " << fLevels.size() <<
" level(s):";
625 for(
const auto& level : fLevels) {
626 std::cout <<
" " << level.first;
628 std::cout <<
", debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
630 for(
const auto& level : fLevels) {
631 level.second.Print();
636TLevelScheme::TLevelScheme(
const std::string& filename,
bool debug)
639 SetName(
"TLevelScheme");
640 SetLabel(
"Level Scheme");
644 if(!filename.empty()) {
646 std::cout <<
"file " << filename <<
" does not exist or we don't have read permissions" << std::endl;
648 auto lastDot = filename.find_last_of(
'.');
649 if(lastDot == std::string::npos) {
650 std::cout <<
"Failed to find extension => unknown data format" << std::endl;
652 std::string ext = filename.substr(lastDot + 1);
654 ParseENSDF(filename);
656 std::cout <<
"Unknown extension " << ext <<
" => unknown data format" << std::endl;
662 fLevelSchemes.push_back(
this);
665TLevelScheme::TLevelScheme(
const TLevelScheme& rhs)
666 : TPaveLabel(rhs), fDebug(rhs.fDebug), fBands(rhs.fBands), fAuxillaryLevels(rhs.fAuxillaryLevels),
667 fQValue(rhs.fQValue), fQValueUncertainty(rhs.fQValueUncertainty),
668 fNeutronSeparation(rhs.fNeutronSeparation), fNeutronSeparationUncertainty(rhs.fNeutronSeparationUncertainty),
669 fGammaWidth(rhs.fGammaWidth), fGammaDistance(rhs.fGammaDistance), fBandGap(rhs.fBandGap),
670 fLeftMargin(rhs.fLeftMargin), fRightMargin(rhs.fRightMargin), fBottomMargin(rhs.fBottomMargin), fTopMargin(rhs.fTopMargin),
671 fMinWidth(rhs.fMinWidth), fMaxWidth(rhs.fMaxWidth)
673 fLevelSchemes.push_back(
this);
676void TLevelScheme::ListLevelSchemes()
678 for(
auto& scheme : fLevelSchemes) {
679 std::cout <<
" \"" << scheme->GetLabel() <<
"\"";
681 std::cout << std::endl;
684TLevelScheme* TLevelScheme::GetLevelScheme(
const char* name)
686 for(
auto& scheme : fLevelSchemes) {
687 if(strcmp(name, scheme->GetLabel()) == 0) {
692 std::cout <<
"Failed to find level scheme \"" << name <<
"\", " << fLevelSchemes.size() <<
" level schemes exist";
698TLevel* TLevelScheme::AddLevel(
const double energy,
const std::string& bandName,
const std::string& label)
702 if(fDebug) { Print(); }
704 for(
auto& band : fBands) {
705 if(bandName == band.GetLabel()) {
707 std::cout <<
"Found band \"" << band.GetLabel() <<
"\" (" << &band <<
") with " << band.NofLevels() <<
" levels" << std::endl;
709 return band.AddLevel(energy, label);
712 std::cout <<
"Band \"" << band.GetLabel() <<
"\" does not match " << bandName << std::endl;
715 fBands.emplace_back(
this, bandName);
716 auto& newBand = fBands.back();
717 newBand.Debug(fDebug);
719 std::cout <<
"Created band \"" << newBand.GetLabel() <<
"\" (" << &newBand <<
") with " << newBand.NofLevels() <<
" level" << std::endl;
721 std::cout << std::endl;
723 return newBand.AddLevel(energy, label);
726TLevel* TLevelScheme::GetLevel(
double energy)
728 for(
auto& band : fBands) {
729 auto* level = band.GetLevel(energy);
730 if(level !=
nullptr) {
736 std::cout <<
"Failed to find level with energy " << energy <<
" in " << fBands.size() <<
" bands:" << std::endl;
737 for(
const auto& band : fBands) {
744TLevel* TLevelScheme::FindLevel(
double energy,
double energyUncertainty)
746 for(
auto& band : fBands) {
747 auto* level = band.FindLevel(energy, energyUncertainty);
748 if(level !=
nullptr) {
754 std::cout <<
"Failed to find level with energy " << energy <<
" +- " << energyUncertainty <<
" in " << fBands.size() <<
" bands:" << std::endl;
755 for(
const auto& band : fBands) {
762TGamma* TLevelScheme::FindGamma(
double energy,
double energyUncertainty)
766 auto list = FindGammas(energy - energyUncertainty, energy + energyUncertainty);
769 std::cerr <<
"Failed to find any gamma ray in range [" << energy - energyUncertainty <<
", " << energy + energyUncertainty <<
"]" << std::endl;
773 auto* result = list[0];
774 for(
size_t i = 1; i < list.size(); ++i) {
775 if(std::fabs(list[i]->Energy() - energy) < std::fabs(result->Energy() - energy)) { result = list[i]; }
781std::vector<TGamma*> TLevelScheme::FindGammas(
double lowEnergy,
double highEnergy)
784 std::vector<TGamma*> result;
786 for(
auto& band : fBands) {
788 for(
auto& [levelEnergy, level] : band) {
790 for(
auto& [finalEnergy, gamma] : level) {
791 if(lowEnergy <= gamma.Energy() && gamma.Energy() <= highEnergy) {
792 result.push_back(&gamma);
801void TLevelScheme::BuildGammaMap(
double levelEnergy)
806 if(!fGammaMap.empty()) {
return; }
808 for(
auto& band : fBands) {
809 for(
auto& [energy, level] : band) {
810 if(energy <= levelEnergy) {
814 for(
auto& [finalEnergy, gamma] : level) {
815 if(finalEnergy >= levelEnergy) {
816 fGammaMap.insert({finalEnergy, &gamma});
822 std::cout <<
"Built map of " << fGammaMap.size() <<
" gamma rays populating levels above or equal " << levelEnergy <<
" keV" << std::endl;
826std::map<double, double> TLevelScheme::FeedingGammas(
double levelEnergy,
double factor)
833 std::map<double, double> result;
834 BuildGammaMap(levelEnergy);
836 auto range = fGammaMap.equal_range(levelEnergy);
838 std::cout <<
"Got " << std::distance(range.first, range.second) <<
" gamma rays feeding level at " << levelEnergy <<
" kev (factor " << factor <<
")" << std::endl;
840 for(
auto& it = range.first; it != range.second; ++it) {
842 std::cout <<
"Adding gamma " << it->second <<
": ";
845 result[it->second->Energy()] += factor * it->second->BranchingRatioPercent();
846 auto tmp = FeedingGammas(it->second->InitialEnergy(), factor * it->second->BranchingRatioPercent());
847 for(
auto& [energy, tmpFactor] : tmp) {
848 result[energy] += tmpFactor;
853 std::cout <<
"returning list of " << result.size() <<
" gammas feeding level at " << levelEnergy <<
" keV" << std::endl;
858std::map<double, double> TLevelScheme::DrainingGammas(
double levelEnergy,
double factor)
866 auto* level = GetLevel(levelEnergy);
867 std::map<double, double> result;
868 if(level ==
nullptr) {
869 std::cerr <<
"Failed to find level at " << levelEnergy <<
" keV, returning empty list of gammas draining that level" << std::endl;
875 std::cout << level <<
": looping over " << level->NofDrainingGammas() <<
" gammas for level at " << levelEnergy <<
" keV (factor " << factor <<
")" << std::endl;
879 for(
auto& [finalEnergy, gamma] : *level) {
881 std::cout <<
"Adding gamma: ";
885 auto branchingRatio = gamma.BranchingRatioPercent();
886 result[gamma.Energy()] += factor * branchingRatio;
888 if(gamma.FinalEnergy() > 0.) {
889 auto tmp = DrainingGammas(finalEnergy, factor * branchingRatio);
890 for(
auto& [energy, tmpFactor] : tmp) {
891 result[energy] += tmpFactor;
897 std::cout <<
"returning list of " << result.size() <<
" gammas draining level at " << levelEnergy <<
" keV" << std::endl;
902std::vector<std::tuple<double, std::vector<double>>> TLevelScheme::ParallelGammas(
double initialEnergy,
double finalEnergy,
double factor)
906 auto* level = GetLevel(initialEnergy);
907 std::vector<std::tuple<double, std::vector<double>>> result;
908 if(level ==
nullptr) {
909 std::cerr <<
"Failed to find level at " << initialEnergy <<
" keV, returning empty list of gammas" << std::endl;
915 std::cout << level <<
": looping over " << level->NofDrainingGammas() <<
" gammas for level at " << initialEnergy <<
" keV (factor " << factor <<
")" << std::endl;
918 result.emplace_back(1., std::vector<double>());
920 for(
auto& [levelEnergy, gamma] : *level) {
922 if(levelEnergy < finalEnergy) {
924 std::cout <<
"skipping gamma ";
930 std::get<0>(result.back()) *= gamma.BranchingRatioPercent();
931 std::get<1>(result.back()).insert(std::get<1>(result.back()).end(), gamma.Energy());
933 std::cout <<
"Added gamma ";
935 std::cout <<
"New result:";
936 for(
auto& entry : result) {
937 std::cout <<
" " << std::get<0>(entry) <<
"-";
938 for(
auto& e : std::get<1>(entry)) {
939 std::cout << e <<
",";
942 std::cout << std::endl;
945 if(levelEnergy > finalEnergy) {
946 auto tmp = ParallelGammas(levelEnergy, finalEnergy, factor * gamma.BranchingRatioPercent());
950 auto it = result.insert(result.end(), tmp.size() - 1, result.back());
954 std::cout <<
"Got " << tmp.size() <<
" paths, so added " << tmp.size() - 1 <<
" copies of last element:";
955 for(
auto& entry : result) {
956 std::cout <<
" " << std::get<0>(entry) <<
"-";
957 for(
auto& e : std::get<1>(entry)) {
958 std::cout << e <<
",";
961 std::cout << std::endl;
963 for(
auto& combo : tmp) {
965 std::get<0>(*it) *= std::get<0>(combo);
966 std::get<1>(*it).insert(std::get<1>(*it).end(), std::get<1>(combo).begin(), std::get<1>(combo).end());
970 std::cout <<
"Got " << tmp.size() <<
" more gammas, new result:";
971 for(
auto& entry : result) {
972 std::cout <<
" " << std::get<0>(entry) <<
"-";
974 for(
auto& e : std::get<1>(entry)) {
975 std::cout << e <<
",";
978 std::cout <<
"total " << sum;
980 std::cout << std::endl;
989 std::cout <<
"Failed to find path from " << levelEnergy <<
" to " << finalEnergy <<
", removed last gamma ray";
990 for(
auto& entry : result) {
991 std::cout <<
" " << std::get<0>(entry) <<
"-";
992 for(
auto& e : std::get<1>(entry)) {
993 std::cout << e <<
",";
996 std::cout << std::endl;
1002 result.emplace_back(1., std::vector<double>());
1004 std::cout <<
"Reached final level, added new (empty) entry to result" << std::endl;
1009 if(std::get<1>(result.back()).empty()) {
1016void TLevelScheme::MoveToBand(
const char* bandName, TLevel* level)
1021 std::cout <<
"TLevelScheme: Trying to move level " << level <<
" at " << level->Energy() <<
" keV to band \"" << bandName <<
"\"" << std::endl;
1024 for(i = 0; i < fBands.size(); ++i) {
1025 if(strcmp(bandName, fBands[i].GetLabel()) == 0) {
1027 std::cout <<
"Found band \"" << fBands[i].GetLabel() <<
"\" (" << &fBands[i] <<
") with " << fBands[i].NofLevels() <<
" levels" << std::endl;
1029 fBands[i].AddLevel(level);
1033 std::cout <<
"Band \"" << fBands[i].GetLabel() <<
"\" does not match " << bandName << std::endl;
1037 if(i == fBands.size()) {
1039 std::cout <<
"Haven't found band \"" << bandName <<
"\" among existing bands, creating new band" << std::endl;
1041 fBands.emplace_back(
this, bandName);
1042 auto& newBand = fBands.back();
1043 newBand.Debug(fDebug);
1045 std::cout <<
"Created band \"" << newBand.GetLabel() <<
"\" (" << &newBand <<
") with " << newBand.NofLevels() <<
" level" << std::endl;
1047 std::cout << std::endl;
1049 newBand.AddLevel(level);
1052 for(
auto& band : fBands) {
1054 std::cout <<
"Checking band \"" << band.GetLabel() <<
"\": ";
1056 if(strcmp(bandName, band.GetLabel()) == 0) {
1058 std::cout <<
"this is the new band, not deleting it here!" << std::endl;
1063 std::cout <<
"this is not the new band, removing it here!" << std::endl;
1065 band.RemoveLevel(level);
1071void TLevelScheme::Refresh()
1074 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1075 if(canvas !=
nullptr) {
1080void TLevelScheme::UnZoom()
const
1082 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1083 if(canvas !=
nullptr) {
1084 canvas->Range(fX1, fY1, fX2, fY2);
1090void TLevelScheme::Draw(Option_t*)
1092 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
1093 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1094 if(canvas ==
nullptr) {
1095 canvas =
new GCanvas(
"LevelScheme",
"Level Scheme");
1102 auto minMaxLevel = fBands[0].GetMinMaxLevelEnergy();
1104 std::vector<std::pair<double, double>> minMaxGamma;
1105 for(
auto& band : fBands) {
1106 auto minMax = band.GetMinMaxLevelEnergy();
1107 if(minMax.first < minMaxLevel.first) { minMaxLevel.first = minMax.first; }
1108 if(minMax.second > minMaxLevel.second) { minMaxLevel.second = minMax.second; }
1109 if(fDebug) { std::cout <<
"Incrementing width from " << width; }
1110 width += band.Width(fGammaDistance);
1111 if(fDebug) { std::cout <<
" to " << width <<
" using " << band.Width(fGammaDistance) << std::endl; }
1112 minMaxGamma.push_back(band.GetMinMaxGamma());
1114 width +=
static_cast<double>(fBands.size() - 1) * fBandGap;
1117 fY1 = minMaxLevel.first;
1118 fY2 = minMaxLevel.second;
1119 double height = fY2 - fY1;
1121 if(fBottomMargin < 0) {
1122 fY1 -= height / 10.;
1124 fY1 -= fBottomMargin;
1126 if(fTopMargin < 0) {
1127 fY2 += height / 10.;
1136 if(fLeftMargin < 0) {
1141 if(fRightMargin < 0) {
1144 fX2 += fRightMargin;
1147 if(fDebug) { std::cout <<
"got x1 - x2 " << fX1 <<
" - " << fX2 <<
", and y1 - y2 " << fY1 <<
" - " << fY2 << std::endl; }
1148 canvas->Range(fX1, fY1, fX2, fY2);
1151 SetX1(fX2 - fBandGap);
1153 if(fTopMargin < 0) {
1154 SetY1(fX2 - height / 12.);
1156 SetY1(fX2 - fTopMargin * 0.75);
1163 if(fGammaWidth == EGammaWidth::kGlobal) {
1166 for(
auto& [min, max] : minMaxGamma) {
1167 if(min < minMaxGamma[0].first) { minMaxGamma[0].first = min; }
1168 if(max > minMaxGamma[0].second) { minMaxGamma[0].second = max; }
1169 std::cout << min <<
" - " << max <<
": " << minMaxGamma[0].first <<
" - " << minMaxGamma[0].second << std::endl;
1176 for(
size_t b = 0; b < fBands.size(); ++b) {
1177 double right = left + fBands[b].Width(fGammaDistance);
1178 if(fDebug) { std::cout << b <<
": Using width " << fBands[b].Width(fGammaDistance) <<
" and left " << left <<
" we get right " << right << std::endl; }
1179 fBands[b].SetX1(left);
1180 fBands[b].SetY1(-1.5 * height / 20.);
1181 fBands[b].SetX2(right);
1182 fBands[b].SetY2(-height / 40.);
1183 fBands[b].SetFillColor(10);
1187 auto& [min, max] = minMaxGamma[0];
1188 if(fGammaWidth == EGammaWidth::kBand) {
1190 min = minMaxGamma[b].first;
1191 max = minMaxGamma[b].second;
1193 double scalingGain = (fMaxWidth - fMinWidth) / (max - min);
1194 double scalingOffset = fMinWidth - scalingGain * min;
1195 if(fGammaWidth == EGammaWidth::kNoWidth) {
1198 scalingOffset = fMinWidth;
1201 double labelSize = TLevel::TextSize() * std::min(fX2 - fX1, fY2 - fY1);
1209 std::vector<std::vector<std::pair<double, int>>> groups;
1211 for(
auto& [energy, level] : fBands[b]) {
1212 std::vector<size_t> potentialGroups;
1213 for(
size_t i = 0; i < groups.size(); ++i) {
1214 for(
size_t j = 0; j < groups[i].size(); ++j) {
1218 double average = std::accumulate(groups[i].begin(), groups[i].end(), 0., [](
double r, std::pair<double, int> p) { r += p.first;
return r; }) /
static_cast<double>(groups[i].size());
1220 if(energy - (average + labelSize * (
static_cast<double>(j) -
static_cast<double>(groups[i].size() - 1) / 2.)) < labelSize * (index - groups[i][j].second)) {
1222 std::cout << energy - groups[i][j].first <<
" (" << energy <<
" - " << groups[i][j].first <<
") < " << labelSize * (index - groups[i][j].second) <<
" (" << labelSize <<
"*(" << index <<
"-" << groups[i][j].second <<
")), adding to group " << i << std::endl;
1224 potentialGroups.push_back(i);
1229 std::cout << energy - groups[i][j].first <<
" (" << energy <<
" - " << groups[i][j].first <<
") >= " << labelSize * (index - groups[i][j].second) <<
" (" << labelSize <<
"*(" << index <<
"-" << groups[i][j].second <<
")), NOT adding to group " << i << std::endl;
1234 if(potentialGroups.empty()) {
1235 groups.emplace_back(1, std::make_pair(energy, index));
1236 }
else if(potentialGroups.size() == 1) {
1237 groups[potentialGroups[0]].push_back(std::make_pair(energy, index));
1240 std::cout <<
"combining groups";
1241 for(
const auto& potentialGroup : potentialGroups) {
1242 std::cout <<
" " << potentialGroup;
1244 std::cout << std::endl;
1247 for(
auto potentialGroup : potentialGroups) {
1248 groups[potentialGroups[0]].insert(groups[potentialGroups[0]].end(), groups[potentialGroup].begin(), groups[potentialGroup].end());
1249 groups.erase(groups.begin() + potentialGroup);
1251 groups[potentialGroups[0]].emplace_back(energy, index);
1252 std::sort(groups[potentialGroups[0]].begin(), groups[potentialGroups[0]].end());
1257 std::cout <<
"got " << groups.size() <<
" groups:" << std::endl;
1258 for(
auto& group : groups) {
1259 for(
auto& level : group) {
1260 std::cout << level.second <<
" " << level.first <<
", ";
1262 std::cout << std::endl;
1266 std::vector<std::pair<double, double>> centers;
1267 for(
auto& group : groups) {
1268 double average = std::accumulate(group.begin(), group.end(), 0., [](
double r, std::pair<double, double> p) { r += p.first; return r; }) /
static_cast<double>(group.size());
1269 for(
size_t i = 0; i < group.size(); ++i) {
1270 centers.emplace_back(average,
static_cast<double>(i) -
static_cast<double>(group.size() - 1) / 2.);
1274 std::cout <<
"centers: ";
1275 for(
auto& [center, diff] : centers) {
1276 std::cout << center <<
" " << diff <<
", ";
1278 std::cout << std::endl;
1284 for(
auto& [energy, level] : fBands[b]) {
1286 std::cout << std::endl;
1287 std::cout <<
"starting calculations for drawing level at " << energy << std::endl;
1290 double move = centers[index].first - energy + labelSize * centers[index].second;
1292 std::cout <<
"calculations for drawing level at " << energy <<
": move " << move <<
" (" << centers[index].first <<
" - " << energy <<
" + " << labelSize <<
"*" << centers[index].second <<
") => " << energy + move <<
", " << left <<
"-" << right << std::endl;
1295 level.Draw(left, right);
1298 level.DrawLabel(right);
1299 level.DrawEnergy(left);
1304 if(fDebug) { level.Print(); }
1307 for(
auto& [finalEnergy, gamma] : level) {
1311 for(b2 = 0; b2 < fBands.size(); ++b2) {
1312 for(
auto& [energy2, level2] : fBands[b2]) {
1313 if(finalEnergy == level2.Energy()) {
1315 std::cout <<
"band " << b2 <<
": " << finalEnergy <<
" == " << level2.Energy() << std::endl;
1321 std::cout <<
"band " << b2 <<
": " << finalEnergy <<
" != " << level2.Energy() << std::endl;
1324 if(found) {
break; }
1328 std::cout <<
"Warning, failed to find final level at " << finalEnergy <<
" keV for gamma-ray!" << std::endl;
1332 gamma.Scaling(scalingOffset, scalingGain);
1335 double gY1 = level.Energy();
1336 double gY2 = finalEnergy;
1344 if(fDebug) { std::cout << b <<
" == " << b2 <<
": intra band " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1345 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1346 gX2 = left +
static_cast<double>(g) * fGammaDistance;
1349 if(fDebug) { std::cout << b <<
" < " << b2 <<
": inter band to right " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1350 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1351 gX2 = left +
static_cast<double>(g) * fGammaDistance + (gY1 - gY2) / 10.;
1352 double shift = right + fBandGap;
1355 shift = std::accumulate(fBands.begin() + b + 1, fBands.begin() + b2, right + fBandGap, [&](
double r, TBand& el) { r += el.Width(fGammaDistance) + fBandGap; return r; });
1357 DrawAuxillaryLevel(gY2, right +
static_cast<double>(g) * fGammaDistance, shift - fBandGap / 2.);
1360 if(fDebug) { std::cout << b <<
" > " << b2 <<
": inter band to left " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1361 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1362 gX2 = left +
static_cast<double>(g) * fGammaDistance - (gY1 - gY2) / 10.;
1363 double shift = left - fBandGap;
1366 shift = std::accumulate(fBands.begin() + b2 + 1, fBands.begin() + b, left - fBandGap, [&](
double r, TBand& el) { r -= el.Width(fGammaDistance) + fBandGap; return r; });
1368 DrawAuxillaryLevel(gY2, left +
static_cast<double>(g) * fGammaDistance, shift + fBandGap / 2.);
1373 if(fDebug) { std::cout << b <<
" == " << b2 <<
": intra band " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1374 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1375 gX2 = left +
static_cast<double>(g) * fGammaDistance;
1377 }
else if(b + 1 == b2) {
1378 if(fDebug) { std::cout << b <<
"+1 == " << b2 <<
": inter band " << g <<
" to right " << right <<
"-" << right + fBandGap << std::endl; }
1379 gX1 = right - fGammaDistance / 2.;
1380 gX2 = right + fBandGap + fGammaDistance / 2.;
1381 }
else if(b == b2 + 1) {
1382 if(fDebug) { std::cout << b <<
" == " << b2 <<
"+1: inter band " << g <<
" to left " << left <<
"-" << left - fBandGap << std::endl; }
1383 gX1 = left + fGammaDistance / 2.;
1384 gX2 = left - fBandGap - fGammaDistance / 2.;
1386 if(fDebug) { std::cout << b <<
" < " << b2 <<
": inter band far " << g <<
" right " << right <<
", band gap " << fBandGap << std::endl; }
1388 gX2 = right + fBandGap / 8.;
1389 double shift = right + fBandGap;
1392 shift = std::accumulate(fBands.begin() + b + 1, fBands.begin() + b2, right + fBandGap, [&](
double r, TBand& el) { r += el.Width(fGammaDistance) + fBandGap; return r; });
1394 DrawAuxillaryLevel(gY2, right, shift - fBandGap / 2.);
1396 if(fDebug) { std::cout << b <<
" > " << b2 <<
": inter band far " << g <<
" left " << left <<
", band gap " << fBandGap << std::endl; }
1398 gX2 = left - fBandGap / 8.;
1399 double shift = left - fBandGap;
1402 shift = std::accumulate(fBands.begin() + b2 + 1, fBands.begin() + b, left - fBandGap, [&](
double r, TBand& el) { r -= el.Width(fGammaDistance) + fBandGap; return r; });
1404 DrawAuxillaryLevel(gY2, left, shift + fBandGap / 2.);
1408 gamma.Draw(gX1, gY1, gX2, gY2);
1410 if(level.begin() != level.end()) {
1412 std::cout <<
"Level has gamma-rays, incrementing g from " << g << std::endl;
1420 left = right + fBandGap;
1424 std::cout <<
"Canvas " << canvas <<
" " << canvas->GetName() <<
" has " << canvas->GetListOfPrimitives()->GetSize() <<
" primitives:" << std::endl;
1425 canvas->GetListOfPrimitives()->Print();
1430void TLevelScheme::DrawAuxillaryLevel(
const double& energy,
const double& left,
const double& right)
1433 std::cout <<
"Drawing auxillary level at " << energy <<
" keV from " << left <<
" to " << right << std::endl;
1436 if(fAuxillaryLevels.count(energy) > 0) {
1438 auto range = fAuxillaryLevels.equal_range(energy);
1439 for(
auto it = range.first; it != range.second; ++it) {
1440 if(it->second.GetX1() == left && it->second.GetX2() == right) {
return; }
1444 auto it = fAuxillaryLevels.emplace(std::piecewise_construct, std::forward_as_tuple(energy), std::forward_as_tuple(left, energy, right, energy));
1445 it->second.SetLineStyle(2);
1449void TLevelScheme::Print(Option_t*)
const
1451 std::cout <<
this <<
": got " << fBands.size() <<
" bands: ";
1452 for(
size_t b = 0; b < fBands.size(); ++b) {
1453 std::cout <<
" " << b <<
"-" << &fBands[b] <<
"-" << fBands[b].GetLabel();
1455 std::cout <<
", debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
1457 for(
const auto& band : fBands) {
1463void TLevelScheme::ParseENSDF(
const std::string& filename)
1467 std::ifstream input(filename);
1468 if(!input.is_open()) {
1469 std::cerr <<
DRED <<
"Failed to open \"" << filename <<
"\"" <<
RESET_COLOR << std::endl;
1474 std::istringstream str;
1475 TLevel* currentLevel =
nullptr;
1485 std::getline(input, line);
1486 SetLabel(line.substr(0, 5).c_str());
1488 std::cout <<
"Reading level scheme for " << GetLabel() << std::endl;
1490 if(line.substr(9, 14) ==
"ADOPTED LEVELS") {
1491 std::cout << R
"(Data set is not "ADOPTED LEVELS" or "ADOPTED LEVELS, GAMMAS", but ")" << line.substr(9, 14) << "\", don't know how to read that (" << line <<
")" << std::endl;
1496 std::getline(input, line);
1497 }
while(line[5] !=
' ');
1506 if(line.substr(5, 4) ==
" Q ") {
1509 str.str(line.substr(9, 10));
1512 str.str(line.substr(19, 2));
1513 str >> fQValueUncertainty;
1514 if(fDebug) { std::cout <<
"reading S_n old \"" << str.str() <<
"\" @ " << str.tellg() << (str.fail() ?
" failed" :
" good"); }
1516 str.str(line.substr(21, 8));
1517 if(fDebug) { std::cout <<
", new \"" << str.str() <<
"\" @ " << str.tellg() << (str.fail() ?
" failed" :
" good"); }
1518 str >> fNeutronSeparation;
1519 if(fDebug) { std::cout <<
" => S_n " << fNeutronSeparation << std::endl; }
1521 str.str(line.substr(29, 2));
1522 str >> fNeutronSeparationUncertainty;
1524 std::cout <<
"Found q-value line: " << fQValue <<
" +- " << fQValueUncertainty <<
", S_n " << fNeutronSeparation <<
" +- " << fNeutronSeparationUncertainty << std::endl;
1525 std::cout <<
"\"" << line.substr(9, 10) <<
"\", \"" << line.substr(19, 2) <<
"\", \"" << line.substr(21, 8) <<
"\", \"" << line.substr(29, 2) <<
"\"" << std::endl;
1528 std::cout <<
"Ignoring q-value comment \"" << line <<
"\"" << std::endl;
1533 if(fDebug) { std::cout <<
"Ignoring cross-reference \"" << line <<
"\"" << std::endl; }
1536 if(fDebug) { std::cout <<
"Ignoring parent \"" << line <<
"\"" << std::endl; }
1541 if(fDebug) { std::cout <<
"Ignoring normalization \"" << line <<
"\"" << std::endl; }
1545 if(line[5] ==
' ' && line[6] ==
' ') {
1548 double energyUncertainty = 0.;
1549 if(fDebug) { std::cout <<
"reading level energy old \"" << str.str() <<
"\""; }
1551 str.str(line.substr(9, 10));
1552 if(fDebug) { std::cout <<
", new \"" << str.str() <<
"\""; }
1554 if(fDebug) { std::cout <<
" => energy " << energy << std::endl; }
1556 str.str(line.substr(19, 2));
1557 str >> energyUncertainty;
1561 std::string spinParity = line.substr(21, 18);
1563 std::string halfLife = line.substr(39, 10);
1565 std::string halfLifeUncertainty = line.substr(49, 6);
1566 trimWS(halfLifeUncertainty);
1569 if(!spinParity.empty()) {
1570 label += spinParity;
1572 if(!halfLife.empty()) {
1574 label += halfLifeUncertainty;
1577 std::cout <<
"Adding new level " << energy <<
" +- " << energyUncertainty <<
", " << spinParity <<
", half-life " << halfLife <<
" +- " << halfLifeUncertainty << std::endl;
1578 std::cout <<
"\"" << line.substr(9, 10) <<
"\", \"" << line.substr(19, 2) <<
"\", \"" << line.substr(21, 18) <<
"\", \"" << line.substr(39, 10) <<
"\", \"" << line.substr(49, 6) <<
"\"" << std::endl;
1581 currentLevel = AddLevel(energy, GetLabel(), label);
1582 currentLevel->EnergyUncertainty(energyUncertainty);
1584 std::cout <<
"Ignoring level \"" << line <<
"\"" << std::endl;
1590 if(line[5] ==
' ' && line[6] ==
' ') {
1591 if(currentLevel ==
nullptr) {
1592 std::cout <<
"Found unassigned gamma, ignoring it (" << line <<
")!" << std::endl;
1597 double energyUncertainty = 0.;
1599 str.str(line.substr(9, 10));
1602 str.str(line.substr(19, 2));
1603 str >> energyUncertainty;
1605 double photonIntensity = 0.;
1606 double photonIntensityUncertainty = 0.;
1608 str.str(line.substr(21, 8));
1609 str >> photonIntensity;
1611 str.str(line.substr(29, 2));
1612 str >> photonIntensityUncertainty;
1614 std::string multipolarity = line.substr(31, 10);
1617 double mixingRatio = 0.;
1618 double mixingRatioUncertainty = 0.;
1620 str.str(line.substr(41, 8));
1623 str.str(line.substr(49, 6));
1624 str >> mixingRatioUncertainty;
1626 double conversionCoeff = 0.;
1627 double conversionCoeffUncertainty = 0.;
1629 str.str(line.substr(55, 7));
1630 str >> conversionCoeff;
1632 str.str(line.substr(62, 2));
1633 str >> conversionCoeffUncertainty;
1635 double totalIntensity = 0.;
1636 double totalIntensityUncertainty = 0.;
1638 str.str(line.substr(64, 10));
1639 str >> totalIntensity;
1641 str.str(line.substr(74, 2));
1642 str >> totalIntensityUncertainty;
1645 std::cout <<
"Adding gamma with energy " << energy <<
" +- " << energyUncertainty <<
", " << photonIntensity <<
" +- " << photonIntensityUncertainty <<
", " << multipolarity <<
", " << mixingRatio <<
" +- " << mixingRatioUncertainty <<
", " << conversionCoeff <<
" +- " << conversionCoeffUncertainty <<
", " << totalIntensity <<
" +- " << totalIntensityUncertainty <<
", final level energy " << currentLevel->Energy() - energy << std::endl;
1646 std::cout <<
"\"" << line.substr(9, 10) <<
"\", \"" << line.substr(19, 2) <<
"\", \"" << line.substr(21, 8) <<
"\", \"" << line.substr(29, 2) <<
"\", \"" << line.substr(31, 10) <<
"\", \"" << line.substr(41, 8) <<
"\", \"" << line.substr(49, 6) <<
"\", \"" << line.substr(55, 7) <<
"\", \"" << line.substr(62, 2) <<
"\", \"" << line.substr(64, 10) <<
"\", \"" << line.substr(74, 2) <<
"\"" << std::endl;
1648 auto* gamma = currentLevel->AddGamma(currentLevel->Energy() - energy, energyUncertainty, multipolarity.c_str(), photonIntensity, totalIntensity);
1649 if(gamma !=
nullptr) {
1650 gamma->BranchingRatioUncertainty(photonIntensityUncertainty);
1651 gamma->TransitionStrengthUncertainty(totalIntensityUncertainty);
1655 std::cout <<
"Ignoring gamma \"" << line <<
"\"" << std::endl;
1659 if(fDebug) { std::cout <<
"Ignoring beta \"" << line <<
"\"" << std::endl; }
1662 if(fDebug) { std::cout <<
"Ignoring EC \"" << line <<
"\"" << std::endl; }
1665 if(fDebug) { std::cout <<
"Ignoring alpha \"" << line <<
"\"" << std::endl; }
1668 if(fDebug) { std::cout <<
"Ignoring delayed \"" << line <<
"\"" << std::endl; }
1671 if(fDebug) { std::cout <<
"Ignoring reference \"" << line <<
"\"" << std::endl; }
1674 if(fDebug) { std::cout <<
"Ignoring comment \"" << line <<
"\"" << std::endl; }
1678 if(fDebug) { std::cout <<
"Skipping unknown character " << line[7] <<
" from line \"" << line <<
"\"" << std::endl; }
1681 }
while(std::getline(input, line) && !line.empty());
1683 if(fDebug) { std::cout <<
"Done reading \"" << filename <<
"\"" << std::endl; }
void trimWS(std::string &line)
bool FileExists(const char *filename)