KAHIBARO
Discord Login Register

23.4 Naming Conventions

Why Naming Conventions Matter

Good naming is one of the simplest ways to make ROOT analysis code easier to read, debug, and share. In a typical analysis you may have hundreds of histograms, trees, functions, and variables. If names are not consistent, you will quickly lose track of what is stored where, what is being plotted, and which file or macro produced a given result.

Consistent conventions help you and your collaborators answer questions like "Where is the selection histogram for electrons?" or "What does h1 actually represent?" without opening code line by line. They also reduce mistakes such as overwriting objects, misreading units, or applying cuts to the wrong quantity.

This chapter focuses on practical naming patterns for C++ identifiers and ROOT objects in analysis code. It does not introduce new ROOT concepts, but shows how to name the things you are already creating so your project remains understandable and maintainable.

Important: Choose a convention once and apply it consistently across macros, source files, and ROOT files. Inconsistent naming is almost as problematic as no naming convention at all.

General Principles for Names

There is no single "official" ROOT naming standard for user code, but there are a few widely used principles that work very well in physics analysis.

First, names should be descriptive. A name like hMuPt is immediately more informative than h1. It suggests a histogram (h), related to muons (Mu), and their transverse momentum (Pt). Similarly, treeData is more informative than t or mytree.

Second, prefer clarity over brevity. A long but clear name is usually better than a short but cryptic one, especially when you or someone else returns to the code months later. That said, many physics terms are naturally short and conventional, such as pt, eta, phi, E, which are reasonable to use.

Third, keep style consistent. If you decide to use camelCase for variables, do not mix it with snake_case for similar concepts in the same codebase. If histograms for electrons begin with hEl, do not suddenly use hElectron for only some of them.

A very common C++ style that fits nicely with ROOT analysis code is:

Table 1: Common style choices for user analysis code

CategoryTypical styleExample
VariablescamelCasenEvents, muPt
FunctionscamelCase starting verbfillHistos, selectEvent
ClassesPascalCaseEventSelector, Muon
ConstantskCamelCase with k-prefixkPi, kElectronMass

You do not have to follow these exact choices, but using one coherent style is extremely helpful.

Rule: Use descriptive, stable names for quantities that appear in many places in your analysis. Do not rename the same physical concept under slightly different names in different macros.

C++ Variable and Function Names

In ROOT analysis you write C++ variables, functions, and sometimes classes, either directly in the ROOT prompt, in macros, or in compiled code. The underlying C++ rules are always the same: names must start with a letter or underscore, cannot contain spaces, and may contain letters, digits, and underscores.

For basic analysis macros, a good pattern is to use short but descriptive variable names that reflect their role and physical meaning.

For scalar variables that represent physical observables, combine a short physics abbreviation with the unit or context when useful. For example, you might use ptGeV or energyMeV. If a given branch in a TTree is named pt, you can mirror that in your variable pt.

For loop indices and small local variables, using terser names like i, j, or idx is acceptable, especially in short loops. If those indices are connected to specific concepts, such as detector layers, you might prefer iLayer or iHit.

Function names are clearer when they read like commands or queries. Examples include fillHistograms, applySelection, computeInvariantMass, or isGoodEvent. This makes the flow easy to read when scanning the macro: you see a set of function calls that describe the analysis steps.

If you define functions that return something, let the name hint at the return value. For example, getMuonPt suggests it returns a momentum value, while selectGoodMuons suggests it performs a selection and returns a container or count. Avoid generic verbs without context such as doStuff.

Finally, avoid reusing the same variable name for different purposes in a large scope. Reassigning n first as number of events, then as number of bins in a histogram, creates confusion and is a common source of mistakes.

Naming ROOT Objects

ROOT objects, such as histograms, graphs, canvases, and functions, require two separate ideas for naming: the C++ variable name and the internal ROOT object name. The C++ variable name exists in the C++ code. The ROOT object name is a string stored inside the object that ROOT uses for identification, particularly when writing to and reading from ROOT files.

It is very helpful to adopt a pattern where C++ variables and ROOT object names are closely related but not necessarily identical. For example, if you have a histogram:

cpp
TH1F *hMuPt = new TH1F("hMuPt", "Muon p_{T};p_{T} [GeV];Events", 100, 0.0, 100.0);

The C++ variable is hMuPt and the ROOT object name is the string "hMuPt". Using the same string for both makes it easy to find the object later using file browsers and code. You can then read it back from a file with:

cpp
TH1F *hMuPt = (TH1F*)file->Get("hMuPt");

This alignment between variable and object name avoids having to track two entirely different naming schemes.

In larger analyses, you may decide that ROOT object names encode a minimal structure while C++ variables carry more contextual information. For example, you might choose "hMuPt" as the ROOT name and use hMuPtAfterBasicSelection as the C++ variable, but you should only do this if there is a clear and consistent logic.

It is especially important to make ROOT object names unique within a given ROOT file or directory. If two histograms share the same ROOT name and you write both to the same file or directory, one will overwrite the other. This is a common and frustrating error that consistent naming largely avoids.

Rule: Ensure that ROOT object names are unique within a given directory or file. If the same object name is reused, the previous object can be silently overwritten when writing to a ROOT file.

Histograms, Graphs, and Canvases

Histograms, graphs, and canvases are central to ROOT analysis, and consistent naming of these objects saves a lot of work.

For histograms, it is common to use a prefix that indicates the type of object and then a short description of what is being binned. A very standard pattern is:

Combining this with a short observable name gives names such as hPt, hMuEta, hElEnergy, or h2EtaPhi. If there are several variants of the same histogram with different selections, suffixes can encode the selection, for example hPtAll, hPtSelected, hPtSignal, or hPtBackground.

Graph names can follow a similar strategy. For TGraph and related classes, people often use g as a prefix such as gResolution, gCalib, or gEffVsPt. For TMultiGraph, a prefix like mg distinguishes it from single graphs, for instance mgComparisonPt.

Canvases usually do not need extremely precise names, but recognizable ones make interactive work and saved files easier to manage. A short prefix like c for TCanvas is standard. For example, cPtSpectra, cEffVsPt, or simply c1, c2 for quick tests. For an analysis that will be revisited, names like cMuonKinematics or cFinalResult are more informative than generic numbers.

Remember that histograms, graphs, and canvases often appear in ROOT files, in plot image filenames, and in macros. Using the same base name for all representations helps trace the flow, for example a canvas cMuonPt, a plot file cMuonPt.pdf, and a histogram hMuPt drawn on that canvas.

TTree Branches and Variables

For TTrees and branches, naming is especially critical because these names define the structure of your persistent data. You will rely on these names both in traditional TTree loops and in modern interfaces such as RDataFrame, and sometimes even from other tools or languages like PyROOT.

It is very helpful to distinguish between event level branches and per object or per hit quantities. Event level quantities, such as run number, event number, or global weights, can have simple names like run, event, weight, or nVertex.

When representing collections, such as multiple particles per event, you often store std::vector branches. In that case, use a plural or collection indicative name for the branch, such as mu_pt, mu_eta, mu_phi, or jet_pt. This makes it obvious that these variables are vectors when reading analysis code.

Consistent abbreviations for physics objects help. For example, you might choose:

Table 2: Common physics abbreviations for branches

Object typeSuggested abbreviationExamples
Electronel or eleel_pt, el_eta
Muonmumu_pt, mu_charge
Jetjetjet_pt, jet_eta, jet_btag
Photonph or phoph_pt, ph_iso
Missing energymetmet, met_phi

Pick a set of abbreviations and stick with it in all TTrees you create for a project.

It is also useful to encode units or context in some branch names if ambiguity might cause mistakes. For example, you can decide that all energies and transverse momenta are stored in GeV and use names such as pt with documentation, or you can write ptGeV directly. What matters is that the choice is clear and documented.

Branch names are often mirrored by local variables in event loops. For readability, you can use similar names like float mu_pt_0 for the first muon transverse momentum in a fixed layout tree, or reuse mu_pt as a vector in the analysis code for a vector branch. Avoid renaming branches to completely unrelated variable names when reading them, because this creates another mental mapping layer.

Finally, TTree names should reflect the data content or processing stage. For example Events, RecoTree, SimTree, DataTree, or AnalysisTree are typical names. If you produce several different trees in an analysis, a suffix can reflect the selection or processing, such as EventsSelected or EventsWithWeights.

Rule: Avoid renaming the same physical quantity with different branch names in different ROOT files within the same project. Consistent branch naming makes combining and reusing data much easier.

Files, Directories, and Output Names

Beyond C++ identifiers and ROOT object names, a full analysis produces ROOT files, text outputs, configuration files, and image files. Naming conventions for these artifacts are essential when a project grows beyond a few quick tests.

ROOT file names should convey the dataset and processing step. For instance, you might name input data files data_run123.root or mc_Zmumu.root, and processed analysis outputs analysis_run123_selection.root or histograms_Zmumu.root. A common structure is:

An example might be data_Zmumu_v1.root and mc_Zmumu_v1.root. When you later refine your analysis, you can create data_Zmumu_v2.root, which makes the version history explicit.

Inside ROOT files, you can use directories (TDirectory) to organize objects by analysis step or object type. Directories with names like histos, graphs, fits, control_plots, or final_plots make it easier to navigate your file in the ROOT browser. Avoid dumping every object into the top level unless the file is intentionally small.

For plot image files, using the same base name as the canvas or central histogram keeps things traceable. For example, a canvas cMuonPt containing histogram hMuPt could be saved as muon_pt_spectrum.png or cMuonPt.png. Including information about selection or cuts in the filename is often valuable, for example muon_pt_after_cuts.png or muon_pt_inclusive.pdf.

If your analysis uses configuration or parameter files, their names should reflect the role and the intended usage. For example, config_selection.cfg, config_plotting.json, or weights_trigger.root. This ties into broader configuration practices, but even simple naming helps identify the function of each file when reviewing a directory listing.

Consistency Across a Project

All the individual naming suggestions above are most powerful when applied consistently across your entire project. That includes multiple macros, C++ source files, ROOT files, and scripts, as well as possible Python code when you use PyROOT.

To maintain consistency, it is often useful to write down your chosen conventions in a small text file or documentation page at the beginning of a project. This might describe which prefixes you use for histograms, which abbreviations represent particle types, how you encode units, and how you name input and output ROOT files. New collaborators can read this once and immediately understand the structure of the analysis.

It is also important to reuse names rather than inventing new variants. If you call a variable met in one macro, do not call the same physical quantity missingET in another macro and E_T_miss in a third. Instead, choose one name and use it everywhere. This reduces confusion when searching across files and in logic that combines outputs from different steps.

Consistent naming also interacts with other good practices described in this part of the course. When you separate analysis code from plotting code, your common naming conventions bridge those modules. Functions that operate on hMuPt in one file and on plots of hMuPt in another file rely on the shared meaning of that name. Similarly, when you avoid hard coded values using configuration parameters, naming conventions for configuration keys must be as consistent as variable names in the code.

Finally, be careful when copying and modifying existing macros. Copying code that uses older or different naming styles into a newer project can introduce inconsistency. When you adapt code, take the time to rename objects and variables to match your chosen convention. This initial effort pays off in simpler debugging and clearer analysis logic later on.

Views: 13

Comments

Please login to add a comment.

Don't have an account? Register now!