Announcing GooFit 2.1

GooFit logo

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 Variables.

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.


GooFit on GitHubGooFit webpage • API documentationChangelogConverting to 2.1


  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. ↩︎