From f9f811e7f1f32cba753a0bb2bb14fc3f1cad6b86 Mon Sep 17 00:00:00 2001 From: xmif1 Date: Thu, 3 Sep 2026 20:37:58 +0000 Subject: [PATCH 1/4] Add TMVA BDT training and inference benchmarks Benchmark the training of TMVA BDT classifiers over a grid of NTrees and MaxDepth configurations, and their batch inference via TMVA::Experimental::RReader. Also add the MakeRandomTTree.h header providing a convenience function to generate random TTree instances, based on the random TTree generator in CrossValidationBenchmarks.cxx. This squashes the commits from the CERN summer student project by Xandru Mifsud, supervised by Lorenzo Moneta (PR #231). --- root/tmva/tmva/BoostedDTBenchmarks.cxx | 179 +++++++++++++++++++++++++ root/tmva/tmva/CMakeLists.txt | 5 + root/tmva/tmva/MakeRandomTTree.h | 41 ++++++ 3 files changed, 225 insertions(+) create mode 100644 root/tmva/tmva/BoostedDTBenchmarks.cxx create mode 100644 root/tmva/tmva/MakeRandomTTree.h diff --git a/root/tmva/tmva/BoostedDTBenchmarks.cxx b/root/tmva/tmva/BoostedDTBenchmarks.cxx new file mode 100644 index 000000000..4e772e85d --- /dev/null +++ b/root/tmva/tmva/BoostedDTBenchmarks.cxx @@ -0,0 +1,179 @@ +/* Authored by Xandru Mifsud (CERN Summer Student) and Lorenzo Moneta (Summer Project Supervisor) */ + +#include "TSystem.h" +#include "TTree.h" +#include "TFile.h" + +#include "TMVA/RReader.hxx" +#include "TMVA/RTensorUtils.hxx" +#include "TMVA/DataLoader.h" +#include "TMVA/Factory.h" +#include "TMVA/MethodBase.h" +#include "TMVA/Types.h" + +#include "benchmark/benchmark.h" + +#include "MakeRandomTTree.h" + +using namespace TMVA::Experimental; +using namespace std; + +static void BM_TMVA_BDTTraining(benchmark::State &state){ + // Parameters + UInt_t nVars = 4; + UInt_t nEvents = 500; + Bool_t mem_stats = (state.range(0) == 2000) && (state.range(1) == 10) && (state.range(2) == 1); + + // Memory benchmark data placeholder + ProcInfo_t pinfo; + Long_t init_mem_res, term_mem_res; init_mem_res = term_mem_res = 0; + double mem_res = 0.0; + + // Open output file + TString outfileName( "bdt_bench_train_output.root" ); + TFile* outputFile = TFile::Open(outfileName, "RECREATE"); + + // Set up (generate one extra event for testing) + TTree *sigTree = genTree("sigTree", nEvents, nVars,0.3, 0.5, 100); + TTree *bkgTree = genTree("bkgTree", nEvents, nVars,-0.3, 0.5, 101); + + // Prepare a DataLoader instance, registering the signal and background TTrees + auto *dataloader = new TMVA::DataLoader("bdt-bench"); + dataloader->AddSignalTree(sigTree); + dataloader->AddBackgroundTree(bkgTree); + + // Register variables in dataloader, using naming convention for randomly generated TTrees in MakeRandomTTree.h + for(UInt_t i = 0; i < nVars; i++){ + string var_name = "var" + to_string(i); + string var_leaflist = var_name + "/F"; + + dataloader->AddVariable(var_name.c_str(), 'D'); + } + + // For each benchmark we specifically ignore this test event such that we exclusively benchmark training. + dataloader->PrepareTrainingAndTestTree("", + Form("SplitMode=Block:nTrain_Signal=%i:nTrain_Background=%i:!V", nEvents, nEvents)); + + // Benchmarking + UInt_t iter_c = 0; + for(auto _: state){ + ROOT::EnableImplicitMT(state.range(2)); + + // Create factory instance + auto factory = new TMVA::Factory("bdt-bench", outputFile, + "Silent:!DrawProgressBar:AnalysisType=Classification"); + + // Get current memory usage statistics after setup + if(mem_stats && iter_c == 0){ + gSystem->GetProcInfo(&pinfo); + init_mem_res = pinfo.fMemResident; + } + + // Construct training options string + string opts = "!V:!H:NTrees=" + to_string(state.range(0)) + ":MaxDepth=" + to_string(state.range(1)); + + // Train a TMVA method + string key = to_string(state.range(0)) + "_" + to_string(state.range(1)) + "_" + to_string(state.range(2)); + auto method = factory->BookMethod(dataloader, TMVA::Types::kBDT, "BDT_" + key, opts); + TMVA::Event::SetIsTraining(kTRUE); + method->TrainMethod(); + + // Maintain Memory statistics (independent from Google Benchmark) + if(mem_stats && iter_c == 0){ + gSystem->GetProcInfo(&pinfo); + term_mem_res = pinfo.fMemResident; + mem_res += (double) (term_mem_res - init_mem_res); + } + + TMVA::Event::SetIsTraining(kFALSE); + method->Data()->DeleteAllResults(TMVA::Types::kTraining, method->GetAnalysisType()); + + // Destroy factory entirely + factory->DeleteAllMethods(); + factory->fMethodsMap.clear(); + delete factory; + + // DEBUG + // cout << "[DEBUG] " << key << ": res_mem_init = " << (double) init_mem_res << ", res_mem_term = " << (double) term_mem_res << endl; + + iter_c++; + } + + if(mem_stats){ + mem_res *= iter_c; + state.counters["Resident Memory"] = benchmark::Counter(mem_res, benchmark::Counter::kAvgIterations); + } + + // Teardown + delete sigTree; + delete bkgTree; + + outputFile->Close(); + delete outputFile; +} +BENCHMARK(BM_TMVA_BDTTraining)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}, {1, 4, 8, 16}}); + +static void BM_TMVA_BDTTesting(benchmark::State &state){ + // Parameters + UInt_t nVars = 4; + UInt_t nEvents = 500; + Bool_t mem_stats = (state.range(0) == 2000) && (state.range(1) == 10) && (state.range(2) == 1); + + // Memory benchmark data placeholder + ProcInfo_t pinfo; + Long_t init_mem_res, term_mem_res; init_mem_res = term_mem_res = 0; + double mem_res = 0.0; + + // Open output file + TString outfileName( "bdt_bench_test_output.root" ); + TFile* outputFile = TFile::Open(outfileName, "RECREATE"); + + // Set up + auto inputFile = new TFile("bdt_bench_test_input.root","RECREATE"); + TTree *testTree = genTree("testTree", nEvents, nVars,0.3, 0.5, 102, false); + testTree->Write(); + delete testTree; + inputFile->Close(); + delete inputFile; + + ROOT::RDataFrame testDF("testTree","bdt_bench_test_input.root"); + auto testTensor = AsTensor(testDF); + + // Benchmarking + UInt_t iter_c = 0; + for(auto _: state){ + ROOT::EnableImplicitMT(state.range(2)); + + // Test a TMVA method via RReader + string key = to_string(state.range(0)) + "_" + to_string(state.range(1)) + "_" + to_string(state.range(2)); + + // Get current memory usage statistics after setup + if(mem_stats && iter_c == 0){ + gSystem->GetProcInfo(&pinfo); + init_mem_res = pinfo.fMemResident; + } + + RReader model("./bdt-bench/weights/bdt-bench_BDT_" + key + ".weights.xml"); + model.Compute(testTensor); + + // Maintain Memory statistics (independent from Google Benchmark) + if(mem_stats && iter_c == 0){ + gSystem->GetProcInfo(&pinfo); + term_mem_res = pinfo.fMemResident; + mem_res += (double) (term_mem_res - init_mem_res); + } + + iter_c++; + } + + if(mem_stats){ + mem_res *= iter_c; + state.counters["Resident Memory"] = benchmark::Counter(mem_res, benchmark::Counter::kAvgIterations); + } + + // Teardown + outputFile->Close(); +} +BENCHMARK(BM_TMVA_BDTTesting)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}, {1, 4, 8, 16}}); + +BENCHMARK_MAIN(); diff --git a/root/tmva/tmva/CMakeLists.txt b/root/tmva/tmva/CMakeLists.txt index a55abf4fc..e57484a32 100644 --- a/root/tmva/tmva/CMakeLists.txt +++ b/root/tmva/tmva/CMakeLists.txt @@ -3,6 +3,11 @@ if(ROOT_tmva_FOUND) CrossValidationBenchmarks.cxx LABEL short LIBRARIES Core Tree MathCore TMVA) + + RB_ADD_GBENCHMARK(BoostedDTBenchmarks + BoostedDTBenchmarks.cxx + LABEL short + LIBRARIES Core Tree TreePlayer MathCore RIO XMLIO ROOTDataFrame TMVA) endif() if(ROOT_tmva_FOUND AND ROOT_tmva-cpu_FOUND AND ROOT_imt_FOUND) diff --git a/root/tmva/tmva/MakeRandomTTree.h b/root/tmva/tmva/MakeRandomTTree.h new file mode 100644 index 000000000..59b234834 --- /dev/null +++ b/root/tmva/tmva/MakeRandomTTree.h @@ -0,0 +1,41 @@ +#include "TRandom3.h" +#include "TTree.h" + +// Utility function for generating a random TTree with Gaussian float data, for the specified number of points and vars +TTree* genTree(std::string name, UInt_t nPoints, const UInt_t nVars, Double_t offset, Double_t scale = 0.3, UInt_t seed = 100, + bool evtCol = true){ + // Initialisation + TRandom3 rng(seed); + Float_t vars[nVars]; for(auto& var: vars){ var = 0.0;} + UInt_t id = 0; + + // Create new TTree instance + auto data = new TTree(name.c_str(),name.c_str()); + + // Add a branch corresponding to each variable + for(UInt_t i = 0; i < nVars; i++){ + std::string var_name = "var" + std::to_string(i); + std::string var_leaflist = var_name + "/F"; + + data->Branch(var_name.c_str(), vars + i, var_leaflist.c_str()); + } + + // And add a branch for the (unique) Event identifier + if(evtCol){ + data->Branch("EventNumber", &id, "EventNumber/I"); + } + + // Populate TTree instance with Gaussian data + for(UInt_t j = 0; j < nPoints; j++){ + for(UInt_t i = 0; i < nVars; i++){ + vars[i] = rng.Gaus(offset, scale); + } + + data->Fill(); + id++; + } + + // Important: Disconnects the tree from the memory locations of vars[i] + data->ResetBranchAddresses(); + return data; +} \ No newline at end of file From e4a36125461bb20437424202dc293abea4d88146 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 3 Sep 2026 20:38:34 +0000 Subject: [PATCH 2/4] Remove memory statistics from BDT benchmarks As noted in the original PR, the reported memory statistics were not necessarily correct: they were sampled only on the first iteration and then rescaled by the iteration count, which does not measure what the counter name suggests. --- root/tmva/tmva/BoostedDTBenchmarks.cxx | 61 -------------------------- 1 file changed, 61 deletions(-) diff --git a/root/tmva/tmva/BoostedDTBenchmarks.cxx b/root/tmva/tmva/BoostedDTBenchmarks.cxx index 4e772e85d..c4b6e0e5d 100644 --- a/root/tmva/tmva/BoostedDTBenchmarks.cxx +++ b/root/tmva/tmva/BoostedDTBenchmarks.cxx @@ -22,13 +22,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ // Parameters UInt_t nVars = 4; UInt_t nEvents = 500; - Bool_t mem_stats = (state.range(0) == 2000) && (state.range(1) == 10) && (state.range(2) == 1); - - // Memory benchmark data placeholder - ProcInfo_t pinfo; - Long_t init_mem_res, term_mem_res; init_mem_res = term_mem_res = 0; - double mem_res = 0.0; - // Open output file TString outfileName( "bdt_bench_train_output.root" ); TFile* outputFile = TFile::Open(outfileName, "RECREATE"); @@ -54,8 +47,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ dataloader->PrepareTrainingAndTestTree("", Form("SplitMode=Block:nTrain_Signal=%i:nTrain_Background=%i:!V", nEvents, nEvents)); - // Benchmarking - UInt_t iter_c = 0; for(auto _: state){ ROOT::EnableImplicitMT(state.range(2)); @@ -63,12 +54,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ auto factory = new TMVA::Factory("bdt-bench", outputFile, "Silent:!DrawProgressBar:AnalysisType=Classification"); - // Get current memory usage statistics after setup - if(mem_stats && iter_c == 0){ - gSystem->GetProcInfo(&pinfo); - init_mem_res = pinfo.fMemResident; - } - // Construct training options string string opts = "!V:!H:NTrees=" + to_string(state.range(0)) + ":MaxDepth=" + to_string(state.range(1)); @@ -78,13 +63,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ TMVA::Event::SetIsTraining(kTRUE); method->TrainMethod(); - // Maintain Memory statistics (independent from Google Benchmark) - if(mem_stats && iter_c == 0){ - gSystem->GetProcInfo(&pinfo); - term_mem_res = pinfo.fMemResident; - mem_res += (double) (term_mem_res - init_mem_res); - } - TMVA::Event::SetIsTraining(kFALSE); method->Data()->DeleteAllResults(TMVA::Types::kTraining, method->GetAnalysisType()); @@ -92,16 +70,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ factory->DeleteAllMethods(); factory->fMethodsMap.clear(); delete factory; - - // DEBUG - // cout << "[DEBUG] " << key << ": res_mem_init = " << (double) init_mem_res << ", res_mem_term = " << (double) term_mem_res << endl; - - iter_c++; - } - - if(mem_stats){ - mem_res *= iter_c; - state.counters["Resident Memory"] = benchmark::Counter(mem_res, benchmark::Counter::kAvgIterations); } // Teardown @@ -117,13 +85,6 @@ static void BM_TMVA_BDTTesting(benchmark::State &state){ // Parameters UInt_t nVars = 4; UInt_t nEvents = 500; - Bool_t mem_stats = (state.range(0) == 2000) && (state.range(1) == 10) && (state.range(2) == 1); - - // Memory benchmark data placeholder - ProcInfo_t pinfo; - Long_t init_mem_res, term_mem_res; init_mem_res = term_mem_res = 0; - double mem_res = 0.0; - // Open output file TString outfileName( "bdt_bench_test_output.root" ); TFile* outputFile = TFile::Open(outfileName, "RECREATE"); @@ -139,36 +100,14 @@ static void BM_TMVA_BDTTesting(benchmark::State &state){ ROOT::RDataFrame testDF("testTree","bdt_bench_test_input.root"); auto testTensor = AsTensor(testDF); - // Benchmarking - UInt_t iter_c = 0; for(auto _: state){ ROOT::EnableImplicitMT(state.range(2)); // Test a TMVA method via RReader string key = to_string(state.range(0)) + "_" + to_string(state.range(1)) + "_" + to_string(state.range(2)); - // Get current memory usage statistics after setup - if(mem_stats && iter_c == 0){ - gSystem->GetProcInfo(&pinfo); - init_mem_res = pinfo.fMemResident; - } - RReader model("./bdt-bench/weights/bdt-bench_BDT_" + key + ".weights.xml"); model.Compute(testTensor); - - // Maintain Memory statistics (independent from Google Benchmark) - if(mem_stats && iter_c == 0){ - gSystem->GetProcInfo(&pinfo); - term_mem_res = pinfo.fMemResident; - mem_res += (double) (term_mem_res - init_mem_res); - } - - iter_c++; - } - - if(mem_stats){ - mem_res *= iter_c; - state.counters["Resident Memory"] = benchmark::Counter(mem_res, benchmark::Counter::kAvgIterations); } // Teardown From cd9da781336d94d83daf3c3a9a98b07cd5cf2847 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 3 Sep 2026 20:38:47 +0000 Subject: [PATCH 3/4] Drop the thread count axis from the BDT benchmarks ROOT::EnableImplicitMT() has no effect if implicit multi-threading is already enabled, so only the very first configuration determined the size of the thread pool and the thread count axis produced duplicated measurements. Properly re-enabling IMT per configuration does not help either: neither the BDT training nor the RReader inference scale with the IMT pool size at this problem size, so drop the axis instead of fixing it. This reduces the number of configurations from 160 to 40. --- root/tmva/tmva/BoostedDTBenchmarks.cxx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/root/tmva/tmva/BoostedDTBenchmarks.cxx b/root/tmva/tmva/BoostedDTBenchmarks.cxx index c4b6e0e5d..bf9660a52 100644 --- a/root/tmva/tmva/BoostedDTBenchmarks.cxx +++ b/root/tmva/tmva/BoostedDTBenchmarks.cxx @@ -48,8 +48,6 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ Form("SplitMode=Block:nTrain_Signal=%i:nTrain_Background=%i:!V", nEvents, nEvents)); for(auto _: state){ - ROOT::EnableImplicitMT(state.range(2)); - // Create factory instance auto factory = new TMVA::Factory("bdt-bench", outputFile, "Silent:!DrawProgressBar:AnalysisType=Classification"); @@ -58,7 +56,7 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ string opts = "!V:!H:NTrees=" + to_string(state.range(0)) + ":MaxDepth=" + to_string(state.range(1)); // Train a TMVA method - string key = to_string(state.range(0)) + "_" + to_string(state.range(1)) + "_" + to_string(state.range(2)); + string key = to_string(state.range(0)) + "_" + to_string(state.range(1)); auto method = factory->BookMethod(dataloader, TMVA::Types::kBDT, "BDT_" + key, opts); TMVA::Event::SetIsTraining(kTRUE); method->TrainMethod(); @@ -79,7 +77,7 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ outputFile->Close(); delete outputFile; } -BENCHMARK(BM_TMVA_BDTTraining)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}, {1, 4, 8, 16}}); +BENCHMARK(BM_TMVA_BDTTraining)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}}); static void BM_TMVA_BDTTesting(benchmark::State &state){ // Parameters @@ -101,10 +99,8 @@ static void BM_TMVA_BDTTesting(benchmark::State &state){ auto testTensor = AsTensor(testDF); for(auto _: state){ - ROOT::EnableImplicitMT(state.range(2)); - // Test a TMVA method via RReader - string key = to_string(state.range(0)) + "_" + to_string(state.range(1)) + "_" + to_string(state.range(2)); + string key = to_string(state.range(0)) + "_" + to_string(state.range(1)); RReader model("./bdt-bench/weights/bdt-bench_BDT_" + key + ".weights.xml"); model.Compute(testTensor); @@ -113,6 +109,6 @@ static void BM_TMVA_BDTTesting(benchmark::State &state){ // Teardown outputFile->Close(); } -BENCHMARK(BM_TMVA_BDTTesting)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}, {1, 4, 8, 16}}); +BENCHMARK(BM_TMVA_BDTTesting)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}}); BENCHMARK_MAIN(); From 8cdaaab273afae5c2f41f21ffc707059c709d359 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 3 Sep 2026 20:39:31 +0000 Subject: [PATCH 4/4] Tidy up BDT benchmarks Write the ROOT files produced during the benchmarks to RB_TEMP_FS like the other benchmarks, drop the unused output file of the testing benchmark, and skip the testing benchmark with a clear error instead of crashing if the weight files from the training benchmark are missing. Also replace a variable-length array, which is not standard C++. --- root/tmva/tmva/BoostedDTBenchmarks.cxx | 33 +++++++++++++++----------- root/tmva/tmva/MakeRandomTTree.h | 7 ++++-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/root/tmva/tmva/BoostedDTBenchmarks.cxx b/root/tmva/tmva/BoostedDTBenchmarks.cxx index bf9660a52..7e05e3360 100644 --- a/root/tmva/tmva/BoostedDTBenchmarks.cxx +++ b/root/tmva/tmva/BoostedDTBenchmarks.cxx @@ -13,6 +13,8 @@ #include "benchmark/benchmark.h" +#include "rootbench/RBConfig.h" + #include "MakeRandomTTree.h" using namespace TMVA::Experimental; @@ -23,10 +25,10 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ UInt_t nVars = 4; UInt_t nEvents = 500; // Open output file - TString outfileName( "bdt_bench_train_output.root" ); + TString outfileName( RB::GetTempFs() + "/bdt_bench_train_output.root" ); TFile* outputFile = TFile::Open(outfileName, "RECREATE"); - // Set up (generate one extra event for testing) + // Set up TTree *sigTree = genTree("sigTree", nEvents, nVars,0.3, 0.5, 100); TTree *bkgTree = genTree("bkgTree", nEvents, nVars,-0.3, 0.5, 101); @@ -43,7 +45,7 @@ static void BM_TMVA_BDTTraining(benchmark::State &state){ dataloader->AddVariable(var_name.c_str(), 'D'); } - // For each benchmark we specifically ignore this test event such that we exclusively benchmark training. + // Use all events for training such that we exclusively benchmark training. dataloader->PrepareTrainingAndTestTree("", Form("SplitMode=Block:nTrain_Signal=%i:nTrain_Background=%i:!V", nEvents, nEvents)); @@ -83,31 +85,34 @@ static void BM_TMVA_BDTTesting(benchmark::State &state){ // Parameters UInt_t nVars = 4; UInt_t nEvents = 500; - // Open output file - TString outfileName( "bdt_bench_test_output.root" ); - TFile* outputFile = TFile::Open(outfileName, "RECREATE"); // Set up - auto inputFile = new TFile("bdt_bench_test_input.root","RECREATE"); + string infileName = RB::GetTempFs() + "/bdt_bench_test_input.root"; + auto inputFile = new TFile(infileName.c_str(),"RECREATE"); TTree *testTree = genTree("testTree", nEvents, nVars,0.3, 0.5, 102, false); testTree->Write(); delete testTree; inputFile->Close(); delete inputFile; - ROOT::RDataFrame testDF("testTree","bdt_bench_test_input.root"); + ROOT::RDataFrame testDF("testTree",infileName); auto testTensor = AsTensor(testDF); + // The weight files are produced by BM_TMVA_BDTTraining, which runs first + // because it is registered first. Running BM_TMVA_BDTTesting alone (e.g. + // via --benchmark_filter) is not supported. + string key = to_string(state.range(0)) + "_" + to_string(state.range(1)); + string weightFile = "./bdt-bench/weights/bdt-bench_BDT_" + key + ".weights.xml"; + if(gSystem->AccessPathName(weightFile.c_str())){ + state.SkipWithError(("weight file " + weightFile + " not found, it is produced by BM_TMVA_BDTTraining").c_str()); + return; + } + for(auto _: state){ // Test a TMVA method via RReader - string key = to_string(state.range(0)) + "_" + to_string(state.range(1)); - - RReader model("./bdt-bench/weights/bdt-bench_BDT_" + key + ".weights.xml"); + RReader model(weightFile); model.Compute(testTensor); } - - // Teardown - outputFile->Close(); } BENCHMARK(BM_TMVA_BDTTesting)->ArgsProduct({{2000, 1000, 400, 100}, {10, 8, 6, 4, 2}}); diff --git a/root/tmva/tmva/MakeRandomTTree.h b/root/tmva/tmva/MakeRandomTTree.h index 59b234834..1cc0e2d3d 100644 --- a/root/tmva/tmva/MakeRandomTTree.h +++ b/root/tmva/tmva/MakeRandomTTree.h @@ -1,12 +1,15 @@ #include "TRandom3.h" #include "TTree.h" +#include +#include + // Utility function for generating a random TTree with Gaussian float data, for the specified number of points and vars TTree* genTree(std::string name, UInt_t nPoints, const UInt_t nVars, Double_t offset, Double_t scale = 0.3, UInt_t seed = 100, bool evtCol = true){ // Initialisation TRandom3 rng(seed); - Float_t vars[nVars]; for(auto& var: vars){ var = 0.0;} + std::vector vars(nVars, 0.0); UInt_t id = 0; // Create new TTree instance @@ -17,7 +20,7 @@ TTree* genTree(std::string name, UInt_t nPoints, const UInt_t nVars, Double_t of std::string var_name = "var" + std::to_string(i); std::string var_leaflist = var_name + "/F"; - data->Branch(var_name.c_str(), vars + i, var_leaflist.c_str()); + data->Branch(var_name.c_str(), vars.data() + i, var_leaflist.c_str()); } // And add a branch for the (unique) Event identifier