158 ClassImp(TFractionFitter);
164 TFractionFitter::TFractionFitter() :
166 fLowLimitX(0), fHighLimitX(0),
167 fLowLimitY(0), fHighLimitY(0),
168 fLowLimitZ(0), fHighLimitZ(0),
169 fData(0), fIntegralData(0),
194 TFractionFitter::TFractionFitter(TH1* data, TObjArray *MCs, Option_t *option) :
195 fFitDone(kFALSE), fChisquare(0), fPlot(0) {
199 fHighLimitX = fData->GetNbinsX();
200 if (fData->GetDimension() > 1) {
202 fHighLimitY = fData->GetNbinsY();
203 if (fData->GetDimension() > 2) {
205 fHighLimitZ = fData->GetNbinsZ();
208 fNpar = MCs->GetEntries();
210 for (par = 0; par < fNpar; ++par) {
211 fMCs.Add(MCs->At(par));
213 TString s = Form(
"Prediction for MC sample %i",par);
214 TH1* pred = (TH1*) ((TH1*)MCs->At(par))->Clone(s);
218 fIntegralMCs =
new Double_t[fNpar];
219 fFractions =
new Double_t[fNpar];
222 fWeights.Expand(fNpar);
224 fFractionFitter =
new ROOT::Fit::Fitter();
229 if (opt.Contains(
"Q") ) {
230 fFractionFitter->Config().MinimizerOptions().SetPrintLevel(0);
232 else if (opt.Contains(
"V") ) {
233 fFractionFitter->Config().MinimizerOptions().SetPrintLevel(2);
236 fFractionFitter->Config().MinimizerOptions().SetPrintLevel(1);
238 Double_t defaultFraction = 1.0/((Double_t)fNpar);
239 Double_t defaultStep = 0.01;
241 std::vector<ROOT::Fit::ParameterSettings> & parameters = fFractionFitter->Config().ParamsSettings();
242 parameters.reserve(fNpar);
243 for (par = 0; par < fNpar; ++par) {
244 TString name(
"frac"); name += par;
245 parameters.push_back(ROOT::Fit::ParameterSettings(name.Data(), defaultFraction, defaultStep) );
248 if (fFractionFitter->Config().MinimizerOptions().ErrorDef() == 1.0 )
249 fFractionFitter->Config().MinimizerOptions().SetErrorDef(0.5);
256 TFractionFitter::~TFractionFitter() {
257 if (fFractionFitter)
delete fFractionFitter;
258 delete[] fIntegralMCs;
260 if (fPlot)
delete fPlot;
270 void TFractionFitter::SetData(TH1* data) {
282 void TFractionFitter::SetMC(Int_t parm, TH1* MC) {
297 void TFractionFitter::SetWeight(Int_t parm, TH1* weight) {
299 if (fWeights[parm]) {
300 fWeights.RemoveAt(parm);
303 if (weight->GetNbinsX() != fData->GetNbinsX() ||
304 (fData->GetDimension() > 1 && weight->GetNbinsY() != fData->GetNbinsY()) ||
305 (fData->GetDimension() > 2 && weight->GetNbinsZ() != fData->GetNbinsZ())) {
306 Error(
"SetWeight",
"Inconsistent weights histogram for source %d", parm);
309 TString ts =
"weight hist: "; ts += weight->GetName();
310 fWeights.AddAt(weight,parm);
318 ROOT::Fit::Fitter* TFractionFitter::GetFitter()
const {
319 return fFractionFitter;
326 void TFractionFitter::CheckParNo(Int_t parm)
const {
327 if (parm < 0 || parm > fNpar) {
328 Error(
"CheckParNo",
"Invalid parameter number %d",parm);
340 void TFractionFitter::SetRangeX(Int_t low, Int_t high) {
341 fLowLimitX = (low > 0 ) ? low : 1;
342 fHighLimitX = ( high > 0 && high <= fData->GetNbinsX()) ? high : fData->GetNbinsX();
349 void TFractionFitter::ReleaseRangeX() {
351 fHighLimitX = fData->GetNbinsX();
363 void TFractionFitter::SetRangeY(Int_t low, Int_t high) {
364 if (fData->GetDimension() < 2) {
365 Error(
"SetRangeY",
"Y range cannot be set for 1D histogram");
369 fLowLimitY = (low > 0) ? low : 1;
370 fHighLimitY = (high > 0 && high <= fData->GetNbinsY()) ? high : fData->GetNbinsY();
377 void TFractionFitter::ReleaseRangeY() {
379 fHighLimitY = fData->GetNbinsY();
392 void TFractionFitter::SetRangeZ(Int_t low, Int_t high) {
393 if (fData->GetDimension() < 3) {
394 Error(
"SetRangeZ",
"Z range cannot be set for 1D or 2D histogram");
399 fLowLimitZ = (low > 0) ? low : 1;
400 fHighLimitZ = (high > 0 && high <= fData->GetNbinsZ()) ? high : fData->GetNbinsZ();
407 void TFractionFitter::ReleaseRangeZ() {
409 fHighLimitZ = fData->GetNbinsZ();
417 void TFractionFitter::ExcludeBin(Int_t bin) {
418 int excluded = fExcludedBins.size();
419 for (
int b = 0; b < excluded; ++b) {
420 if (fExcludedBins[b] == bin) {
421 Error(
"ExcludeBin",
"bin %d already excluded", bin);
425 fExcludedBins.push_back(bin);
434 void TFractionFitter::IncludeBin(Int_t bin) {
435 for (std::vector<Int_t>::iterator it = fExcludedBins.begin();
436 it != fExcludedBins.end(); ++it) {
438 fExcludedBins.erase(it);
444 Error(
"IncludeBin",
"bin %d was not excluded", bin);
451 bool TFractionFitter::IsExcluded(Int_t bin)
const {
452 for (
unsigned int b = 0; b < fExcludedBins.size(); ++b)
453 if (fExcludedBins[b] == bin)
return true;
462 void TFractionFitter::Constrain(Int_t parm, Double_t low, Double_t high) {
464 assert( parm >= 0 && parm < (
int) fFractionFitter->Config().ParamsSettings().size() );
465 fFractionFitter->Config().ParSettings(parm).SetLimits(low,high);
471 void TFractionFitter::UnConstrain(Int_t parm) {
473 fFractionFitter->Config().ParSettings(parm).RemoveLimits();
483 void TFractionFitter::CheckConsistency() {
485 Error(
"CheckConsistency",
"Nonexistent data histogram");
488 Int_t minX, maxX, minY, maxY, minZ, maxZ;
490 GetRanges(minX, maxX, minY, maxY, minZ, maxZ);
493 for (z = minZ; z <= maxZ; ++z) {
494 for (y = minY; y <= maxY; ++y) {
495 for (x = minX; x <= maxX; ++x) {
496 if (IsExcluded(fData->GetBin(x, y, z)))
continue;
498 fIntegralData += fData->GetBinContent(x, y, z);
502 if (fIntegralData <= 0) {
503 Error(
"CheckConsistency",
"Empty data histogram");
506 TClass* cl = fData->Class();
508 fNDF = fNpfits - fNpar;
511 Error(
"CheckConsistency",
"Need at least two MC histograms");
515 for (par = 0; par < fNpar; ++par) {
516 TH1 *h = (TH1*)fMCs.At(par);
518 Error(
"CheckConsistency",
"Nonexistent MC histogram for source #%d",par);
521 if ((! h->Class()->InheritsFrom(cl)) || h->GetNbinsX() != fData->GetNbinsX() ||
522 (fData->GetDimension() > 1 && h->GetNbinsY() != fData->GetNbinsY()) ||
523 (fData->GetDimension() > 2 && h->GetNbinsZ() != fData->GetNbinsZ())) {
524 Error(
"CheckConsistency",
"Histogram inconsistency for source #%d",par);
527 fIntegralMCs[par] = 0;
528 for (z = minZ; z <= maxZ; ++z) {
529 for (y = minY; y <= maxY; ++y) {
530 for (x = minX; x <= maxX; ++x) {
531 Int_t bin = fData->GetBin(x, y, z);
532 if (IsExcluded(bin))
continue;
533 Double_t MCEvents = h->GetBinContent(bin);
535 Error(
"CheckConsistency",
"Number of MC events (bin = %d, par = %d) cannot be negative: "
536 " their distribution is binomial (see paper)", bin, par);
538 fIntegralMCs[par] += MCEvents;
542 if (fIntegralMCs[par] <= 0) {
543 Error(
"CheckConsistency",
"Empty MC histogram #%d",par);
552 TFitResultPtr TFractionFitter::Fit() {
556 delete fPlot; fPlot = 0;
560 ROOT::Math::Functor fcnFunction(
this, &TFractionFitter::EvaluateFCN, fNpar);
561 fFractionFitter->SetFCN(static_cast<ROOT::Math::IMultiGenFunction&>(fcnFunction));
564 Bool_t status = fFractionFitter->FitFCN();
565 if (!status) Warning(
"Fit",
"Abnormal termination of minimization.");
570 ComputeChisquareLambda();
573 TFitResult* fr =
new TFitResult(fFractionFitter->Result());
574 TString name = TString::Format(
"TFractionFitter_result_of_%s",fData->GetName() );
575 fr->SetName(name); fr->SetTitle(name);
576 return TFitResultPtr(fr);
582 void TFractionFitter::ErrorAnalysis(Double_t UP) {
584 Error(
"ErrorAnalysis",
"Fit not yet performed");
589 Double_t up = UP > 0 ? UP : 0.5;
590 fFractionFitter->Config().MinimizerOptions().SetErrorDef(up);
591 Bool_t status = fFractionFitter->CalculateMinosErrors();
593 Error(
"ErrorAnalysis",
"Error return from MINOS: %d",fFractionFitter->Result().Status());
601 void TFractionFitter::GetResult(Int_t parm, Double_t& value, Double_t& error)
const {
604 Error(
"GetResult",
"Fit not yet performed");
607 value = fFractionFitter->Result().Parameter(parm);
608 error = fFractionFitter->Result().Error(parm);
620 TH1* TFractionFitter::GetPlot() {
622 Error(
"GetPlot",
"Fit not yet performed");
627 const Double_t * par = fFractionFitter->Result().GetParams();
629 ComputeFCN(f, par, 3);
638 void TFractionFitter::GetRanges(Int_t& minX, Int_t& maxX, Int_t& minY, Int_t& maxY,
639 Int_t& minZ, Int_t& maxZ)
const {
640 if (fData->GetDimension() < 2) {
641 minY = maxY = minZ = maxZ = 0;
644 }
else if (fData->GetDimension() < 3) {
663 void TFractionFitter::ComputeFCN(Double_t& f,
const Double_t* xx, Int_t flag)
667 Int_t minX, maxX, minY, maxY, minZ, maxZ;
669 GetRanges(minX, maxX, minY, maxY, minZ, maxZ);
670 for (mc = 0; mc < fNpar; ++mc) {
672 TH1 *h = (TH1*)fMCs[mc];
673 TH1 *hw = (TH1*)fWeights[mc];
676 for (z = minZ; z <= maxZ; ++z) {
677 for (y = minY; y <= maxY; ++y) {
678 for (x = minX; x <= maxX; ++x) {
679 if (IsExcluded(fData->GetBin(x, y, z)))
continue;
680 Double_t weight = hw->GetBinContent(x, y, z);
682 Error(
"ComputeFCN",
"Invalid weight encountered for MC source %d",mc);
685 tot += weight * h->GetBinContent(x, y, z);
689 }
else tot = fIntegralMCs[mc];
690 fFractions[mc] = xx[mc] * fIntegralData / tot;
694 TString ts =
"Fraction fit to hist: "; ts += fData->GetName();
695 fPlot = (TH1*) fData->Clone(ts.Data());
700 for (z = minZ; z <= maxZ; ++z) {
701 for (y = minY; y <= maxY; ++y) {
702 for (x = minX; x <= maxX; ++x) {
703 bin = fData->GetBin(x, y, z);
704 if (IsExcluded(bin))
continue;
708 Double_t ti = 0.0; Double_t aki = 0.0;
709 FindPrediction(bin, ti, k0, aki);
711 Double_t prediction = 0;
712 for (mc = 0; mc < fNpar; ++mc) {
713 TH1 *h = (TH1*)fMCs[mc];
714 TH1 *hw = (TH1*)fWeights[mc];
715 Double_t binPrediction;
716 Double_t binContent = h->GetBinContent(bin);
717 Double_t weight = hw ? hw->GetBinContent(bin) : 1;
718 if (k0 >= 0 && fFractions[mc] == fFractions[k0]) {
721 binPrediction = binContent > 0 ? binContent / (1+weight*fFractions[mc]*ti) : 0;
724 prediction += fFractions[mc]*weight*binPrediction;
725 result -= binPrediction;
726 if (binContent > 0 && binPrediction > 0)
727 result += binContent*TMath::Log(binPrediction);
730 ((TH1*)fAji.At(mc))->SetBinContent(bin, binPrediction);
735 fPlot->SetBinContent(bin, prediction);
738 result -= prediction;
739 Double_t found = fData->GetBinContent(bin);
740 if (found > 0 && prediction > 0)
741 result += found*TMath::Log(prediction);
754 void TFractionFitter::FindPrediction(
int bin, Double_t &t_i,
int& k_0, Double_t &A_ki)
const {
755 std::vector<Double_t> wgtFrac(fNpar);
756 std::vector<Double_t> a_ji(fNpar);
757 Double_t d_i = fData->GetBinContent(bin);
761 for (Int_t par = 0; par < fNpar; ++par) {
762 a_ji[par] = ((TH1*)fMCs.At(par))->GetBinContent(bin);
763 TH1* hw = (TH1*)fWeights.At(par);
764 wgtFrac[par] = hw ? hw->GetBinContent(bin) * fFractions[par] : fFractions[par];
765 if (wgtFrac[par] == 0) {
766 Error(
"FindPrediction",
"Fraction[%d] = 0!", par);
772 if (TMath::Nint(d_i) == 0) {
782 Double_t maxWgtFrac = wgtFrac[0];
783 for (Int_t par = 1; par < fNpar; ++par) {
784 if (wgtFrac[par] > maxWgtFrac) {
786 maxWgtFrac = wgtFrac[par];
789 Double_t t_min = -1 / maxWgtFrac;
792 Int_t nMax = 1; Double_t contentsMax = a_ji[k_0];
793 for (Int_t par = 0; par < fNpar; ++par) {
794 if (par == k_0)
continue;
795 if (wgtFrac[par] == maxWgtFrac) {
797 contentsMax += a_ji[par];
803 if (contentsMax == 0) {
804 A_ki = d_i / (1.0 + maxWgtFrac);
805 for (Int_t par = 0; par < fNpar; ++par) {
806 if (par == k_0 || wgtFrac[par] == maxWgtFrac)
continue;
807 A_ki -= a_ji[par] * wgtFrac[par] / (maxWgtFrac - wgtFrac[par]);
820 t_i = 0; Double_t step = 0.2;
821 Int_t maxIter = 100000;
822 for(Int_t i = 0; i < maxIter; ++i) {
823 if (t_i >= 1 || t_i < t_min) {
827 Double_t func = - d_i / (1.0 - t_i);
828 Double_t deriv = func / (1.0 - t_i);
829 for (Int_t par = 0; par < fNpar; ++par) {
830 Double_t r = 1.0 / (t_i + 1.0 / wgtFrac[par]);
831 func += a_ji[par] * r;
832 deriv -= a_ji[par] * r * r;
834 if (TMath::Abs(func) < 1e-12)
return;
835 Double_t delta = - func / deriv;
836 if (TMath::Abs(delta) > step)
837 delta = (delta > 0) ? step : -step;
839 if (TMath::Abs(delta) < 1e-13)
return;
842 Warning(
"FindPrediction",
"Did not find solution for t_i in %d iterations", maxIter);
852 void TFractionFitFCN(Int_t& npar, Double_t* gin, Double_t& f, Double_t* par, Int_t flag) {
853 TFractionFitter* fitter =
dynamic_cast<TFractionFitter*
>(fFractionFitter->GetObjectFit());
855 Error(
"TFractionFitFCN",
"Invalid fit object encountered!");
858 fitter->ComputeFCN(npar, gin, f, par, flag);
880 Double_t TFractionFitter::GetChisquare()
const
891 Int_t TFractionFitter::GetNDF()
const
893 if (fNDF == 0)
return fNpfits-fNpar;
900 Double_t TFractionFitter::GetProb()
const
902 Int_t ndf = fNpfits - fNpar;
903 if (ndf <= 0)
return 0;
904 return TMath::Prob(fChisquare,ndf);
911 void TFractionFitter::ComputeChisquareLambda()
914 Error(
"ComputeChisquareLambda",
"Fit not yet (successfully) performed");
923 Int_t minX, maxX, minY, maxY, minZ, maxZ;
924 GetRanges(minX, maxX, minY, maxY, minZ, maxZ);
928 for(Int_t x = minX; x <= maxX; x++) {
929 for(Int_t y = minY; y <= maxY; y++) {
930 for(Int_t z = minZ; z <= maxZ; z++) {
931 if (IsExcluded(fData->GetBin(x, y, z)))
continue;
932 Double_t di = fData->GetBinContent(x, y, z);
933 Double_t fi = fPlot->GetBinContent(x, y, z);
934 if(fi != 0) logLyn += di * TMath::Log(fi) - fi;
935 if(di != 0) logLmn += di * TMath::Log(di) - di;
936 for(Int_t j = 0; j < fNpar; j++) {
937 Double_t aji = ((TH1*)fMCs.At(j))->GetBinContent(x, y, z);
938 Double_t bji = ((TH1*)fAji.At(j))->GetBinContent(x, y, z);
939 if(bji != 0) logLyn += aji * TMath::Log(bji) - bji;
940 if(aji != 0) logLmn += aji * TMath::Log(aji) - aji;
946 fChisquare = -2*logLyn + 2*logLmn;
958 TH1* TFractionFitter::GetMCPrediction(Int_t parm)
const
962 Error(
"GetMCPrediction",
"Fit not yet performed");
965 return (TH1*) fAji.At(parm);