GooFit 2.1 introduces the full-featured Python bindings to GooFit. These bindings mimic the C++ usage of GooFit, including bindings for all PDFs, and also provide NumPy-centric conversions, live Jupyter notebook printing, pip install, and more. Most of the examples in C++ are provided in Python form, as well.
Several other API changes were made. Observables are now distinguished from Variables and provided as a separate class. Both these classes are now passed around by copy everywhere.1 The three and four body amplitude classes have been refactored and simplified. OpenMP is now supported via homebrew on macOS; GooFit is one of the only packages that currently can build with OpenMP on the default macOS compiler. Eigen is now available, and CLI11 has been updated to version 1.3.
GooFit 2.1 will receive continuing support while development on GooFit 2.2 presses on with a new indexing scheme for PDFs.
Comparison of C++ and Python syntax
This is a basic example that creates an exponential and fits it.
Initialization
C++
You will need to include the parts of GooFit you plan to use, such as the PDF you need. You will also be much better off if you make a GooFit Application, though you don’t absolutely have to.
#include <goofit/Application.h>
#include <goofit/PDFs/basic/ExpPdf.h>
#include <goofit/UnbinnedDataSet.h>
#include <goofit/Variable.h>
using namespace GooFit;
int main(int argc, char **argv) {
GooFit::Application app("Exponential",
argc, argv);
// Options could be added here
GOOFIT_PARSE(app);
Python
We will import everything from the GooFit namespace; though in real code you might be better explicitly leaving things scoped. Since Python is easy to directly edit, a CLI parser is not added here.
from goofit import *
import numpy as np
print_goofit_info()
Preparing the data
C++
We will use a trick to make an exponential distribution and a call to rand()
;
usually you will either have real data or you will use a more sophisticated
method to generate data.
// Independent variable.
Observable xvar{"xvar", 0, 10};
// Data set
UnbinnedDataSet data(xvar);
// Generate toy events.
for(int i = 0; i < 100000; ++i) {
xvar.setValue(xvar.getUpperLimit()
- log(1+rand()/2));
if(xvar)
data.addEvent();
}
Python
Here, we can use Python’s buffer interface with NumPy to import a NumPy distribution. You could import real data this way too! If we wanted to mimic the C++ code, that works as well.
# Independent variable
xvar = Observable("xvar", 0, 10)
# Data set
data = UnbinnedDataSet(xvar)
# Make NumPy data
xdata = np.random.exponential(size=100000)
# Import data (needs to be `1xN`)
# and filter out-of-range values
data.from_matrix(xdata[np.newaxis, :], filter=True)
Making the PDF
This part is pretty much identical. You don’t have to worry about PDF lifetimes in Python. You don’t have to worry about Variable lifetimes in either C++ or Python.
C++
Variable alpha{"alpha", -2, 0.1, -10, 10};
ExpPdf exppdf{"exppdf", xvar, alpha};
Python
alpha = Variable("alpha", -2, 0.1, -10, 10)
exppdf = ExpPdf("exppdf", xvar, alpha)
Fitting
For simplicity, we will use RooFit style .fitTo
, though making a fit manager
is also supported in both systems for more complex fits.
C++
exppdf.fitTo(&data);
Python
exppdf.fitTo(data)
Results
Both methods print the same Minuit2 information as the fit occurs (the printout
is live, even in a Jupyter Notebook). Both allow you to control the verbosity in
the fit manager or .fitTo
method.
You can directly access the final values from the original Variable
s.
C++
double val = alpha.getValue();
double err = alpha.getError();
Python
val = alpha.value
err = alpha.error
If you wanted to use .getValue()
and friends instead of the property access
you see above, that is supported as well for easy transition from C++ code.
Useful links:
GooFit on GitHub • GooFit webpage • API documentation • Changelog • Converting to 2.1
-
Variables and Observables internally use smart pointers to keep track of the internal shared value. So as long as once instance is still available, even just inside a PDF, the variable is stays alive in either C++ or Python. ↩︎