I've been having some issues using the PyRoot implementation of RooFit.
After much debugging, I decided to strip out the essential code and try it
in both a .C macro and the PyRoot implementation. Both are attached to this
post.
I'm working with B decays and looking at deltaT, the difference in flight
time between two B's. This really doesn't matter, but I include this
explanation for completeness.
The code reads in two numbers from the accompanying text file: deltaT and
the error on deltaT. I want to fit deltaT where I *fix* the flight time of
the true B and assume that resolution effects in my detector are smearing
the true distribution. So I create the Gaussian model using two Gaussians,
one of which is dependent on the *per event errors* read in from the text
file. I then create the RooDecay PDF, use this to make a RooExtendPdf (for
extended ML fits, and fit. This is similar to the RooFit tutorials rf306
and rf307, except I do not make a RooProdPdf.
Both the .C and .py version fit exactly the same and return exactly the
same values.
Here's where things break down....
When I plot the *projection* of the PDF onto the data, they give very
different results. I *believe* the error lies in the implementation of the
ProjWData argument to RooAbsPdf.plotOn(). This argument specifies which
variables should or should not be integrated over....I think. I'm sure
Wouter could explain that better than I.
In the .py script, the ProjWData seems to have no effect, while it does
change things in the .C file.
I hope these scripts and summary of our experience is a help in debugging
this. Thanks in advance.
Tomo
it’s an ownership issue: even though the interface o ProjWData takes a const& (which allows temporaries to be passed), internally the RooFit code ends up taking a pointer to that temporary.
To fix, extend the lifetime of the RooArgSet until at least beyond the plotOn call:argset = RooArgSet(SDeltaT)
total.plotOn(frame, RooFit.ProjWData(argset,Data))
Cheers,
Wim
Thanks from both Tomo and I on this. We had been going around and around on this issue.
But a further question: is this a bug or a feature? How is ProjWData different from other parameters that can be passed in? Is this a bug in how RooFit is written?
While the fit converged (for this example) it's disconcerting to me that I can use ProjWData just like any other parameter with plotOn...get no errors...and yet not get the intended plot. I'm not criticizing PyRoot...or even RooFit for that matter...but I'm nervous about this implementation. I would've been happier with an error in PyRoot if there was a problem with persistence. Or am I asking for too much?
the difference in behavior between python and C++ is a technicality: the life-time of temporary objects is determined differently.
However, I do think that the roofit implementation is inviting problems, rather than python life-time being an issue. E.g. in roofit/roofitcore/src/RooAbsCollection.cxx where the RooArgSet ends up in the RooAbsCollection::add() member function somewhere down from the ProjWData call, the input to add is either a const RooAbsArg& or a const RooAbsCollection& which could be temporaries. However, the code then proceeds in casting away the const-ness using a function-style cast and taking a non-const pointer to the possibly temporary object.