Fitting fractions and the constraints needed for that

In our group we have developed a fitting framework based on HistFactory and RooFit that usually uses the signal strengths of the signal and background processes as the fitting parameters.

However for what i am doing now i need to reparametrize these to fractions.

So i go from the parameters

mu_1, mu_2, mu_3 (signal strengths/scaling of histograms)

to Ntot, f_1, f_2, f_3 (overall scaling of all histograms and the fractions)

by expressing the original parameters as functions of the new ones.

However i need the hard constraints that all the fraction parameters are between 0 and 1 and that they sum up to one.

What i tried to far is to express f_3 as 1-f_1-f_2 to satisfy the sum condition. Sadly this means that i have no way to control f_3 to be between 0 and 1. This also causes the problem that i have no handle on the uncertainties of f_3.

Is there a way to keep all 3 fractions in with their values bound between 0 and 1 AND force their sum to be equal to 1?

You have to add a constraint term. In Pseudo-code, it’s something like

RooAddition constrSum(..., ..., RooArgSet(f1, f2, f3));
RooRealVar targetSum(..., ..., 1);
RooRealVar constrStrength(..., ..., 0.001); // Can adjust impact of constraint here
RooGaussian constraint(..., ..., targetSum, constrSum, constrStrength);

Now, you have two ways of adding this constraint to the likelihood:

  1. “Internal” Make a product pdf of you current model and add the constraint to this model.
  2. You add it just before fitting.

Those are demonstrated here:
https://root.cern.ch/doc/master/rf604__constraints_8C.html

Depending on how you want to use/store the model, one or the other can be more helpful.

You may also check out the factory("EDIT:: function or RooCustomizer directly:
It replaces nodes in an existing model.
https://root.cern.ch/doc/master/rf513__wsfactory__tools_8C.html
[Online version broken, fixing it now] $ROOTSYS/tutorials/roofit/rf514_RooCustomizer.C

Thanks for the advice. I tried this but still do not get good enough results.

Like with the fit i was doing before (f_3=1-Sum) i am getting different nominal values compared to the fit using the signal strengths directly, which automatically includes all of these constraints onto the fractions and is what we have been using in previous analysis.

Here i tried different values of constrStrength. For anything larger than 0.005 i get pretty different values compared to the mu fit. For 0.005 itself i get an error for the BKG only fit

Minuit2Minimizer: Minimize with max-calls 7500 convergence for edm < 1 strategy 1
MnSeedGenerator: for initial parameters FCN = -1e+30
...
Info in <Minuit2>: CombinedMinimumBuilder: both migrad and simplex method fail.
Info in <Minuit2>: Minuit2Minimizer::Minimize : Minimization did NOT converge, Edm is above max
Minuit2Minimizer : Invalid Minimum - status = 3
FVAL  = -1e+30
Edm   = 1e+30
Nfcn  = 55

for values even smaller this also happens to the fit including the signal.
Is there any way to fix this?

Otherwise i will probably try the fit where i eliminate one parameter again but also add a heavyside part to the pdf to that to make sure that the sum does not get larger than one.

What is the best way to add a Stepfunction constraint term for the sum of the other fraction parameters?

How did you implement the constraint? Maybe there’s a typo. The fact that the function is supposed to be -1E30 looks suspicious.

A step function is a bad way to constrain a parameter, because its gradient almost always vanishes. That means that if the fitter goes into the “wrong” direction, it doesn’t “see” where the “right” direction is to correct the mistake. That’s why you need something that has a non-vanishing derivative.
People often use quadratic terms for this, or Gaussians.

It is implemented as:

  RooAddition constrSum("add","add", RooArgList(*f_WZLL,*f_WZLT,*f_WZTL,*f_WZTT));
  RooRealVar targetSum("target", "target", 1.00);
  RooRealVar constrStrength("strength","strength", 0.005); // Can adjust impact of constraint here
  RooGaussian constraint("constraint","constraint", constrSum, targetSum, constrStrength);
...
  const RooArgList constraintset(constraint);
  return pdf->fitTo(*data, ExternalConstraints(constraintset), Save(),
          SumW2Error(false),//PrintLevel(-1),// Warnings(false),
          Minimizer("Minuit2", "minimize"),Strategy(2),//Offset(true),
          Hesse(true),Minos(true),//PrintEvalErrors(-1),
          Extended(true));//,NumCPU(5));  Range()

I tested this for different values of “constrStrength”. For 1 i obviously get poor values and large uncertainties. For 0.1 and 0.01 i get slightly off values and decent uncertainties. For values even smaller i get the errors above.

I know that Non-differentiable functions are bad for this. However i do need pretty hard constrains for that because that is the physics behind this that the fraction can not be negative and i want to reproduce the results of the fit using “mus” where this is all true by default. So i would need a very strong constraint on the Sum of the remaining fractions to be lower than 1.

Some results from the different fits:

mu fit:
mu=0.9165+0.5137-0.5545
muLT=1.7416+5.2248-1.7416
muTL=1.0054+4.7772-1.0054
muTT=0.905+0.1962-0.1967

fit with 3 fraction parameters (f_TT removed)(nominal values recalculated from Ntot and f_X values)
mu=0.9157
muLT=1.7414
muTL=1.0142
muTT=0.9037

fit with 3 fraction parameters (f_LTremoved)(nominal values recalculated from Ntot and f_X values)
mu=0.9113
muLT=1.8804
muTL=0.888
muTT=0.8986

fit with 4 fraction parameters (gauss constraint on Sum=1 with strength=0.008)(nominal values recalculated from Ntot and f_X values)
mu=0.9376
muLT=1.3251
muTL=1.1847
muTT=0.9124
(1-Sum of fractions=-0.0001)

We can see that using the 3 Parameter fit removing f_TT gives results very close to the mu fit(i would still like them to agree more to be honest) but that the one where i remove LT gives fairly worse results. The one with the gaussian constraint also gives significantly worse values compared to the nominal fit.

For the first fraction fit it might be enough to increase the fit precision a bit (can that be done?) while for the second one i think the Sum(3 fractions)<1 is necessary. For the last one i do not know what to do.

1 Like

I just realised that you go from 3 parameters to 4 (Ntot floats, doesn’t it?), so there must be ambiguities and large uncertainties/correlations. I would therefore express one fraction parameter by 1 - frac1 - frac2, and set their ranges to [0, 1].
In addition, add the constraint that the fractions sum to 1 using something that rises fast, e.g. x^2 or higher powers. Something like (x<0) * x*x + (x>1) * (x-1)*(x-1)

It’s presumably best to eliminate the fraction parameter that has the highest correlations with the others.

You can calculate the uncertainty of frac3 using “standard” error propagation, but you have to take into account the correlation term between frac1 and frac2 when you do so.

Yes, it’s the epsilon of the minimiser:
https://root.cern.ch/doc/master/classRooMinimizer.html#a8c6dd7bc917072bfead2e6ce7e8ffa83

https://root.cern.ch/doc/master/rf601__intminuit_8C.html

I go from 4 parameters (mu(_LL),mu_LT,mu_TL,mu_TT) to 4 Ntot, f_LL,f_LT,f_TL,f_TT.

and did reparametrization so that i express one of the fractions as 1- the others.

So mu_LT=Ntot*f_LT/N0(LT) for LT,TL,LL

and mu_TT=Ntot*(1-f_LL-f_LT-f_TL)/N0(TT)

and set the ranges for f_LL,f_LT,f_TL to [0,1]

this way i assure that all fractions sum to 1 (because that is how the last one is defined). these are the fits with 3 fraction i mentioned above. Here the problem is just that the fit could set all 3 fractions to something like 0.8 making the implicit fraction f_TT=-1.4

In this approach i eliminate f_TT because it is the one with the lowest risk of becoming negative (see values above).

LT and TL are very similar in shape so i would like to eliminate one of them instead but then i run the problem of the implicit fraction becoming negativ.

So here i should add a fast rising constraint that the the sum of the 3 explicit fractions is smaller than 1.

What would be the best way to add that to the fit (ideally in pseudo code).

Then i could either do error propagation for the last parameter uncertainties or when the fits give the exact same results regardless of which parameter i make implicit i can just run the fit twice to get the uncertainties for all parameters. Although standard propagation is probably faster.

Yes, it’s the epsilon of the minimiser:
ROOT: RooMinimizer Class Reference

ROOT: tutorials/roofit/rf601_intminuit.C File Reference

Is there an easy way to set this when using pdf->fitTo() or do i have to switch to the interactive fitting?

I guess

RooFormulaVar x(..., ..., "1-f1-f2", RooArgSet(f1, f2))
RooGenericPdf constraintPdf(..., ..., "(x<0)*x*x*x*x + (x>1)*x*x*x*x", x);

should go in the right direction. (Or a different constraint formula, or x*x, etc).

You can set some global fitter settings in ROOT before using RooFit:
ROOT::Math::MinimizerOptions
I believe the tolerance is what you are looking for.

1 Like

Setting ROOT::Math::MinimizerOptions::SetDefaultTolerance() to some value does not seem to change anything for the fit.The “edm” values that it stops at are unchanged.

And it seems that i can not pass that as an option when using fitTo(). At least i can not find them here.

Hi,
Yes, it is correct there is no option in fitTo. If you want to modify the tolerance, you need to create the NLL and use the RooMinimizer class to minimise it. In the RooMinimizer you can call RooMinimizer::setEps. The default value used by RooFit is 1.0, you can try using smaller (or larger) values

Lorenzo

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.