Commit b8c369e2 authored by Jon Butterworth's avatar Jon Butterworth

Merge branch 'jgrosseo/rivet-master' into HEAD

parents b7dedad5 02f9a4a2
......@@ -51,7 +51,8 @@ namespace Rivet {
// needed since centrality does not make any difference here. However,
// in some cases in this analysis the binning differ from each other,
// so this is easy-to-implement way to account for that.
std::string namePP = _histNch[PBPB][ihist]->name() + "-pp";
std::string namePP = mkAxisCode(ihist+1,1,1) + "-pp";
// The binning is taken from the reference data
book(_histNch[PP][ihist], namePP, refData(ihist+1, 1, 1));
......@@ -47,6 +47,11 @@ how to implement and contribute your own analyses.
## Writing a Rivet analysis
[What is an Analysis?](
[What is a Projection?](
[How does Rivet histograms work?](
[Writing a simple analysis](
## Projections
Projections are arguably the most important objects in Rivet - they're certainly the part that does most of the work. A projection is an object which calculates a property or properties from an Event. Such properties can be a single number (e.g. multiplicity in a certain phase space), a single complex object (e.g. sphericity tensor) or a list of such objects (e.g. a set of boosted jets or charged particles).
In case you're confused by the name, "projection" was chosen since their task is to project out quantities of interest from the complexities of whole events - they don't strictly obey the definition of an algebraic projection operator!
### A few details about projections
All Rivet projections inherit from the abstract `Projection` class, which defines the interface elements supported by all projections. You don't need to worry about this too much - it basically forces you to supply `project()` and `compare()` methods which can be used polymorphically by Rivet's internal mechanisms.
The projections are used by Analysis objects. Internally, projections are compared via the `Projection::compare(...)` method which allows duplicate instantiations of the same projection to be avoided - as a result, the second (and so on) time a given projection is called for a particular event, it will simply return its cached value rather than repeating the computation.
### Specific projections
Here are some examples of projections available in the current release of Rivet:
* Beam - obtain the beam from an event
* FinalState - get the final state particles
* FinalStateHCM - get the final state particles, shifted to the HCM frame
* VetoedFinalState - get the final state particles, minus selected particle types
* FastJets - jet algorithms accessed via FastJet
* MissingMomentum - what it says on the tin
* Multiplicity - count the FS particles of various types
* Sphericity - the sphericity tensor, from which the sphericity, oblateness and planarity can be obtained
* ParisiTensor - linearized quadratic momentum tensor, from which the Parisi C and D variables can be obtained
* Thrust - the thrust tensor, defining the thrust axes and scalars
* DISKinematics - kinematics of DIS events
* DISLepton - obtain the scattered lepton in DIS events
### How to use projections
For this example we'll use the FinalState projection in an analysis. The analysis header file must include the interface of FinalState, with a `#include "Rivet/Projections/FinalState.hh"` directive.
Create and initialize projections in the analysis `init` method:
void init() {
FinalState fs(-1.0, 1.0, 0.5);
addProjection(fs, "FS");
addProjection(Multiplicity(fs), "Mult");
addProjection(Thrust(fs), "Thrust");
Then, when using the projection, you'll probably want to have something like this in the `analyze(...)` method:
void MyAnalysis::analyze(const Event& e) {
// Project into final state
const FinalState& fs = appl<FinalState>(e, "FS");
Note that it's good practice to make the returned projection a `const` reference -- this guarantees that the cached result will remain unchanged between repeated calls, perhaps in distinct analyses.
If using a projection inside another projection, the same applies for initialising it in the constructor of the "client" class, and the use of the projection on each event should be in the body of the `MyProjection::project(...)` method.
### Writing a projection
The best documentation when writing a projection is to look at some existing ones and use them as templates - pick a short one like `ChargedFinalState` or `Beam` since their structure is easier to see. Issues to be particularly aware of include:
* Use without registration - it's advised that you do the actual calculation in a user-callable method called `calc`, so that the projection can be used without having to be centrally registered and attached to the event.
* Caching - make sure that the `project` method stores everything you need to reproduce the calculation result with minimal CPU effort. This will require some member variables explicitly put there for caching. You might want to become familiar with the `mutable` keyword, and use it **very carefully**, if the cache needs to be updated while accessing methods of a `const` projection. Make sure you reuse cached values wherever possible, by using other projections where available.
* Comparing with other projections - the `compare` method provides a way for Rivet's internal workings to discriminate between projections which are handled polymorphically (i.e. they're all just `Projection*` as far as Rivet's type system is concerned). `compare` should return `CmpState:EQ` if two projections are effectively identical - i.e. not just the same type, but also the same configuration parameters and equivalent internal projections - and `CmpState::NEQ` if they are not identical. See some existing projections for guidance.
* `new` and `delete` in projections - the projection and analysis destructors are pretty ineffectual things, since they **only get called at the end of the whole run**, rather than in between each event: if `new` is called during the `project` phase, `delete` had better be called in the same phase or you'll have a horrendous memory leak. Anyway, you shouldn't be using `new` unless you have a good reason, and remember: references are just as efficient as pointers and a lot safer!
As well as the logical decisions to be made in designing a projection, to integrate a projection into the build system, you will have to modify the `include/Rivet/` and `src/Projections/` files. These should be fairly easy to understand: just add your projection's header and implementation file names to the appropriate lists of projections to be built.
## Histogramming in Rivet
Histogramming in Rivet is currently handled via the YODA data analysis interfaces: see ([] for more information on YODA.
### Booking histograms
Most of the time you will want to book histograms from within an Analysis. Rivet provides machinery to handle the both contruction of the histogram and making the histogram available for writing. There are several ways of booking a histogram:
* book evenly spaced bins in a range, by specifying the endpoints and the number of bins
* pass a specific `std::vector` of bin edges
* automatically book with the right bin edges based on the reference data file.
Any "official" Rivet analyses will use the latter method, and we recommend that you do so, too. If you are starting a new analysis, and the reference data is found in HepData (the INSPIRE record will provide a link to "Data: HepData"), it can be downloaded from there -- and will even be done automatically if an analysis skeleton is written by the `rivet-mkanalysis` script.
The `book` method takes a pointer to any histogram type (all derived from `YODA::AnalysisObject) as the first argument, and will initialize the object behind the pointer accordingly.
### Tell me more about this auto-booking thing...
Maybe this isn't so obvious after all! The idea is that most Rivet analyses should be comparable with experimental data, such as that in the HepData database.
Since the MC and ref data must have the same binnings to be meaningfully compared, and since encoding long lists of bin edges into your code is annoying, error-prone and ugly, our booking system will use the reference data files as a template from which to book the MC histogram. The reference files will be searched for in the installation path of Rivet. The internal path to the reference histograms is the same as for the MC histograms, but all inside a top-level virtual directory called "REF". For example, MC histo `/MY_ANALYSIS/my-histo` can be auto-booked from reference histo `/REF/MY_ANALYSIS/my-hist`
For those histograms dumped from HepData, the histogram naming system is a little strange: Every 1D histogram that you might want to make is stored in HepData as a combination of an x-axis and a y-axis for a given dataset --- HepData datasets can have multiple axes of either kind, so that e.g. several measurements binned the same way can be encoded as multiple y-axes on a single x-axis. So, armed with the dataset, x-axis and y-axis IDs, if you call:
// In MyAnalysis class definition:
Histo1DPtr myHisto;
// In implementation:
void MyAnalysis::init() {
book(myHisto, 1, 1, 2);
then you'll get `myHisto` initialized with the right binning.
### Filling histograms
Histograms are usually filled in your analysis' `analyze()` method, using the normal YODA fill() method, e.g.
Note that contrary to what you may be used to from ROOT or other analysis frameworks, it is not neccessary to fill
the event weight into the histogram. This is handled automatically by Rivet.
## What is a "Rivet analysis"?
Before starting to write your own Rivet analysis, it might be beneficial to read a little more about
what an analysis is on the technical side. Briefly:
There is one Analysis for every physics paper implemented.
They produce the histograms which can be compared to the published plots in the paper.
They calculate event properties and implement kinematic cuts using [Projections](
They book, fill and output histograms using the YODA interface via auxilliary RivetHistogramming code. Each event is passed to the analysis and operated on by the projections. The result of the projections operating on the event determines whether the event is accepted and what is plotted.
All the Analyses to be used are instantiated at the beginning of a Rivet run.
All Analyses inherit from the Analysis.hh abstract base class.
### Writing your own analysis
Rivet uses ''pluggable'' analyses: this system allows users to build and run their own analysis without needing to re-build the Rivet library.
See [Writing a simple analysis]( for instructions on writing your own analysis routine.
### How analyses get loaded
When you build your new analysis a `` library will be created, which Rivet needs to find.
Rivet scans several directories at runtime to find the library files containing analyses. Specifically, the following search locations are tried, in order:
* a directory listed in `RIVET_ANALYSIS_PATH}
* the directory where `` is installed (i.e. the Rivet `$prefix/lib` directory)
* the current directory.
If a duplicate analysis is found in more than one location, Rivet will complain but will not crash. The first version to be found will be used.
Note that (to reduce the number of attempted loadings) *the library name must contain the word `Rivet` and end in the appropriate shared library suffix for the OS: this is .so for Linux and Macs*.
### Real Data
YODA files for all measurements are distributed with Rivet for comparison to the generated plots. These files are obtained from [HepData](, but distributed with the Rivet code for standalone running.
These data files are also used to auto-book the histograms which are filled by the Monte Carlo. See [Book and use histograms](
  • @agbuckley, this merge seems to have picked up some of your documentation changes from the master branch too. That was an accident, sorry. I hope it doesn't cause any problems. I'm still working the git stuff out...

Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment