Dynamically defined logical expressions (tests/cuts)

Ole Hansen
Rev 1.0, 14 June 2003

Overview

An important feature of the C+ analyzer is the ability to define arithmetic and logical expressions dynamically (on the fly) without the need to recompile any code. Underlying both types of expressions are "global variables" that are represented by the THaVar class and collected in the global variable list THaVarList. Each analysis module (detector, apparatus, physics module) normally adds internal variables of interest to the global variable list gHaVars as part of its initialization and removes those variables from the list in its destructor. For an example, see THaScintillator. In this way, analysis results are conveniently available for use in expressions and by THaOutput.

Arithmetic expressions are supported by the THaFormula class, while tests/cuts are special cases of THaFormulas which evaluate to either 1 or 0 (true or false) and are represented by the THaCut class. In the C++ analyzer, THaFormulas are primarily used in the THaOutput system, while THaCuts are used for two purposes: (1) in THaOutput as conditions on histograms; and (2) to control the flow of the data analysis in the standard analysis algorithm. The latter is supported by a special global list of tests, THaCutList, THaCutList supports the concept of "blocks" of cuts which can be evaluated as a unit. Blocks are evaluated at the end of each stage of the analysis (Decode/Reconstruct/Physics).

The interactive interface to the analyzer, THaInterface, automatically creates an instance of THaVarList and THaCutList upon startup. These are called the "global variable list" and "global cut list", respecively. They are accessible via the global variables gHaVars and gHaCuts from anywhere in the analyzer if you #include "THaGlobals.h.

Examples

A short tutorial on using the test/cut classes along with the global variable system follows. As mentioned, the relevant classes are: Here is a sample session to demonstrate the use of these classes:
analyzer [0] double xvar=10             // Define a variable xvar
analyzer [1] gHaVars->Define("x",xvar)  // Add xvar to global var list, name it "x"
analyzer [2] gHaVars->PrintFull()       // Show all global vars defined including their current values
  OBJ: THaVar     x     x
  (Double_t)[1]  10

analyzer [3] gHaCuts->Define("cut1","x>0")      // Define a cut named "cut1" that is true if x>0.
analyzer [4] gHaCuts->Define("cut2","abs(x)>5") // dto., but |x|>5
analyzer [5] gHaCuts->Print()                   // List all defined cuts
  Name  Def       T  Block    Called     Passed
  -------------------------------------------------
  cut1  x>0       0  Default  0          0 (0.0%)
  cut2  abs(x)>5  0  Default  0          0 (0.0%)

analyzer [6] gHaCuts->Eval()                   // Evaluate all defined cuts
analyzer [7] gHaCuts->Print()
  Name  Def       T  Block    Called     Passed
  -------------------------------------------------
  cut1  x>0       1  Default  1          1 (100%)
  cut2  abs(x)>5  1  Default  1          1 (100%)

(Note the current value ("T") of each of the cuts. Both are true since both
conditions are true for x=10).

analyzer [8] xvar=2                           // Give xvar a new value
analyzer [9] gHaCuts->Eval()                  // Evaluate the cuts again
analyzer [10] gHaCuts->Print()
  Name  Def       T  Block    Called     Passed
  -------------------------------------------------
  cut1  x>0       1  Default  2          2 (100%)
  cut2  abs(x)>5  0  Default  2          1 (50%)

(Note that cut2 is now false since |x| is less than 5.)

analyzer [11] gHaCuts->Result("cut2")        // Retrieve result of cut2
                                             // NB: This does not re-evaluate the cut
  (Int_t)0
analyzer [11] gHaCuts->Result("cut1")
  (Int_t)1

Tests may refer to other tests already defined in gHaCuts. When evaluating cuts containing other tests, the referenced tests are not re-evaluated, but the result of their last evaluation is used (as in the call to THaCutList::Result() above). This ensures that the test statistics (i.e. number of calls/number of passes) remain consistent when evaluating all the tests for an event. Here's an example, continuing from above:

analyzer [12] gHaCuts->Define("cut3","cut1&&!cut2") // Define cut based on two previously-defined cuts
analyzer [13] gHaCuts->Eval()                       // Evaluate defined cuts again
analyzer [14] gHaCuts->Print()
  Name  Def          T  Block    Called     Passed
  ----------------------------------------------------
  cut1  x>0          1  Default  3          3 (100%)
  cut2  abs(x)>5     0  Default  3          1 (33.3%)
  cut3  cut1&&!cut2  1  Default  1          1 (100%)

Using tests to control the analysis

To define tests to be evaluated at each stage of the analysis, the definitions of the cuts are placed in a plain-text input file, the "cut definition file". The file name must be given to the analyzer via a call to SetCutFile(). Example:
analyzer [24] THaAnalyzer* analyzer = new THaAnalyzer;
analyzer [25] analyzer->SetCutFile("cuts.def")
The format of the file is illustrated in the following example:
# Demo cut definition file
#
Block: RawDecode

evtyp1            g.evtyp==1          // Event type 1 (=HRSR main trigger)
poshel            g.helicity==1
neghel            g.helicity==-1
goodhel           poshel||neghel
RawDecode_master  evtyp1

Block: Decode

NoisyU1           R.vdc.u1.nhit>50
NoisyV1           R.vdc.v1.nhit>50
NoisyU2           R.vdc.u2.nhit>50
NoisyV2           R.vdc.v2.nhit>50
NoisyVDC          NoisyU1||NoisyV1||NoisyU2||NoisyV2
EnoughShowerHits  R.sh.nhit>10
Decode_master     !NoisyVDC
See the "examples" directory and the Quickstart Guide for more examples.

Notes:

See also THaCutList::Load().

If a test with the name "blockname"_master is defined (example "Decode_master"), then if this test is false for a given event, further analysis of that event will be skipped.

A summary of the test results is printed to the screen at the end of the analysis. A copy of the printout ("cut summary") can be written to a file if the name of the file is set via a call to SetSummaryFile() before starting the analysis.

Using tests as conditions in THaOutput

Tests defined in the cut definition file as well as separately-defined tests can be used as conditions for filling histograms. For details, please see the documentation of THaOutput.


Last modified: Mon Jun 16 13:36:35 EDT 2003

Maintained by Ole Hansen