Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python Interface for MaCh3 #176

Merged
merged 28 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cd1a7b3
better structure for python binding code
ewanwm Oct 9, 2024
7b3b09b
add python wrapping for minimal set of things to get FitterBase worki…
ewanwm Oct 9, 2024
50a893b
Merge remote-tracking branch 'origin/develop' into feature_fitter_pyt…
ewanwm Oct 9, 2024
68f406b
sphinx docs for new python stuff
ewanwm Oct 9, 2024
a9726c8
add bindings for mcmc and minuit fitters
ewanwm Oct 10, 2024
7ac3896
add bindings for YAML stuff
ewanwm Oct 10, 2024
75635b5
make the documentation mode better
ewanwm Oct 10, 2024
b54ea8a
add covarianceBase binding
ewanwm Oct 10, 2024
6426534
add bindings for covariance objects and can now run MCMC fitter from …
ewanwm Oct 10, 2024
7c88f15
MORE documentation
ewanwm Oct 10, 2024
b8263c8
forgot to add this...
ewanwm Oct 10, 2024
a44219b
would you believe it, more bindings
ewanwm Oct 11, 2024
52dd462
fix spline monolith and make it now usable in python!
ewanwm Oct 14, 2024
b6bdf91
Fix the memory issues with splines! It was the single knot splines ca…
ewanwm Oct 14, 2024
c8cb374
some additional function bindings and some extra c++ getters for cova…
ewanwm Oct 15, 2024
dd38b2c
some more functionality to make life a bit easier
ewanwm Oct 15, 2024
66e73a9
bind the non-default samplePDFFDBase constructor
ewanwm Oct 16, 2024
dd51f86
Merge remote-tracking branch 'origin/develop' into feature_fitter_pyt…
ewanwm Oct 16, 2024
1537058
remove binding for c++ function that was removed
ewanwm Oct 16, 2024
88669d2
move some description stuff to actual documentation rather than just …
ewanwm Oct 16, 2024
2b519d4
typo
ewanwm Oct 18, 2024
18aded7
Merge remote-tracking branch 'origin/develop' into feature_fitter_pyt…
ewanwm Oct 18, 2024
74eaed2
fix bindings for samplePDF to be up to date with new interface
ewanwm Oct 18, 2024
cdc560e
D O C U M E N T A T I O N
ewanwm Oct 18, 2024
78e156b
more documentation improvements
ewanwm Oct 21, 2024
a5ca68f
Merge remote-tracking branch 'origin/develop' into feature_fitter_pyt…
ewanwm Oct 21, 2024
41c4011
add spline example plot to docs
ewanwm Oct 21, 2024
71bbf45
small tweaks to make work with low mem floats and use std::vector ins…
ewanwm Oct 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,24 +210,12 @@ add_subdirectory(samplePDF)
add_subdirectory(mcmc)
add_subdirectory(Diagnostics)
add_subdirectory(plotting)

################################# pybind11 stuff ##################################

if( MaCh3_PYTHON_ENABLED )
## EM: make a module target out of all the python*Module.cpp files (currently just one...)
pybind11_add_module(
pyMaCh3 MODULE
pyMaCh3.cpp
plotting/plottingUtils/pythonPlottingModule.cpp
)
## EM: only works with code compiled with -fPIC enabled.. I think this flag can things slightly slower
## so would be good to find a way around this.
set_property( TARGET pyMaCh3 PROPERTY POSITION_INDEPENDENT_CODE ON )
target_link_libraries( pyMaCh3 PUBLIC Plotting )
install( TARGETS pyMaCh3 DESTINATION pyMaCh3/)
if (MaCh3_PYTHON_ENABLED)
add_subdirectory(python)
endif()



#This is to export the target properties of MaCh3
#Anything that links to "MaCh3" will get all of these target properties
add_library(MaCh3 INTERFACE)
Expand Down
3 changes: 2 additions & 1 deletion Doc/sphinx/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
sphinx
sphinx-rtd-theme
sphinx-automodapi
sphinx-mdinclude
sphinx-mdinclude
enum-tools[sphinx]
3 changes: 2 additions & 1 deletion Doc/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"sphinx.ext.autosummary",
"sphinx.ext.napoleon",
"sphinx_automodapi.automodapi",
'sphinx_mdinclude'
"sphinx_mdinclude",
"enum_tools.autoenum"
]

templates_path = ['_templates']
Expand Down
10 changes: 10 additions & 0 deletions Doc/sphinx/source/covariance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Covariance
==========

This module contains the covariance objetcs which Mach3 uses to deal with systematic parameters. It also includes
the :py:class:`pyMaCh3.covariance.CovarianceBase` class which you can use to implement your own!

.. automodapi:: pyMaCh3.covariance
:members:
:undoc-members:
:show-inheritance:
10 changes: 10 additions & 0 deletions Doc/sphinx/source/fitter.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Fitter
======

This module contains the various MaCh3 fitter algorithms which are available, as well as
the :py:class:`pyMaCh3.fitter.FitterBase` class which you can use to implement your own!

.. automodapi:: pyMaCh3.fitter
:members:
:undoc-members:
:show-inheritance:
51 changes: 51 additions & 0 deletions Doc/sphinx/source/manager.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Manager
=======

This module handles the high level stuff like config options and YAML stuff. The main class is the :py:class:`pyMaCh3.manager.Manager` class. \
You can read more about the manager and config files on `the wiki page <https://github.com/mach3-software/MaCh3/wiki/01.-Manager-and-config-handling>`_. \
YAML stuff works essentially the same as in the c++ version but with some caveats.
The main difference is that in the python version, the way that you access the actual data of a yaml node is different due to the way the python binding of the c++ code works.

Lets take the following YAML snippet as an example ::

Example:
Int: 1234
Str: 'TestString'
IntArray: ['0', '1', '2']
StrArray: ['val1', 'val2', 'val3']

In the c++ version you would access these by doing ::

// for the integer
int testInt = node['Int'].as<int>()
// for the string
std::string testStr = node['Str'].as<std::string>()
// for the integer array
... = node['IntArray'].as<std::vector<int>>()
// and for the string array
... = node['StrArray'].as<std::vector<std::string>>()

In the python version however things are different. Arrays are interpreted as arrays of YAML nodes and all of the underlying data are stored as strings. \
So to access the data as above you would need to do ::

test_int = int(node['Int'].data())
test_str = node['Str'].data()
## then for the arrays
int1 = int(node['IntArray'][0].data())
int2 = int(node['IntArray'][1].data())
int3 = int(node['IntArray'][2].data())

str1 = node['StrArray'][0].data()
str2 = node['StrArray'][1].data()
str3 = node['StrArray'][2].data()

Parsing arrays can be made a bit less painful using list comprehension ::

int_list = [int(i.data()) for i in node['IntArray']]
str_list = [i.data() for i in node['StrArray']]


.. automodapi:: pyMaCh3.manager
:members:
:undoc-members:
:show-inheritance:
17 changes: 0 additions & 17 deletions Doc/sphinx/source/plotting.md

This file was deleted.

21 changes: 20 additions & 1 deletion Doc/sphinx/source/plotting.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
plotting
========

.. mdinclude:: plotting.md
The plotting module can be used to make beautiful plots. See the `plotting wiki page <https://github.com/mach3-software/MaCh3/wiki/15.-Plotting>`_ for information on how to configure the plotting library to work with your MaCh3 output files and other non-MaCh3 based fitters so you can compare results.

The main class to worry about is :py:class:`pyMaCh3.plotting.PlottingManager` which provides the
high level functionality and gives you access to everything else you should need.

To use this in your plotting script simply do ::

## import the plotting module
from pyMach3 import plotting
## need sys to read command line arguments
import sys

man = plotting.PlottingManager()
## give the command line arguments to the manager
manager.parse_inputs(sys.argv)

## Now plot stuff!!
## ...



.. automodapi:: pyMaCh3.plotting
:members:
Expand Down
5 changes: 5 additions & 0 deletions Doc/sphinx/source/pyMaCh3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ pyMaCh3
.. toctree::
:maxdepth: 4

manager.rst
sample-pdf.rst
splines.rst
fitter.rst
covariance.rst
plotting.rst
15 changes: 15 additions & 0 deletions Doc/sphinx/source/sample-pdf.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Sample PDF
==========

This module deals with sampling from the posterior density function of your
particular experimental model at different points, given your data.

In order to do this, you will generally need to create a SamplePDF object derived from :py:class:`pyMaCh3.fitter.SamplePDFFDBase`
for each sample of events for your experiment. For some more details on this you can see `the wiki page <https://github.com/mach3-software/MaCh3/wiki/04.-Making-a-samplePDF-experiment-class>`_ on this.
The code examples there are written using c++ however the general ideas are the same.
Happy sampling!

.. automodapi:: pyMaCh3.sample_pdf
:members:
:undoc-members:
:show-inheritance:
Binary file added Doc/sphinx/source/spline-examples.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions Doc/sphinx/source/splines.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Splines
=======

This module provides the utility for dealing with spline parameters. For some background reading se the `Splines wiki page <https://github.com/mach3-software/MaCh3/wiki/05.-Splines>`_.

The main class which represents individual spline functions is :py:class:`pyMaCh3.splines.ResponseFunction`.
This is an abstract representation which covers multiple different types of interpolation, where the type of interpolation is specified at the time of construction.
The available interpolation types are defined by :py:class:`pyMaCh3.splines.InterpolationType`. Here are some examples

.. image:: spline-examples.png
:width: 400
:alt: Examples of linear, TSpline3 and monotonic interpolation

To construct a ResponseFunction you must specify the x and y positions of the knots, and the interpolation type like in the following example::

from pyMaCh3 import splines

TSpline3_response_1 = splines.ResponseFunction([0.0, 1.0, 2.0], [1.0, 0.5, 2.0], splines.InterpolationType.Cubic_TSpline3)
linear_response_1 = splines.ResponseFunction([10.0, 11.0, 12.0], [6.0, 0.0, 0.5], splines.InterpolationType.Linear)

TSpline3_response_2 = splines.ResponseFunction([0.0, 1.0, 2.0], [2.0, 3.0, 0.0], splines.InterpolationType.Cubic_TSpline3)
linear_response_2 = splines.ResponseFunction([10.0, 11.0, 12.0], [3.0, 0.0, 4.5], splines.InterpolationType.Linear)

Another important part of this module is the :py:class:`pyMaCh3.splines.EventSplineMonolith` class which allows you to easily and speedily deal with event-by-event splines in your analysis.
To build this you first need to construct a response function for each event-by-event spline parameter for each of your events as in the example above.

Let's take those example responses and build a simple EventSplineMonolith::

monolith = splines.EventSplineMonolith([[TSpline3_response_1, linear_response_1], [TSpline3_response_2, linear_response_2]])

This will create an EventSplineMonolith which can deal with the reweighting of two events with two spline parameters.
We now need to be able to set the values of the parameters so that we can calculate event weights.
This is done using the :py:func:`pyMaCh3.splines.EventSplineMonolith.set_param_value_array` function.
This allows us to bind a numpy array to our EventSplineMonolith, whose values we can change, and this will set the values of the parameters inside of the monolith.
This works as follows::

# we need to keep track of how many parameters we have
# in our case this is two
n_parameters = 2

# we initialise the array, the initial values don't matter too much so we'll make them zero
param_array = np.zeros((n_parameters,))

# now we bind this array to the monolith we made above
monolith.set_param_value_array(param_array)

# now changes made in the param_array will be propagated to the monolith
param_array[0] = 0.5
param_array[1] = 11.042

.. warning::
Once your array has been bound to your spline monolith that you keep it safe and don't overwrite it by doing something like::

param_array = np.array([0.5, 11.0])

as this will mean the original array (the one that is bound to your monolith will be lost forever and you will no longer be able to set parameter values!).
You need to set the values using indexes as above, or if you want to set them all at once you use slicing like::

param_array[...] = [0.5, 11.0]

This may seem a bit faffy but it is intended to avoid unneccessary copying from python to c++ so we can keep things nice and speedy.

Happy splining!

.. automodapi:: pyMaCh3.splines
:members:
:undoc-members:
:show-inheritance:
4 changes: 4 additions & 0 deletions covariance/covarianceBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ class covarianceBase {
/// element of a new array. There must be a clever C++ way to be careful
inline const double* retPointer(const int iParam) {return &(_fPropVal.data()[iParam]);}

/// @brief Get a reference to the proposed parameter values
/// Can be useful if you want to track these without having to copy values using getProposed()
inline const std::vector<double> &getParPropVec() {return _fPropVal;}

//Some Getters
/// @brief Get total number of parameters
inline int GetNumParams() {return _fNumPar;}
Expand Down
3 changes: 3 additions & 0 deletions covariance/covarianceXsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class covarianceXsec : public covarianceBase {
/// @brief Get interpolation type for a given parameter
/// @param i spline parameter index, not confuse with global index
inline SplineInterpolation GetParSplineInterpolation(const int i) {return SplineParams.at(i)._SplineInterpolationType;}
/// @brief Get the name of the spline associated with the spline at index i
/// @param i spline parameter index, not to be confused with global index
std::string GetParSplineName(const int i) {return _fSplineNames[i];}

//DB Get spline parameters depending on given DetID
const std::vector<int> GetGlobalSystIndexFromDetID(const int DetID, const SystType Type);
Expand Down
10 changes: 0 additions & 10 deletions pyMaCh3.cpp

This file was deleted.

21 changes: 21 additions & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

################################# pybind11 stuff ##################################

if( MaCh3_PYTHON_ENABLED )
## EM: make a module target out of all the python*Module.cpp files (currently just one...)
pybind11_add_module(
pyMaCh3 MODULE
pyMaCh3.cpp
plotting.cpp
fitter.cpp
samplePDF.cpp
manager.cpp
covariance.cpp
splines.cpp
)
## EM: only works with code compiled with -fPIC enabled.. I think this flag can make things slightly slower
## so would be good to find a way around this.
set_property( TARGET pyMaCh3 PROPERTY POSITION_INDEPENDENT_CODE ON )
target_link_libraries( pyMaCh3 PUBLIC MaCh3::All )
install( TARGETS pyMaCh3 DESTINATION pyMaCh3/)
endif()
Loading