KAHIBARO
Discord Login Register

13.8. Applying Selection Cuts

Simple cuts

Selection cuts are rules that decide which entries of a TTree are used in an analysis and which are ignored. In ROOT, the most direct way to apply cuts is with the TTree::Draw interface, using a C++ like expression as a string.

The basic syntax for drawing a histogram of a branch with a cut is:

cpp
tree->Draw("variable", "cut_expression");

The first argument tells ROOT what to plot or compute. The second argument is the selection cut. Only entries for which the cut expression evaluates to true are included.

For example, suppose your TTree has a branch energy. To draw a histogram including only events with energy above 1 GeV, you can write:

cpp
tree->Draw("energy", "energy > 1.0");

Internally, ROOT loops over all entries in the TTree, evaluates energy > 1.0 for each entry, and fills the histogram only when the expression is true.

ROOT also supports cuts when drawing expressions of several variables. For instance, to plot energy versus time only for entries with time in a given range:

cpp
tree->Draw("energy:time", "time > 0 && time < 100");

Here the first argument energy:time selects a 2D plot, and the second argument restricts which events contribute.

Whenever you omit the cut argument altogether, all entries are used:

cpp
tree->Draw("energy"); // no selection cut

You can also count how many events pass a cut by drawing a constant:

cpp
tree->Draw("1", "energy > 1.0");
Long64_t nSelected = tree->GetSelectedRows();

After the Draw call, GetSelectedRows() gives the number of entries that satisfied the cut.

A useful mental model is: the cut expression is evaluated per entry, using the branch values of that entry, and it must evaluate to a nonzero value to accept that entry.

Key rule: In TTree::Draw(var, cut), the cut expression is evaluated for every entry. Only entries where the expression is true (nonzero) are used.

Multiple conditions

Real analyses almost always need more than one requirement at the same time. For example, you might want events with energy above a threshold and also within a certain time window, or you might want to require one condition or another. Multiple conditions are combined directly in the cut string.

To require that all conditions hold simultaneously, you combine them with logical AND:

cpp
tree->Draw("energy", "energy > 1.0 && time > 0 && time < 100");

This selects only entries where the energy is above 1.0 and the time is between 0 and 100.

To accept entries that satisfy either of two conditions, you use logical OR:

cpp
tree->Draw("energy", "region == 1 || region == 2");

This includes events from region 1 or region 2.

To reject entries with a certain property, you use logical NOT:

cpp
tree->Draw("energy", "!(status == 0)");

which is equivalent to

cpp
tree->Draw("energy", "status != 0");

You can combine several kinds of conditions and use parentheses to control the grouping. For example, to select events in a given time window and belonging to one of two detector regions:

cpp
tree->Draw("energy", "time > 0 && time < 100 && (region == 1 || region == 2)");

Here, only events with 0 < time < 100 and region equal to 1 or 2 are used.

Conditions can also involve arithmetic expressions, not only simple comparisons of single branches. For example, with branches px, py, and pz, you can cut on the magnitude of momentum:

cpp
tree->Draw("pz", "sqrt(px*px + py*py + pz*pz) > 1.0");

As long as the expression is valid C++ with functions and operators known to ROOT, you can use it in a cut.

You can test your selection by first counting how many entries pass it:

cpp
tree->Draw("1", "time > 0 && time < 100 && energy > 1.0");
std::cout << "Events passing selection: " << tree->GetSelectedRows() << std::endl;

This helps you quickly see whether your selection is reasonable.

It is a good habit to start with a simple selection and then gradually add more conditions, so it is clear which condition has which effect on the number of events and on the resulting distributions.

Logical operators

Selection cuts use the same logical and comparison operators that you use in C++ code. The most common are:

TypeOperatorMeaningExample
Comparison==equal toregion == 1
Comparison!=not equal tostatus != 0
Comparison<less thanenergy < 5.0
Comparison>greater thantime > 0
Comparison<=less than or equal tonHits <= 10
Comparison>=greater than or equal tonHits >= 3
Logical&&logical AND (both conditions true)energy > 1 && time < 100
Logical`\\`logical OR (at least one is true)`region == 1 \\region == 2`
Logical!logical NOT (negation)!(status == 0)

Comparison operators compare branch values to constants or to other branch values. The result of a comparison is a boolean value, true or false. Logical operators combine these boolean values into more complex conditions.

The logical AND operator && is true only if both sides are true. The logical OR operator || is true if at least one side is true. The logical NOT operator ! inverts the truth value.

Operator precedence is important when combining several conditions. In C++ and ROOT expressions:

  1. Arithmetic operations like +, -, *, / are evaluated first.
  2. Comparison operators like >, <, >=, <=, ==, != come next.
  3. Logical NOT ! is applied.
  4. Logical AND && is evaluated.
  5. Logical OR || is evaluated last.

Whenever in doubt, use parentheses to specify the intended grouping. For example:

cpp
// Clear grouping of OR vs AND
"energy > 1.0 && (region == 1 || region == 2)"

Without parentheses, an expression like

cpp
"energy > 1.0 && region == 1 || region == 2"

is interpreted as

cpp
"(energy > 1.0 && region == 1) || region == 2"

which is not the same as requiring energy > 1.0 for both regions.

You can also use conditional expressions involving mathematical functions and type conversions, as long as they are available to the ROOT interpreter:

cpp
"abs(eta) < 2.5 && pt > 0.5"

where abs and similar functions are resolved by ROOT.

Finally, cuts can also use weights, although the meaning is slightly different. If you pass a weight expression as the third argument to Draw, you keep the logical cut separate from the event weights:

cpp
tree->Draw("energy", "energy > 1.0", "weight");

Here, the second argument still defines which events are used, through logical operators and comparisons. The third argument provides a numerical weight for each selected event.

Important: Logical operators in cuts obey C++ precedence rules. Use parentheses to control grouping and avoid relying on implicit precedence when combining && and ||.

Understanding and using these logical operators correctly is the basis of building clear and reliable selection cuts for event based analyses in ROOT.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!