KAHIBARO
Discord Login Register

2.4 Conditional Statements

Table of Contents

if

Conditional statements let your code make decisions: you check a condition, and depending on whether it is true or false, ROOT (and C++) executes different blocks of code. In analysis code this is how you apply cuts, choose how to fill histograms, or decide how to treat special cases.

The simplest conditional in C++ is the if statement. Its structure is:

cpp
if (condition) {
   // code that runs only if condition is true
}

The condition is any expression that can be evaluated as a boolean. It is usually a comparison using operators like ==, !=, <, >, <=, >=, or a logical combination with && (and), || (or), and ! (not).

For example, in a ROOT macro you might write:

cpp
double energy = 5.3;
if (energy > 5.0) {
   std::cout << "High energy event" << std::endl;
}

If energy is greater than 5.0, the message is printed. If the condition is false, the code inside the braces is skipped.

The braces {} define a block of code. For a single statement you can omit the braces, but it is safer to keep them, especially in analysis code where you often add more lines later. For example:

cpp
if (nHits == 0)
   std::cout << "No hits" << std::endl;   // legal, but easy to break if you add more code

If you later add a second line without braces, only the first line is protected by the if, which can create subtle bugs.

Conditions can combine several requirements. A typical event selection in a ROOT analysis might look like this:

cpp
if (energy > 1.0 && energy < 10.0) {
   hEnergy->Fill(energy);
}

Here the histogram is filled only when both parts of the condition are true, so this is a simple energy window cut.

You can also use logical || to accept events that satisfy at least one condition:

cpp
if (charge == 1 || charge == -1) {
   hCharge->Fill(charge);
}

This code selects events with positively or negatively charged particles, but not neutral ones.

Important rule: In C++ and ROOT macros, the if condition must be placed in parentheses, and the safest practice is to always use braces around the controlled block, even for a single statement.

else

The else clause allows you to run one block of code when the condition is true and a different block when it is false. The general form is:

cpp
if (condition) {
   // code if condition is true
} else {
   // code if condition is false
}

For example, you might want to fill two different histograms depending on the value of a variable:

cpp
double energy = 3.2;
if (energy >= 2.0) {
   hSignal->Fill(energy);
} else {
   hBackground->Fill(energy);
}

When energy is at least 2.0, the event is treated as signal and the first histogram is filled. Otherwise it is treated as background.

You can use else to handle default or corner cases, such as zero or negative values that you want to record separately:

cpp
if (time > 0) {
   hTime->Fill(time);
} else {
   hBadTime->Fill(time);
}

Only one of the two blocks is executed for each pass through the if statement. There is no situation where both the if and the else blocks run.

Be careful not to place a stray semicolon right after the if condition:

cpp
if (energy > 1.0); {             // WRONG: semicolon ends the if
   hEnergy->Fill(energy);        // always executed
}

The semicolon after if (energy > 1.0) ends the if statement, so the block in braces runs unconditionally. This is a common source of logic errors in C++.

Important rule: if (condition) statement; is valid, but if (condition); makes the condition useless. Avoid a semicolon directly after the if parentheses unless you intentionally want an empty body.

else if

Often you need to test several mutually exclusive conditions and choose exactly one of several actions. This is where else if chains are useful. The structure is:

cpp
if (condition1) {
   // code for condition1
} else if (condition2) {
   // code for condition2
} else if (condition3) {
   // code for condition3
} else {
   // code if none of the above is true
}

C++ evaluates the conditions from top to bottom. The first condition that is true determines which block runs, and the rest are skipped. If no condition is true and you provided an else at the end, the else block runs.

This is useful in ROOT analysis when you assign events to categories. For example, defining energy regions:

cpp
double energy = 4.7;
if (energy < 1.0) {
   hLow->Fill(energy);
} else if (energy < 5.0) {
   hMedium->Fill(energy);
} else if (energy < 10.0) {
   hHigh->Fill(energy);
} else {
   hVeryHigh->Fill(energy);
}

In this chain, each event goes into exactly one histogram. The ordering of the conditions matters. Once energy < 5.0 is true, the later conditions are not checked, even if they would also be true.

You can also combine comparisons inside else if conditions to define more complex regions, such as detector quadrants or angular sectors:

cpp
if (eta > 0.0 && phi >= 0.0) {
   hQuadrant1->Fill(eta, phi);
} else if (eta > 0.0 && phi < 0.0) {
   hQuadrant2->Fill(eta, phi);
} else if (eta <= 0.0 && phi < 0.0) {
   hQuadrant3->Fill(eta, phi);
} else {
   hQuadrant4->Fill(eta, phi);
}

Here again, each event ends up in exactly one category.

When designing else if chains, pay attention to the intervals you define so that they are complete and do not overlap unintentionally. For example, if you wrote two conditions like if (energy < 5.0) and later else if (energy < 3.0), the second one would never be used, because any value less than 3.0 is also less than 5.0 and will already satisfy the first condition.

Important rule: In an if / else if / else chain, only the block belonging to the first true condition is executed. Always order and define your conditions so that the ranges are non‑overlapping and cover all cases you care about.

Views: 13

Comments

Please login to add a comment.

Don't have an account? Register now!