A Basic Template

FluxReader comes with a template script, called FluxReaderTemplate.C. Its contents will be reproduced here with more details than the actual comments that appear in the script. However, before this, note that all scripts should have a similar format and flow: they start with some standard preprocessor directives (this includes the include files), a Parameters object is constructed and configured, a FluxReader object is constructed and configured, an output file is created and the Dk2Nu files are read.

These first lines are necessary to have the code run. The important thing to note is that the function name matches the script name, without the ".C" file extension.

#ifdef __CINT__
void FluxReaderTemplate()
  std::cout << "Sorry, you must run in compiled mode." << std::endl;

Here are the necessary include files, grouped by C/C++, ROOT, Package, and Other External includes. Most of the includes are fairly self-explanatory in the main function body (e.g., Parameters.h is needed for a Parameters object). To alleviate any possible confusion, Detectors.h lists predefined detectors (like knova_fd), Utilities.h defines the Bins function, and Vars.h lists predefined Var objects (like kEnergy).

#include <iostream>
#include <string>

#include "TFile.h" 

#include "Detectors.h" 
#include "FluxReader.h" 
#include "Parameters.h" 
#include "Utilities.h" 
#include "Vars.h" 

This is the namespace that all of the objects live in.

using namespace flxrd;

Here is the main body of the code. The main function has to be defined here again, and it must still match the script name as above.

void FluxReaderTemplate()

Here is where a Parameters object is constructed and configured. The optional boolean input to the constructor determines whether to handle neutrino parent sign (true) or ignore it (false). Parameters sets up some standard defaults for most options, but it does not set up a default set of detectors. At least one must be added by the user, and the easiest thing to do is use a predefined Detector from Detectors.h.

  Parameters p(false);


Next a FluxReader object is constructed and configured. The string input, which supports shell style wildcards, points to the set of Dk2Nu files to run over. Configuration of a FluxReader object essentially means adding Spectra to create. The five inputs are the parameters to run over, the title (and output directory name) of the spectra, the axis label, a vector of bin edges, and variable to fill.

  // Set up the input string outside of the constructor
  string dk2nu_loc = "/nusoft/data/flux/dk2nu/nova/2010/flugg_mn000z200i_20101117.gpcfgrid_lowth/";
  dk2nu_loc += "*dk2nu.root";
  FluxReader *fr = new FluxReader(dk2nu_loc, 2); // The second input says to only use 2 files

  fr->AddSpectra(p, "enu", "Energy (GeV)", Bins(100, 0., 10.), kEnergy);

To actually run FluxReader, the FluxReader::ReadFlux function is called with a TFile (or TDirectory). Thus, the file must be opened first! Make sure to edit this path in your own code to a directory that you have write permissions.

  TFile* out = new TFile("/nova/ana/users/gkafka/FluxReader/demo0.root", "RECREATE");


These last lines are some more standards. They essentially just finish cleaning up. The endif preprocessor directive actually closes the logic from the very beginning!

  delete fr;


Other Demo Scripts

Along with FluxReaderTemplate.C, FluxReader comes with many demo scripts. The scripts have a general order, and their naming convention shows this. The demos are named according to Demo#_<Tutorial>.C, where # is a single integer that indicates the order of the demo scripts, and <Tutorial> is a short descriptor of what the script showcases. To use them, simply open the demos, edit the output file location to a writeable area, and run!

Where to Add/Use Classes

As a general guide, here is where to add/use the various classes. Some of this is just style, but I won't say when that is--and that will help ensure that any one user is able to read anyone else's script! If the script being built is complicated enough that some of these steps are done in other functions, try to call those functions in the following order as best as possible. (Note: the demo scripts do not necessarily follow this order, but this is done to introduce components one step at a time.)

Parameters phase:
  • NuFlav and/or Parent definitions
  • Detector definitions
  • Parameters construction
  • Parameters configuration, common to all Spectra
Spectra phase:
  • Var and/or Weight definitions
  • External weight setup
  • FluxReader construction
  • FluxReader::AddSpectra and Spectra specific Parameters configuration
Filling phase:
  • Output file setup
  • FluxReader::ReadFlux
  • Output file and FluxReader clean up
  • Combiner construction and use

Preprocessor Directives

So, why do those #ifdef, #else, and #endif lines appear (and that first version of the main function that only outputs a message)? The short answer is that they are necessary to make scripts run; without them, ROOT will output some error messages.

The long answer, which is not fully detailed here, has to deal with the compiler ROOT uses for compiled macros. There is an issue reading the std::function object, which is necessary for the Var and Weight objects, which are necessary for the Spectra objects, which are necessary for outputting distributions. Details aside, these lines ensure that the std::function object can be used properly, and that means happily filled distributions for you, the user.