-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Tutorial] How to create ROOT Dictionary for a custom class is a stand-alone C++ project #13205
Merged
jalopezg-git
merged 47 commits into
root-project:master
from
atolosadelgado:custom_class_tree_example
Aug 27, 2023
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
d942c13
Tutorial added, about how to create ROOT Dictionary for a custom class
atolosadelgado b33ef85
Update tutorials/tree/dictionary/README.md
atolosadelgado 0bbff47
Update tutorials/tree/dictionary/CMakeLists.txt
atolosadelgado 1104f8e
Update tutorials/tree/dictionary/README.md
atolosadelgado 74f5837
Update tutorials/tree/dictionary/data2Tree.cpp
atolosadelgado c8cf91d
Update tutorials/tree/dictionary/data2Tree.cpp
atolosadelgado 566019d
Update tutorials/tree/dictionary/readTree.cpp
atolosadelgado 7bb519a
Update tutorials/tree/dictionary/writeTree.cpp
atolosadelgado 5c87723
Update tutorials/tree/dictionary/writeTree.cpp
atolosadelgado ee0adaa
Functions writeTree and readTree are now compiled separataly as state…
atolosadelgado a476225
Unique pointer is used now for holding the TFile object as stated here
atolosadelgado c7be2ca
New line added to end of file as stated here
atolosadelgado 3184750
delete half sentence, as stated here
atolosadelgado 2bbd027
Removed PIC flag according to P. Canal,
atolosadelgado 322663c
Removed include and link ROOT directories, removed ROOT flags, as sta…
atolosadelgado 75fe159
Removed as stated in
atolosadelgado ea91a9b
comment added as stated in
atolosadelgado db5f376
header files updated as stated in
atolosadelgado c2811c0
std::unique_ptr<TTree> used, redundant write/close calls removed, as …
atolosadelgado ff8990a
close file call removed, as stated in
atolosadelgado c27ba72
Added property to export symbols and create data2TreeLib.lib file, as…
atolosadelgado f187820
space removed as stated in https://github.com/root-project/root/pull/…
atolosadelgado 8918f82
opening of file method back to TFile::Open, check of file status impr…
atolosadelgado 5d68c66
std:cerr replaced by std:cout for expected output, as stated in https…
atolosadelgado 0566cd2
method to open file changed back to TFile::Open method, as stated in …
atolosadelgado 9ee2527
ÂTTree::Fill method called just once after filling data into objects,…
atolosadelgado dabe214
debug message removed as stated in https://github.com/root-project/ro…
atolosadelgado 556f639
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado d998e6e
cerr replaced by cout
atolosadelgado caf5a05
cout replaced by cerr for 2 warning messages
atolosadelgado 191250e
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado 5e694ff
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado ddcef7e
Exception thrown if not possible to open file, as suggested in
atolosadelgado 825ddc5
Extension hpp/cpp changed to hxx/cxx, according to
atolosadelgado 7a2e0b0
Example of how to print values from a DataFrame, suggested by
atolosadelgado 92ae246
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado edb9278
Description of CMakelists updated, as suggested by
atolosadelgado 264d23e
List of ROOT components simplified according to
atolosadelgado 3ddec6f
Line removed according to
atolosadelgado 03c72c6
Extended explanation about dictionary added, according to
atolosadelgado 7df705d
clang format passes, as suggested in
atolosadelgado d835e4b
Note about the dot role at the end of the branch name, as suggested in
63f13e3
Little expansion of README file
f7f9fe4
Clang format is ok now...
238b980
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado 9ae5a98
Merge branch 'root-project:master' into custom_class_tree_example
atolosadelgado 49ee1f3
More details in CMakeList added, according to
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. | ||
# All rights reserved. | ||
# | ||
# For the licensing terms see $ROOTSYS/LICENSE. | ||
# For the list of contributors see $ROOTSYS/README/CREDITS. | ||
|
||
##################################################################################################################### | ||
|
||
# Details about integrating ROOT into CMake projects: | ||
# https://root.cern/manual/integrate_root_into_my_cmake_project/ | ||
|
||
##################################################################################################################### | ||
|
||
# CMakeLists.txt that creates a library with dictionary and a main program | ||
cmake_minimum_required(VERSION 3.9 FATAL_ERROR) | ||
|
||
project(treeUsingCustomClass) | ||
|
||
#---Locate the ROOT package and defines a number of variables (e.g. ROOT_INCLUDE_DIRS) | ||
find_package(ROOT REQUIRED COMPONENTS Tree TreePlayer ROOTDataFrame) | ||
|
||
#---Include a CMake module which makes use of the previous variables and loads modules | ||
# with useful macros or functions such as ROOT_GENERATE_DICTIONARY | ||
# For further details: https://root-forum.cern.ch/t/how-to-integrate-root-into-my-project-with-cmake/37175 | ||
include(${ROOT_USE_FILE}) | ||
|
||
#---Add include directory of ROOT to the build | ||
include_directories(${CMAKE_SOURCE_DIR}) | ||
|
||
# CMake function provided by ROOT, used to generate the dictionary file, G__data2Tree.cxx | ||
# See this link for further details: | ||
# https://root.cern/manual/io_custom_classes/#using-cmake | ||
ROOT_GENERATE_DICTIONARY(G__data2Tree data2Tree.hxx LINKDEF data2TreeLinkDef.hxx) | ||
|
||
#---Create a shared library from | ||
# * the previously generated dictionary, G__data2Tree.cxx | ||
# * the class implementation | ||
add_library(data2TreeLib SHARED data2Tree.cxx G__data2Tree.cxx) | ||
target_link_libraries(data2TreeLib ${ROOT_LIBRARIES} ) | ||
|
||
atolosadelgado marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#--- This is needed on Windows in order to export the symbols and create the data2TreeLib.lib file | ||
if(MSVC) | ||
set_target_properties(data2TreeLib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) | ||
endif() | ||
|
||
#---Create a main program using the library | ||
add_executable(treeExample main.cpp writeTree.cxx readTree.cxx readTreeDF.cxx) | ||
target_link_libraries(treeExample ${ROOT_LIBRARIES} data2TreeLib) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
How to read and write custom classes in TTree | ||
============================================= | ||
|
||
This example shows how to use ROOT as a toolkit to write and read a TTree containing custom classes. | ||
|
||
# Starting steps | ||
|
||
1. Build the project, it requires ROOT | ||
|
||
``` | ||
cmake -B build -S . | ||
cmake --build build | ||
``` | ||
|
||
2. Run the executable | ||
|
||
``` | ||
./build/treeExample | ||
``` | ||
|
||
3. Inspect the output rootfile, and the source code. | ||
|
||
jalopezg-git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Files | ||
|
||
This example shows how to use ROOT as a library in a C++ project. The C++ main function is defined in the file main.cpp. The code that writes the TTree onto disk is contained in the file writeTree.cxx. The files readTree.cxx and readTreeDF.cxx show two different ROOT interfaces to read a TTree. The files data2tree.* contain the code for the custom class that fills the TTree. | ||
|
||
## Definition of custom class | ||
|
||
The TTree can be seen as a collection of objects (branches), with a number of attributes (leaves). The name of the branch corresponds to the name of the instantiated object. The name of the leaves corresponds to the name of the attributes. | ||
|
||
The class that is present in the TTree is declared in the file data2tree.hpp, and the methods defined in the file data2tree.cpp. | ||
|
||
To be able to read and write objects of a particular user-defined type, ROOT I/O needs to know some information about the class/struct, e.g. the class members and their types, offset of each data member, etc. This information is contained in a ROOT dictionary; see [I/O of custom classes](https://root.cern/manual/io_custom_classes/#generating-dictionaries) for more information. | ||
|
||
The linkdef file contains some instructions for ROOT, to specify which classes will require a dictionary: | ||
jalopezg-git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
``` | ||
#pragma link C++ class myFancyClass+; | ||
``` | ||
|
||
If for example `std::vector` of such class is also used in the TTree as well, it should be notified to ROOT as another separated instruction: | ||
|
||
``` | ||
#pragma link C++ class std::vector<myFancyClass>+; | ||
``` | ||
|
||
# Links: | ||
* ROOT documentation: https://root.cern/manual/io_custom_classes/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
// This file contains the definition of the class method | ||
// The class method was declared in the corresponding .hpp file | ||
|
||
#include "data2Tree.hxx" | ||
|
||
void myDetectorData::clear() | ||
{ | ||
time = 0; | ||
energy = 0; | ||
detectorID = 0; | ||
correlatedDetectors_v.clear(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
// This file declares a class, with some members and method | ||
// The definition of the method is done in the corresponding .cpp file | ||
|
||
#ifndef __data2Tree__ | ||
#define __data2Tree__ | ||
|
||
#include <vector> | ||
|
||
class myDetectorData { | ||
public: | ||
//-- Example of method... | ||
void clear(); | ||
|
||
//-- Class members | ||
//-- initialized by construction, C++11 | ||
double time = 1; | ||
double energy = 2; | ||
int detectorID = 3; | ||
std::vector<double> correlatedDetectors_v = {1, 2, 3}; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
// This file contains a selection of types that will be described in the ROOT dictionary. | ||
// Further details in: https://root.cern/manual/io_custom_classes/#selecting-dictionary-entries-linkdefh | ||
|
||
#ifdef __CLING__ | ||
|
||
#pragma link C++ class myDetectorData + ; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
#include <iostream> | ||
|
||
void writeTree(); | ||
void readTree(); | ||
void readTreeDF(); | ||
|
||
int main() | ||
{ | ||
std::cout << "Starting writeTree()..." << std::endl; | ||
writeTree(); | ||
std::cout << "Starting writeTree()... Done! " << std::endl; | ||
std::cout << "Starting readTree()..." << std::endl; | ||
readTree(); | ||
std::cout << "Starting readTree()... Done! " << std::endl; | ||
std::cout << "Starting readTreeDF()..." << std::endl; | ||
readTreeDF(); | ||
std::cout << "Starting readTreeDF()... Done! " << std::endl; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
#include <iostream> | ||
|
||
#include <TFile.h> | ||
#include <TTree.h> | ||
#include <TTreeReader.h> | ||
#include <TTreeReaderValue.h> | ||
|
||
#include "data2Tree.hxx" | ||
|
||
void readTree() | ||
{ | ||
|
||
std::unique_ptr<TFile> ifile{TFile::Open("testFile.root", "read")}; | ||
if (!ifile || ifile->IsZombie()) { | ||
std::cerr << "Problem opening the file testFile.root" << std::endl; | ||
return; | ||
} | ||
|
||
// Create a TTreeReader to read the tree named "myTree" | ||
TTreeReader aReader("myTree", ifile.get()); | ||
|
||
// Create TTreeReaderValues for the branches "branch1" and "branch2" | ||
TTreeReaderValue<myDetectorData> branch1(aReader, "branch1."); | ||
TTreeReaderValue<myDetectorData> branch2(aReader, "branch2."); | ||
|
||
// Loop over the entries of the tree | ||
while (aReader.Next()) { | ||
if (branch1->time != 0) | ||
std::cout << " -Branch1 : time: " << branch1->time << "\t energy: " << branch1->energy << std::endl; | ||
else if (branch2->time != 0) | ||
std::cout << " +Branch2 : time: " << branch2->time << "\t energy: " << branch2->energy << std::endl; | ||
else | ||
std::cerr << "WARNING: entry " << aReader.GetCurrentEntry() << " is empty! " << std::endl; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
/* Example of reading a TTree using the RDataFrame interface | ||
* Documentation of RDataFrame: https://root.cern/doc/master/classROOT_1_1RDataFrame.html | ||
*/ | ||
|
||
#include <ROOT/RDataFrame.hxx> | ||
|
||
#include "data2Tree.hxx" | ||
|
||
void readTreeDF() | ||
{ | ||
|
||
ROOT::RDataFrame df{"myTree", "testFile.root"}; | ||
df.Display({"branch1.time", "branch1.energy", "branch2.time", "branch2.energy"}, /*nRows*/ 10)->Print(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Author: Alvaro Tolosa-Delgado CERN 07/2023 | ||
// Author: Jorge Agramunt Ros IFIC(Valencia,Spain) 07/2023 | ||
|
||
/************************************************************************* | ||
* Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. * | ||
* All rights reserved. * | ||
* * | ||
* For the licensing terms see $ROOTSYS/LICENSE. * | ||
* For the list of contributors see $ROOTSYS/README/CREDITS. * | ||
*************************************************************************/ | ||
|
||
#include <iostream> | ||
|
||
#include <TFile.h> | ||
#include <TTree.h> | ||
#include <TTreeReader.h> | ||
#include <TTreeReaderValue.h> | ||
|
||
#include "data2Tree.hxx" | ||
|
||
void writeTree() | ||
{ | ||
std::unique_ptr<TFile> ofile{TFile::Open("testFile.root", "recreate")}; | ||
if (!ofile || ofile->IsZombie()) { | ||
throw std::runtime_error("Could not open file testFile.root"); | ||
} | ||
|
||
std::unique_ptr<TTree> myTree = std::make_unique<TTree>("myTree", ""); | ||
myDetectorData obj_for_branch1; | ||
myDetectorData obj_for_branch2; | ||
|
||
// NOTE: the dot at the end of the branch name is semantically relevant and recommended | ||
// because it causes the sub-branch names to be prefixed by the name of the top level branch. | ||
// Without the dot, the prefix is not there. | ||
// Here, objects of the same class appear in multiple branches, adding the dot removes ambiguities. | ||
myTree->Branch("branch1.", &obj_for_branch1); | ||
myTree->Branch("branch2.", &obj_for_branch2); | ||
|
||
for (int i = 0; i < 10; ++i) { | ||
//-- if i is even, fill branch2 and set branch1's entry to zero | ||
if (i % 2 == 0) { | ||
obj_for_branch1.clear(); | ||
obj_for_branch2.time = i + 5; | ||
obj_for_branch2.energy = 2 * i + 5; | ||
obj_for_branch2.detectorID = 3 * i + 5; | ||
} | ||
//-- if i is odd, we do the opposite | ||
else { | ||
obj_for_branch2.clear(); | ||
obj_for_branch1.time = i + 1; | ||
obj_for_branch1.energy = 2 * i + 1; | ||
obj_for_branch1.detectorID = 3 * i + 1; | ||
atolosadelgado marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
myTree->Fill(); | ||
} | ||
|
||
myTree->Print(); | ||
|
||
ofile->Write(); // This write the files and the TTree | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way of including ROOT is a bit outdated, see a more modern way here: https://cliutils.gitlab.io/modern-cmake/chapters/packages/ROOT.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I think those tips are worth to be included as part of the official ROOT documentation :)