Analysis-Utilities 26.9.9
C++/ROOT utilities for nuclear measurement data analysis
Loading...
Searching...
No Matches
RooFitUtils.hpp
Go to the documentation of this file.
1#ifndef ROOFITUTILS_H
2#define ROOFITUTILS_H
3
4#include "FittingUtils.hpp"
5#include "PlottingUtils.hpp"
7
8#include <RooAbsData.h>
9#include <RooAbsPdf.h>
10#include <RooAbsReal.h>
11#include <RooAddPdf.h>
12#include <RooArgList.h>
13#include <RooArgSet.h>
14#include <RooCategory.h>
15#include <RooCmdArg.h>
16#include <RooDataSet.h>
17#include <RooFitResult.h>
18#include <RooFormulaVar.h>
19#include <RooGaussian.h>
20#include <RooGenericPdf.h>
21#include <RooGlobalFunc.h>
22#include <RooMsgService.h>
23#include <RooPolynomial.h>
24#include <RooRealVar.h>
25#include <RooSimultaneous.h>
26
27#include <TBranch.h>
28#include <TGraph.h>
29#include <TH1.h>
30#include <TLeaf.h>
31#include <TMath.h>
32#include <TString.h>
33#include <TSystem.h>
34#include <TTree.h>
35#include <algorithm>
36#include <fstream>
37#include <iomanip>
38#include <iostream>
39#include <map>
40#include <set>
41#include <vector>
42
56inline RooCmdArg BestAvailableBackend() {
57#if defined(AU_ROOFIT_BACKEND_CUDA) && AU_ROOFIT_BACKEND_CUDA
58 return RooFit::EvalBackend::Cuda();
59#else
60 return RooFit::EvalBackend::Cpu();
61#endif
62}
63
74namespace RooFitFunctions {
83RooAbsPdf *MakeGaussian(const TString &name, RooRealVar &x, RooRealVar &mu,
84 RooRealVar &sigma);
93RooAbsPdf *MakeStepShelf(const TString &name, RooRealVar &x, RooRealVar &mu,
94 RooRealVar &sigma);
104RooAbsPdf *MakeLowExpTail(const TString &name, RooRealVar &x, RooRealVar &mu,
105 RooRealVar &sigma, RooRealVar &tau_ratio);
115RooAbsPdf *MakeLowLinTail(const TString &name, RooRealVar &x, RooRealVar &mu,
116 RooRealVar &sigma, RooRealVar &slope);
126RooAbsPdf *MakeHighExpTail(const TString &name, RooRealVar &x, RooRealVar &mu,
127 RooRealVar &sigma, RooRealVar &tau_ratio);
135RooAbsPdf *MakeLinearBackground(const TString &name, RooRealVar &x,
136 RooRealVar &slope);
137} // namespace RooFitFunctions
138
151 RooRealVar *mu = nullptr;
152 RooRealVar *sigma = nullptr;
153 RooRealVar *gaus_yield = nullptr;
154 RooRealVar *ratio_step = nullptr;
155 RooRealVar *ratio_low_exp = nullptr;
156 RooRealVar *tau_ratio_low_exp = nullptr;
157 RooRealVar *ratio_low_lin = nullptr;
158 RooRealVar *slope_low_lin = nullptr;
159 RooRealVar *ratio_high_exp = nullptr;
160 RooRealVar *tau_ratio_high_exp = nullptr;
161
162 RooAbsPdf *gauss_pdf = nullptr;
163 RooAbsPdf *step_pdf = nullptr;
164 RooAbsPdf *low_exp_pdf = nullptr;
165 RooAbsPdf *low_lin_pdf = nullptr;
166 RooAbsPdf *high_exp_pdf = nullptr;
167
168 RooFormulaVar *step_yield = nullptr;
169 RooFormulaVar *low_exp_yield = nullptr;
170 RooFormulaVar *low_lin_yield = nullptr;
171 RooFormulaVar *high_exp_yield = nullptr;
172};
173
179 RooRealVar *bkg_yield = nullptr;
180 RooRealVar *bkg_slope = nullptr;
181 RooAbsPdf *bkg_pdf = nullptr;
182};
183
192 TString name;
193 TH1 *hist;
194 std::vector<Double_t> events;
199 std::vector<Double_t> mu_inits;
200 std::vector<Bool_t> mu_fixed;
201 std::vector<Bool_t> use_step_per_peak;
202 Bool_t bkg_yield_fixed = kFALSE;
203 Bool_t bkg_slope_fixed = kFALSE;
204 Bool_t lock_shape_after_seed = kFALSE;
205 // Per-peak shape-lock override. When non-empty and lock_shape_after_seed is
206 // true, each entry controls whether THAT peak's shape is locked. When empty,
207 // all peaks are locked (backward-compatible with lock_shape_after_seed).
208 std::vector<Bool_t> shape_lock_per_peak;
210 Bool_t use_step;
214};
215
228
244 TString channel;
245 Int_t peak_hi = 1;
246 Int_t peak_lo = 0;
247 Double_t delta = 0;
248 Double_t sigma = 0;
249};
250
281private:
282 TH1 *working_hist_;
283 std::vector<Double_t> events_;
284 Float_t fit_range_low_;
285 Float_t fit_range_high_;
286 Float_t display_bin_width_kev_;
287
288 Bool_t use_flat_background_;
289 Bool_t use_step_;
290 Bool_t use_low_exp_tail_;
291 Bool_t use_low_lin_tail_;
292 Bool_t use_high_exp_tail_;
293
294 Bool_t use_manual_init_;
295 Bool_t interactive_;
296 Bool_t fit_debug_;
297 // See SetRefitAfterLoad(). Default kFALSE preserves the historic behaviour.
298 Bool_t refit_after_load_ = kFALSE;
299 // Upper bound on the exponential tail decay ratios tau/sigma. See
300 // SetTailRatioMax().
301 Double_t tail_ratio_max_ = 100.0;
302 std::vector<Double_t> manual_params_;
303
304 RooRealVar *x_;
305 RooDataSet *unbinned_data_;
306 RooAddPdf *total_pdf_;
307 Int_t num_peaks_;
308
309 std::vector<RooFitPeakModel> peaks_;
311 std::vector<RooAbsArg *> owned_args_;
312
313 std::vector<RooFitChannelConfig> sim_channels_;
314 std::vector<RooFitParamLink> sim_links_;
315 std::vector<RooFitSeparationConstraint> sim_sep_constraints_;
316 RooArgSet sim_constraint_set_;
317 std::map<TString, FitResult> sim_seeds_;
318 std::map<TString, std::vector<RooFitPeakModel>> sim_channel_peaks_;
319 std::map<TString, RooFitBackgroundModel> sim_channel_bkg_;
320 std::map<TString, RooAbsPdf *> sim_channel_pdfs_;
321 std::map<TString, RooDataSet *> sim_channel_data_;
322 std::map<TString, TString> sim_channel_range_names_;
323 RooCategory *sim_category_;
324 RooSimultaneous *sim_pdf_;
325 RooDataSet *sim_combined_data_;
326 Bool_t sim_mode_;
327
328 void InitState();
329 void BuildDisplayHistogram();
330 void BuildUnbinnedData();
331 static RooDataSet *BuildUnbinnedDataFrom(const std::vector<Double_t> &events,
332 RooRealVar *x);
333 RooRealVar *ResolveOrCreate(const TString &channel, const TString &param_name,
334 std::map<TString, RooRealVar *> &registry,
335 Double_t init_val, Double_t lo, Double_t hi);
336 Bool_t BuildChannelModel(const RooFitChannelConfig &cfg,
337 std::map<TString, RooRealVar *> &registry);
338 void ApplySeedToChannel(const TString &channel);
339 void ApplyChannelMuLocks();
340 void ApplyChannelBkgLocks();
341 void ApplyChannelShapeLocks();
342 void SaveSimInteractiveParams(const TString &input_name,
343 const TString &base_label);
344 Bool_t LoadSimInteractiveParams(const TString &input_name,
345 const TString &base_label);
346 TString ParamFullName(const TString &channel, const TString &param);
347 TString SourceForTarget(const TString &target);
348 void BuildSeparationConstraints();
349 Double_t ComputeChannelChi2(const TString &channel,
350 const std::vector<RooFitPeakModel> &peaks,
351 const RooFitBackgroundModel &bkg, Int_t &ndof);
352 void PlotChannel(const TString &channel, Int_t num_peaks,
353 const std::vector<RooFitPeakModel> &peaks,
354 const RooFitBackgroundModel &bkg, const TString &input_name,
355 const TString &base_label, const TString &chi2_label);
356 PeakFitResult ExtractPeakResultFor(const RooFitPeakModel &p);
357
358 Double_t EstimateBackground();
359
360 void BuildPeak(Int_t peak_idx, Double_t mu_init, Double_t sigma_init,
361 Double_t peak_height, Double_t range_width);
362 void BuildBackground(Double_t bkg_estimate, Double_t peak_height,
363 Double_t range_width);
364 void BuildTotalModel();
365 void ConfigureComponentFlagsForPeak(Int_t peak_idx);
366
367 void FixComponent(Int_t peak_idx, const TString &component);
368 void ReleaseComponent(Int_t peak_idx, const TString &component);
369 Bool_t ComponentIsActive(Int_t peak_idx, const TString &component);
370
371 std::vector<RooRealVar *> CollectFloatingParams();
372 std::vector<RooRealVar *> CollectAllParams();
373 RooFitResult *RunFit(Bool_t quiet);
374 Double_t ComputeReducedChi2(RooFitResult *fit_result, Int_t &ndof);
375
376 void SnapshotParams(std::vector<Double_t> &vals, std::vector<Double_t> &errs,
377 std::vector<Bool_t> &consts);
378 void RestoreParams(const std::vector<Double_t> &vals,
379 const std::vector<Double_t> &errs,
380 const std::vector<Bool_t> &consts);
381 void TestLowSideGroup(Int_t peak_idx, Double_t &best_chi2,
382 std::vector<Double_t> &best_vals,
383 std::vector<Double_t> &best_errs,
384 std::vector<Bool_t> &best_const);
385 void TestHighTailIndependent(Int_t peak_idx, Double_t &best_chi2,
386 std::vector<Double_t> &best_vals,
387 std::vector<Double_t> &best_errs,
388 std::vector<Bool_t> &best_const);
389
390 PeakFitResult ExtractPeakResult(Int_t peak_idx);
391
392 // Extract per-parameter diagnostics (value, error, limits, near-limit flags)
393 // from all RooRealVar objects in a channel's peak and background models.
394 std::vector<FitParameterDiagnostic>
395 ExtractParameterDiagnostics(const TString &channel);
396
397 // Single-channel variant for non-simultaneous fits.
398 std::vector<FitParameterDiagnostic> ExtractParameterDiagnosticsSingle();
399
400 void SaveInteractiveParams(const TString &input_name,
401 const TString &peak_name);
402 Bool_t LoadInteractiveParams(const TString &input_name,
403 const TString &peak_name);
404 void AdoptSavedRange(const TString &input_name, const TString &peak_name);
405 void AdoptSavedSimRange(const TString &input_name, const TString &base_label);
406
407 void SortPeaksByMu(Int_t num_peaks);
408 void AppendPeakGraphs(std::vector<TGraph *> &components, Int_t peak_idx,
409 Style_t line_style, RooAbsPdf *background_pdf,
410 Double_t bkg_yield_val, Int_t npts, Double_t x_step,
411 Double_t bin_width);
412
413 void RegisterOwned(RooAbsArg *arg);
414
415public:
417 static constexpr const char *kFitRangeName = "fitrange";
418
425 RooFitUtils();
442 RooFitUtils(const std::vector<Double_t> &events, Float_t fit_range_low,
443 Float_t fit_range_high, Float_t display_bin_width_kev,
444 Bool_t use_flat_background = kFALSE, Bool_t use_step = kFALSE,
445 Bool_t use_low_exp_tail = kFALSE,
446 Bool_t use_low_lin_tail = kFALSE,
447 Bool_t use_high_exp_tail = kFALSE);
449 ~RooFitUtils();
450
457 static std::vector<Double_t> LoadEventsFromTree(TTree *tree,
458 const TString &branch_name);
467 static TH1F *BuildDisplayHistogramFrom(const std::vector<Double_t> &events,
468 Float_t fit_range_low,
469 Float_t fit_range_high,
470 Float_t display_bin_width_kev);
483 static void RefillDisplayHistogram(TH1 *hist,
484 const std::vector<Double_t> &events,
485 Float_t fit_range_low,
486 Float_t fit_range_high,
487 Float_t display_bin_width_kev);
488
491 void SetBackgroundModel(Bool_t use_flat_background) {
492 use_flat_background_ = use_flat_background;
493 }
494
496 void SetStep(Bool_t use_step = kTRUE) { use_step_ = use_step; }
499 void SetLowExpTail(Bool_t use_low_exp_tail = kTRUE) {
500 use_low_exp_tail_ = use_low_exp_tail;
501 }
502
504 void SetLowLinTail(Bool_t use_low_lin_tail = kTRUE) {
505 use_low_lin_tail_ = use_low_lin_tail;
506 }
507
509 void SetHighExpTail(Bool_t use_high_exp_tail = kTRUE) {
510 use_high_exp_tail_ = use_high_exp_tail;
511 }
512
524 void SetInteractive(Bool_t interactive = kTRUE) {
525 interactive_ = interactive;
526 }
527
536 void SetFitDebug(Bool_t fit_debug = kTRUE) { fit_debug_ = fit_debug; }
537
556 void SetRefitAfterLoad(Bool_t refit = kTRUE) { refit_after_load_ = refit; }
557
573 void SetTailRatioMax(Double_t ratio_max) { tail_ratio_max_ = ratio_max; }
574
579 void SetManualParameters(const std::vector<Double_t> &params);
585 void SetManualParameter(Int_t index, Double_t value);
588 use_manual_init_ = kFALSE;
589 manual_params_.clear();
590 }
591
598 void PlotFitSinglePeak(const TString input_name, const TString peak_name,
599 const TString label = "");
606 void PlotFitDoublePeak(const TString input_name, const TString peak_name,
607 const TString label = "");
614 void PlotFitTriplePeak(const TString input_name, const TString peak_name,
615 const TString label = "");
616
629 FitResult FitSinglePeak(const TString input_name, const TString peak_name);
645 FitResult FitDoublePeak(const TString input_name, const TString peak_name,
646 Double_t mu1_init, Double_t mu2_init,
647 Bool_t link_sigma = kFALSE);
656 FitResult FitDoublePeak(const TString input_name, const TString peak_name,
657 const PeakFitResult &constrained_peak,
658 Double_t mu2_init);
667 FitResult FitTriplePeak(const TString input_name, const TString peak_name,
668 const FitResult &constrained_peaks,
669 Double_t mu3_init);
670
709 void AddChannel(
710 const TString &name, const std::vector<Double_t> &events,
711 Float_t fit_range_low, Float_t fit_range_high,
712 Float_t display_bin_width_kev, Int_t num_peaks,
713 const std::vector<Double_t> &mu_inits,
714 Bool_t use_flat_background = kFALSE, Bool_t use_step = kFALSE,
715 Bool_t use_low_exp_tail = kFALSE, Bool_t use_low_lin_tail = kFALSE,
716 Bool_t use_high_exp_tail = kFALSE,
717 const std::vector<Bool_t> &mu_fixed = std::vector<Bool_t>(),
718 Bool_t bkg_yield_fixed = kFALSE, Bool_t bkg_slope_fixed = kFALSE,
719 Bool_t lock_shape_after_seed = kFALSE,
720 const std::vector<Bool_t> &use_step_per_peak = std::vector<Bool_t>(),
721 const std::vector<Bool_t> &shape_lock_per_peak = std::vector<Bool_t>());
727 void LinkParameter(const TString &target, const TString &source);
743 void ConstrainPeakSeparation(const TString &channel, Int_t peak_hi,
744 Int_t peak_lo, Double_t delta, Double_t sigma);
756 void LinkPeakShape(const TString &target_channel, Int_t target_peak,
757 const TString &source_channel, Int_t source_peak);
763 void SeedChannel(const TString &channel_name, const FitResult &result);
784 std::vector<FitResult> FitSimultaneous(const TString &input_name,
785 const TString &base_label);
786
806 void DumpChannelCSV(const TString &channel, const TString &csv_path,
807 Int_t npts = 1000);
808};
809
810#endif
Binned chi-squared photopeak fitting on a TF1 + Minuit2 backend.
Custom RooFit PDF components for gamma-ray photopeak fitting.
RooCmdArg BestAvailableBackend()
The best RooFit evaluation backend this build supports.
void ClearManualParameters()
Discard manual starting values and return to automatic guesses.
void LinkParameter(const TString &target, const TString &source)
Tie one parameter to another, fitting them as one degree of freedom.
void SetLowExpTail(Bool_t use_low_exp_tail=kTRUE)
Offer the low-energy exponential tail.
RooFitUtils()
Construct in simultaneous mode.
void SetStep(Bool_t use_step=kTRUE)
Offer the step shelf to the component search.
void ConstrainPeakSeparation(const TString &channel, Int_t peak_hi, Int_t peak_lo, Double_t delta, Double_t sigma)
Constrain the spacing between two peaks to a known value.
void PlotFitSinglePeak(const TString input_name, const TString peak_name, const TString label="")
Draw and save the single-peak fit with its residual panel.
void LinkPeakShape(const TString &target_channel, Int_t target_peak, const TString &source_channel, Int_t source_peak)
Tie a peak's whole shape to another peak's.
void SeedChannel(const TString &channel_name, const FitResult &result)
Use a prior single-channel fit as starting values for a channel.
void DumpChannelCSV(const TString &channel, const TString &csv_path, Int_t npts=1000)
Export a converged channel to CSV for plotting elsewhere.
void SetInteractive(Bool_t interactive=kTRUE)
Open the GUI editor after the automated fit.
void SetBackgroundModel(Bool_t use_flat_background)
Choose the background shape.
void SetHighExpTail(Bool_t use_high_exp_tail=kTRUE)
Offer the high-energy exponential tail.
void SetTailRatioMax(Double_t ratio_max)
Cap the dimensionless tail decay ratio tau / sigma.
void SetRefitAfterLoad(Bool_t refit=kTRUE)
Treat saved interactive parameters as a seed, not as the answer.
void PlotFitTriplePeak(const TString input_name, const TString peak_name, const TString label="")
Draw and save the triple-peak fit with its residual panel.
void SetLowLinTail(Bool_t use_low_lin_tail=kTRUE)
Offer the low-energy linear tail.
static std::vector< Double_t > LoadEventsFromTree(TTree *tree, const TString &branch_name)
Read a branch into the event vector the constructor expects.
FitResult FitSinglePeak(const TString input_name, const TString peak_name)
Fit one peak, pruning components that do not earn their place.
FitResult FitTriplePeak(const TString input_name, const TString peak_name, const FitResult &constrained_peaks, Double_t mu3_init)
Fit three peaks with the first two constrained by an earlier fit.
void SetFitDebug(Bool_t fit_debug=kTRUE)
Un-suppress RooFit evaluation errors during a simultaneous fit.
void PlotFitDoublePeak(const TString input_name, const TString peak_name, const TString label="")
Draw and save the double-peak fit with its residual panel.
static void RefillDisplayHistogram(TH1 *hist, const std::vector< Double_t > &events, Float_t fit_range_low, Float_t fit_range_high, Float_t display_bin_width_kev)
Rebin an existing display histogram in place.
static TH1F * BuildDisplayHistogramFrom(const std::vector< Double_t > &events, Float_t fit_range_low, Float_t fit_range_high, Float_t display_bin_width_kev)
Bin events into a display histogram.
std::vector< FitResult > FitSimultaneous(const TString &input_name, const TString &base_label)
Run one joint extended-likelihood fit across every channel.
void AddChannel(const TString &name, const std::vector< Double_t > &events, Float_t fit_range_low, Float_t fit_range_high, Float_t display_bin_width_kev, Int_t num_peaks, const std::vector< Double_t > &mu_inits, Bool_t use_flat_background=kFALSE, Bool_t use_step=kFALSE, Bool_t use_low_exp_tail=kFALSE, Bool_t use_low_lin_tail=kFALSE, Bool_t use_high_exp_tail=kFALSE, const std::vector< Bool_t > &mu_fixed=std::vector< Bool_t >(), Bool_t bkg_yield_fixed=kFALSE, Bool_t bkg_slope_fixed=kFALSE, Bool_t lock_shape_after_seed=kFALSE, const std::vector< Bool_t > &use_step_per_peak=std::vector< Bool_t >(), const std::vector< Bool_t > &shape_lock_per_peak=std::vector< Bool_t >())
Register one spectrum as a channel of the simultaneous fit.
FitResult FitDoublePeak(const TString input_name, const TString peak_name, Double_t mu1_init, Double_t mu2_init, Bool_t link_sigma=kFALSE)
Fit two peaks from centroid guesses.
static constexpr const char * kFitRangeName
Name of the RooFit range this class fits over.
~RooFitUtils()
Destroys every RooFit object this instance created.
void SetManualParameter(Int_t index, Double_t value)
Override one starting value.
void SetManualParameters(const std::vector< Double_t > &params)
Supply explicit starting values for every parameter.
Factories for the custom photopeak PDF components.
RooAbsPdf * MakeLowExpTail(const TString &name, RooRealVar &x, RooRealVar &mu, RooRealVar &sigma, RooRealVar &tau_ratio)
Build a LowExpTail component.
RooAbsPdf * MakeLowLinTail(const TString &name, RooRealVar &x, RooRealVar &mu, RooRealVar &sigma, RooRealVar &slope)
Build a LowLinTail component.
RooAbsPdf * MakeGaussian(const TString &name, RooRealVar &x, RooRealVar &mu, RooRealVar &sigma)
Build a Gaussian component.
RooAbsPdf * MakeLinearBackground(const TString &name, RooRealVar &x, RooRealVar &slope)
Build a linear background component.
RooAbsPdf * MakeHighExpTail(const TString &name, RooRealVar &x, RooRealVar &mu, RooRealVar &sigma, RooRealVar &tau_ratio)
Build a HighExpTail component.
RooAbsPdf * MakeStepShelf(const TString &name, RooRealVar &x, RooRealVar &mu, RooRealVar &sigma)
Build a StepShelf component.
Result of one fit: peaks, background, quality, and diagnostics.
Fitted parameters and errors for one peak.
The RooFit objects making up one channel's background.
One channel of a simultaneous fit: its data, model and locks.
std::vector< Bool_t > use_step_per_peak
std::vector< Double_t > mu_inits
std::vector< Bool_t > shape_lock_per_peak
std::vector< Bool_t > mu_fixed
std::vector< Double_t > events
Every RooFit object making up one peak.
RooRealVar * sigma
RooFormulaVar * high_exp_yield
RooRealVar * ratio_low_exp
RooAbsPdf * low_exp_pdf
RooRealVar * ratio_low_lin
RooRealVar * slope_low_lin
RooRealVar * tau_ratio_low_exp
RooFormulaVar * low_exp_yield
RooAbsPdf * low_lin_pdf
RooRealVar * ratio_step
RooAbsPdf * gauss_pdf
RooRealVar * mu
RooAbsPdf * step_pdf
RooRealVar * tau_ratio_high_exp
RooAbsPdf * high_exp_pdf
RooFormulaVar * low_lin_yield
RooRealVar * ratio_high_exp
RooFormulaVar * step_yield
RooRealVar * gaus_yield
A known spacing between two peaks, imposed as a Gaussian penalty.
Int_t peak_hi
Index of the upper peak.
Double_t delta
Known separation, in the observable's units.
Int_t peak_lo
Index of the lower peak.
Double_t sigma
Uncertainty on delta; must be positive.
TString channel
Channel the two peaks belong to.