3#if __cplusplus >= 201703L
18float TGamma::fTextSize = 0.020;
19float TLevel::fTextSize = 0.025;
21std::vector<TLevelScheme*> TLevelScheme::fLevelSchemes;
22bool TLevelScheme::fDrawLevelEnergy =
true;
23bool TLevelScheme::fDrawLevelLabel =
true;
24bool TLevelScheme::fDrawName =
true;
25bool TLevelScheme::fDrawBandLabel =
true;
27TGamma::TGamma(TLevelScheme* levelScheme, std::string label,
const double& br,
const double& ts)
28 : fBranchingRatio(br), fTransitionStrength(ts), fLabelText(std::move(label)), fLevelScheme(levelScheme)
30 fLabelText.insert(0, 1,
' ');
34TGamma::TGamma(
const TGamma& rhs)
37 if(fDebug || rhs.fDebug) {
38 std::cout << __PRETTY_FUNCTION__ <<
": copying gamma \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
42 fEnergy = rhs.fEnergy;
43 fEnergyUncertainty = rhs.fEnergyUncertainty;
44 fUseTransitionStrength = rhs.fUseTransitionStrength;
45 fScalingGain = rhs.fScalingGain;
46 fScalingOffset = rhs.fScalingOffset;
47 fBranchingRatio = rhs.fBranchingRatio;
48 fBranchingRatioUncertainty = rhs.fBranchingRatioUncertainty;
49 fBranchingRatioPercent = rhs.fBranchingRatioPercent;
50 fBranchingRatioPercentUncertainty = rhs.fBranchingRatioPercentUncertainty;
51 fTransitionStrength = rhs.fTransitionStrength;
52 fTransitionStrengthUncertainty = rhs.fTransitionStrengthUncertainty;
53 fLabelText = rhs.fLabelText;
55 fLevelScheme = rhs.fLevelScheme;
56 fInitialEnergy = rhs.fInitialEnergy;
57 fFinalEnergy = rhs.fFinalEnergy;
60TGamma& TGamma::operator=(
const TGamma& rhs)
62 if(fDebug || rhs.fDebug) {
63 std::cout << __PRETTY_FUNCTION__ <<
": copying gamma \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
68 fEnergy = rhs.fEnergy;
69 fEnergyUncertainty = rhs.fEnergyUncertainty;
70 fUseTransitionStrength = rhs.fUseTransitionStrength;
71 fScalingGain = rhs.fScalingGain;
72 fScalingOffset = rhs.fScalingOffset;
73 fBranchingRatio = rhs.fBranchingRatio;
74 fBranchingRatioUncertainty = rhs.fBranchingRatioUncertainty;
75 fBranchingRatioPercent = rhs.fBranchingRatioPercent;
76 fBranchingRatioPercentUncertainty = rhs.fBranchingRatioPercentUncertainty;
77 fTransitionStrength = rhs.fTransitionStrength;
78 fTransitionStrengthUncertainty = rhs.fTransitionStrengthUncertainty;
79 fLabelText = rhs.fLabelText;
81 fLevelScheme = rhs.fLevelScheme;
82 fInitialEnergy = rhs.fInitialEnergy;
83 fFinalEnergy = rhs.fFinalEnergy;
89void TGamma::UpdateWidth()
91 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
92 auto arrowsize =
static_cast<Width_t
>((fUseTransitionStrength ? fTransitionStrength : fBranchingRatio) * fScalingGain + fScalingOffset);
93 SetLineWidth(arrowsize);
96void TGamma::UpdateLabel()
98 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
99 if(fLabel !=
nullptr) {
100 fLabel->SetText(fLabel->GetX(), fLabel->GetY(), fLabelText.c_str());
104void TGamma::Draw(
const double& x1,
const double& y1,
const double& x2,
const double& y2)
112 SetFillColor(GetLineColor());
114 if(fLabel ==
nullptr) {
115 fLabel =
new TLatex((x1 + x2) / 2., (y1 + y2) / 2., fLabelText.c_str());
117 fLabel->SetText((x1 + x2) / 2., (y1 + y2) / 2., fLabelText.c_str());
119 fLabel->SetTextColor(GetLineColor());
120 fLabel->SetTextAlign(12);
121 fLabel->SetTextFont(42);
122 fLabel->SetTextSize(fTextSize);
124 if(fDebug) { Print(); }
127void TGamma::Print(Option_t*)
const
130 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;
133std::map<double, double> TGamma::CoincidentGammas()
136 if(fLevelScheme ==
nullptr) {
137 std::cerr <<
"Parent level scheme not set, can't find coincident gamma rays" << std::endl;
141 std::cout <<
"Looking for coincident gammas for gamma of " << fEnergy <<
" kev from level at " << fInitialEnergy <<
" keV to level at " << fFinalEnergy <<
" keV" << std::endl;
143 fLevelScheme->ResetGammaMap();
144 auto result = fLevelScheme->FeedingGammas(fInitialEnergy, fBranchingRatioPercent);
146 std::cout <<
"Got " << result.size() <<
" gammas feeding level at " << fInitialEnergy << std::endl;
148 if(fFinalEnergy > 0) {
149 auto draining = fLevelScheme->DrainingGammas(fFinalEnergy);
151 std::cout <<
"Plus " << draining.size() <<
" gammas draining level at " << fFinalEnergy << std::endl;
153 for(
auto& [energy, factor] : draining) {
154 result[energy] += factor;
158 std::cout <<
"Got " << result.size() <<
" coincident gammas:";
159 for(
auto& element : result) {
160 std::cout <<
" " << element.first <<
" (" << element.second <<
"%)";
162 std::cout << std::endl;
168void TGamma::PrintCoincidentGammas()
170 auto map = CoincidentGammas();
171 std::cout << map.size() <<
" coincident gammas for gamma " << fEnergy <<
" +- " << fEnergyUncertainty <<
" (" << fInitialEnergy <<
" to " << fFinalEnergy <<
"):";
172 for(
auto gamma : map) {
173 std::cout <<
" " << gamma.first <<
" (" << gamma.second <<
"%)";
175 std::cout << std::endl;
178std::vector<std::tuple<double, std::vector<double>>> TGamma::ParallelGammas()
182 if(fLevelScheme ==
nullptr) {
183 std::cerr <<
"Parent level scheme not set, can't find parallel gamma rays" << std::endl;
187 std::cout <<
"Looking for parallel gammas for gamma of " << fEnergy <<
" kev from level at " << fInitialEnergy <<
" keV to level at " << fFinalEnergy <<
" keV" << std::endl;
189 auto result = fLevelScheme->ParallelGammas(fInitialEnergy, fFinalEnergy);
191 auto last = std::remove_if(result.begin(), result.end(), [](std::tuple<
double, std::vector<double>> x) { return std::get<1>(x).size() < 2; });
193 std::cout <<
"Removing " << std::distance(last, result.end()) <<
" paths, keeping " << std::distance(result.begin(), last) << std::endl;
195 result.erase(last, result.end());
197 std::sort(result.begin(), result.end(), [](std::tuple<
double, std::vector<double>> one, std::tuple<
double, std::vector<double>> two) { return std::get<0>(one) > std::get<0>(two); });
214void TGamma::PrintParallelGammas()
216 auto vec = ParallelGammas();
217 std::cout << vec.size() <<
" parallel paths for gamma " << fEnergy <<
" +- " << fEnergyUncertainty <<
" (" << fInitialEnergy <<
" to " << fFinalEnergy <<
"):" << std::endl;
218 for(
auto& element : vec) {
219 std::cout << std::get<0>(element) <<
":";
220 double totalEnergy = 0.;
221 for(
auto& energy : std::get<1>(element)) {
222 std::cout <<
" " << energy;
223 totalEnergy += energy;
225 std::cout <<
" (" << totalEnergy <<
")" << std::endl;
229TLevel::TLevel(TLevelScheme* levelScheme,
const double& energy,
const std::string& label)
231 if(fDebug && levelScheme ==
nullptr) {
232 std::cout <<
"Warning, nullptr provided to new band \"" << label <<
"\" for parent level scheme, some functions might no be available" << std::endl;
234 fLevelScheme = levelScheme;
239TLevel::TLevel(
const TLevel& rhs)
242 if(fDebug || rhs.fDebug) {
243 std::cout << __PRETTY_FUNCTION__ <<
": copying level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
247 fEnergy = rhs.fEnergy;
248 fEnergyUncertainty = rhs.fEnergyUncertainty;
250 fGammas = rhs.fGammas;
251 fNofFeeding = rhs.fNofFeeding;
252 fLevelScheme = rhs.fLevelScheme;
253 fLevelLabel = rhs.fLevelLabel;
254 fEnergyLabel = rhs.fEnergyLabel;
255 fOffset = rhs.fOffset;
257 std::cout << __PRETTY_FUNCTION__ <<
": copied level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " << this <<
")" << std::endl;
264 std::cout <<
"Deleting level \"" << fLabel <<
"\" at " << fEnergy <<
" keV (" <<
this <<
")" << std::endl;
268TLevel& TLevel::operator=(
const TLevel& rhs)
270 if(fDebug || rhs.fDebug) {
271 std::cout << __PRETTY_FUNCTION__ <<
": copying level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
275 TPolyLine::operator=(rhs);
277 fEnergy = rhs.fEnergy;
279 fGammas = rhs.fGammas;
280 fNofFeeding = rhs.fNofFeeding;
281 fLevelScheme = rhs.fLevelScheme;
282 fLevelLabel = rhs.fLevelLabel;
283 fEnergyLabel = rhs.fEnergyLabel;
284 fOffset = rhs.fOffset;
286 std::cout << __PRETTY_FUNCTION__ <<
": copied level \"" << rhs.fLabel <<
"\" to \"" << fLabel <<
"\" (" << &rhs <<
" to " <<
this <<
")" << std::endl;
293TGamma* TLevel::AddGamma(
const double levelEnergy,
const char* label,
double br,
double ts)
298 return AddGamma(levelEnergy, 0., label, br, ts);
301TGamma* TLevel::AddGamma(
const double levelEnergy,
const double energyUncertainty,
const char* label,
double br,
double ts)
306 auto* level = fLevelScheme->FindLevel(levelEnergy, energyUncertainty);
307 if(level ==
nullptr) {
308 std::cerr <<
DRED <<
"Failed to find level at " << levelEnergy <<
" keV, can't add gamma!" <<
RESET_COLOR << std::endl;
313 if(fGammas.count(level->Energy()) == 1) {
315 std::cout <<
"Already found gamma ray from ";
317 std::cout <<
" to " << levelEnergy <<
"/" << level->Energy() <<
" keV";
324 fGammas.emplace(std::piecewise_construct, std::forward_as_tuple(level->Energy()), std::forward_as_tuple(fLevelScheme, label, br, ts));
325 fGammas[level->Energy()].Debug(fDebug);
326 fGammas[level->Energy()].Energy(Energy() - levelEnergy);
327 fGammas[level->Energy()].EnergyUncertainty(energyUncertainty);
328 fGammas[level->Energy()].InitialEnergy(fEnergy);
329 fGammas[level->Energy()].FinalEnergy(level->Energy());
332 double sum = std::accumulate(fGammas.begin(), fGammas.end(), 0., [](
double r, std::pair<const double, TGamma>& g) { r += g.second.BranchingRatio(); return r; });
333 for(
auto& [en, gamma] : fGammas) {
334 gamma.BranchingRatioPercent(gamma.BranchingRatio() / sum);
335 gamma.BranchingRatioPercentUncertainty(gamma.BranchingRatioUncertainty() / sum);
338 if(fDebug) { Print(); }
340 fLevelScheme->Refresh();
342 return &(fGammas[level->Energy()]);
345void TLevel::MoveToBand(
const char* val)
347 if(fLevelScheme ==
nullptr) {
348 std::cerr << __PRETTY_FUNCTION__ <<
": Parent level scheme pointer not set!" << std::endl;
352 std::cout <<
"Trying to move level " <<
this <<
" at " << Energy() <<
" keV to band \"" << val <<
"\" using " << fLevelScheme << std::endl;
354 fLevelScheme->MoveToBand(val,
this);
357std::pair<double, double> TLevel::GetMinMaxGamma()
const
359 if(fGammas.empty()) {
return std::make_pair(-1., -1.); }
360 auto result = std::make_pair(fGammas.begin()->second.Width(), fGammas.begin()->second.Width());
361 for(
const auto& [energy, gamma] : fGammas) {
362 if(gamma.Width() < result.first) { result.first = gamma.Width(); }
363 if(gamma.Width() > result.second) { result.second = gamma.Width(); }
369void TLevel::Draw(
const double& left,
const double& right)
371 std::vector<double> x;
372 std::vector<double> y;
374 double tickLength = (fOffset == 0. ? 0. : 10.);
378 y.push_back(fEnergy + fOffset);
379 x.push_back(left + tickLength);
380 y.push_back(fEnergy + fOffset);
381 x.push_back(left + tickLength + std::fabs(fOffset) / 2.);
382 y.push_back(fEnergy);
383 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; }
385 x.push_back(left + tickLength + std::fabs(fOffset) / 2.);
386 y.push_back(fEnergy);
387 x.push_back(right - tickLength - std::fabs(fOffset) / 2.);
388 y.push_back(fEnergy);
390 x.push_back(right - tickLength - std::fabs(fOffset) / 2.);
391 y.push_back(fEnergy);
392 x.push_back(right - tickLength);
393 y.push_back(fEnergy + fOffset);
395 y.push_back(fEnergy + fOffset);
396 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; }
398 SetPolyLine(x.size(), x.data(), y.data());
400 if(fDebug) { std::cout <<
"Drew TPolyLine using x " << left <<
"-" << right <<
" and y " << fEnergy <<
" with a width of " << GetLineWidth() <<
" and offset " << fOffset << std::endl; }
403double TLevel::DrawLabel(
const double& pos)
405 if(fLevelLabel ==
nullptr) {
406 fLevelLabel =
new TLatex(pos, fEnergy + fOffset, fLabel.c_str());
408 fLevelLabel->SetText(pos, fEnergy + fOffset, fLabel.c_str());
410 fLevelLabel->SetTextColor(GetLineColor());
411 fLevelLabel->SetTextAlign(12);
412 fLevelLabel->SetTextFont(42);
413 fLevelLabel->SetTextSize(fTextSize);
415 return fLevelLabel->GetXsize();
418double TLevel::DrawEnergy(
const double& pos)
420 if(fEnergyLabel ==
nullptr) {
421 fEnergyLabel =
new TLatex(pos, fEnergy + fOffset, Form(
"%.0f keV", fEnergy));
423 fEnergyLabel->SetText(pos, fEnergy + fOffset, Form(
"%.0f keV", fEnergy));
425 fEnergyLabel->SetTextColor(GetLineColor());
426 fEnergyLabel->SetTextAlign(32);
427 fEnergyLabel->SetTextFont(42);
428 fEnergyLabel->SetTextSize(fTextSize);
429 fEnergyLabel->Draw();
430 return fEnergyLabel->GetXsize();
433void TLevel::Print(Option_t*)
const
435 std::cout <<
"Level \"" << fLabel <<
"\" (" <<
this <<
") at " << fEnergy <<
" keV has " << fGammas.size() <<
" draining gammas and " << fNofFeeding <<
" feeding gammas, debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
437 for(
const auto& [level, gamma] : fGammas) {
438 std::cout <<
"gamma to level " << level <<
" \"" << gamma.LabelText() <<
"\"" << std::endl;
443TBand::TBand(TLevelScheme* levelScheme,
const std::string& label)
445 if(levelScheme ==
nullptr) {
446 std::cout <<
"Warning, nullptr provided to new band \"" << label <<
"\" for parent level scheme, some functions might no be available" << std::endl;
448 fLevelScheme = levelScheme;
449 SetLabel(label.c_str());
454TBand::TBand(
const TBand& rhs)
457 if(fDebug || rhs.fDebug) {
458 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;
462 fLevels = rhs.fLevels;
463 fLevelScheme = rhs.fLevelScheme;
465 if(fDebug || rhs.fDebug) {
466 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;
470TBand& TBand::operator=(
const TBand& rhs)
473 TPaveLabel::operator=(rhs);
474 if(fDebug || rhs.fDebug) {
475 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;
478 fLevels = rhs.fLevels;
479 fLevelScheme = rhs.fLevelScheme;
480 if(fDebug || rhs.fDebug) {
481 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;
488TLevel* TBand::GetLevel(
double energy)
491 if(fLevels.count(energy) == 0) {
492 std::cout <<
this <<
": failed to find level with " << energy <<
" keV" << std::endl;
497 std::cout <<
this <<
": found ";
498 fLevels.find(energy)->second.Print();
499 std::cout <<
"energy " << energy <<
" - " << &(fLevels.find(energy)->second) << std::endl;
501 return &(fLevels.find(energy)->second);
504TLevel* TBand::FindLevel(
double energy,
double energyUncertainty)
508 auto low = fLevels.lower_bound(energy - energyUncertainty);
509 auto high = fLevels.upper_bound(energy + energyUncertainty);
512 std::cout <<
this <<
": failed to find level with " << energy <<
" +- " << energyUncertainty <<
" keV" << std::endl;
517 if(std::distance(low, high) == 1) {
519 std::cout <<
this <<
": found ";
521 std::cout <<
"energy " << energy <<
" +- " << energyUncertainty <<
" - " << &(low->second) << std::endl;
523 return &(low->second);
526 double en = low->first;
527 TLevel* level = &(low->second);
528 for(
auto& it = ++low; it != high; ++it) {
529 if(std::fabs(energy - en) > std::fabs(energy - it->first)) {
531 level = &(it->second);
535 std::cout <<
this <<
": found " << std::distance(low, high) <<
" levels, closest is";
537 std::cout <<
"energy " << energy <<
" +- " << energyUncertainty <<
" - " << level << std::endl;
542std::pair<double, double> TBand::GetMinMaxGamma()
const
544 if(fLevels.empty()) {
throw std::runtime_error(
"Trying to get min/max gamma width from empty band"); }
545 auto result = fLevels.begin()->second.GetMinMaxGamma();
546 for(
const auto& [energy, level] : fLevels) {
547 auto [min, max] = level.GetMinMaxGamma();
548 if(min < result.first) { result.first = min; }
549 if(max > result.second) { result.second = max; }
555TLevel* TBand::AddLevel(
const double energy,
const std::string& label)
562 std::cout << __PRETTY_FUNCTION__ <<
" - " <<
this <<
": Trying to add new level \"" << label <<
"\" at " << energy <<
" keV to " << std::flush;
565 auto [newLevel, success] = fLevels.emplace(std::piecewise_construct, std::forward_as_tuple(energy), std::forward_as_tuple(fLevelScheme, energy, label));
567 std::cerr <<
DRED <<
"Failed to add new level \"" << label <<
"\" at " << energy <<
" keV to " <<
RESET_COLOR;
571 newLevel->second.Debug(fDebug);
573 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;
575 std::cout <<
"New level: ";
576 newLevel->second.Print();
581 fLevelScheme->Refresh();
583 return &(newLevel->second);
586void TBand::AddLevel(TLevel* level)
589 std::cout << __PRETTY_FUNCTION__ <<
" - " <<
this <<
" - \"" << GetLabel() <<
"\": Trying to add new level \"" << level->Label() <<
"\" at " << level->Energy() <<
" keV" << std::endl;
591 auto [iterator, success] = fLevels.insert(std::pair{level->Energy(), *level});
593 std::cout <<
"Failed to insert level at " << level->Energy() <<
" into ";
596 std::cout <<
"Successfully added new level \"" << level->Label() <<
"\" at " << level->Energy() <<
" keV" << std::endl;
601void TBand::RemoveLevel(TLevel* level)
604 auto nofRemoved = fLevels.erase(level->Energy());
606 std::cout <<
"\"" << GetLabel() <<
"\": Removed " << nofRemoved <<
" levels" << std::endl;
611double TBand::Width(
double distance)
const
613 size_t nofGammas = 0.;
615 std::cout <<
" (" << GetLabel() <<
" - " << fLevels.size() <<
": ";
617 for(
const auto& level : fLevels) {
618 nofGammas += level.second.NofDrainingGammas() + 1;
620 std::cout <<
" " << nofGammas <<
" ";
623 if(nofGammas == 0) { nofGammas = 1; }
626 std::cout <<
"=> width " <<
static_cast<double>(nofGammas) * distance <<
") ";
629 return static_cast<double>(nofGammas) * distance;
632void TBand::Print(Option_t*)
const
634 std::cout <<
this <<
": band \"" << GetLabel() <<
"\" " << fLevels.size() <<
" level(s):";
635 for(
const auto& level : fLevels) {
636 std::cout <<
" " << level.first;
638 std::cout <<
", debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
640 for(
const auto& level : fLevels) {
641 level.second.Print();
646TLevelScheme::TLevelScheme(
const std::string& filename,
bool debug)
649 SetName(
"TLevelScheme");
650 SetLabel(
"Level Scheme");
654 if(!filename.empty()) {
656 std::cout <<
"file " << filename <<
" does not exist or we don't have read permissions" << std::endl;
658 auto lastDot = filename.find_last_of(
'.');
659 if(lastDot == std::string::npos) {
660 std::cout <<
"Failed to find extension => unknown data format" << std::endl;
662 std::string ext = filename.substr(lastDot + 1);
664 if(!ParseENSDF(filename)) {
665 throw std::runtime_error(
"Failed to parse ensdf file!");
668 std::cout <<
"Unknown extension " << ext <<
" => unknown data format" << std::endl;
674 fLevelSchemes.push_back(
this);
677TLevelScheme::TLevelScheme(
const TLevelScheme& rhs)
678 : TPaveLabel(rhs), fDebug(rhs.fDebug), fBands(rhs.fBands), fAuxillaryLevels(rhs.fAuxillaryLevels),
679 fQValue(rhs.fQValue), fQValueUncertainty(rhs.fQValueUncertainty),
680 fNeutronSeparation(rhs.fNeutronSeparation), fNeutronSeparationUncertainty(rhs.fNeutronSeparationUncertainty),
681 fGammaWidth(rhs.fGammaWidth), fGammaDistance(rhs.fGammaDistance), fBandGap(rhs.fBandGap),
682 fLeftMargin(rhs.fLeftMargin), fRightMargin(rhs.fRightMargin), fBottomMargin(rhs.fBottomMargin), fTopMargin(rhs.fTopMargin),
683 fMinWidth(rhs.fMinWidth), fMaxWidth(rhs.fMaxWidth)
685 fLevelSchemes.push_back(
this);
688void TLevelScheme::ListLevelSchemes()
690 for(
auto& scheme : fLevelSchemes) {
691 std::cout <<
" \"" << scheme->GetLabel() <<
"\"";
693 std::cout << std::endl;
696TLevelScheme* TLevelScheme::GetLevelScheme(
const char* name)
698 for(
auto& scheme : fLevelSchemes) {
699 if(strcmp(name, scheme->GetLabel()) == 0) {
704 std::cout <<
"Failed to find level scheme \"" << name <<
"\", " << fLevelSchemes.size() <<
" level schemes exist";
710TLevel* TLevelScheme::AddLevel(
const double energy,
const std::string& bandName,
const std::string& label)
714 if(fDebug) { Print(); }
716 for(
auto& band : fBands) {
717 if(bandName == band.GetLabel()) {
719 std::cout <<
"Found band \"" << band.GetLabel() <<
"\" (" << &band <<
") with " << band.NofLevels() <<
" levels" << std::endl;
721 return band.AddLevel(energy, label);
724 std::cout <<
"Band \"" << band.GetLabel() <<
"\" does not match " << bandName << std::endl;
727 fBands.emplace_back(
this, bandName);
728 auto& newBand = fBands.back();
729 newBand.Debug(fDebug);
731 std::cout <<
"Created band \"" << newBand.GetLabel() <<
"\" (" << &newBand <<
") with " << newBand.NofLevels() <<
" level" << std::endl;
733 std::cout << std::endl;
735 return newBand.AddLevel(energy, label);
738TLevel* TLevelScheme::GetLevel(
double energy)
740 for(
auto& band : fBands) {
741 auto* level = band.GetLevel(energy);
742 if(level !=
nullptr) {
748 std::cout <<
"Failed to find level with energy " << energy <<
" in " << fBands.size() <<
" bands:" << std::endl;
749 for(
const auto& band : fBands) {
756TLevel* TLevelScheme::FindLevel(
double energy,
double energyUncertainty)
758 for(
auto& band : fBands) {
759 auto* level = band.FindLevel(energy, energyUncertainty);
760 if(level !=
nullptr) {
767 std::cout <<
"Failed to find level with energy " << energy <<
" +- " << energyUncertainty <<
" in " << fBands.size() <<
" bands:" << std::endl;
768 for(
const auto& band : fBands) {
776TGamma* TLevelScheme::FindGamma(
double energy,
double energyUncertainty)
780 auto list = FindGammas(energy - energyUncertainty, energy + energyUncertainty);
783 std::cerr <<
"Failed to find any gamma ray in range [" << energy - energyUncertainty <<
", " << energy + energyUncertainty <<
"]" << std::endl;
787 auto* result = list[0];
788 for(
size_t i = 1; i < list.size(); ++i) {
789 if(std::fabs(list[i]->Energy() - energy) < std::fabs(result->Energy() - energy)) { result = list[i]; }
795std::vector<TGamma*> TLevelScheme::FindGammas(
double lowEnergy,
double highEnergy)
798 std::vector<TGamma*> result;
800 for(
auto& band : fBands) {
802 for(
auto& [levelEnergy, level] : band) {
804 for(
auto& [finalEnergy, gamma] : level) {
805 if(lowEnergy <= gamma.Energy() && gamma.Energy() <= highEnergy) {
806 result.push_back(&gamma);
815void TLevelScheme::BuildGammaMap(
double levelEnergy)
820 if(!fGammaMap.empty()) {
return; }
822 for(
auto& band : fBands) {
823 for(
auto& [energy, level] : band) {
824 if(energy <= levelEnergy) {
828 for(
auto& [finalEnergy, gamma] : level) {
829 if(finalEnergy >= levelEnergy) {
830 fGammaMap.insert({finalEnergy, &gamma});
836 std::cout <<
"Built map of " << fGammaMap.size() <<
" gamma rays populating levels above or equal " << levelEnergy <<
" keV" << std::endl;
840std::map<double, double> TLevelScheme::FeedingGammas(
double levelEnergy,
double factor)
847 std::map<double, double> result;
848 BuildGammaMap(levelEnergy);
850 auto range = fGammaMap.equal_range(levelEnergy);
852 std::cout <<
"Got " << std::distance(range.first, range.second) <<
" gamma rays feeding level at " << levelEnergy <<
" kev (factor " << factor <<
")" << std::endl;
854 for(
auto& it = range.first; it != range.second; ++it) {
856 std::cout <<
"Adding gamma " << it->second <<
": ";
859 result[it->second->Energy()] += factor * it->second->BranchingRatioPercent();
860 auto tmp = FeedingGammas(it->second->InitialEnergy(), factor * it->second->BranchingRatioPercent());
861 for(
auto& [energy, tmpFactor] : tmp) {
862 result[energy] += tmpFactor;
867 std::cout <<
"returning list of " << result.size() <<
" gammas feeding level at " << levelEnergy <<
" keV" << std::endl;
872std::map<double, double> TLevelScheme::DrainingGammas(
double levelEnergy,
double factor)
880 auto* level = GetLevel(levelEnergy);
881 std::map<double, double> result;
882 if(level ==
nullptr) {
883 std::cerr <<
"Failed to find level at " << levelEnergy <<
" keV, returning empty list of gammas draining that level" << std::endl;
889 std::cout << level <<
": looping over " << level->NofDrainingGammas() <<
" gammas for level at " << levelEnergy <<
" keV (factor " << factor <<
")" << std::endl;
893 for(
auto& [finalEnergy, gamma] : *level) {
895 std::cout <<
"Adding gamma: ";
899 auto branchingRatio = gamma.BranchingRatioPercent();
900 result[gamma.Energy()] += factor * branchingRatio;
902 if(gamma.FinalEnergy() > 0.) {
903 auto tmp = DrainingGammas(finalEnergy, factor * branchingRatio);
904 for(
auto& [energy, tmpFactor] : tmp) {
905 result[energy] += tmpFactor;
911 std::cout <<
"returning list of " << result.size() <<
" gammas draining level at " << levelEnergy <<
" keV" << std::endl;
916std::vector<std::tuple<double, std::vector<double>>> TLevelScheme::ParallelGammas(
double initialEnergy,
double finalEnergy,
double factor)
920 auto* level = GetLevel(initialEnergy);
921 std::vector<std::tuple<double, std::vector<double>>> result;
922 if(level ==
nullptr) {
923 std::cerr <<
"Failed to find level at " << initialEnergy <<
" keV, returning empty list of gammas" << std::endl;
929 std::cout << level <<
": looping over " << level->NofDrainingGammas() <<
" gammas for level at " << initialEnergy <<
" keV (factor " << factor <<
")" << std::endl;
932 result.emplace_back(1., std::vector<double>());
934 for(
auto& [levelEnergy, gamma] : *level) {
936 if(levelEnergy < finalEnergy) {
938 std::cout <<
"skipping gamma ";
944 std::get<0>(result.back()) *= gamma.BranchingRatioPercent();
945 std::get<1>(result.back()).insert(std::get<1>(result.back()).end(), gamma.Energy());
947 std::cout <<
"Added gamma ";
949 std::cout <<
"New result:";
950 for(
auto& entry : result) {
951 std::cout <<
" " << std::get<0>(entry) <<
"-";
952 for(
auto& e : std::get<1>(entry)) {
953 std::cout << e <<
",";
956 std::cout << std::endl;
959 if(levelEnergy > finalEnergy) {
960 auto tmp = ParallelGammas(levelEnergy, finalEnergy, factor * gamma.BranchingRatioPercent());
964 auto it = result.insert(result.end(), tmp.size() - 1, result.back());
968 std::cout <<
"Got " << tmp.size() <<
" paths, so added " << tmp.size() - 1 <<
" copies of last element:";
969 for(
auto& entry : result) {
970 std::cout <<
" " << std::get<0>(entry) <<
"-";
971 for(
auto& e : std::get<1>(entry)) {
972 std::cout << e <<
",";
975 std::cout << std::endl;
977 for(
auto& combo : tmp) {
979 std::get<0>(*it) *= std::get<0>(combo);
980 std::get<1>(*it).insert(std::get<1>(*it).end(), std::get<1>(combo).begin(), std::get<1>(combo).end());
984 std::cout <<
"Got " << tmp.size() <<
" more gammas, new result:";
985 for(
auto& entry : result) {
986 std::cout <<
" " << std::get<0>(entry) <<
"-";
988 for(
auto& e : std::get<1>(entry)) {
989 std::cout << e <<
",";
992 std::cout <<
"total " << sum;
994 std::cout << std::endl;
1003 std::cout <<
"Failed to find path from " << levelEnergy <<
" to " << finalEnergy <<
", removed last gamma ray";
1004 for(
auto& entry : result) {
1005 std::cout <<
" " << std::get<0>(entry) <<
"-";
1006 for(
auto& e : std::get<1>(entry)) {
1007 std::cout << e <<
",";
1010 std::cout << std::endl;
1016 result.emplace_back(1., std::vector<double>());
1018 std::cout <<
"Reached final level, added new (empty) entry to result" << std::endl;
1023 if(std::get<1>(result.back()).empty()) {
1030void TLevelScheme::MoveToBand(
const char* bandName, TLevel* level)
1035 std::cout <<
"TLevelScheme: Trying to move level " << level <<
" at " << level->Energy() <<
" keV to band \"" << bandName <<
"\"" << std::endl;
1038 for(i = 0; i < fBands.size(); ++i) {
1039 if(strcmp(bandName, fBands[i].GetLabel()) == 0) {
1041 std::cout <<
"Found band \"" << fBands[i].GetLabel() <<
"\" (" << &fBands[i] <<
") with " << fBands[i].NofLevels() <<
" levels" << std::endl;
1043 fBands[i].AddLevel(level);
1047 std::cout <<
"Band \"" << fBands[i].GetLabel() <<
"\" does not match " << bandName << std::endl;
1051 if(i == fBands.size()) {
1053 std::cout <<
"Haven't found band \"" << bandName <<
"\" among existing bands, creating new band" << std::endl;
1055 fBands.emplace_back(
this, bandName);
1056 auto& newBand = fBands.back();
1057 newBand.Debug(fDebug);
1059 std::cout <<
"Created band \"" << newBand.GetLabel() <<
"\" (" << &newBand <<
") with " << newBand.NofLevels() <<
" level" << std::endl;
1061 std::cout << std::endl;
1063 newBand.AddLevel(level);
1066 for(
auto& band : fBands) {
1068 std::cout <<
"Checking band \"" << band.GetLabel() <<
"\": ";
1070 if(strcmp(bandName, band.GetLabel()) == 0) {
1072 std::cout <<
"this is the new band, not deleting it here!" << std::endl;
1077 std::cout <<
"this is not the new band, removing it here!" << std::endl;
1079 band.RemoveLevel(level);
1085void TLevelScheme::Refresh()
1088 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1089 if(canvas !=
nullptr) {
1094void TLevelScheme::UnZoom()
const
1096 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1097 if(canvas !=
nullptr) {
1098 canvas->Range(fX1, fY1, fX2, fY2);
1104void TLevelScheme::Draw(Option_t*)
1106 if(fDebug) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
1107 auto* canvas =
static_cast<GCanvas*
>(gROOT->GetListOfCanvases()->FindObject(
"LevelScheme"));
1108 if(canvas ==
nullptr) {
1109 canvas =
new GCanvas(
"LevelScheme",
"Level Scheme");
1116 auto minMaxLevel = fBands[0].GetMinMaxLevelEnergy();
1118 std::vector<std::pair<double, double>> minMaxGamma;
1119 for(
auto& band : fBands) {
1120 auto minMax = band.GetMinMaxLevelEnergy();
1121 if(minMax.first < minMaxLevel.first) { minMaxLevel.first = minMax.first; }
1122 if(minMax.second > minMaxLevel.second) { minMaxLevel.second = minMax.second; }
1123 if(fDebug) { std::cout <<
"Incrementing width from " << width; }
1124 width += band.Width(fGammaDistance);
1125 if(fDebug) { std::cout <<
" to " << width <<
" using " << band.Width(fGammaDistance) << std::endl; }
1126 minMaxGamma.push_back(band.GetMinMaxGamma());
1128 width +=
static_cast<double>(fBands.size() - 1) * fBandGap;
1131 fY1 = minMaxLevel.first;
1132 fY2 = minMaxLevel.second;
1133 double height = fY2 - fY1;
1135 if(fBottomMargin < 0) {
1136 fY1 -= height / 10.;
1138 fY1 -= fBottomMargin;
1140 if(fTopMargin < 0) {
1141 fY2 += height / 10.;
1150 if(fLeftMargin < 0) {
1155 if(fRightMargin < 0) {
1158 fX2 += fRightMargin;
1161 if(fDebug) { std::cout <<
"got x1 - x2 " << fX1 <<
" - " << fX2 <<
", and y1 - y2 " << fY1 <<
" - " << fY2 << std::endl; }
1162 canvas->Range(fX1, fY1, fX2, fY2);
1165 SetX1(fX2 - fBandGap);
1167 if(fTopMargin < 0) {
1168 SetY1(fX2 - height / 12.);
1170 SetY1(fX2 - fTopMargin * 0.75);
1175 if(fDrawName) { TPaveLabel::Draw(); }
1177 if(fGammaWidth == EGammaWidth::kGlobal) {
1180 for(
auto& [min, max] : minMaxGamma) {
1181 if(min < minMaxGamma[0].first) { minMaxGamma[0].first = min; }
1182 if(max > minMaxGamma[0].second) { minMaxGamma[0].second = max; }
1183 std::cout << min <<
" - " << max <<
": " << minMaxGamma[0].first <<
" - " << minMaxGamma[0].second << std::endl;
1190 for(
size_t b = 0; b < fBands.size(); ++b) {
1191 double right = left + fBands[b].Width(fGammaDistance);
1192 if(fDebug) { std::cout << b <<
": Using width " << fBands[b].Width(fGammaDistance) <<
" and left " << left <<
" we get right " << right << std::endl; }
1193 fBands[b].SetX1(left);
1194 fBands[b].SetY1(-1.5 * height / 20.);
1195 fBands[b].SetX2(right);
1196 fBands[b].SetY2(-height / 40.);
1197 fBands[b].SetFillColor(10);
1198 if(fDrawBandLabel) { fBands[b].Draw(); }
1201 auto& [min, max] = minMaxGamma[0];
1202 if(fGammaWidth == EGammaWidth::kBand) {
1204 min = minMaxGamma[b].first;
1205 max = minMaxGamma[b].second;
1207 double scalingGain = (fMaxWidth - fMinWidth) / (max - min);
1208 double scalingOffset = fMinWidth - scalingGain * min;
1209 if(fGammaWidth == EGammaWidth::kNoWidth) {
1212 scalingOffset = fMinWidth;
1215 double labelSize = TLevel::TextSize() * std::min(fX2 - fX1, fY2 - fY1);
1223 std::vector<std::vector<std::pair<double, int>>> groups;
1225 for(
auto& [energy, level] : fBands[b]) {
1226 std::vector<size_t> potentialGroups;
1227 for(
size_t i = 0; i < groups.size(); ++i) {
1228 for(
size_t j = 0; j < groups[i].size(); ++j) {
1232 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());
1234 if(energy - (average + labelSize * (
static_cast<double>(j) -
static_cast<double>(groups[i].size() - 1) / 2.)) < labelSize * (index - groups[i][j].second)) {
1236 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;
1238 potentialGroups.push_back(i);
1243 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;
1248 if(potentialGroups.empty()) {
1249 groups.emplace_back(1, std::make_pair(energy, index));
1250 }
else if(potentialGroups.size() == 1) {
1251 groups[potentialGroups[0]].push_back(std::make_pair(energy, index));
1254 std::cout <<
"combining groups";
1255 for(
const auto& potentialGroup : potentialGroups) {
1256 std::cout <<
" " << potentialGroup;
1258 std::cout << std::endl;
1261 for(
auto potentialGroup : potentialGroups) {
1262 groups[potentialGroups[0]].insert(groups[potentialGroups[0]].end(), groups[potentialGroup].begin(), groups[potentialGroup].end());
1263 groups.erase(groups.begin() + potentialGroup);
1265 groups[potentialGroups[0]].emplace_back(energy, index);
1266 std::sort(groups[potentialGroups[0]].begin(), groups[potentialGroups[0]].end());
1271 std::cout <<
"got " << groups.size() <<
" groups:" << std::endl;
1272 for(
auto& group : groups) {
1273 for(
auto& level : group) {
1274 std::cout << level.second <<
" " << level.first <<
", ";
1276 std::cout << std::endl;
1280 std::vector<std::pair<double, double>> centers;
1281 for(
auto& group : groups) {
1282 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());
1283 for(
size_t i = 0; i < group.size(); ++i) {
1284 centers.emplace_back(average,
static_cast<double>(i) -
static_cast<double>(group.size() - 1) / 2.);
1288 std::cout <<
"centers: ";
1289 for(
auto& [center, diff] : centers) {
1290 std::cout << center <<
" " << diff <<
", ";
1292 std::cout << std::endl;
1298 for(
auto& [energy, level] : fBands[b]) {
1300 std::cout << std::endl;
1301 std::cout <<
"starting calculations for drawing level at " << energy << std::endl;
1304 double move = centers[index].first - energy + labelSize * centers[index].second;
1306 std::cout <<
"calculations for drawing level at " << energy <<
": move " << move <<
" (" << centers[index].first <<
" - " << energy <<
" + " << labelSize <<
"*" << centers[index].second <<
") => " << energy + move <<
", " << left <<
"-" << right << std::endl;
1309 level.Draw(left, right);
1312 if(fDrawLevelLabel) { level.DrawLabel(right); }
1313 if(fDrawLevelEnergy) { level.DrawEnergy(left); }
1318 if(fDebug) { level.Print(); }
1321 for(
auto& [finalEnergy, gamma] : level) {
1325 for(b2 = 0; b2 < fBands.size(); ++b2) {
1326 for(
auto& [energy2, level2] : fBands[b2]) {
1327 if(finalEnergy == level2.Energy()) {
1329 std::cout <<
"band " << b2 <<
": " << finalEnergy <<
" == " << level2.Energy() << std::endl;
1335 std::cout <<
"band " << b2 <<
": " << finalEnergy <<
" != " << level2.Energy() << std::endl;
1338 if(found) {
break; }
1342 std::cout <<
"Warning, failed to find final level at " << finalEnergy <<
" keV for gamma-ray!" << std::endl;
1346 gamma.Scaling(scalingOffset, scalingGain);
1349 double gY1 = level.Energy();
1350 double gY2 = finalEnergy;
1358 if(fDebug) { std::cout << b <<
" == " << b2 <<
": intra band " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1359 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1360 gX2 = left +
static_cast<double>(g) * fGammaDistance;
1363 if(fDebug) { std::cout << b <<
" < " << b2 <<
": inter band to right " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1364 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1365 gX2 = left +
static_cast<double>(g) * fGammaDistance + (gY1 - gY2) / 10.;
1366 double shift = right + fBandGap;
1369 shift = std::accumulate(fBands.begin() + b + 1, fBands.begin() + b2, right + fBandGap, [&](
double r, TBand& el) { r += el.Width(fGammaDistance) + fBandGap; return r; });
1371 DrawAuxillaryLevel(gY2, right +
static_cast<double>(g) * fGammaDistance, shift - fBandGap / 2.);
1374 if(fDebug) { std::cout << b <<
" > " << b2 <<
": inter band to left " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1375 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1376 gX2 = left +
static_cast<double>(g) * fGammaDistance - (gY1 - gY2) / 10.;
1377 double shift = left - fBandGap;
1380 shift = std::accumulate(fBands.begin() + b2 + 1, fBands.begin() + b, left - fBandGap, [&](
double r, TBand& el) { r -= el.Width(fGammaDistance) + fBandGap; return r; });
1382 DrawAuxillaryLevel(gY2, left +
static_cast<double>(g) * fGammaDistance, shift + fBandGap / 2.);
1387 if(fDebug) { std::cout << b <<
" == " << b2 <<
": intra band " << g <<
" at position " <<
static_cast<double>(g) * fGammaDistance << std::endl; }
1388 gX1 = left +
static_cast<double>(g) * fGammaDistance;
1389 gX2 = left +
static_cast<double>(g) * fGammaDistance;
1391 }
else if(b + 1 == b2) {
1392 if(fDebug) { std::cout << b <<
"+1 == " << b2 <<
": inter band " << g <<
" to right " << right <<
"-" << right + fBandGap << std::endl; }
1393 gX1 = right - fGammaDistance / 2.;
1394 gX2 = right + fBandGap + fGammaDistance / 2.;
1395 }
else if(b == b2 + 1) {
1396 if(fDebug) { std::cout << b <<
" == " << b2 <<
"+1: inter band " << g <<
" to left " << left <<
"-" << left - fBandGap << std::endl; }
1397 gX1 = left + fGammaDistance / 2.;
1398 gX2 = left - fBandGap - fGammaDistance / 2.;
1400 if(fDebug) { std::cout << b <<
" < " << b2 <<
": inter band far " << g <<
" right " << right <<
", band gap " << fBandGap << std::endl; }
1402 gX2 = right + fBandGap / 8.;
1403 double shift = right + fBandGap;
1406 shift = std::accumulate(fBands.begin() + b + 1, fBands.begin() + b2, right + fBandGap, [&](
double r, TBand& el) { r += el.Width(fGammaDistance) + fBandGap; return r; });
1408 DrawAuxillaryLevel(gY2, right, shift - fBandGap / 2.);
1410 if(fDebug) { std::cout << b <<
" > " << b2 <<
": inter band far " << g <<
" left " << left <<
", band gap " << fBandGap << std::endl; }
1412 gX2 = left - fBandGap / 8.;
1413 double shift = left - fBandGap;
1416 shift = std::accumulate(fBands.begin() + b2 + 1, fBands.begin() + b, left - fBandGap, [&](
double r, TBand& el) { r -= el.Width(fGammaDistance) + fBandGap; return r; });
1418 DrawAuxillaryLevel(gY2, left, shift + fBandGap / 2.);
1422 gamma.Draw(gX1, gY1, gX2, gY2);
1424 if(level.begin() != level.end()) {
1426 std::cout <<
"Level has gamma-rays, incrementing g from " << g << std::endl;
1434 left = right + fBandGap;
1438 std::cout <<
"Canvas " << canvas <<
" " << canvas->GetName() <<
" has " << canvas->GetListOfPrimitives()->GetSize() <<
" primitives:" << std::endl;
1439 canvas->GetListOfPrimitives()->Print();
1444void TLevelScheme::DrawAuxillaryLevel(
const double& energy,
const double& left,
const double& right)
1447 std::cout <<
"Drawing auxillary level at " << energy <<
" keV from " << left <<
" to " << right << std::endl;
1450 if(fAuxillaryLevels.count(energy) > 0) {
1452 auto range = fAuxillaryLevels.equal_range(energy);
1453 for(
auto it = range.first; it != range.second; ++it) {
1454 if(it->second.GetX1() == left && it->second.GetX2() == right) {
return; }
1458 auto it = fAuxillaryLevels.emplace(std::piecewise_construct, std::forward_as_tuple(energy), std::forward_as_tuple(left, energy, right, energy));
1459 it->second.SetLineStyle(2);
1463void TLevelScheme::Print(Option_t*)
const
1465 std::cout <<
this <<
": got " << fBands.size() <<
" bands: ";
1466 for(
size_t b = 0; b < fBands.size(); ++b) {
1467 std::cout <<
" " << b <<
"-" << &fBands[b] <<
"-" << fBands[b].GetLabel();
1469 std::cout <<
", debugging" << (fDebug ?
"" :
" not") <<
" enabled" << std::endl;
1471 for(
const auto& band : fBands) {
1477bool TLevelScheme::ParseENSDF(
const std::string& filename)
1481 std::ifstream input(filename);
1482 if(!input.is_open()) {
1483 std::cerr <<
DRED <<
"Failed to open \"" << filename <<
"\"" <<
RESET_COLOR << std::endl;
1488 std::istringstream str;
1489 TLevel* currentLevel =
nullptr;
1499 std::getline(input, line);
1500 SetLabel(line.substr(0, 5).c_str());
1502 std::cout <<
"Reading level scheme for " << GetLabel() << std::endl;
1508 if(line.substr(9, 14) !=
"ADOPTED LEVELS") {
1509 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;
1514 std::getline(input, line);
1515 }
while(line[5] !=
' ');
1520 std::cout <<
" \"" << line <<
"\"" << std::endl;
1527 if(line.substr(5, 4) ==
" Q ") {
1530 str.str(line.substr(9, 10));
1533 str.str(line.substr(19, 2));
1534 str >> fQValueUncertainty;
1535 if(fDebug) { std::cout <<
"reading S_n old \"" << str.str() <<
"\" @ " << str.tellg() << (str.fail() ?
" failed" :
" good"); }
1537 str.str(line.substr(21, 8));
1538 if(fDebug) { std::cout <<
", new \"" << str.str() <<
"\" @ " << str.tellg() << (str.fail() ?
" failed" :
" good"); }
1539 str >> fNeutronSeparation;
1540 if(fDebug) { std::cout <<
" => S_n " << fNeutronSeparation << std::endl; }
1542 str.str(line.substr(29, 2));
1543 str >> fNeutronSeparationUncertainty;
1545 std::cout <<
"Found q-value line: " << fQValue <<
" +- " << fQValueUncertainty <<
", S_n " << fNeutronSeparation <<
" +- " << fNeutronSeparationUncertainty << std::endl;
1546 std::cout <<
"\"" << line.substr(9, 10) <<
"\", \"" << line.substr(19, 2) <<
"\", \"" << line.substr(21, 8) <<
"\", \"" << line.substr(29, 2) <<
"\"" << std::endl;
1549 std::cout <<
"Ignoring q-value comment \"" << line <<
"\"" << std::endl;
1554 if(fDebug) { std::cout <<
"Ignoring cross-reference \"" << line <<
"\"" << std::endl; }
1557 if(fDebug) { std::cout <<
"Ignoring parent \"" << line <<
"\"" << std::endl; }
1562 if(fDebug) { std::cout <<
"Ignoring normalization \"" << line <<
"\"" << std::endl; }
1566 if(line[5] ==
' ' && line[6] ==
' ') {
1569 double energyUncertainty = 0.;
1570 if(fDebug) { std::cout <<
"reading level energy old \"" << str.str() <<
"\""; }
1572 str.str(line.substr(9, 10));
1573 if(fDebug) { std::cout <<
", new \"" << str.str() <<
"\""; }
1575 if(fDebug) { std::cout <<
" => energy " << energy << std::endl; }
1577 str.str(line.substr(19, 2));
1578 str >> energyUncertainty;
1582 std::string spinParity = line.substr(21, 18);
1584 std::string halfLife = line.substr(39, 10);
1586 std::string halfLifeUncertainty = line.substr(49, 6);
1587 trimWS(halfLifeUncertainty);
1590 if(!spinParity.empty()) {
1591 label += spinParity;
1593 if(!halfLife.empty()) {
1595 label += halfLifeUncertainty;
1598 std::cout <<
"Adding new level " << energy <<
" +- " << energyUncertainty <<
", " << spinParity <<
", half-life " << halfLife <<
" +- " << halfLifeUncertainty << std::endl;
1599 std::cout <<
"\"" << line.substr(9, 10) <<
"\", \"" << line.substr(19, 2) <<
"\", \"" << line.substr(21, 18) <<
"\", \"" << line.substr(39, 10) <<
"\", \"" << line.substr(49, 6) <<
"\"" << std::endl;
1602 currentLevel = AddLevel(energy, GetLabel(), label);
1603 currentLevel->EnergyUncertainty(energyUncertainty);
1605 std::cout <<
"Ignoring level \"" << line <<
"\"" << std::endl;
1611 if(line[5] ==
' ' && line[6] ==
' ') {
1612 if(currentLevel ==
nullptr) {
1613 std::cout <<
"Found unassigned gamma, ignoring it (" << line <<
")!" << std::endl;
1618 double energyUncertainty = 0.;
1620 str.str(line.substr(9, 10));
1623 str.str(line.substr(19, 2));
1624 str >> energyUncertainty;
1626 double photonIntensity = 0.;
1627 double photonIntensityUncertainty = 0.;
1629 str.str(line.substr(21, 8));
1630 str >> photonIntensity;
1632 str.str(line.substr(29, 2));
1633 str >> photonIntensityUncertainty;
1635 std::string multipolarity = line.substr(31, 10);
1638 double mixingRatio = 0.;
1639 double mixingRatioUncertainty = 0.;
1641 str.str(line.substr(41, 8));
1644 str.str(line.substr(49, 6));
1645 str >> mixingRatioUncertainty;
1647 double conversionCoeff = 0.;
1648 double conversionCoeffUncertainty = 0.;
1650 str.str(line.substr(55, 7));
1651 str >> conversionCoeff;
1653 str.str(line.substr(62, 2));
1654 str >> conversionCoeffUncertainty;
1656 double totalIntensity = 0.;
1657 double totalIntensityUncertainty = 0.;
1659 str.str(line.substr(64, 10));
1660 str >> totalIntensity;
1662 str.str(line.substr(74, 2));
1663 str >> totalIntensityUncertainty;
1666 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;
1667 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;
1669 auto* gamma = currentLevel->AddGamma(currentLevel->Energy() - energy, currentLevel->EnergyUncertainty() + energyUncertainty, multipolarity.c_str(), photonIntensity, totalIntensity);
1670 if(gamma !=
nullptr) {
1671 gamma->BranchingRatioUncertainty(photonIntensityUncertainty);
1672 gamma->TransitionStrengthUncertainty(totalIntensityUncertainty);
1676 std::cout <<
"Ignoring gamma \"" << line <<
"\"" << std::endl;
1680 if(fDebug) { std::cout <<
"Ignoring beta \"" << line <<
"\"" << std::endl; }
1683 if(fDebug) { std::cout <<
"Ignoring EC \"" << line <<
"\"" << std::endl; }
1686 if(fDebug) { std::cout <<
"Ignoring alpha \"" << line <<
"\"" << std::endl; }
1689 if(fDebug) { std::cout <<
"Ignoring delayed \"" << line <<
"\"" << std::endl; }
1692 if(fDebug) { std::cout <<
"Ignoring reference \"" << line <<
"\"" << std::endl; }
1695 if(fDebug) { std::cout <<
"Ignoring comment \"" << line <<
"\"" << std::endl; }
1699 if(fDebug) { std::cout <<
"Skipping unknown character " << line[7] <<
" from line \"" << line <<
"\"" << std::endl; }
1702 }
while(std::getline(input, line) && !line.empty());
1704 if(fDebug) { std::cout <<
"Done reading \"" << filename <<
"\"" << std::endl; }
void trimWS(std::string &line)
bool FileExists(const char *filename)