ROOT Version 6.32 Release Notes

2024-05-26

Introduction

ROOT version 6.32.00 was released on 28 May 2024. This release is a long term support one, ideal for inclusion in production or data taking software stacks of experiments.

For more information, see:

http://root.cern

The following people have contributed to this new version:

Anton Alkin, Sungkyunkwan University
Guilherme Amadio, CERN/IT,
Abhigyan Acherjee, University of Cincinnati,
Bertrand Bellenot, CERN/EP-SFT,
Jakob Blomer, CERN/EP-SFT,
Rene Brun,
Carsten Burgard, DESY
Will Buttinger, RAL,
Philippe Canal, FNAL,
Jolly Chen, CERN/EP-SFT,
Olivier Couet, CERN/EP-SFT,
Marta Czurylo, CERN/EP-SFT,
Monica Dessole, CERN/EP-SFT,
Mattias Ellert, Uppsala University,
Gerri Ganis, CERN/EP-SFT,
Florine de Geus, CERN/University of Twente,
Andrei Gheata, CERN/EP-SFT,
Bernhard Manfred Gruber,
Enrico Guiraud, Jonas Hahnfeld, CERN/Goethe University Frankfurt,
Fernando Hueso Gonzalez, University of Valencia
Attila Krasznahorkay, CERN/EP-ADP-OS,
Wim Lavrijsen, LBL,
Dennis Klein, GSI,
Christoph Langenbruch, Heidelberg University/LHCb,
Sergey Linev, GSI,
Javier Lopez-Gomez,
Pere Mato, CERN/EP-SFT,
Alaettin Serhan Mete, Argonne,
Thomas Madlener, DESY,
Lorenzo Moneta, CERN/EP-SFT,
Alja Mrak Tadel, UCSD/CMS,
Axel Naumann, CERN/EP-SFT,
Dante Niewenhuis, VU Amsterdam
Luis Antonio Obis Aparicio, University of Zaragoza, Ianna Osborne, Princeton University,
Vincenzo Eduardo Padulano, CERN/EP-SFT,
Danilo Piparo, CERN/EP-SFT,
Fons Rademakers, CERN/IT,
Jonas Rembser, CERN/EP-SFT,
Andrea Rizzi, University of Pisa,
Andre Sailer, CERN/EP-SFT,
Garima Singh, ETH,
Juraj Smiesko, CERN/RCS-PRJ-FC, Pavlo Svirin, National Technical University of Ukraine,
Maciej Szymanski, Argonne,
Christian Tacke, Darmstadt University,
Matevz Tadel, UCSD/CMS,
Alvaro Tolosa Delgado, CERN/RCS-PRJ-FC,
Devajith Valaparambil Sreeramaswamy, CERN/EP-SFT,
Peter Van Gemmeren, Argonne,
Vassil Vassilev, Princeton/CMS,
Wouter Verkerke, NIKHEF/ATLAS, Stefan Wunsch

Deprecation and Removal

Core Libraries

The Cling interpreter now relies on LLVM version 16.

I/O Libraries

hadd respects compression settings

Fixed a bug that was previously changing the compression settings to a single digit number instead of the full value (by default 101).

TTree Libraries

Add files from subdirectories with TChain::Add globbing

It is now possible to add files from multiple subdirectories with TChain::Add globbing. For example,

TChain::Add("/path/to/tree/*/*.root")

grabs all the root files with the path /path/to/tree/somedir/file.root (but not /path/to/tree/file.root and /path/to/tree/somedir/anotherdir/file.root).

Another example:

TChain::Add("/path/to/tree/subdir[0-9]/*.root")

This grabs all the root files in subdirectories that have a name starting with subdir and ending with some digit.

Improved efficiency of TTree friends with indices

TTreeIndex and TChainIndex classes now implement the Clone method such that it does not use the ROOT I/O to clone the index but just does a copy in memory. Notably, this improves processing efficiency for RDataFrame in multithreaded execution since the same index must be copied over to all the threads and attached to the current tree for proper event matching.

RNTuple

ROOT’s experimental successor of TTree has seen a number of updates since the last release. Specifically, 6.32 includes the following changes:

Please, report any issues regarding the above mentioned features should you encounter them. RNTuple is still in pre-production. The on-disk format is scheduled to be finalized by the end of 2024. Thus, we appreciate feedback and suggestions for improvement.

Histogram Libraries

Parallelism

RooFit Libraries

New CPU likelihood evaluation backend by default

The new vectorizing CPU evaluation backend is not the default for RooFit likelihoods. Likelihood minimization is now up to 10x faster on a single CPU core.

If you experience unexpected problems related to the likelihood evaluation, you can revert back to the old backend by passing RooFit::EvalBackend("legacy") to RooAbsPdf::fitTo() or RooAbsPdf::createNLL().

In case you observe any slowdowns with the new likelihood evaluation, please open a GitHub issue about this, as such a performance regression is considered a bug.

Asymptotically correct uncertainties for extended unbinned likelihood fits

Added correct treatment of extended term in asymptotically correct method for uncertainty determination in the presence of weights. This improvement will allow for extended unbinned maximum likelihood fits to use the asymptotically correct method when using the RooFit::AsymptoticError() command argument in RooAbsPdf::fitTo(). See also this writeup on extended weighted fits that is also linked from the reference guide. The pull request that introduced this feature might also be a good reference.

Compile your code with memory safe interfaces

If you define the ROOFIT_MEMORY_SAFE_INTERFACES preprocessor macro, the RooFit interface changes in a way such that memory leaks are avoided.

The most prominent effect of this change is that many functions that used to return an owning pointer (e.g., a pointer to an object that you need to manually delete) are then returning a std::unique_pt for automatic memory management.

For example this code would not compile anymore, because there is the risk that the caller forgets to delete params:

RooArgSet * params = pdf.getParameters(nullptr);

If you wrap such return values in a std::unique_ptr, then your code will compile both with and without memory safe interfaces:

std::unique_ptr<RooArgSet> params{pdf.getParameters(nullptr)};

Also some virtual RooFit functions like RooAbsReal::createIntegral() are returning a different type conditional on ROOFIT_MEMORY_SAFE_INTERFACES. If you are overriding such a function, you need to use the RooFit::OwningPtr return type, which is an alias for std::unique_ptr in memory-safe mode or an alias for a raw pointer otherwise.

RooFit::OwningPtr<RooAbsReal> RooAbsReal::createIntegral(...) const override
{
   std::unique_ptr<RooAbsReal> integral;
   // Prepare a std::unique_ptr as the return value
   ...
   // Use the RooFit::makeOwningPtr<T>() helper to translate the
   // std::unique_ptr to the actual return type (either std::unique_ptr<T> or T*).
   return RooFit::makeOwningPtr<RooAbsReal>(std::move(integral));
}

The biggest application of the memory-safe interfaces is to spot memory leaks in RooFit-based frameworks. If you make sure that your framework compiles both with and without ROOFIT_MEMORY_SAFE_INTERFACES, you can get rid of all memory leaks related to RooFit user error! After making the necessary changes, you can remove the marco definition again to keep backwards compatibility.

Note that the memory-safe interfaces might become the default at some point, so doing this backwards-compatible migration early is strongly encouraged and appreciated.

Removal of some memory-unsafe interfaces

Deprecation of legacy iterators

The following methods related to the RooFit legacy iterators are deprecated and will be removed in ROOT 6.34. They should be replaced with the suitable STL-compatible interfaces, or you can just use range-based loops:

Deprecation of legacy test statistics classes in public interface

Instantiating the following classes and even including their header files is deprecated, and the headers will be removed in ROOT 6.34:

Please use the higher-level functions RooAbsPdf::createNLL() and RooAbsPdf::createChi2() if you want to create objects that represent test statistics.

Change of RooParamHistFunc

The RooParamHistFunc didn’t take any observable RooRealVar as constructor argument. It assumes as observable the internal variables in the passed RooDataHist. This means it was in most contexts unusable, because the input can’t be changed, other than loading a different bin in the dataset.

Furthermore, there was actually a constructor that took a RooAbsArg x, but it was simply ignored.

To fix all these problems, the existing constructors were replaced by a new one that takes the observable explicitly.

Since the old constructors resulted in wrong computation graphs that caused trouble with the new CPU evaluation backend, they had to be removed without deprecation. Please adapt your code if necessary.

Renaming of some RooFit classes

The RooPower was renamed to RooPowerSum, and RooExpPoly was renamed to RooLegacyExpPoly.

This was a necessary change, because the names of these classes introduced in ROOT 6.28 collided with some classes in CMS combine, which were around already long before. Therefore, the classes had to be renamed to not cause any problems for CMS.

In the unlikeliy case where you should have used these new classes for analysis already, please adapt your code to the new names and re-create your workspaces.

RDataFrame

Graphics backends

The ROOT release 6.32 brings a lot of impressive enhancements to the Web Graphics package, greatly surpassing the features and capabilities of version 6.30. This update provides users with a more robust Web Graphics.

2D Graphics Libraries

3D Graphics Libraries

REve

REveBoxSet screenshot with cone shape type. The set is using value to color map with overflow and underflow mark. The single REveBoxet object has a secondary selection enabled, where one can set a custom tooltip on mouse hover of an individual instance.

PROOF Libraries

By default, PROOF is not configured and built any more. It will be deprecated in the future given that its functionality is now provided by the superior RDataFrame and its distributed version, DistRDF.

PyROOT

PyROOT was rebased on the latest version of the cppyy library. This means PyROOT benefits from many upstream improvements and fixes, for example related to the conversion of NumPy arrays to vectors, implicit conversion from nested Python tuples to nested initializer lists, and improved overload resolution.

Related to this cppyy upgrade, there are some changes in PyROOT behavior.

Different representation of std::string

Calling repr() on a cppyy.gbl.std.string object now comes with a “b” prefix, i.e. a bytes object is returned instead of a Python string. This is an intentional change for better unicode support.

See: https://github.com/root-project/root/issues/15153#issuecomment-2040504962

No more implicit conversion of static size char buffer to Python strings

A static size character buffer of type char[n] is not converted to a Python string anymore. The reason for this: since it was previously assumed the string was null-terminated, there was no way to get the bytes after a null, even if you wanted to.

import ROOT

ROOT.gInterpreter.Declare("""
struct Struct { char char_buffer[5] {}; }; // struct with char[n]
void fill_char_buffer(Struct & st) {
    std::string foo{"foo"};
    std::memcpy(st.char_buffer, foo.data(), foo.size());
}
""")

struct = ROOT.Struct()
ROOT.fill_char_buffer(struct)
char_buffer = struct.char_buffer

# With thew new cppyy, you get access to the lower level buffer instead of a
# Python string:
print("struct.char_buffer            : ", char_buffer)

# However, you can turn the buffer into a string very easily with as_string():
print("struct.char_buffer.as_string(): ", char_buffer.as_string())

The output of this script with ROOT 6.32:

struct.char_buffer            :  <cppyy.LowLevelView object at 0x74c7a2682fb0>
struct.char_buffer.as_string():  foo

Deprecate the attribute pythonization of TDirectory in favor of item-getting syntax

The new recommended way to get objects from a TFile or any TDirectory in general is now via __getitem__:

tree = my_file["my_tree"] # instead of my_file.my_tree

This is more consistent with other Python collections (like dictionaries), makes sure that member functions can’t be confused with branch names, and easily allows you to use string variables as keys.

With the new dictionary-like syntax, you can also get objects with names that don’t qualify as a Python variable. Here is a short demo:

import ROOT

with ROOT.TFile.Open("my_file.root", "RECREATE") as my_file:

    # Populate the TFile with simple objects.
    my_file.WriteObject(ROOT.std.string("hello world"), "my_string")
    my_file.WriteObject(ROOT.vector["int"]([1, 2, 3]), "my vector")

    print(my_file["my_string"])  # new syntax
    print(my_file.my_string)  # old deprecated syntax

    # With the dictionary syntax, you can also use names that don't qualify as
    # a Python variable:
    print(my_file["my vector"])
    # print(my_file.my vector) # the old syntax would not work here!

The old pythonization with the __getattr__ syntax still works, but emits a deprecation warning and will be removed from ROOT 6.34.

Removal of Python 2 support

ROOT does no longer support Python 2. The minimum Python version necessary to use ROOT in a Python application is 3.8. As a consequence, any reference to Python 2 in ROOT code was removed and certain configuration options are no longer usable, e.g.

The cmake build system now looks for the standard Python3 package and previously custom Python-related cmake variables are now just the ones automatically produced by cmake (see https://cmake.org/cmake/help/latest/module/FindPython.html).

More usage of the public cppyy API

Many implementation details of the ROOT pythonizations were moved from C++ functions to pure Python bindings using the public cppyy API. This helps in the integration with the tool but also improves code efficiency and memory usage.

Class Reference Guide

Build, Configuration and Testing Infrastructure

Release v6.32.00 is the first one integrated and tested entirely through the new GitHub based build system.

Bugs and Issues fixed in this release

More than 200 items were addressed for this release. The full list is:

Release 6.32.02

Published on June 18, 2024

Items addressed in this release

HEAD of the v6-32-00-patches branch