Writing custom analyses¶
HEJ 2 and the HEJ fixed-order generator can generate HepMC files, so you can always run a Rivet analysis on these. However if you compiled HEJ 2 with Rivet you can use the native Rivet interface. For example
analysis:
rivet: [MC_XS, MC_JETS]
output: HEJ
would call the generic
MC_XS and
MC_JETS analysis
and write the result into HEJ[.Scalename].yoda
.
HEJ 2 will then run Rivet over all different scales seperatly and
write out each into a different yoda file. Alternatively instead
of using Rivet, you can provide a custom analysis inside a C++ library.
An analysis is a class that derives from the abstract Analysis
base class provided by HEJ 2. It has to implement three public
functions:
The
pass_cuts
member function return true if and only if the given event (first argument) passes the analysis cutsThe
fill
member function adds an event to the analysis, which for example can be used to fill histograms. HEJ 2 will only pass events for whichpass_cuts
has returned true.The
finalise
member function is called after all events have been processed. It can be used, for example, to print out or save the analysis results.
The pass_cuts
and fill
functions take two arguments: the
resummation event generated by HEJ 2 and the original fixed-order
input event. Usually, the second argument can be ignored. It can be
used, for example, for implementing cuts that depend on the ratio of the
weights between the fixed-order and the resummation event.
In addition to the two member functions, there has to be a global
make_analysis function that takes the analysis parameters in the form of
a YAML Node
and returns a std::unique_ptr
to the
Analysis.
The following code creates the simplest conceivable analysis.
#include <memory> // for std::unique_ptr
#include "HEJ/Analysis.hh"
class MyAnalysis: public HEJ::Analysis {
public:
MyAnalysis(YAML::Node const & /* config */) {}
void fill(
HEJ::Event const & /* event */,
HEJ::Event const & /* FO_event */
) override {
}
bool pass_cuts(
HEJ::Event const & /* event */,
HEJ::Event const & /* FO_event */
) override {
return true;
}
void finalise() override {
}
};
extern "C"
std::unique_ptr<HEJ::Analysis> make_analysis(
YAML::Node const & config
){
return std::make_unique<MyAnalysis>(config);
}
You can save this code to a file, for example myanalysis.cc
, and
compile it into a shared library. Using the g++
compiler, the
library can be built with
g++ $(HEJ-config --cxxflags) -fPIC -shared -Wl,-soname,libmyanalysis.so -o libmyanalysis.so myanalysis.cc
With g++
it is also good practice to add
__attribute__((visibility("default")))
after extern "C"
in the above code snippet and then compile with the additional flag
-fvisibility=hidden
to prevent name clashes.
You can use the analysis in HEJ 2 or the HEJ fixed-order generator by adding
analysis:
plugin: /path/to/libmyanalysis.so
to the .yml configuration file.
As a more interesting example, here is the code for an analysis that sums up the total cross section and prints the result to both standard output and a file specified in the .yml config with
analysis:
plugin: analysis/build/directory/src/libmy_analysis.so
output: outfile
To access the configuration at run time, HEJ 2 uses the yaml-cpp library; for more details see the yaml-cpp tutorial. The analysis code itself is
#include <memory>
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include "HEJ/Analysis.hh"
#include "HEJ/Event.hh"
#include "yaml-cpp/yaml.h"
class MyAnalysis: public HEJ::Analysis {
public:
MyAnalysis(YAML::Node const & config):
xsection_{0.}, xsection_error_{0.},
outfile_{config["output"].as<std::string>()}
{}
void fill(
HEJ::Event const & event,
HEJ::Event const & /* FO_event */
) override {
const double wt = event.central().weight;
xsection_ += wt;
xsection_error_ += wt*wt;
}
bool pass_cuts(
HEJ::Event const & /* event */,
HEJ::Event const & /* FO_event */
) override {
return true;
}
void finalise() override {
std::cout << "cross section: " << xsection_ << " +- "
<< std::sqrt(xsection_error_) << "\n";
std::ofstream fout{outfile_};
fout << "cross section: " << xsection_ << " +- "
<< std::sqrt(xsection_error_) << "\n";
}
private:
double xsection_, xsection_error_;
std::string outfile_;
};
extern "C"
std::unique_ptr<HEJ::Analysis> make_analysis(
YAML::Node const & config
){
return std::make_unique<MyAnalysis>(config);
}