Commit 6b3fbe7c authored by Christian Bierlich's avatar Christian Bierlich Committed by Christian Bierlich
Browse files

transfering more wiki

parent 05a6d88c
......@@ -40,4 +40,6 @@ well as how to implement and contribute your own analyses.
[Working with development source](developer.md)
[Submitting an analyses](submitanalysis.md)
[Submitting an analysis](submitanalysis.md)
[Coding style](codingstyle.md)
## Coding style guide
It's important that Rivet code be fairly homogeneous in coding style, so that all the analyses and projections are good examples for non-core developers to copy, and so that everyone can read each class without having to double-think.
Some of the rules below might seem rather petty, but please stick by them (and complain at Andy if you think you've got a good reason for doing otherwise!) As with all rules, they're there to be broken, but only if you can justify doing so :-)
### General code style
* Header files should have a `*.hh` suffix, implementation files with a `*.cc` suffix;
* Private member variables should have a `_` prefix followed by a ''lower case'' letter, e.g. `private: int _myFoo;`. Don't use starting underscores followed by capital letters, or double underscores at all - both can clash with internal symbols;
* Prefer the prefix incrementation to postfix incrementation: `++i` rather than `i++`. For e.g. iterators, this can be a not-insignificant performance boost, and since this is a well-known idiom it's lazy to do otherwise - when I see post-increments in code, it makes me wonder if the author really knows what they're doing!
* Use the One True Brace Style (1TBS) for all code submitted to Rivet: see [wikipedia.](http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS) And also...
* Your code will be more readable if you space things out a bit:
```
// prefer
if (foo < bar) {...
// to
if(foo<bar){...
```
,
```
// prefer
for (int i = 0; i < N; ++i) {
// to
for(int i=0;i<N;++i){
```
and
```
// prefer
if (foo == bar) {
// to
if(foo==bar){
```
It's not Fortran: spaces are not expensive! We will edit code not supplied in this format.
* Also leave a couple of blank lines between function definitions, and occasional blank lines between blocks inside functions and class definitions to better emphasise the algorithm/data structures;
* Use two spaces rather than tabs for indentation. You should be able to set up your code editor to do this automatically - for example, try adding this to your `.emacs` file if you're an emacs user:
```
(setq-default c-basic-indent 2)
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)
```
While silly flame wars rage on this topic, most people are agreed that consistency is important: since most editors these days should be able to indent "to the correct amount" automatically, using spaces is completely unambiguous, with no extra typing required.
* Although it may seem horrid to Europeans, use American spelling e.g. (color rather than colour) in function and publicly-visible parameter/variable names;
* Use line wrapping sensibly rather than religiously - 80 characters is a good default length, but if wrapping your 110 character line (e.g. a for loop using lengthy iterator names) obscures the code structure then you'll need to make a choice. Maybe it can be reduced by using a sensible `typedef`, or a temporary variable - often sensible anyway;
* Don't comment the `#endif`s in header guards - it just leads to inconsistencies when new header files are made by "copy and paste". Similarly, don't use comments which mention the filename: they lead to inconsistencies via renamings and copyings, and if you need to print the source then the IDE/editor will probably attach the filename to the printout anyway.
* Try to minimise the {{{#include}}} entries in header files, especially if they refer to external library objects: binary library link dependencies are one thing, but header dependencies are usually one step too far. This may require storing member variables as pointers, so that a forward declaration of the variable's class can be used rather than a header `#include` that might induce a transitive dependency.
### Analysis coding style
* Prefer not to use pointers ''at all'' in projection and analysis code. The one exception to this is YODA histograms, where you have no option but to use pointers. See below for more information.
* Histogram objects should be private and their names should start with "`_hist`";
* All Rivet analyses are plugins via the `Analysis` interface, and virtually no analyses inherit from any base class other than `Analysis`. Hence there is no need for header files, and analyses should be written completely inline with the implementations as part of the class definition, all in the `.cc` file.
* Use the `MSG_DEBUG(...)`, `MSG_INFO(...)` etc. macros in place of `getLog() << ... << endl;`.
* If your analysis includes the same sets of plots (binnings and cuts can differ), then don't register histograms for each energy, e.g. `_hist_blah_900GeV`, `_hist_blah_7000GeV`, etc.: just make one `_hist_blah` and use the `sqrtS()` function in the `init()` method of the analysis to book it from the appropriate histogram code. Then in the `analyze()` method, you can just call `fill()` without having to work out which variable you should be filling. This can save a ''lot'' of repetitive copy 'n' paste code, and we will reject supplied analyses which should do this and haven't, since otherwise they are a maintenance nightmare.
### Why to not use pointers
The "don't use pointers" rule may seem particularly perverse. Aren't they core to how C++ works? Well, for most purposes the answer is "no". While there are certainly areas of C++ code where pointers are useful, they tend to only be the places where references can't be used: polymorphic containers, storage of abstract base classes, and member variables with reference semantics. References are safe, while pointers are the single most common cause of segfaults and difficult-to-find bugs: prefer references whenever possible.
One particular reason to discourage pointers is that we want analysis and projection classes to be writeable by non-C++ experts: if pointers are involved, the level of required expertise is immediately raised (even if you don't realise that that's the case). Using pointers also forces projection authors to have to write custom constructors, destructors, copy constructors and copy assignment operators (cf. the "if you need one, you'll need all three" idiom): that's a lot of work and potential bugs that could have been avoided. This rule is sometimes referred to as the Law of the Big Three: see http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10 (and the rest of this excellent C++ resource!) for details.
......@@ -254,7 +254,7 @@ With the
RatioPlot=1
RatioPlotReference=<histogram_ID>
```
options you can create ratio plots for two or more histograms. Note that you must specify your reference data ID. This option is used by the [`compare-histos`](compare-histos.html) script.
options you can create ratio plots for two or more histograms. Note that you must specify your reference data ID. This option is used by the `compare-histos` script.
```
RatioPlotMode=<default|deviation|datamc>
......
## Instructions for writing a Rivet routine/analysis
At this point you have probably run Rivet a few times, maybe different analyses, different generators, and played around with plotting options. To really utilize the full power of the framework, one does, however, need to write analysis code -- it is an analysis framework after all.
The best tip for writing analyses, is to find an existing similar analysis, from the large library of already existing ones, and take inspiration from that. But even then, it is important to have the basics right.
### Writing the analysis code
Here we are going to write a new analysis for use with Rivet. This is done "stand-alone", i.e. you don't have to modify the code of Rivet itself: in fact, you can follow these instructions using a system install of Rivet to which you have no write permissions.
All analysis routines are implemented as sub-classes of the Rivet "Analysis" class: pretty much all the magic that binds the analysis object into the Rivet system is handled in this base class, meaning that your code can really concentrate on implementing the physics goals of the analysis.
### The analysis "wizard"
You could make your analysis by copying some example code and then going through a load of search and replace fiddling, but in fact there is a much easier way: the `rivet-mkanalysis` script. This script is installed along with the rest of the Rivet system, and will generate template analysis files for you.
You can get some help info by running `rivet-mkanalysis --help`, but the basic usage (to generate the files in your current directory) is `rivet-mkanalysis MY_ANALYSIS_NAME`. A three part name, separated by underscores, is a Rivet convention that we recommend you to use: the first part is the experiment name, the second is the year of publication, and the third is the ID code for the corresponding paper in the [Inspire HEP database](http://inspirehep.net), preceded by an "I". You can get the Inspire ID from an Inspire record page by looking at the URL: it will be the numerical trailing part of the address following `record/`, e.g. 849050 in the record [http://inspirehep.net/record/849050.](http://inspirehep.net/record/849050)
So, for example, `ATLAS_2010_I849050` would be the standard name for the analysis link given above... although in fact that one (the first ATLAS minimum bias paper) is in the Rivet collection under the name `ATLAS_2010_S8591806`, which uses the older ''SPIRES'' database ID. Please use Inspire IDs rather than SPIRES ones for new analyses -- we intend to update all analyses to the Inspire naming in a future release.
Running the `rivet-mkanalysis` script with the appropriate analysis name will have generated a `.cc` C++ source file template, and template metadata files for information about the analysis (`.info`) and specifications of titles, axis labels, etc. for the plots which the analysis will produce (`.plot`). These templates will include, if possible, extra analysis metadata such as a BibTeX publication entry in the `.info` file.
### Structure
For simplicity, Rivet analysis classes are usually written in just one `.cc` file, i.e. no header declaration. This is because classes are almost always not inherited from, and all that the Rivet system needs to know is that it can be treated as an `Analysis*` pointer: avoiding header files makes everything more compact and removes a source of errors and annoyance.
An analysis has the following components:
* a no-argument constructor;
* three analysis event loop methods: `init`, `analyze` and `finalize`;
* a minimal hook into the plugin system
It is also possible to add some metadata methods which describe the analysis, references to publications, experiment, etc., but we strongly recommend that you put this information into the "YAML" format (see http://www.yaml.org) `.info` template that the `rivet-mkanalysis` script generated for you instead: this way the code will remain clean and minimal, and you can update the metadata without needing to recompile. All analyses bundled with Rivet store their metadata in external files.
Useful analyses also contain member variables for the analysis: event weight counters and histograms are the most common of these. Conventionally, we declare the class member variables with a leading underscore: see the [Coding Style Guide](codingstyle.md) for more information on our recommended uniform coding style. Histogram pointer members (for which we use special smart pointers with clever machinery inside) are preferred to start with an "h", e.g. `Histo1DPtr _h_pT`.
### Implementation
The constructor and three event loop methods are used for the following:
* Constructor: set whether the generator cross-section is needed. Minimal!
* `init`: book histograms, initialise counters, etc.
* `analyze`: select particles, filter according to cuts, loop over combinations, construct observables, fill histograms. This is where the per-event aspect of the analysis algorithm goes.
* `finalize`: normalize/scale/divide histograms, tuples, etc.
This probably looks similar to every analysis system you've ever used, so hopefully you're not worried about Rivet being weird or difficult to learn ;-)
Rivet provides implementations of many calculational tools, called "projections". These are just observable calculator objects with a silly name, so don't get worried. (They automatically cache their results, to make Rivet automatically efficient, but you don't have to worry about that since it's, well, automatic.) The projections are used by calling the analysis' `apply(event)` method. This will return a const reference to the completed projection object and takes the type of the reference as a template argument, e.g.
```
const FinalState& cfs = apply<FinalState>(event, "Tracks");
```
The name "Tracks" here will have been registered in the `init` method as referring to a projection of type "ChargedFinalState" --- a calculator which provides a list of charged particles with certain basic cuts applied. This is done via the `declare` method. Note that a) you don't have to manage the memory yourself, and b) polymorphism via the reference is both allowed and encouraged. If b) means nothing to you, don't worry... we just want to reassure C++ fiends who might think we're cramping their style!
### Example
Here is an example of the whole Rivet analysis shebang. We've compressed it into a single .cc file since the `analyze` method is nice and short and there is no reason to make a header:
```
#include "Rivet/Analysis.hh"
#include "Rivet/Projections/FinalState.hh"
#include "Rivet/Projections/ChargedFinalState.hh"
#include "Rivet/Projections/FastJets.hh"
namespace Rivet {
class MyAnalysis : public Analysis {
public:
/// Default constructor
MyAnalysis() : Analysis("MYANALYSIS") { }
/// @name Analysis methods
//@{
void init() {
const FinalState fs(Cuts::abseta < 5);
declare(FastJets(fs, FastJets::ANTIKT, 0.5), "Jets");
declare(ChargedFinalState(Cuts::abseta < 2.5 && Cuts::pT > 500*MeV), "Tracks");
}
void analyze(const Event& event) {
const Jets& jets = apply<ChargedFinalState>(event, "Jets")
.jetsByPt(Cuts::pT > 20*GeV && Cuts::abseta < 4.4);
MSG_DEBUG("Jet multiplicity = " << jets.size());
const Particles& trks = apply<FinalState>(event, "Tracks").particles();
MSG_DEBUG("Track multiplicity = " << trks.size());
}
// No histos, so no need for a finalize()!
//@}
};
// Magic required by the plugin system
DECLARE_RIVET_PLUGIN(MyAnalysis);
}
```
### Cut objects
Note the use of objects in the `Cuts` namespace to specify kinematic cuts on particles or jets selected by projections, or returned from them as lists. These predefined objects of type `Rivet::Cut` can be combined together using arbitrary combinations of logical operators, with the combined object also being of type `Cut`.
Many functions in Rivet accept a (potentially compound) `Cut` as an argument, so this is a very flexible, unambiguous, and human-readable way to express analysis selection logic. There is not much to know from the user point of view beyond what you see above!
The standard Rivet predefined cuts are (all in the `Rivet::Cuts` namespace): `pT`, `Et`, `mass`, `phi`, `eta`, `abseta`, `rap`, `absrap`.
### Compiling and linking
To use your new analysis, you need to build it into a Rivet analysis plugin library, with a name of the form `Rivet*.so` library. You can do this manually, but to make life easier there is again a helper script, used as follows:
`rivet-buildplugin RivetMyAnalyses.so MyAnalysis.cc MyOtherAnalysis.cc # etc.`
Note that the name of the library has to start with the word "Rivet" or it will not get loaded at runtime. By default, if no ".so" first argument is given, the name =RivetAnalysis.so= will be used.
### Running
You can now use your new analysis right away. Provided that the `RivetMyAnalysis.so` shared library file, or a similarly-named symbolic link to it, is in a directory listed in your `RIVET_ANALYSIS_PATH` environment variable, it will work right away with the `rivet` command:
```
> ls
RivetMyAnalysis.so MyAnalysis.cc
> export RIVET_ANALYSIS_PATH=$PWD
> rivet --list-analyses
[...]
MYANALYSIS
> rivet --show-analysis MYANALYSIS
MyAnalysis
==========
Spires ID: NONE
Spires URL: http://www.slac.stanford.edu/spires/find/hep/www?rawcmd=key+NONE
Experiment: NONE
Year of publication: NONE
Description:
A do-nothing analysis for demonstrating how to make a plugin
References:
```
Alternatively, you can use the `--analysis-path` flag to `rivet`:
```
> rivet --list-analyses --analysis-path=$PWD
```
### Making it useful
Hopefully that's enough to get you started. The other main things to learn are booking (and "auto-booking") of histograms and other data objects, and use of the Rivet projections and analysis objects. For this, we recommend that you take a look at the code of some of the standard analyses, and read more information about projections and histogramming on this wiki and in the Rivet PDF manual.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment