From 73da76120156da2822cb948b5d6463983eae243f Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 28 May 2021 19:58:12 +0200 Subject: [PATCH 001/309] [DF] Add test for #8276 --- tree/dataframe/test/dataframe_helpers.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tree/dataframe/test/dataframe_helpers.cxx b/tree/dataframe/test/dataframe_helpers.cxx index 44fd9f97d8095..33bae46a5c87c 100644 --- a/tree/dataframe/test/dataframe_helpers.cxx +++ b/tree/dataframe/test/dataframe_helpers.cxx @@ -56,6 +56,19 @@ TEST(RDFHelpers, PassAsVec) EXPECT_EQ(1u, *df.Filter(PassAsVec<2, int>(TwoOnesDeque), {"one", "_1"}).Count()); } + +// this tests https://github.com/root-project/root/issues/8276 +TEST(RDFHelpers, ReturnPassAsVec) +{ + auto returnPassAsVecLambda = [] { + double f = 42; + auto fn = [f](std::vector) { return f; }; + return PassAsVec<1, int>(fn); + }; + auto fn = returnPassAsVecLambda(); + EXPECT_EQ(fn(0), 42.); +} + class SaveGraphTestHelper { private: RDataFrame rd1; From a2814390d0cee37a93f8970d08b613536eb24148 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 28 May 2021 19:57:23 +0200 Subject: [PATCH 002/309] [DF] Do not store references to callables in PassAsVec Make sure to always store the callables by value. This fixes #8276. --- tree/dataframe/inc/ROOT/RDFHelpers.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/dataframe/inc/ROOT/RDFHelpers.hxx b/tree/dataframe/inc/ROOT/RDFHelpers.hxx index ed6a276d96427..13e1056adc1c3 100644 --- a/tree/dataframe/inc/ROOT/RDFHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDFHelpers.hxx @@ -49,7 +49,7 @@ template class PassAsVecHelper, T, F> { template using AlwaysT = T; - F fFunc; + typename std::decay::type fFunc; public: PassAsVecHelper(F &&f) : fFunc(std::forward(f)) {} From 68fcd7afd55824b3b9328229a69b2279a1c33fac Mon Sep 17 00:00:00 2001 From: Enric Tejedor Saavedra Date: Fri, 28 May 2021 12:01:56 +0200 Subject: [PATCH 003/309] [PyROOT] Add Python include paths with -isystem Prevent warnings about the 'register' keyword in Python2 headers. The explicit silencing of such warnings can also be removed. --- bindings/jupyroot/CMakeLists.txt | 11 +---------- bindings/pyroot/cppyy/CPyCppyy/CMakeLists.txt | 13 +++---------- bindings/pyroot/pythonizations/CMakeLists.txt | 15 ++++----------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/bindings/jupyroot/CMakeLists.txt b/bindings/jupyroot/CMakeLists.txt index 6205226680eab..8510b4db10b14 100644 --- a/bindings/jupyroot/CMakeLists.txt +++ b/bindings/jupyroot/CMakeLists.txt @@ -52,16 +52,7 @@ foreach(val RANGE ${how_many_pythons}) target_link_libraries(${libname} PUBLIC -Wl,--unresolved-symbols=ignore-all Core) endif() - target_include_directories(${libname} PRIVATE ${python_include_dir}) - - # Disables warnings originating from deprecated register keyword in Python - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - endif() - if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - target_compile_options(${libname} PRIVATE -Wno-deprecated-register) - endif() + target_include_directories(${libname} SYSTEM PRIVATE ${python_include_dir}) # Compile .py files foreach(py_source ${py_sources}) diff --git a/bindings/pyroot/cppyy/CPyCppyy/CMakeLists.txt b/bindings/pyroot/cppyy/CPyCppyy/CMakeLists.txt index d8bf461350d3a..2144d97d580bb 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/CMakeLists.txt +++ b/bindings/pyroot/cppyy/CPyCppyy/CMakeLists.txt @@ -82,26 +82,19 @@ foreach(val RANGE ${how_many_pythons}) target_compile_options(${libname} PRIVATE -Wno-cast-function-type) endif() - # Disables warnings originating from deprecated register keyword in Python - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - endif() - if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - target_compile_options(${libname} PRIVATE -Wno-deprecated-register) - endif() - # Disables warnings due to new field tp_vectorcall in Python 3.8 if(NOT MSVC AND ${python_version_string} VERSION_GREATER_EQUAL "3.8") target_compile_options(${libname} PRIVATE -Wno-missing-field-initializers) endif() + target_include_directories(${libname} + SYSTEM PUBLIC ${python_include_dir}) + target_include_directories(${libname} PRIVATE ${CMAKE_SOURCE_DIR}/core/foundation/inc # needed for string_view backport ${CMAKE_BINARY_DIR}/ginclude PUBLIC - ${python_include_dir} $ $ ) diff --git a/bindings/pyroot/pythonizations/CMakeLists.txt b/bindings/pyroot/pythonizations/CMakeLists.txt index 1f5874a16ec4a..94db56b215835 100644 --- a/bindings/pyroot/pythonizations/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/CMakeLists.txt @@ -111,23 +111,16 @@ foreach(val RANGE ${how_many_pythons}) endif() target_include_directories(${libname} - PRIVATE ${python_include_dir} - PUBLIC $) + SYSTEM PRIVATE ${python_include_dir}) + + target_include_directories(${libname} + PUBLIC $) # Disables warnings caused by Py_RETURN_TRUE/Py_RETURN_FALSE if(NOT MSVC) target_compile_options(${libname} PRIVATE -Wno-strict-aliasing) endif() - # Disables warnings originating from deprecated register keyword in Python - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - endif() - if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) - target_compile_options(${libname} PRIVATE -Wno-register) - target_compile_options(${libname} PRIVATE -Wno-deprecated-register) - endif() - # Compile .py files foreach(py_source ${py_sources}) install(CODE "execute_process(COMMAND ${python_executable} -m py_compile ${localruntimedir}/${py_source})") From 33ed14cd03ca86c7c4d069e04cbdf5b24d4e600b Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Fri, 28 May 2021 16:01:54 +0000 Subject: [PATCH 004/309] [clad] Bump clad version to v0.8. The new release includes some improvements: * Implement #pragma clad ON/OFF/DEFAULT to control regions where clad is active * Add getCode() interface for interactive use See more at: https://github.com/vgvassilev/clad/blob/v0.8/docs/ReleaseNotes.md --- interpreter/cling/tools/plugins/clad/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/cling/tools/plugins/clad/CMakeLists.txt b/interpreter/cling/tools/plugins/clad/CMakeLists.txt index d7e3a5d93b0e2..0237b4a0f6b9c 100644 --- a/interpreter/cling/tools/plugins/clad/CMakeLists.txt +++ b/interpreter/cling/tools/plugins/clad/CMakeLists.txt @@ -69,7 +69,7 @@ endif() ExternalProject_Add( clad GIT_REPOSITORY https://github.com/vgvassilev/clad.git - GIT_TAG v0.7 + GIT_TAG v0.8 UPDATE_COMMAND "" CMAKE_ARGS -G ${CMAKE_GENERATOR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} From a155ae7fae846c9b8a3638083cb0ef3ceb9ddd19 Mon Sep 17 00:00:00 2001 From: Enric Tejedor Saavedra Date: Mon, 31 May 2021 11:18:51 +0200 Subject: [PATCH 005/309] [PyROOT][8183] Do not increment STL-like iterator in first iteration This fixes the iteration over a TTreeReader, since incrementing its iterator before the loop body of the first iteration runs causes the current entry of the reader to always be one position ahead. From: https://bitbucket.org/wlav/cpycppyy/commits/8222848093bd687d67f2b89172764e0964cb14f0 --- .../pyroot/cppyy/CPyCppyy/src/Pythonize.cxx | 100 +++++++++++------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/Pythonize.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/Pythonize.cxx index 92c48f01286a3..f587f41907db3 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/Pythonize.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/Pythonize.cxx @@ -653,19 +653,38 @@ PyObject* MapContains(PyObject* self, PyObject* obj) return result; } + //- STL container iterator support -------------------------------------------- +static const ptrdiff_t PS_END_ADDR = 7; // non-aligned address, so no clash +static const ptrdiff_t PS_FLAG_ADDR = 11; // id. +static const ptrdiff_t PS_COLL_ADDR = 13; // id. + PyObject* StlSequenceIter(PyObject* self) { // Implement python's __iter__ for std::iterator<>s PyObject* iter = PyObject_CallMethodObjArgs(self, PyStrings::gBegin, nullptr); if (iter) { PyObject* end = PyObject_CallMethodObjArgs(self, PyStrings::gEnd, nullptr); - if (end) - PyObject_SetAttr(iter, PyStrings::gEnd, end); - Py_XDECREF(end); - - // add iterated collection as attribute so its refcount stays >= 1 while it's being iterated over - PyObject_SetAttr(iter, CPyCppyy_PyText_FromString("_collection"), self); + if (end) { + if (CPPInstance_Check(iter)) { + // use the data member cache to store extra state on the iterator object, + // without it being visible on the Python side + auto& dmc = ((CPPInstance*)iter)->GetDatamemberCache(); + dmc.push_back(std::make_pair(PS_END_ADDR, end)); + + // set a flag, indicating first iteration (reset in __next__) + Py_INCREF(Py_False); + dmc.push_back(std::make_pair(PS_FLAG_ADDR, Py_False)); + + // make sure the iterated over collection remains alive for the duration + Py_INCREF(self); + dmc.push_back(std::make_pair(PS_COLL_ADDR, self)); + } else { + // could store "end" on the object's dictionary anyway, but if end() returns + // a user-customized object, then its __next__ is probably custom, too + Py_DECREF(end); + } + } } return iter; } @@ -856,44 +875,47 @@ Py_hash_t StlStringHash(PyObject* self) PyObject* StlIterNext(PyObject* self) { // Python iterator protocol __next__ for STL forward iterators. - PyObject* next = nullptr; - PyObject* last = PyObject_GetAttr(self, PyStrings::gEnd); + bool mustIncrement = true; + PyObject* last = nullptr; + if (CPPInstance_Check(self)) { + auto& dmc = ((CPPInstance*)self)->GetDatamemberCache(); + for (auto& p: dmc) { + if (p.first == PS_END_ADDR) { + last = p.second; + Py_INCREF(last); + } else if (p.first == PS_FLAG_ADDR) { + mustIncrement = p.second == Py_True; + if (!mustIncrement) { + Py_DECREF(p.second); + Py_INCREF(Py_True); + p.second = Py_True; + } + } + } + } + PyObject* next = nullptr; if (last) { // handle special case of empty container (i.e. self is end) - if (PyObject_RichCompareBool(last, self, Py_EQ) == 0) { - // first, get next from the _current_ iterator as internal state may change - // when call post or pre increment - next = PyObject_CallMethodObjArgs(self, PyStrings::gDeref, nullptr); - if (!next) PyErr_Clear(); - - // use postinc, even as the C++11 range-based for loops prefer preinc b/c - // that allows the current value from the iterator to be had from __deref__, - // an issue that does not come up in C++ - static PyObject* dummy = PyInt_FromLong(1l); - PyObject* iter = PyObject_CallMethodObjArgs(self, PyStrings::gPostInc, dummy, nullptr); - if (!iter) { - // allow preinc, as in that case likely __deref__ is not defined and it - // is the iterator rather that is returned in the loop - PyErr_Clear(); - iter = PyObject_CallMethodObjArgs(self, PyStrings::gPreInc, nullptr); - } - if (iter) { - // prefer != as per C++11 range-based for - int isNotEnd = PyObject_RichCompareBool(last, iter, Py_NE); - if (isNotEnd && !next) { - // if no dereference, continue iterating over the iterator - Py_INCREF(iter); - next = iter; + if (!PyObject_RichCompareBool(last, self, Py_EQ)) { + bool iter_valid = true; + if (mustIncrement) { + // prefer preinc, but allow post-inc; in both cases, it is "self" that has + // the updated state to dereference + PyObject* iter = PyObject_CallMethodObjArgs(self, PyStrings::gPreInc, nullptr); + if (!iter) { + PyErr_Clear(); + static PyObject* dummy = PyInt_FromLong(1l); + iter = PyObject_CallMethodObjArgs(self, PyStrings::gPostInc, dummy, nullptr); } - Py_DECREF(iter); - } else { - // fail current next, even if available - Py_XDECREF(next); - next = nullptr; + iter_valid = iter && PyObject_RichCompareBool(last, self, Py_NE); + Py_XDECREF(iter); + } + + if (iter_valid) { + next = PyObject_CallMethodObjArgs(self, PyStrings::gDeref, nullptr); + if (!next) PyErr_Clear(); } - } else { - PyErr_SetString(PyExc_StopIteration, ""); } Py_DECREF(last); } From 55774a90caac46dd9b540557aa8d9c47c86c2fba Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Sat, 29 May 2021 13:56:26 +0200 Subject: [PATCH 006/309] [DF] Fix datasource_more test failures on Windows --- tree/dataframe/test/datasource_more.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/dataframe/test/datasource_more.cxx b/tree/dataframe/test/datasource_more.cxx index 683c3907f70c3..cd83f6da188a2 100644 --- a/tree/dataframe/test/datasource_more.cxx +++ b/tree/dataframe/test/datasource_more.cxx @@ -60,6 +60,7 @@ TEST(RArraysDS, SnapshotAndShortSyntaxForCollectionSizes) auto *blist = t->GetListOfBranches(); EXPECT_EQ(blist->GetEntries(), 1u); EXPECT_STREQ(blist->At(0)->GetName(), "var"); + f.Close(); // Windows does not allow deletion/recreation of files that are still in use. // Snapshot must throw if #var is passed explicitly EXPECT_THROW(df.Snapshot("t", fname, {"#var"}), std::runtime_error); From 3471e684526176b16ee76377e48d8a4fe850eda5 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Tue, 1 Jun 2021 09:33:09 +0200 Subject: [PATCH 007/309] [DF] Fix gcc 11 warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../tree/dataframe/test/dataframe_interface.cxx:451:28: warning: loop variable ‘col’ of type ‘const string&’ {aka ‘const std::__cxx11::basic_string&’} binds to a temporary constructed from type ‘const char* const’ [-Wrange-loop-construct] --- tree/dataframe/test/dataframe_interface.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tree/dataframe/test/dataframe_interface.cxx b/tree/dataframe/test/dataframe_interface.cxx index 9a37e1c0ff499..354b0b4dc7b70 100644 --- a/tree/dataframe/test/dataframe_interface.cxx +++ b/tree/dataframe/test/dataframe_interface.cxx @@ -1,6 +1,7 @@ +#include "ROOT/RCsvDS.hxx" #include "ROOT/RDataFrame.hxx" +#include "ROOT/RStringView.hxx" #include "ROOT/RTrivialDS.hxx" -#include "ROOT/RCsvDS.hxx" #include "TMemFile.h" #include "TSystem.h" #include "TTree.h" @@ -448,7 +449,7 @@ TEST(RDataFrameInterface, ColumnWithSimpleStruct) ROOT::RDataFrame df(t); const std::vector expected({ "c.a", "a", "c.b", "b", "c" }); EXPECT_EQ(df.GetColumnNames(), expected); - for (const std::string &col : {"c.a", "a"}) { + for (std::string_view col : {"c.a", "a"}) { EXPECT_DOUBLE_EQ(df.Mean(col).GetValue(), 42.); // compiled EXPECT_DOUBLE_EQ(df.Mean(col).GetValue(), 42.); // jitted } From ac774c6c743f7b8b837d8223b67781049591f73c Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Mon, 31 May 2021 18:50:35 +0200 Subject: [PATCH 008/309] [tree][NFC] Fix typos in doc --- tree/tree/src/TTree.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 29cf5430fab57..93f2dcbba64cf 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -3256,8 +3256,8 @@ TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" * //////////////////////////////////////////////////////////////////////////////// /// Set branch addresses of passed tree equal to ours. -/// If undo is true, reset the branch address instead of copying them. -/// This insures 'separation' of a cloned tree from its original +/// If undo is true, reset the branch addresses instead of copying them. +/// This ensures 'separation' of a cloned tree from its original. void TTree::CopyAddresses(TTree* tree, Bool_t undo) { From 9c282b20cdf69aed9ce8c71adfbe9027b7fadbc7 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Mon, 31 May 2021 15:23:09 +0200 Subject: [PATCH 009/309] [DF] Avoid potential nullptr dereference TLeaf::GetTypeName might return a nullptr if dictionaries for the type are missing. --- tree/dataframe/src/RDFUtils.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tree/dataframe/src/RDFUtils.cxx b/tree/dataframe/src/RDFUtils.cxx index cc15f9c60f6de..0f83f900cf4d8 100644 --- a/tree/dataframe/src/RDFUtils.cxx +++ b/tree/dataframe/src/RDFUtils.cxx @@ -137,7 +137,8 @@ std::string ComposeRVecTypeName(const std::string &valueType) std::string GetLeafTypeName(TLeaf *leaf, const std::string &colName) { - std::string colType = leaf->GetTypeName(); + const char *colTypeCStr = leaf->GetTypeName(); + std::string colType = colTypeCStr == nullptr ? "" : colTypeCStr; if (colType.empty()) throw std::runtime_error("Could not deduce type of leaf " + colName); if (leaf->GetLeafCount() != nullptr && leaf->GetLenStatic() == 1) { From a9f4ad4e7f2a25d8d9c0af8899403cab94b01541 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Tue, 1 Jun 2021 10:04:48 +0200 Subject: [PATCH 010/309] Fix Makefile.win32 for latest versions of Visual Studio Cleanup and remove obsolete options and compiler flags --- test/Makefile.win32 | 123 +++++++++----------------------------------- 1 file changed, 24 insertions(+), 99 deletions(-) diff --git a/test/Makefile.win32 b/test/Makefile.win32 index 9a0231dd8ef71..f490a6dcff74c 100644 --- a/test/Makefile.win32 +++ b/test/Makefile.win32 @@ -49,27 +49,19 @@ OutPutOpt = -out: # Win32 system with Microsoft Visual C/C++ -## VS2012 (VC11): configure subsystem version -## See: https://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx -## (APPVER used in win32.mak to set subsystem version) -!if ([nmake /? 2>&1 | findstr /c:"Version 11\." > nul ] == 0) || \ - ([nmake /? 2>&1 | findstr /c:"Version 12\." > nul ] == 0) -APPVER = 5.01 -cc = cl -link = link -implib = lib -lflags = $(lflags) /INCREMENTAL:NO /NOLOGO -DLLENTRY = @12 -conlflags = $(lflags) -subsystem:console -guilflags = $(lflags) -subsystem:windows -dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll -!else -!include -!endif +APPVER = 5.01 +cc = cl +link = link +implib = lib +lflags = $(lflags) /INCREMENTAL:NO /NOLOGO +DLLENTRY = @12 +conlflags = $(lflags) -subsystem:console +guilflags = $(lflags) -subsystem:windows +dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll CC = $(cc) CXX = $(cc) CXXFLAGS = -nologo -EHs -GR -DWIN32 -W3 -D_WIN32 -D_WINDOWS \ - -I$(ROOTSYS)/include -wd4244 \ + -I$(ROOTSYS)/include -wd4244 -D_CRT_SECURE_NO_DEPRECATE \ -FIw32pragma.h LD = $(link) @@ -85,37 +77,15 @@ CXXOPT = -Z7 -MD LDOPT = -debug !endif -# Check if nmake version is 8.xx or 9.xx -!if ([nmake /? 2>&1 | findstr /c:"Version 8\." > nul ] == 0) || \ - ([nmake /? 2>&1 | findstr /c:"Version 9\." > nul ] == 0) -MT_EXE = mt -nologo -manifest $@.manifest -outputresource:$@;1 -MT_DLL = mt -nologo -manifest $@.manifest -outputresource:$@;2 -EXTRAFLAGS = -D_CRT_SECURE_NO_DEPRECATE -!else if ([nmake /? 2>&1 | findstr /c:"Version 10\." > nul ] == 0) || \ - ([nmake /? 2>&1 | findstr /c:"Version 11\." > nul ] == 0) || \ - ([nmake /? 2>&1 | findstr /c:"Version 12\." > nul ] == 0) -EXTRAFLAGS = -D_CRT_SECURE_NO_DEPRECATE -!else -MT_EXE = -MT_DLL = -EXTRAFLAGS = -G5 -!endif - - -LDFLAGS = $(LDOPT) $(conlflags) -nologo -include:_G__cpp_setupG__Hist \ - -include:_G__cpp_setupG__Graf -include:_G__cpp_setupG__G3D \ - -include:_G__cpp_setupG__GPad -include:_G__cpp_setupG__Tree \ - -include:_G__cpp_setupG__Rint -include:_G__cpp_setupG__PostScript \ - -include:_G__cpp_setupG__Matrix -include:_G__cpp_setupG__Physics +LDFLAGS = $(LDOPT) $(conlflags) -nologo SOFLAGS = $(dlllflags:-pdb:none=) -ROOTLIBS = $(ROOTSYS)\lib\libCore.lib \ - $(ROOTSYS)\lib\libCint.lib $(ROOTSYS)\lib\libHist.lib \ +ROOTLIBS = $(ROOTSYS)\lib\libCore.lib $(ROOTSYS)\lib\libHist.lib \ $(ROOTSYS)\lib\libGraf.lib $(ROOTSYS)\lib\libGraf3d.lib \ $(ROOTSYS)\lib\libGpad.lib $(ROOTSYS)\lib\libTree.lib \ $(ROOTSYS)\lib\libRint.lib $(ROOTSYS)\lib\libPostscript.lib \ $(ROOTSYS)\lib\libMatrix.lib $(ROOTSYS)\lib\libPhysics.lib \ $(ROOTSYS)\lib\libNet.lib $(ROOTSYS)\lib\libRIO.lib \ - $(ROOTSYS)\lib\libMathCore.lib + $(ROOTSYS)\lib\libMathCore.lib $(ROOTSYS)\lib\libTreePlayer.lib LIBS = $(ROOTLIBS) GLIBS = $(LIBS) $(ROOTSYS)\lib\libGui.lib $(ROOTSYS)\lib\libGraf.lib \ $(ROOTSYS)\lib\libGpad.lib @@ -192,17 +162,17 @@ STRESSGUILIBS = $(ROOTSYS)\lib\libASImage.lib $(ROOTSYS)\lib\libASImageGui.lib \ $(ROOTSYS)\lib\libRecorder.lib $(ROOTSYS)\lib\libGuiHtml.lib !if exist("$(ROOTSYS)\lib\libGenVector.lib") -STRESSVECO = stressVector.$(ObjSuf) -STRESSVECS = stressVector.$(SrcSuf) -STRESSVEC = stressVector$(ExeSuf) +STRESSVECO = stressVector.$(ObjSuf) +STRESSVECS = stressVector.$(SrcSuf) +STRESSVEC = stressVector$(ExeSuf) STRESSMATHO = stressMathCore.$(ObjSuf) STRESSMATHS = stressMathCore.$(SrcSuf) STRESSMATHLIBS = $(ROOTSYS)\lib\libGenVector.lib -TRACKMATHSRC = TrackMathCoreDict.$(SrcSuf) -TRACKMATHOBJ = TrackMathCoreDict.$(ObjSuf) -TRACKMATHLIB = libTrackMathCoreDict.$(DllSuf) +TRACKMATHSRC = TrackMathCoreDict.$(SrcSuf) +TRACKMATHOBJ = TrackMathCoreDict.$(ObjSuf) +TRACKMATHLIB = libTrackMathCoreDict.$(DllSuf) STRESSMATH = stressMathCore$(ExeSuf) !endif @@ -249,9 +219,9 @@ STRESSO = stress.$(ObjSuf) STRESSS = stress.$(SrcSuf) STRESS = stress$(ExeSuf) -STRESSGEOMETRYO = stressGeometry.$(ObjSuf) -STRESSGEOMETRYS = stressGeometry.$(SrcSuf) -STRESSGEOMETRY = stressGeometry$(ExeSuf) +STRESSGEOMETRYO = stressGeometry.$(ObjSuf) +STRESSGEOMETRYS = stressGeometry.$(SrcSuf) +STRESSGEOMETRY = stressGeometry$(ExeSuf) STRESSSHAPESO = stressShapes.$(ObjSuf) STRESSSHAPESS = stressShapes.$(SrcSuf) @@ -366,193 +336,158 @@ $(EVENTSO): $(EVENTO) BINDEXPLIB $* $(EVENTO) > $*.def lib -nologo -MACHINE:IX86 $(EVENTO) -def:$*.def $(OutPutOpt)$(EVENTLIB) $(LD) $(SOFLAGS) $(LDFLAGS) $(EVENTO) $*.exp $(LIBS) $(OutPutOpt)$(EVENTSO) - $(MT_DLL) @echo "$(EVENTSO) done" $(EVENTMTSO): $(EVENTMTO) BINDEXPLIB $* $(EVENTMTO) > $*.def lib -nologo -MACHINE:IX86 $(EVENTMTO) -def:$*.def $(OutPutOpt)$(EVENTMTLIB) $(LD) $(SOFLAGS) $(LDFLAGS) $(EVENTMTO) $*.exp $(LIBS) $(OutPutOpt)$(EVENTMTSO) - $(MT_DLL) @echo "$(EVENTMTSO) done" $(EVENT): $(EVENTSO) $(MAINEVENTO) $(LD) $(LDFLAGS) $(MAINEVENTO) $(EVENTLIB) $(LIBS) $(OutPutOpt)$(EVENT) - $(MT_EXE) @echo "$(EVENT) done" $(HWORLD): $(HWORLDO) $(LD) $(LDFLAGS) $(HWORLDO) $(GLIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(CTORTURE): $(CTORTUREO) $(LD) $(LDFLAGS) $(CTORTUREO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(HSIMPLE): $(HSIMPLEO) $(LD) $(LDFLAGS) $(HSIMPLEO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(MINEXAM): $(MINEXAMO) $(LD) $(LDFLAGS) $(MINEXAMO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(TSTRING): $(TSTRINGO) $(LD) $(LDFLAGS) $(TSTRINGO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(TCOLLEX): $(TCOLLEXO) $(LD) $(LDFLAGS) $(TCOLLEXO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(TCOLLBM): $(TCOLLBMO) $(LD) $(LDFLAGS) $(TCOLLBMO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(VVECTOR): $(VVECTORO) $(LD) $(LDFLAGS) $(VVECTORO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(VMATRIX): $(VMATRIXO) $(LD) $(LDFLAGS) $(VMATRIXO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(VLAZY): $(VLAZYO) $(LD) $(LDFLAGS) $(VLAZYO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSL): $(STRESSLO) $(LD) $(LDFLAGS) $(STRESSLO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSG): $(STRESSGO) $(LD) $(LDFLAGS) $(STRESSGO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSGUI): $(STRESSGUIO) $(LD) $(LDFLAGS) $(STRESSGUIO) $(GLIBS) $(STRESSGUILIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSSP): $(STRESSSPO) $(LD) $(LDFLAGS) $(STRESSSPO) $(LIBS) $(ROOTSYS)\lib\libSpectrum.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !if exist("$(ROOTSYS)\lib\libGenVector.lib") $(STRESSVEC): $(STRESSVECO) $(LD) $(LDFLAGS) $(STRESSVECO) $(LIBS) $(ROOTSYS)\lib\libGenVector.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(TRACKMATHLIB): $(TRACKMATHOBJ) $(LD) $(SOFLAGS) $(LDFLAGS) $(TRACKMATHOBJ) $(LIBS) $(ROOTSYS)\lib\libGenVector.lib $(OutPutOpt)$@ - $(MT_DLL) @echo "$@ done" $(STRESSMATH): $(STRESSMATHO) $(TRACKMATHLIB) $(LD) $(LDFLAGS) $(STRESSMATHO) $(LIBS) $(ROOTSYS)\lib\libGenVector.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif !if exist("$(ROOTSYS)\lib\libMathMore.lib") $(STRESSMATHMORE): $(STRESSMATHMOREO) $(LD) $(LDFLAGS) $(STRESSMATHMOREO) $(LIBS) $(ROOTSYS)\lib\libMathMore.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif !if exist("$(ROOTSYS)\lib\libTMVA.lib") $(STRESSTMVA): $(STRESSTMVAO) $(LD) $(LDFLAGS) $(STRESSTMVAO) $(LIBS) $(ROOTSYS)\lib\libTMVA.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif $(TESTBITS): $(TESTBITSO) $(LD) $(LDFLAGS) $(TESTBITSO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(THREADS): $(THREADSO) $(LD) $(LDFLAGS) $(THREADSO) $(LIBS) $(ROOTSYS)\lib\libThread.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(QPRANDOM): $(QPRANDOMO) $(LD) $(LDFLAGS) $(QPRANDOMO) $(LIBS) $(ROOTSYS)\lib\libQuadp.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(GUITEST): $(GUITESTO) $(LD) $(LDFLAGS) $(GUITESTO) $(GLIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(GUIVIEWER): $(GUIVIEWERO) $(LD) $(LDFLAGS) $(GUIVIEWERO) $(GLIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESS): $(STRESSO) $(EVENT) $(LD) $(LDFLAGS) $(STRESSO) $(EVENTLIB) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSGEOMETRY): $(STRESSGEOMETRYO) $(LD) $(LDFLAGS) $(STRESSGEOMETRYO) $(LIBS) $(ROOTSYS)\lib\libGeom.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSSHAPES): $(STRESSSHAPESO) $(LD) $(LDFLAGS) $(STRESSSHAPESO) $(LIBS) $(ROOTSYS)\lib\libGeom.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !if exist("$(ROOTSYS)\lib\libRooFit.lib") $(STRESSROOFIT): $(STRESSROOFITO) $(LD) $(LDFLAGS) $(STRESSROOFITO) $(LIBS) $(ROOTSYS)\lib\libRooFit.lib $(ROOTSYS)\lib\libRooFitCore.lib $(ROOTSYS)\lib\libHtml.lib $(ROOTSYS)\lib\libThread.lib $(ROOTSYS)\lib\libMinuit.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif !if exist("$(ROOTSYS)\lib\libRooStats.lib") $(STRESSROOSTATS): $(STRESSROOSTATSO) $(LD) $(LDFLAGS) $(STRESSROOSTATSO) $(LIBS) $(ROOTSYS)\lib\libRooStats.lib $(ROOTSYS)\lib\libRooFit.lib $(ROOTSYS)\lib\libRooFitCore.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif !if exist("$(ROOTSYS)\lib\libHistFactory.lib") $(STRESSHISTFACTORY): $(STRESSHISTFACTORYO) $(LD) $(LDFLAGS) $(STRESSHISTFACTORYO) $(LIBS) $(ROOTSYS)\lib\libHistFactory.lib $(ROOTSYS)\lib\libRooStats.lib $(ROOTSYS)\lib\libRooFit.lib $(ROOTSYS)\lib\libRooFitCore.lib $(ROOTSYS)\lib\libHtml.lib $(ROOTSYS)\lib\libThread.lib $(ROOTSYS)\lib\libMinuit.lib $(ROOTSYS)\lib\libFoam.lib $(ROOTSYS)\lib\libProof.lib $(EXTRAROOFITLIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif $(STRESSFIT): $(STRESSFITO) $(LD) $(LDFLAGS) $(STRESSFITO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !if exist("$(ROOTSYS)\lib\libUnuran.lib") !if exist("$(ROOTSYS)\lib\libminuit2.lib") $(STRESSHISTOFIT): $(STRESSHISTOFITO) $(LD) $(LDFLAGS) $(STRESSHISTOFITO) $(LIBS) $(ROOTSYS)\lib\libUnuran.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" !endif !endif @@ -564,51 +499,41 @@ $(STRESSENTRYLIST): $(STRESSENTRYLISTO) $(STRESSHEPIX): $(STRESSHEPIXO) $(STRESSGEOMETRY) $(STRESSFIT) $(STRESSL) \ $(STRESSSP) $(STRESS) $(LD) $(LDFLAGS) $(STRESSHEPIXO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSPROOF): $(STRESSPROOFO) $(LD) $(LDFLAGS) $(STRESSPROOFO) $(LIBS) $(ROOTSYS)\lib\libProof.lib $(ROOTSYS)\lib\libThread.lib $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(BENCH): $(BENCHO) $(TBENCHSO) $(LD) $(LDFLAGS) $(BENCHO) $(TBENCHO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" Hello: $(HELLOSO) $(HELLOSO): $(HELLOO) $(LD) $(SOFLAGS) $(LDFLAGS) $(HELLOO) $(GLIBS) $(OutPutOpt)$@ - $(MT_DLL) Aclock: $(ACLOCKSO) $(ACLOCKSO): $(ACLOCKO) $(LD) $(SOFLAGS) $(LDFLAGS) $(ACLOCKO) $(GLIBS) $(OutPutOpt)$@ - $(MT_DLL) Tetris: $(TETRISSO) $(TETRISSO): $(TETRISO) $(LD) $(SOFLAGS) $(LDFLAGS) $(TETRISO) $(GLIBS) $(OutPutOpt)$@ - $(MT_DLL) $(TBENCHSO): $(TBENCHO) $(LD) $(SOFLAGS) $(LDFLAGS) $(TBENCHO) $(LIBS) $(OutPutOpt)$@ - $(MT_DLL) $(STRESSINTERP): $(STRESSINTERPO) $(LD) $(LDFLAGS) $(STRESSINTERPO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSITER): $(STRESSITERO) $(LD) $(LDFLAGS) $(STRESSITERO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" $(STRESSHIST): $(STRESSHISTO) $(LD) $(LDFLAGS) $(STRESSHISTO) $(LIBS) $(OutPutOpt)$@ - $(MT_EXE) @echo "$@ done" clean: @@ -660,8 +585,8 @@ TrackMathCoreDict.$(SrcSuf): TrackMathCore.h TrackMathCoreLinkDef.h @rootcint -f $@ -c TrackMathCore.h TrackMathCoreLinkDef.h stressProof.$(ObjSuf): stressProof.$(SrcSuf) - $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -I$(TUTDIR) -c $** + $(CXX) $(CXXFLAGS) $(CXXOPT) -I$(TUTDIR) -c $** .$(SrcSuf).$(ObjSuf): - $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c $< + $(CXX) $(CXXFLAGS) $(CXXOPT) -c $< From ff50615a41a7d8a33126ab8364dcc38ecd49496a Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Tue, 1 Jun 2021 10:51:11 +0200 Subject: [PATCH 011/309] [skip-ci] Remove references to Netscape (thanks Olivier) --- gui/gui/src/TGClient.cxx | 2 +- gui/gui/src/TGTextEntry.cxx | 28 ++++++++++++++-------------- tutorials/image/hsumanim.C | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gui/gui/src/TGClient.cxx b/gui/gui/src/TGClient.cxx index 65a563c324167..ec6b7ff1d46a9 100644 --- a/gui/gui/src/TGClient.cxx +++ b/gui/gui/src/TGClient.cxx @@ -407,7 +407,7 @@ Bool_t TGClient::GetColorByName(const char *name, Pixel_t &pixel) const status = kFALSE; } else if (!gVirtualX->AllocColor(attributes.fColormap, color)) { Warning("GetColorByName", "couldn't retrieve color %s.\n" - "Please close any other application, like netscape, " + "Please close any other application, like web browsers, " "that might exhaust\nthe colormap and start ROOT again", name); status = kFALSE; } diff --git a/gui/gui/src/TGTextEntry.cxx b/gui/gui/src/TGTextEntry.cxx index c0820a7a12309..1de112b614c0d 100644 --- a/gui/gui/src/TGTextEntry.cxx +++ b/gui/gui/src/TGTextEntry.cxx @@ -34,7 +34,7 @@ Hitting the tab key will generate: kC_TEXTENTRY, kTE_TAB, widget id, 0. This widget has the behaviour e.g. of the "Location" field in -netscape. That includes handling Control/Shift key modifiers and +web browsers. That includes handling Control/Shift key modifiers and scrolling the text. enum TGTextEntry::EEchoMode @@ -1456,19 +1456,19 @@ Bool_t TGTextEntry::HandleFocusChange(Event_t *event) if (!IsEnabled()) return kTRUE; // check this when porting to Win32 - if (event->fType == kFocusIn) { - fCursorOn = kTRUE; - if (!fCurBlink) fCurBlink = new TBlinkTimer(this, 500); - fCurBlink->Reset(); - gBlinkingEntry = this; - gSystem->AddTimer(fCurBlink); - } else { - fCursorOn = kFALSE; - // fSelectionOn = kFALSE; // "netscape location behavior" - if (fCurBlink) fCurBlink->Remove(); - gBlinkingEntry = 0; - } - fClient->NeedRedraw(this); + if (event->fType == kFocusIn) { + fCursorOn = kTRUE; + if (!fCurBlink) fCurBlink = new TBlinkTimer(this, 500); + fCurBlink->Reset(); + gBlinkingEntry = this; + gSystem->AddTimer(fCurBlink); + } else { + fCursorOn = kFALSE; + // fSelectionOn = kFALSE; // "web browser location behavior" + if (fCurBlink) fCurBlink->Remove(); + gBlinkingEntry = 0; + } + fClient->NeedRedraw(this); return kTRUE; } diff --git a/tutorials/image/hsumanim.C b/tutorials/image/hsumanim.C index 49b1dd5468aa5..ecfaa2a1e90bd 100644 --- a/tutorials/image/hsumanim.C +++ b/tutorials/image/hsumanim.C @@ -72,7 +72,7 @@ void hsumanim() { // make infinite animation by adding "++" to the file name if (gROOT->IsBatch()) c1->Print("hsumanim.gif++"); - //You can view the animated file hsumanim.gif with Netscape/IE or mozilla + // you can view the animated file hsumanim.gif with a web browser gBenchmark->Show("hsum"); } From 56db61d44e77e777dce51dce01e152539bd69746 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 19 May 2021 20:52:42 -0400 Subject: [PATCH 012/309] when canceling in Directory Mode, empty iniDir for analogy with FileMode --- gui/gui/src/TGFileDialog.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gui/gui/src/TGFileDialog.cxx b/gui/gui/src/TGFileDialog.cxx index c1664be727eb3..373a3d55b56e3 100644 --- a/gui/gui/src/TGFileDialog.cxx +++ b/gui/gui/src/TGFileDialog.cxx @@ -479,6 +479,8 @@ Bool_t TGFileDialog::ProcessMessage(Long_t msg, Long_t parm1, Long_t) case kIDF_CANCEL: fFileInfo->SetFilename(nullptr); + if (fDlgType == kDOpen || fDlgType == kDSave) + fFileInfo->SetIniDir(nullptr); if (fFc->GetDisplayStat()) fFc->SetDisplayStat(kFALSE); fFileInfo->DeleteFileNamesList(); From 869fddbe3247e8897883f8a5273d4f70c5b6fb36 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Tue, 1 Jun 2021 14:36:46 +0200 Subject: [PATCH 013/309] \anchor names need to be more specific as they are not relative to a page. (#8310) --- core/base/src/TAttFill.cxx | 8 ++++---- core/base/src/TAttLine.cxx | 12 ++++++------ core/base/src/TAttMarker.cxx | 12 ++++++------ core/base/src/TAttText.cxx | 34 +++++++++++++++++----------------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/core/base/src/TAttFill.cxx b/core/base/src/TAttFill.cxx index 57cdfbeff70aa..dfdd2e004684d 100644 --- a/core/base/src/TAttFill.cxx +++ b/core/base/src/TAttFill.cxx @@ -32,10 +32,10 @@ attributes. ## Fill Area attributes Fill Area attributes are: - - [Fill Area color](\ref F1) - - [Fill Area style](\ref F2) + - [Fill Area color](\ref ATTFILL1) + - [Fill Area style](\ref ATTFILL2) -\anchor F1 +\anchor ATTFILL1 ## Fill Area color The fill area color is a color index (integer) pointing in the ROOT color table. @@ -104,7 +104,7 @@ If the current style fill area color is set to 0, then ROOT will force a black&white output for all objects with a fill area defined and independently of the object fill style. -\anchor F2 +\anchor ATTFILL2 ## Fill Area style The fill area style defines the pattern used to fill a polygon. The fill area style of any class inheriting from `TAttFill` can diff --git a/core/base/src/TAttLine.cxx b/core/base/src/TAttLine.cxx index ea8fd7b872ae6..2a5cd3e8dd5ac 100644 --- a/core/base/src/TAttLine.cxx +++ b/core/base/src/TAttLine.cxx @@ -33,11 +33,11 @@ by many other classes (graphics, histograms). It holds all the line attributes. ## Line attributes Line attributes are: - - [Line Color](\ref L1) - - [Line Width](\ref L2) - - [Line Style](\ref L3) + - [Line Color](\ref ATTLINE1) + - [Line Width](\ref ATTLINE2) + - [Line Style](\ref ATTLINE3) -\anchor L1 +\anchor ATTLINE1 ## Line Color The line color is a color index (integer) pointing in the ROOT color table. @@ -69,7 +69,7 @@ in `$ROOTSYS/etc/system.rootrc`, or on Mac with the Cocoa backend. On the file o it is visible with PDF, PNG, Gif, JPEG, SVG, TeX ... but not PostScript. -\anchor L2 +\anchor ATTLINE2 ## Line Width The line width is expressed in pixel units. The line width of any class inheriting from `TAttLine` can @@ -93,7 +93,7 @@ Begin_Macro } End_Macro -\anchor L3 +\anchor ATTLINE3 ## Line Style Line styles are identified via integer numbers. The line style of any class inheriting from `TAttLine` can be changed using the method diff --git a/core/base/src/TAttMarker.cxx b/core/base/src/TAttMarker.cxx index 50a99968e1397..481cb6c63e467 100644 --- a/core/base/src/TAttMarker.cxx +++ b/core/base/src/TAttMarker.cxx @@ -33,12 +33,12 @@ attributes. ## Marker attributes The marker attributes are: - - [Marker color](\ref M1) - - [Marker style](\ref M2) - - [Marker line width](\ref M21) + - [Marker color](\ref ATTMARKER1) + - [Marker style](\ref ATTMARKER2) + - [Marker line width](\ref ATTMARKER21) - [Marker size](\ref M3) -\anchor M1 +\anchor ATTMARKER1 ## Marker color The marker color is a color index (integer) pointing in the ROOT color table. @@ -70,7 +70,7 @@ The transparency is available on all platforms when the flag `OpenGL.CanvasPrefe in `$ROOTSYS/etc/system.rootrc`, or on Mac with the Cocoa backend. On the file output it is visible with PDF, PNG, Gif, JPEG, SVG, TeX ... but not PostScript. -\anchor M2 +\anchor ATTMARKER2 ## Marker style The Marker style defines the markers' shape. @@ -134,7 +134,7 @@ Begin_Macro } End_Macro -\anchor M21 +\anchor ATTMARKER21 ### Marker line width The line width of a marker is not actually a marker attribute since it does diff --git a/core/base/src/TAttText.cxx b/core/base/src/TAttText.cxx index 57829460bdb75..9f2ab52d95ba7 100644 --- a/core/base/src/TAttText.cxx +++ b/core/base/src/TAttText.cxx @@ -34,16 +34,16 @@ by many other classes (graphics, histograms). It holds all the text attributes. ## Text attributes Text attributes are: - - [Text Alignment](\ref T1) - - [Text Angle](\ref T2) - - [Text Color](\ref T3) - - [Text Size](\ref T4) - - [Text Font and Precision](\ref T5) - - [Font quality and speed](\ref T51) - - [How to use True Type Fonts](\ref T52) - - [List of the currently supported fonts](\ref T53) - -\anchor T1 + - [Text Alignment](\ref ATTTEXT1) + - [Text Angle](\ref ATTTEXT2) + - [Text Color](\ref ATTTEXT3) + - [Text Size](\ref ATTTEXT4) + - [Text Font and Precision](\ref ATTTEXT5) + - [Font quality and speed](\ref ATTTEXT51) + - [How to use True Type Fonts](\ref ATTTEXT52) + - [List of the currently supported fonts](\ref ATTTEXT53) + +\anchor ATTTEXT1 ## Text Alignment The text alignment is an integer number (`align`) allowing to control @@ -93,7 +93,7 @@ They allow to write: object->SetTextAlign(kHAlignLeft+kVAlignTop); ~~~ -\anchor T2 +\anchor ATTTEXT2 ## Text Angle Text angle in degrees. @@ -106,7 +106,7 @@ Begin_Macro(source) textangle.C End_Macro -\anchor T3 +\anchor ATTTEXT3 ## Text Color The text color is a color index (integer) pointing in the ROOT @@ -138,7 +138,7 @@ The transparency is available on all platforms when the flag `OpenGL.CanvasPrefe in `$ROOTSYS/etc/system.rootrc`, or on Mac with the Cocoa backend. On the file output it is visible with PDF, PNG, Gif, JPEG, SVG, TeX ... but not PostScript. -\anchor T4 +\anchor ATTTEXT4 ## Text Size If the text precision (see next paragraph) is smaller than 3, the text @@ -169,7 +169,7 @@ The text size of any class inheriting from `TAttText` can be changed using the method `SetTextSize` and retrieved using the method `GetTextSize`. -\anchor T5 +\anchor ATTTEXT5 ## Text Font and Precision The text font code is combination of the font number and the precision. @@ -190,7 +190,7 @@ The text font and precision of any class inheriting from `TAttText` can be changed using the method `SetTextFont` and retrieved using the method `GetTextFont`. -\anchor T51 +\anchor ATTTEXT51 ### Font quality and speed When precision 0 is used, only the original non-scaled system fonts are @@ -201,7 +201,7 @@ Precision 1 and 2 fonts have a different behaviour depending if the True Type Fonts (TTF) are used or not. If TTF are used, you always get very good quality scalable and rotatable fonts. However TTF are slow. -\anchor T52 +\anchor ATTTEXT52 ### How to use True Type Fonts One can activate the TTF by adding (or activating) the following line @@ -225,7 +225,7 @@ printout given by this command: Unix.*.Root.UseTTFonts: true [Global] ~~~ -\anchor T53 +\anchor ATTTEXT53 ### List of the currently supported fonts ~~~ {.cpp} From 8d742e4a49171457b024bbdaa2ac91e08460d30d Mon Sep 17 00:00:00 2001 From: moneta Date: Mon, 31 May 2021 16:48:50 +0200 Subject: [PATCH 014/309] - Veto tutoril multiVarGaus.C when mathmore is not available - Disable printing error message in exampleFunction.py when mathmore is not available --- tutorials/CMakeLists.txt | 1 + tutorials/math/exampleFunction.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index 940cf22e0d589..dd198a798cfaf 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -182,6 +182,7 @@ if(NOT ROOT_mathmore_FOUND) math/LegendreAssoc.C math/Legendre.C math/mathmoreIntegration.C + math/multivarGaus.C math/tStudent.C math/normalDist.C roostats/TestNonCentral.C diff --git a/tutorials/math/exampleFunction.py b/tutorials/math/exampleFunction.py index 9ea6cb36c663a..442b8bb83dfef 100644 --- a/tutorials/math/exampleFunction.py +++ b/tutorials/math/exampleFunction.py @@ -68,7 +68,11 @@ def g(x): return 2 * x gradFunc = ROOT.Math.GradFunctor1D(f, g) #check if ROOT has mathmore -if (ROOT.gSystem.Load("libMathMore") < 0) : +prevLevel = ROOT.gErrorIgnoreLevel +ROOT.gErrorIgnoreLevel=ROOT.kFatal +ret = ROOT.gSystem.Load("libMathMore") +ROOT.gErrorIgnoreLevel=prevLevel +if (ret < 0) : print("ROOT has not Mathmore") print("derivative value at x = 1", gradFunc.Derivative(1) ) From 9296e5ed912b3010456fa4b50db77f2c4c97a09a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sun, 11 Apr 2021 01:59:30 +0200 Subject: [PATCH 015/309] [RF] Remove usage of RooNameSet and use helper functions instead The RooNameSet class is too complicated considering that it fulfills a rather simple purpose, which is to serialize the names of objects in a RooArgSet to a string that can be used to select objects from other RooArgSets. This commit proposes to replace the RooNameSet class by new functions in the RooHelpers namespace: `getColonSeparatedNameString` and `selectFromArgSet`. These functions make use of `std::string` to be much less verbose than the original RooNameSet class. --- roofit/roofitcore/inc/RooAbsPdf.h | 2 -- roofit/roofitcore/inc/RooAddModel.h | 1 - roofit/roofitcore/inc/RooAddPdf.h | 1 - roofit/roofitcore/inc/RooCacheManager.h | 33 ++++++++------------ roofit/roofitcore/inc/RooHelpers.h | 3 ++ roofit/roofitcore/inc/RooNormSetCache.h | 10 +++--- roofit/roofitcore/inc/RooObjCacheManager.h | 2 -- roofit/roofitcore/src/RooAbsArg.cxx | 12 +++---- roofit/roofitcore/src/RooAbsPdf.cxx | 24 +++++++------- roofit/roofitcore/src/RooAbsReal.cxx | 17 +++++----- roofit/roofitcore/src/RooAddModel.cxx | 14 +++------ roofit/roofitcore/src/RooAddition.cxx | 4 +-- roofit/roofitcore/src/RooHelpers.cxx | 33 ++++++++++++++++++++ roofit/roofitcore/src/RooHistFunc.cxx | 4 ++- roofit/roofitcore/src/RooNormSetCache.cxx | 13 ++++---- roofit/roofitcore/src/RooProdPdf.cxx | 23 +++++--------- roofit/roofitcore/src/RooProduct.cxx | 4 +-- roofit/roofitcore/src/RooProjectedPdf.cxx | 21 +++++-------- roofit/roofitcore/src/RooRealSumFunc.cxx | 6 ++-- roofit/roofitcore/src/RooRealSumPdf.cxx | 6 ++-- roofit/roofitcore/src/RooVectorDataStore.cxx | 17 ++++------ 21 files changed, 125 insertions(+), 125 deletions(-) diff --git a/roofit/roofitcore/inc/RooAbsPdf.h b/roofit/roofitcore/inc/RooAbsPdf.h index c64528638a941..c7655eb6bf00a 100644 --- a/roofit/roofitcore/inc/RooAbsPdf.h +++ b/roofit/roofitcore/inc/RooAbsPdf.h @@ -17,8 +17,6 @@ #define ROO_ABS_PDF #include "RooAbsReal.h" -//#include "RooRealIntegral.h" -#include "RooNameSet.h" #include "RooObjCacheManager.h" #include "RooCmdArg.h" diff --git a/roofit/roofitcore/inc/RooAddModel.h b/roofit/roofitcore/inc/RooAddModel.h index 47a98917f91cd..2b7cb77ecd97f 100644 --- a/roofit/roofitcore/inc/RooAddModel.h +++ b/roofit/roofitcore/inc/RooAddModel.h @@ -21,7 +21,6 @@ #include "RooSetProxy.h" #include "RooAICRegistry.h" #include "RooNormSetCache.h" -#include "RooNameSet.h" #include "RooObjCacheManager.h" class RooAddModel : public RooResolutionModel { diff --git a/roofit/roofitcore/inc/RooAddPdf.h b/roofit/roofitcore/inc/RooAddPdf.h index 0e7a36cc0863c..b438b9ea7427c 100644 --- a/roofit/roofitcore/inc/RooAddPdf.h +++ b/roofit/roofitcore/inc/RooAddPdf.h @@ -21,7 +21,6 @@ #include "RooSetProxy.h" #include "RooAICRegistry.h" #include "RooNormSetCache.h" -#include "RooNameSet.h" #include "RooObjCacheManager.h" #include "RooNameReg.h" diff --git a/roofit/roofitcore/inc/RooCacheManager.h b/roofit/roofitcore/inc/RooCacheManager.h index eec16643e91c1..7bc968bcc88d5 100644 --- a/roofit/roofitcore/inc/RooCacheManager.h +++ b/roofit/roofitcore/inc/RooCacheManager.h @@ -26,9 +26,10 @@ #include "RooAbsCache.h" #include "RooAbsCacheElement.h" #include "RooNameReg.h" +#include "RooHelpers.h" +#include "ROOT/RMakeUnique.hxx" #include - -class RooNameSet ; +#include template @@ -84,8 +85,8 @@ class RooCacheManager : public RooAbsCache { } T* getObjByIndex(Int_t index) const ; - const RooNameSet* nameSet1ByIndex(Int_t index) const ; - const RooNameSet* nameSet2ByIndex(Int_t index) const ; + RooArgSet selectFromSet1(RooArgSet const& argSet, int index) const ; + RooArgSet selectFromSet2(RooArgSet const& argSet, int index) const ; virtual void insertObjectHook(T&) { // Interface function to perform post-insert operations on cached object @@ -317,29 +318,21 @@ T* RooCacheManager::getObjByIndex(Int_t index) const } -/// Retrieve RooNameSet associated with slot at given index. +/// Create RooArgSet contatining the objects that are both in the cached set 1 +//with a given index and an input argSet. template -const RooNameSet* RooCacheManager::nameSet1ByIndex(Int_t index) const +RooArgSet RooCacheManager::selectFromSet1(RooArgSet const& argSet, int index) const { - if (index<0||index>=_size) { - oocoutE(_owner,ObjectHandling) << "RooCacheManager::getNormListByIndex: ERROR index (" - << index << ") out of range [0," << _size-1 << "]" << std::endl ; - return 0 ; - } - return &_nsetCache[index].nameSet1() ; + return RooHelpers::selectFromArgSet(argSet, _nsetCache.at(index).nameSet1()); } -/// Retrieve RooNameSet associated with slot at given index. +/// Create RooArgSet contatining the objects that are both in the cached set 2 +//with a given index and an input argSet. template -const RooNameSet* RooCacheManager::nameSet2ByIndex(Int_t index) const +RooArgSet RooCacheManager::selectFromSet2(RooArgSet const& argSet, int index) const { - if (index<0||index>=_size) { - oocoutE(_owner,ObjectHandling) << "RooCacheManager::getNormListByIndex: ERROR index (" - << index << ") out of range [0," << _size-1 << "]" << std::endl ; - return 0 ; - } - return &_nsetCache[index].nameSet2() ; + return RooHelpers::selectFromArgSet(argSet, _nsetCache.at(index).nameSet2()); } diff --git a/roofit/roofitcore/inc/RooHelpers.h b/roofit/roofitcore/inc/RooHelpers.h index 1879f4e84cbee..a426d737c38e9 100644 --- a/roofit/roofitcore/inc/RooHelpers.h +++ b/roofit/roofitcore/inc/RooHelpers.h @@ -121,6 +121,9 @@ std::pair getRangeOrBinningInterval(RooAbsArg const* arg, const bool checkIfRangesOverlap(RooAbsPdf const& pdf, RooAbsData const& data, std::vector const& rangeNames); +std::string getColonSeparatedNameString(RooArgSet const& argSet); +RooArgSet selectFromArgSet(RooArgSet const&, std::string const& names); + } diff --git a/roofit/roofitcore/inc/RooNormSetCache.h b/roofit/roofitcore/inc/RooNormSetCache.h index b6a181018b4cf..14a582757910f 100644 --- a/roofit/roofitcore/inc/RooNormSetCache.h +++ b/roofit/roofitcore/inc/RooNormSetCache.h @@ -18,9 +18,9 @@ #include #include +#include #include "Rtypes.h" -#include "RooNameSet.h" class RooAbsArg; class RooArgSet; @@ -75,8 +75,8 @@ class RooNormSetCache { const RooArgSet* lastSet1() const { return _pairs.empty()?0:_pairs.back().first; } const RooArgSet* lastSet2() const { return _pairs.empty()?0:_pairs.back().second; } - const RooNameSet& nameSet1() const { return _name1; } - const RooNameSet& nameSet2() const { return _name2; } + const std::string& nameSet1() const { return _name1; } + const std::string& nameSet2() const { return _name2; } Bool_t autoCache(const RooAbsArg* self, const RooArgSet* set1, const RooArgSet* set2 = 0, const TNamed* set2RangeName = 0, @@ -94,8 +94,8 @@ class RooNormSetCache { ULong_t _max; //! ULong_t _next; //! - RooNameSet _name1; //! - RooNameSet _name2; //! + std::string _name1; //! + std::string _name2; //! TNamed* _set2RangeName; //! ClassDef(RooNormSetCache, 0) // Management tool for tracking sets of similar integration/normalization sets diff --git a/roofit/roofitcore/inc/RooObjCacheManager.h b/roofit/roofitcore/inc/RooObjCacheManager.h index c9ec150bfcd95..fbf49e52ce9ab 100644 --- a/roofit/roofitcore/inc/RooObjCacheManager.h +++ b/roofit/roofitcore/inc/RooObjCacheManager.h @@ -26,8 +26,6 @@ #include "RooAbsCacheElement.h" #include "RooCacheManager.h" -class RooNameSet; - class RooObjCacheManager : public RooCacheManager { diff --git a/roofit/roofitcore/src/RooAbsArg.cxx b/roofit/roofitcore/src/RooAbsArg.cxx index 2f735fdccdd6b..8ecebb07468b6 100644 --- a/roofit/roofitcore/src/RooAbsArg.cxx +++ b/roofit/roofitcore/src/RooAbsArg.cxx @@ -74,7 +74,6 @@ for single nodes. #include "strlcpy.h" #include "RooSecondMoment.h" -#include "RooNameSet.h" #include "RooWorkspace.h" #include "RooMsgService.h" @@ -641,11 +640,12 @@ RooArgSet* RooAbsArg::getParameters(const RooArgSet* observables, bool stripDisc bool RooAbsArg::getParameters(const RooArgSet* observables, RooArgSet& outputSet, bool stripDisconnected) const { + using RooHelpers::getColonSeparatedNameString; // Check for cached parameter set if (_myws) { - RooNameSet nsetObs(observables ? *observables : RooArgSet()); - const RooArgSet *paramSet = _myws->set(Form("CACHE_PARAMS_OF_PDF_%s_FOR_OBS_%s", GetName(), nsetObs.content())); + auto nsetObs = getColonSeparatedNameString(observables ? *observables : RooArgSet()); + const RooArgSet *paramSet = _myws->set(Form("CACHE_PARAMS_OF_PDF_%s_FOR_OBS_%s", GetName(), nsetObs.c_str())); if (paramSet) { outputSet.add(*paramSet); return false; @@ -660,9 +660,9 @@ bool RooAbsArg::getParameters(const RooArgSet* observables, RooArgSet& outputSet outputSet.sort(); // Cache parameter set - if (_myws && outputSet.getSize() > 10) { - RooNameSet nsetObs(observables ? *observables : RooArgSet()); - _myws->defineSetInternal(Form("CACHE_PARAMS_OF_PDF_%s_FOR_OBS_%s", GetName(), nsetObs.content()), outputSet); + if (_myws && outputSet.size() > 10) { + auto nsetObs = getColonSeparatedNameString(observables ? *observables : RooArgSet()); + _myws->defineSetInternal(Form("CACHE_PARAMS_OF_PDF_%s_FOR_OBS_%s", GetName(), nsetObs.c_str()), outputSet); // cout << " caching parameters in workspace for pdf " << IsA()->GetName() << "::" << GetName() << endl ; } diff --git a/roofit/roofitcore/src/RooAbsPdf.cxx b/roofit/roofitcore/src/RooAbsPdf.cxx index 04aef69c26b2f..c64f858566eb8 100644 --- a/roofit/roofitcore/src/RooAbsPdf.cxx +++ b/roofit/roofitcore/src/RooAbsPdf.cxx @@ -191,6 +191,8 @@ called for each data event. using namespace std; +using RooHelpers::getColonSeparatedNameString; + ClassImp(RooAbsPdf); ClassImp(RooAbsPdf::GenSpec); @@ -583,15 +585,13 @@ Bool_t RooAbsPdf::syncNormalization(const RooArgSet* nset, Bool_t adjustProxies) std::unique_ptr intParams{normInt->getVariables()} ; - RooNameSet cacheParamNames ; - cacheParamNames.setNameList(cacheParamsStr) ; - std::unique_ptr cacheParams{cacheParamNames.select(*intParams)} ; + RooArgSet cacheParams = RooHelpers::selectFromArgSet(*intParams, cacheParamsStr); - if (cacheParams->getSize()>0) { - cxcoutD(Caching) << "RooAbsReal::createIntObj(" << GetName() << ") INFO: constructing " << cacheParams->getSize() - << "-dim value cache for integral over " << depList << " as a function of " << *cacheParams << " in range " << (nr?nr:"") << endl ; - string name = Form("%s_CACHE_[%s]",normInt->GetName(),cacheParams->contentsString().c_str()) ; - RooCachedReal* cachedIntegral = new RooCachedReal(name.c_str(),name.c_str(),*normInt,*cacheParams) ; + if (!cacheParams.empty()) { + cxcoutD(Caching) << "RooAbsReal::createIntObj(" << GetName() << ") INFO: constructing " << cacheParams.getSize() + << "-dim value cache for integral over " << depList << " as a function of " << cacheParams << " in range " << (nr?nr:"") << endl ; + string name = Form("%s_CACHE_[%s]",normInt->GetName(),cacheParams.contentsString().c_str()) ; + RooCachedReal* cachedIntegral = new RooCachedReal(name.c_str(),name.c_str(),*normInt,cacheParams) ; cachedIntegral->setInterpolationOrder(2) ; cachedIntegral->addOwnedComponents(*normInt) ; cachedIntegral->setCacheSource(kTRUE) ; @@ -1156,11 +1156,11 @@ RooAbsReal* RooAbsPdf::createNLL(RooAbsData& data, const RooLinkedList& cmdList) // Collect internal and external constraint specifications RooArgSet allConstraints ; - if (_myws && _myws->set(Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), RooNameSet(*data.get()).content()))) { + if (_myws && _myws->set(Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), getColonSeparatedNameString(*data.get()).c_str()))) { // retrieve from cache const RooArgSet *constr = - _myws->set(Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), RooNameSet(*data.get()).content())); + _myws->set(Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), getColonSeparatedNameString(*data.get()).c_str())); coutI(Minimization) << "createNLL picked up cached constraints from workspace with " << constr->getSize() << " entries" << endl; allConstraints.add(*constr); @@ -1180,10 +1180,10 @@ RooAbsReal* RooAbsPdf::createNLL(RooAbsData& data, const RooLinkedList& cmdList) if (_myws) { // cout << "createNLL: creating cache for allconstraints=" << allConstraints << endl ; coutI(Minimization) << "createNLL: caching constraint set under name " - << Form("CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), RooNameSet(*data.get()).content()) + << Form("CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), getColonSeparatedNameString(*data.get()).c_str()) << " with " << allConstraints.getSize() << " entries" << endl; _myws->defineSetInternal( - Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), RooNameSet(*data.get()).content()), allConstraints); + Form("CACHE_CONSTR_OF_PDF_%s_FOR_OBS_%s", GetName(), getColonSeparatedNameString(*data.get()).c_str()), allConstraints); } } diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index 2b49641e9aa3d..87d111738f096 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -701,15 +701,13 @@ RooAbsReal* RooAbsReal::createIntObj(const RooArgSet& iset2, const RooArgSet* ns RooArgSet* intParams = integral->getVariables() ; - RooNameSet cacheParamNames ; - cacheParamNames.setNameList(cacheParamsStr) ; - RooArgSet* cacheParams = cacheParamNames.select(*intParams) ; - - if (cacheParams->getSize()>0) { - cxcoutD(Caching) << "RooAbsReal::createIntObj(" << GetName() << ") INFO: constructing " << cacheParams->getSize() - << "-dim value cache for integral over " << iset2 << " as a function of " << *cacheParams << " in range " << (rangeName?rangeName:"") << endl ; - string name = Form("%s_CACHE_[%s]",integral->GetName(),cacheParams->contentsString().c_str()) ; - RooCachedReal* cachedIntegral = new RooCachedReal(name.c_str(),name.c_str(),*integral,*cacheParams) ; + RooArgSet cacheParams = RooHelpers::selectFromArgSet(*intParams, cacheParamsStr); + + if (cacheParams.getSize()>0) { + cxcoutD(Caching) << "RooAbsReal::createIntObj(" << GetName() << ") INFO: constructing " << cacheParams.getSize() + << "-dim value cache for integral over " << iset2 << " as a function of " << cacheParams << " in range " << (rangeName?rangeName:"") << endl ; + string name = Form("%s_CACHE_[%s]",integral->GetName(),cacheParams.contentsString().c_str()) ; + RooCachedReal* cachedIntegral = new RooCachedReal(name.c_str(),name.c_str(),*integral,cacheParams) ; cachedIntegral->setInterpolationOrder(2) ; cachedIntegral->addOwnedComponents(*integral) ; cachedIntegral->setCacheSource(kTRUE) ; @@ -720,7 +718,6 @@ RooAbsReal* RooAbsReal::createIntObj(const RooArgSet& iset2, const RooArgSet* ns integral = cachedIntegral ; } - delete cacheParams ; delete intParams ; } diff --git a/roofit/roofitcore/src/RooAddModel.cxx b/roofit/roofitcore/src/RooAddModel.cxx index cc72e8e55aa21..40aee617b813d 100644 --- a/roofit/roofitcore/src/RooAddModel.cxx +++ b/roofit/roofitcore/src/RooAddModel.cxx @@ -741,16 +741,12 @@ Double_t RooAddModel::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, // If cache has been sterilized, revive this slot if (cache==0) { - RooArgSet* vars = getParameters(RooArgSet()) ; - RooArgSet* nset = _intCacheMgr.nameSet1ByIndex(code-1)->select(*vars) ; - RooArgSet* iset = _intCacheMgr.nameSet2ByIndex(code-1)->select(*vars) ; + std::unique_ptr vars{getParameters(RooArgSet())} ; + RooArgSet nset = _intCacheMgr.selectFromSet1(*vars, code-1) ; + RooArgSet iset = _intCacheMgr.selectFromSet2(*vars, code-1) ; - Int_t code2(-1) ; - getCompIntList(nset,iset,compIntList,code2,rangeName) ; - - delete vars ; - delete nset ; - delete iset ; + int code2 = -1 ; + getCompIntList(&nset,&iset,compIntList,code2,rangeName) ; } else { compIntList = &cache->_intList ; diff --git a/roofit/roofitcore/src/RooAddition.cxx b/roofit/roofitcore/src/RooAddition.cxx index e90c8f11cdd3f..ed80856cea13f 100644 --- a/roofit/roofitcore/src/RooAddition.cxx +++ b/roofit/roofitcore/src/RooAddition.cxx @@ -303,9 +303,9 @@ Double_t RooAddition::analyticalIntegral(Int_t code, const char* rangeName) cons if (cache==0) { // cache got sterilized, trigger repopulation of this slot, then try again... std::unique_ptr vars( getParameters(RooArgSet()) ); - std::unique_ptr iset( _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ); + RooArgSet iset = _cacheMgr.selectFromSet2(*vars, code-1); RooArgSet dummy; - Int_t code2 = getAnalyticalIntegral(*iset,dummy,rangeName); + Int_t code2 = getAnalyticalIntegral(iset,dummy,rangeName); assert(code==code2); // must have revived the right (sterilized) slot... return analyticalIntegral(code2,rangeName); } diff --git a/roofit/roofitcore/src/RooHelpers.cxx b/roofit/roofitcore/src/RooHelpers.cxx index c348c21962f03..66bcf25af91e6 100644 --- a/roofit/roofitcore/src/RooHelpers.cxx +++ b/roofit/roofitcore/src/RooHelpers.cxx @@ -20,6 +20,7 @@ #include "RooDataHist.h" #include "RooDataSet.h" #include "RooAbsRealLValue.h" +#include "RooArgList.h" #include "TClass.h" @@ -265,4 +266,36 @@ bool checkIfRangesOverlap(RooAbsPdf const& pdf, RooAbsData const& data, std::vec } +/// Create a string with all sorted names of RooArgSet elements separated by colons. +/// \param[in] arg argSet The input RooArgSet. +std::string getColonSeparatedNameString(RooArgSet const& argSet) { + + RooArgList tmp(argSet); + tmp.sort(); + + std::string content; + for(auto const& arg : tmp) { + content += arg->GetName(); + content += ":"; + } + if(!content.empty()) { + content.pop_back(); + } + return content; +} + + +/// Construct a RooArgSet of objects in a RooArgSet whose names match to those +/// in the names string. +/// \param[in] arg argSet The input RooArgSet. +/// \param[in] arg names The names of the objects to select in a colon-separated string. +RooArgSet selectFromArgSet(RooArgSet const& argSet, std::string const& names) { + RooArgSet output; + for(auto const& name : tokenise(names, ":")) { + if(auto arg = argSet.find(name.c_str())) output.add(*arg); + } + return output; +} + + } diff --git a/roofit/roofitcore/src/RooHistFunc.cxx b/roofit/roofitcore/src/RooHistFunc.cxx index d6ac6bbbf677c..ba77be4935f9f 100644 --- a/roofit/roofitcore/src/RooHistFunc.cxx +++ b/roofit/roofitcore/src/RooHistFunc.cxx @@ -35,6 +35,7 @@ discrete dimensions and may have negative values. #include "RooCategory.h" #include "RooWorkspace.h" #include "RooHistPdf.h" +#include "RooHelpers.h" #include "TError.h" @@ -501,7 +502,8 @@ Bool_t RooHistFunc::areIdentical(const RooDataHist& dh1, const RooDataHist& dh2) dh2.get(i) ; if (fabs(dh1.weight()-dh2.weight())>1e-8) return kFALSE ; } - if (!(RooNameSet(*dh1.get())==RooNameSet(*dh2.get()))) return kFALSE ; + using RooHelpers::getColonSeparatedNameString; + if (getColonSeparatedNameString(*dh1.get()) != getColonSeparatedNameString(*dh2.get())) return kFALSE ; return kTRUE ; } diff --git a/roofit/roofitcore/src/RooNormSetCache.cxx b/roofit/roofitcore/src/RooNormSetCache.cxx index 2bfba9e3380a6..d5932765458b3 100644 --- a/roofit/roofitcore/src/RooNormSetCache.cxx +++ b/roofit/roofitcore/src/RooNormSetCache.cxx @@ -35,6 +35,7 @@ during their lifetime. #include "RooNormSetCache.h" #include "RooArgSet.h" +#include "RooHelpers.h" ClassImp(RooNormSetCache); ; @@ -122,7 +123,6 @@ Bool_t RooNormSetCache::autoCache(const RooAbsArg* self, const RooArgSet* set1, } // B - Check if dependents(set1/set2) are compatible with current cache - RooNameSet nset1d, nset2d; // cout << "RooNormSetCache::autoCache set1 = " << (set1?*set1:RooArgSet()) << " set2 = " << (set2?*set2:RooArgSet()) << endl; // if (set1) set1->Print("v"); @@ -140,10 +140,11 @@ Bool_t RooNormSetCache::autoCache(const RooAbsArg* self, const RooArgSet* set1, // cout << "RooNormSetCache::autoCache set1d = " << *set1d << " set2 = " << *set2d << endl; - nset1d.refill(*set1d); - nset2d.refill(*set2d); + using RooHelpers::getColonSeparatedNameString; - if (nset1d == _name1 && nset2d == _name2 && _set2RangeName == set2RangeName) { + if ( getColonSeparatedNameString(*set1d) == _name1 + && getColonSeparatedNameString(*set2d) == _name2 + && _set2RangeName == set2RangeName) { // Compatible - Add current set1/2 to cache add(set1,set2); @@ -156,8 +157,8 @@ Bool_t RooNormSetCache::autoCache(const RooAbsArg* self, const RooArgSet* set1, if (doRefill) { clear(); add(set1,set2); - _name1.refill(*set1d); - _name2.refill(*set2d); + _name1 = getColonSeparatedNameString(*set1d); + _name2 = getColonSeparatedNameString(*set2d); // cout << "RooNormSetCache::autoCache() _name1 refilled from " << *set1d << " to " ; _name1.printValue(cout) ; cout << endl; // cout << "RooNormSetCache::autoCache() _name2 refilled from " << *set2d << " to " ; _name2.printValue(cout) ; cout << endl; _set2RangeName = (TNamed*) set2RangeName; diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index dc719c26921df..48705d5498097 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -1787,21 +1787,15 @@ Double_t RooProdPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, // If cache has been sterilized, revive this slot if (cache==0) { - RooArgSet* vars = getParameters(RooArgSet()) ; - RooArgSet* nset = _cacheMgr.nameSet1ByIndex(code-1)->select(*vars) ; - RooArgSet* iset = _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ; + std::unique_ptr vars{getParameters(RooArgSet())} ; + RooArgSet nset = _cacheMgr.selectFromSet1(*vars, code-1) ; + RooArgSet iset = _cacheMgr.selectFromSet2(*vars, code-1) ; - Int_t code2 = getPartIntList(nset, iset, rangeName) ; - - delete vars ; + Int_t code2 = getPartIntList(&nset, &iset, rangeName) ; // preceding call to getPartIntList guarantees non-null return // coverity[NULL_RETURNS] - cache = (CacheElem*) _cacheMgr.getObj(nset,iset,&code2,rangeName) ; - - delete nset ; - delete iset ; - + cache = (CacheElem*) _cacheMgr.getObj(&nset,&iset,&code2,rangeName) ; } Double_t val = calculate(*cache,kTRUE) ; @@ -2240,13 +2234,12 @@ void RooProdPdf::setCacheAndTrackHints(RooArgSet& trackNodes) RooArgSet* pdf_nset = findPdfNSet((RooAbsPdf&)(*parg)) ; if (pdf_nset) { // Check if conditional normalization is specified + using RooHelpers::getColonSeparatedNameString; if (string("nset")==pdf_nset->GetName() && pdf_nset->getSize()>0) { - RooNameSet n(*pdf_nset) ; - parg->setStringAttribute("CATNormSet",n.content()) ; + parg->setStringAttribute("CATNormSet",getColonSeparatedNameString(*pdf_nset).c_str()) ; } if (string("cset")==pdf_nset->GetName()) { - RooNameSet c(*pdf_nset) ; - parg->setStringAttribute("CATCondSet",c.content()) ; + parg->setStringAttribute("CATCondSet",getColonSeparatedNameString(*pdf_nset).c_str()) ; } } else { coutW(Optimization) << "RooProdPdf::setCacheAndTrackHints(" << GetName() << ") WARNING product pdf does not specify a normalization set for component " << parg->GetName() << endl ; diff --git a/roofit/roofitcore/src/RooProduct.cxx b/roofit/roofitcore/src/RooProduct.cxx index a2d0a3a70ae5e..9190b98a00f26 100644 --- a/roofit/roofitcore/src/RooProduct.cxx +++ b/roofit/roofitcore/src/RooProduct.cxx @@ -309,8 +309,8 @@ Double_t RooProduct::analyticalIntegral(Int_t code, const char* rangeName) const if (cache==0) { // cache got sterilized, trigger repopulation of this slot, then try again... std::unique_ptr vars( getParameters(RooArgSet()) ); - std::unique_ptr iset( _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ); - Int_t code2 = getPartIntList(iset.get(),rangeName)+1; + RooArgSet iset = _cacheMgr.selectFromSet2(*vars, code-1); + Int_t code2 = getPartIntList(&iset,rangeName)+1; assert(code==code2); // must have revived the right (sterilized) slot... return analyticalIntegral(code2,rangeName); } diff --git a/roofit/roofitcore/src/RooProjectedPdf.cxx b/roofit/roofitcore/src/RooProjectedPdf.cxx index 0366e267507b0..bc008b20e6802 100644 --- a/roofit/roofitcore/src/RooProjectedPdf.cxx +++ b/roofit/roofitcore/src/RooProjectedPdf.cxx @@ -187,24 +187,17 @@ Double_t RooProjectedPdf::analyticalIntegralWN(Int_t code, const RooArgSet* /*no CacheElem *cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ; if (cache) { - Double_t ret= cache->_projection->getVal() ; - return ret ; + return cache->_projection->getVal() ; } else { - RooArgSet* vars = getParameters(RooArgSet()) ; + std::unique_ptr vars{getParameters(RooArgSet())} ; vars->add(intobs) ; - RooArgSet* iset = _cacheMgr.nameSet1ByIndex(code-1)->select(*vars) ; - RooArgSet* nset = _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ; + RooArgSet iset = _cacheMgr.selectFromSet1(*vars, code-1) ; + RooArgSet nset = _cacheMgr.selectFromSet2(*vars, code-1) ; - Int_t code2(-1) ; - const RooAbsReal* proj = getProjection(iset,nset,rangeName,code2) ; - - delete vars ; - delete nset ; - delete iset ; - - Double_t ret = proj->getVal() ; - return ret ; + int code2 = -1 ; + + return getProjection(&iset,&nset,rangeName,code2)->getVal() ; } } diff --git a/roofit/roofitcore/src/RooRealSumFunc.cxx b/roofit/roofitcore/src/RooRealSumFunc.cxx index cbff7435b6486..3f78020acd47f 100644 --- a/roofit/roofitcore/src/RooRealSumFunc.cxx +++ b/roofit/roofitcore/src/RooRealSumFunc.cxx @@ -356,10 +356,10 @@ Double_t RooRealSumFunc::analyticalIntegralWN(Int_t code, const RooArgSet *normS // "RooRealSumFunc("<") // << ": reviving cache "<< endl; std::unique_ptr vars(getParameters(RooArgSet())); - std::unique_ptr iset(_normIntMgr.nameSet2ByIndex(code - 1)->select(*vars)); - std::unique_ptr nset(_normIntMgr.nameSet1ByIndex(code - 1)->select(*vars)); + RooArgSet iset = _normIntMgr.selectFromSet2(*vars, code - 1); + RooArgSet nset = _normIntMgr.selectFromSet1(*vars, code - 1); RooArgSet dummy; - Int_t code2 = getAnalyticalIntegralWN(*iset, dummy, nset.get(), rangeName); + Int_t code2 = getAnalyticalIntegralWN(iset, dummy, &nset, rangeName); assert(code == code2); // must have revived the right (sterilized) slot... (void)code2; cache = (CacheElem *)_normIntMgr.getObjByIndex(code - 1); diff --git a/roofit/roofitcore/src/RooRealSumPdf.cxx b/roofit/roofitcore/src/RooRealSumPdf.cxx index 67d3291fbae9b..fde4464ea4e15 100644 --- a/roofit/roofitcore/src/RooRealSumPdf.cxx +++ b/roofit/roofitcore/src/RooRealSumPdf.cxx @@ -369,10 +369,10 @@ Double_t RooRealSumPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSe if (cache==0) { // revive the (sterilized) cache //cout << "RooRealSumPdf("<") << ": reviving cache "<< endl; std::unique_ptr vars( getParameters(RooArgSet()) ); - std::unique_ptr iset( _normIntMgr.nameSet2ByIndex(code-1)->select(*vars) ); - std::unique_ptr nset( _normIntMgr.nameSet1ByIndex(code-1)->select(*vars) ); + RooArgSet iset = _normIntMgr.selectFromSet2(*vars, code-1); + RooArgSet nset = _normIntMgr.selectFromSet1(*vars, code-1); RooArgSet dummy; - Int_t code2 = getAnalyticalIntegralWN(*iset,dummy,nset.get(),rangeName); + Int_t code2 = getAnalyticalIntegralWN(iset,dummy,&nset,rangeName); R__ASSERT(code==code2); // must have revived the right (sterilized) slot... cache = (CacheElem*) _normIntMgr.getObjByIndex(code-1) ; R__ASSERT(cache!=0); diff --git a/roofit/roofitcore/src/RooVectorDataStore.cxx b/roofit/roofitcore/src/RooVectorDataStore.cxx index 01837396f8f3d..0d431c2b1be17 100644 --- a/roofit/roofitcore/src/RooVectorDataStore.cxx +++ b/roofit/roofitcore/src/RooVectorDataStore.cxx @@ -39,7 +39,6 @@ which returns spans pointing directly to the data. #include "RooFormulaVar.h" #include "RooRealVar.h" #include "RooCategory.h" -#include "RooNameSet.h" #include "RooHistError.h" #include "RooTrace.h" #include "RooHelpers.h" @@ -1008,7 +1007,6 @@ void RooVectorDataStore::cacheArgs(const RooAbsArg* owner, RooArgSet& newVarSet, std::vector argObsList ; // Now need to attach branch buffers of clones - RooArgSet *anset(0), *acset(0) ; for (const auto arg : cloneSet) { arg->attachToVStore(*newCache) ; @@ -1019,20 +1017,17 @@ void RooVectorDataStore::cacheArgs(const RooAbsArg* owner, RooArgSet& newVarSet, const char* catNset = arg->getStringAttribute("CATNormSet") ; if (catNset) { // cout << "RooVectorDataStore::cacheArgs() cached node " << arg->GetName() << " has a normalization set specification CATNormSet = " << catNset << endl ; - RooNameSet rns ; - rns.setNameList(catNset) ; - anset = rns.select(nset?*nset:RooArgSet()) ; - normSet = (RooArgSet*) anset->selectCommon(*argObs) ; + + RooArgSet anset = RooHelpers::selectFromArgSet(nset ? *nset : RooArgSet{}, catNset); + normSet = (RooArgSet*) anset.selectCommon(*argObs) ; } const char* catCset = arg->getStringAttribute("CATCondSet") ; if (catCset) { // cout << "RooVectorDataStore::cacheArgs() cached node " << arg->GetName() << " has a conditional observable set specification CATCondSet = " << catCset << endl ; - RooNameSet rns ; - rns.setNameList(catCset) ; - acset = rns.select(nset?*nset:RooArgSet()) ; - - argObs->remove(*acset,kTRUE,kTRUE) ; + + RooArgSet acset = RooHelpers::selectFromArgSet(nset ? *nset : RooArgSet{}, catCset); + argObs->remove(acset,kTRUE,kTRUE) ; normSet = argObs ; } From 60f00b5b6fdd03b26b8957a96366e71c2017bc28 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 3 May 2021 21:46:56 +0200 Subject: [PATCH 016/309] [RF] Add test for RooCacheManager::selectFromSet Add test for `RooCacheManager::selectFromSet1` and `RooCacheManager::selectFromSet2` to validate the recently-introduced replacement of RooNameSet with free helper functions. --- roofit/roofitcore/test/CMakeLists.txt | 1 + .../roofitcore/test/testRooCacheManager.cxx | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 roofit/roofitcore/test/testRooCacheManager.cxx diff --git a/roofit/roofitcore/test/CMakeLists.txt b/roofit/roofitcore/test/CMakeLists.txt index 9c1d8f6c68fe5..7b55450808091 100644 --- a/roofit/roofitcore/test/CMakeLists.txt +++ b/roofit/roofitcore/test/CMakeLists.txt @@ -7,6 +7,7 @@ # @author Danilo Piparo CERN, 2018 ROOT_ADD_GTEST(simple simple.cxx LIBRARIES RooFitCore) +ROOT_ADD_GTEST(testRooCacheManager testRooCacheManager.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testWorkspace testWorkspace.cxx LIBRARIES RooFitCore RooFit RooStats) if(NOT MSVC OR win_broken_tests) ROOT_ADD_GTEST(testRooDataHist testRooDataHist.cxx LIBRARIES RooFitCore diff --git a/roofit/roofitcore/test/testRooCacheManager.cxx b/roofit/roofitcore/test/testRooCacheManager.cxx new file mode 100644 index 0000000000000..464d109c6bb6d --- /dev/null +++ b/roofit/roofitcore/test/testRooCacheManager.cxx @@ -0,0 +1,62 @@ +// Tests for the RooCacheManager +// Author: Jonas Rembser, CERN, May 2021 + +#include "RooObjCacheManager.h" +#include "RooRealVar.h" + +#include "gtest/gtest.h" + +#include +#include + +TEST(RooCacheManager, TestSelectFromArgSet) +{ + // Test RooCacheManager::selectFromSet1 and RooCacheManager::selectFromSet2. + + // the cached class doesn't matter for this test, it just has to be an object that the cache is going to own + class CacheElem : public RooAbsCacheElement { + public: + virtual ~CacheElem() {} + virtual RooArgList containedArgs(Action) { return {}; } + }; + + // RooObjCacheManager is a wrapper around RooCacheManager + RooObjCacheManager mgr{nullptr, 100}; + + // fill some vector with RooAbsReals for testing + std::vector vars; + for (int i = 0; i < 10; ++i) { + auto name = std::string("v") + std::to_string(i); + vars.emplace_back(name.c_str(), name.c_str(), static_cast(i)); + } + + RooArgSet nset1{vars[0], vars[1], "nset1"}; + RooArgSet iset1{vars[2], vars[3], vars[4], "nset2"}; + + RooArgSet nset2{vars[5], vars[6], vars[7], "nset1"}; + RooArgSet iset2{vars[8], vars[9], "nset2"}; + + int idx1 = mgr.setObj(&nset1, &iset1, new CacheElem); + int idx2 = mgr.setObj(&nset2, &iset2, new CacheElem); + + std::cout << idx1 << std::endl; + std::cout << idx2 << std::endl; + + auto sel11 = mgr.selectFromSet1({vars[0], vars[4]}, idx1); + auto sel12 = mgr.selectFromSet2({vars[2], vars[4]}, idx1); + + auto sel21 = mgr.selectFromSet1({vars[1], vars[6]}, idx2); + auto sel22 = mgr.selectFromSet2({vars[0], vars[1]}, idx2); + + // check if the expected number of args were selected + EXPECT_EQ(sel11.size(), 1); + EXPECT_EQ(sel12.size(), 2); + EXPECT_EQ(sel21.size(), 1); + EXPECT_EQ(sel22.size(), 0); + + // check if the correct args were selected + EXPECT_TRUE(sel11.containsInstance(vars[0])); + EXPECT_TRUE(sel12.containsInstance(vars[2])); + EXPECT_TRUE(sel12.containsInstance(vars[4])); + EXPECT_TRUE(sel21.containsInstance(vars[6])); +} From 1f30b84e6d1cad1434a46210f3df896fc6e7e8e1 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 26 May 2021 15:55:32 +0200 Subject: [PATCH 017/309] [RF] Move deprecated RooNameSet class to RooFitLegacy The `RooNameSet` was nothing more than a string with the names of all elements in a RooArgSet separated by colons. It is not necessary to have a class for that. For now, the `RooNameSet` is moved to RooFitLegacy with the intention of completeley removing it for ROOT 6.28. --- roofit/roofitcore/CMakeLists.txt | 4 ++-- roofit/roofitcore/inc/{ => RooFitLegacy}/RooNameSet.h | 4 +++- roofit/roofitcore/src/{ => RooFitLegacy}/RooNameSet.cxx | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) rename roofit/roofitcore/inc/{ => RooFitLegacy}/RooNameSet.h (94%) rename roofit/roofitcore/src/{ => RooFitLegacy}/RooNameSet.cxx (99%) diff --git a/roofit/roofitcore/CMakeLists.txt b/roofit/roofitcore/CMakeLists.txt index afe21fe236a6f..edc333038182f 100644 --- a/roofit/roofitcore/CMakeLists.txt +++ b/roofit/roofitcore/CMakeLists.txt @@ -146,7 +146,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooMultiGenFunction.h RooMultiVarGaussian.h RooNameReg.h - RooNameSet.h RooNLLVar.h RooNormSetCache.h RooNumber.h @@ -229,6 +228,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooBinSamplingPdf.h RooFitLegacy/RooCatTypeLegacy.h RooFitLegacy/RooCategorySharedProperties.h + RooFitLegacy/RooNameSet.h RooFitLegacy/RooTreeData.h SOURCES src/BidirMMapPipe.cxx @@ -363,7 +363,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore src/RooMultiGenFunction.cxx src/RooMultiVarGaussian.cxx src/RooNameReg.cxx - src/RooNameSet.cxx src/RooNLLVar.cxx src/RooNormSetCache.cxx src/RooNumber.cxx @@ -443,6 +442,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore src/RooFitLegacy/RooCatTypeLegacy.cxx src/RooFitLegacy/RooCategorySharedProperties.cxx src/RooFitLegacy/RooMultiCatIter.cxx + src/RooFitLegacy/RooNameSet.cxx DICTIONARY_OPTIONS "-writeEmptyRootPCM" LIBRARIES diff --git a/roofit/roofitcore/inc/RooNameSet.h b/roofit/roofitcore/inc/RooFitLegacy/RooNameSet.h similarity index 94% rename from roofit/roofitcore/inc/RooNameSet.h rename to roofit/roofitcore/inc/RooFitLegacy/RooNameSet.h index dcfe6923163e8..cf4056c25c6d3 100644 --- a/roofit/roofitcore/inc/RooNameSet.h +++ b/roofit/roofitcore/inc/RooFitLegacy/RooNameSet.h @@ -19,6 +19,8 @@ #include "TObject.h" #include "RooPrintable.h" +#include + class RooArgSet; class RooNameSet : public TObject, public RooPrintable { @@ -59,6 +61,6 @@ class RooNameSet : public TObject, public RooPrintable { static void strdup(Int_t& dstlen, char* &dstbuf, const char* str); ClassDef(RooNameSet,1) // A sterile version of RooArgSet, containing only the names of the contained RooAbsArgs -}; +} R__SUGGEST_ALTERNATIVE("Please use RooHelpers::getColonSeparatedNameString() and RooHelpers::selectFromArgSet()."); #endif diff --git a/roofit/roofitcore/src/RooNameSet.cxx b/roofit/roofitcore/src/RooFitLegacy/RooNameSet.cxx similarity index 99% rename from roofit/roofitcore/src/RooNameSet.cxx rename to roofit/roofitcore/src/RooFitLegacy/RooNameSet.cxx index d010d1066809c..1bc7a260cd3c7 100644 --- a/roofit/roofitcore/src/RooNameSet.cxx +++ b/roofit/roofitcore/src/RooFitLegacy/RooNameSet.cxx @@ -17,7 +17,7 @@ /** \file RooNameSet.cxx \class RooNameSet -\ingroup Roofitcore +\ingroup Roofitlegacy RooNameSet is a utility class that stores the names the objects in a RooArget. This allows to preserve the contents of a RooArgSet @@ -26,16 +26,17 @@ the RooArgSet. A new RooArgSet can be created from a RooNameSet by offering it a list of new RooAbsArg objects. **/ -#include +#include "RooFitLegacy/RooNameSet.h" #include "RooFit.h" #include "Riostream.h" #include "TClass.h" -#include "RooNameSet.h" #include "RooArgSet.h" #include "RooArgList.h" +#include + ClassImp(RooNameSet); //////////////////////////////////////////////////////////////////////////////// From 0af8f7a923747a087e7a0c1ff5b5e4899c8d7d6f Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 31 May 2021 20:23:12 +0200 Subject: [PATCH 018/309] [RF] Take ownership of more temporary RooArgSets in RooGlobalFunc Implement taking ownership of temporary RooArgSets for remaining RooCmdArg creation functions in RooGlobalFunc. This is a followup on d8193ca, where it was forgotten to use the ownership mechanism in ProjectedObservables and ConditionalObservables. --- roofit/roofitcore/inc/RooGlobalFunc.h | 2 ++ roofit/roofitcore/src/RooGlobalFunc.cxx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/roofit/roofitcore/inc/RooGlobalFunc.h b/roofit/roofitcore/inc/RooGlobalFunc.h index 9f1f15add4460..3e46cf9600e18 100644 --- a/roofit/roofitcore/inc/RooGlobalFunc.h +++ b/roofit/roofitcore/inc/RooGlobalFunc.h @@ -207,7 +207,9 @@ RooCmdArg PrefitDataFraction(Double_t data_ratio = 0.0) ; RooCmdArg FitOptions(const char* opts) ; RooCmdArg Optimize(Int_t flag=2) ; RooCmdArg ProjectedObservables(const RooArgSet& set) ; // obsolete, for backward compatibility +RooCmdArg ProjectedObservables(RooArgSet && set) ; // obsolete, for backward compatibility RooCmdArg ConditionalObservables(const RooArgSet& set) ; +RooCmdArg ConditionalObservables(RooArgSet && set) ; RooCmdArg Verbose(Bool_t flag=kTRUE) ; RooCmdArg Save(Bool_t flag=kTRUE) ; RooCmdArg Timer(Bool_t flag=kTRUE) ; diff --git a/roofit/roofitcore/src/RooGlobalFunc.cxx b/roofit/roofitcore/src/RooGlobalFunc.cxx index 22ff1a0c459c3..fe33129c46ece 100644 --- a/roofit/roofitcore/src/RooGlobalFunc.cxx +++ b/roofit/roofitcore/src/RooGlobalFunc.cxx @@ -210,7 +210,9 @@ namespace RooFit { RooCmdArg Minos(const RooArgSet& minosArgs) { return RooCmdArg("Minos",kTRUE,0,0,0,0,0,&minosArgs,0) ; } RooCmdArg Minos(RooArgSet && minosArgs) { return Minos(RooCmdArg::take(std::move(minosArgs))); } RooCmdArg ConditionalObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,0,0,0,0,&set) ; } + RooCmdArg ConditionalObservables(RooArgSet && set) { return ConditionalObservables(RooCmdArg::take(std::move(set))) ; } RooCmdArg ProjectedObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,0,0,0,0,&set) ; } + RooCmdArg ProjectedObservables(RooArgSet && set) { return ProjectedObservables(RooCmdArg::take(std::move(set))) ; } RooCmdArg SplitRange(Bool_t flag) { return RooCmdArg("SplitRange",flag,0,0,0,0,0,0,0) ; } RooCmdArg SumCoefRange(const char* rangeName) { return RooCmdArg("SumCoefRange",0,0,0,0,rangeName,0,0,0) ; } RooCmdArg Constrain(const RooArgSet& params) { return RooCmdArg("Constrain",0,0,0,0,0,0,0,0,0,0,¶ms) ; } From 748f0d928d2ccdf16e200d53b16b7d8564b495b3 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 31 May 2021 20:49:34 +0200 Subject: [PATCH 019/309] [RF] Make Conditional/ProjectedObservables store RooArgSet as object This is to make the RooArgSet payload accessible via RooCmdConfig::decodeObjOnTheFly, which is used in one of the RooNLLVar constructors. This fixes Jira issue ROOT-6895. --- roofit/roofitcore/src/RooAbsPdf.cxx | 4 ++-- roofit/roofitcore/src/RooAbsReal.cxx | 4 ++-- roofit/roofitcore/src/RooGlobalFunc.cxx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/roofit/roofitcore/src/RooAbsPdf.cxx b/roofit/roofitcore/src/RooAbsPdf.cxx index c64f858566eb8..9b67ce5ca5db6 100644 --- a/roofit/roofitcore/src/RooAbsPdf.cxx +++ b/roofit/roofitcore/src/RooAbsPdf.cxx @@ -990,7 +990,7 @@ RooAbsReal* RooAbsPdf::createNLL(RooAbsData& data, const RooLinkedList& cmdList) pc.defineInt("verbose","Verbose",0,0) ; pc.defineInt("optConst","Optimize",0,0) ; pc.defineInt("cloneData","CloneData", 0, 2); - pc.defineSet("projDepSet","ProjectedObservables",0,0) ; + pc.defineObject("projDepSet","ProjectedObservables",0,0) ; pc.defineSet("cPars","Constrain",0,0) ; pc.defineSet("glObs","GlobalObservables",0,0) ; // pc.defineInt("constrAll","Constrained",0,0) ; @@ -1096,7 +1096,7 @@ RooAbsReal* RooAbsPdf::createNLL(RooAbsData& data, const RooLinkedList& cmdList) } RooArgSet projDeps ; - RooArgSet* tmp = pc.getSet("projDepSet") ; + auto tmp = static_cast(pc.getObject("projDepSet")) ; if (tmp) { projDeps.add(*tmp) ; } diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index 87d111738f096..04325e4ec51f9 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -1369,7 +1369,7 @@ TH1* RooAbsReal::createHistogram(const char *name, const RooAbsRealLValue& xvar, pc.defineObject("compSet","SelectCompSet",0) ; pc.defineString("compSpec","SelectCompSpec",0) ; - pc.defineSet("projObs","ProjectedObservables",0,0) ; + pc.defineObject("projObs","ProjectedObservables",0,0) ; pc.defineObject("yvar","YVar",0,0) ; pc.defineObject("zvar","ZVar",0,0) ; pc.defineMutex("SelectCompSet","SelectCompSpec") ; @@ -1394,7 +1394,7 @@ TH1* RooAbsReal::createHistogram(const char *name, const RooAbsRealLValue& xvar, vars.add(*zvar) ; } - RooArgSet* projObs = pc.getSet("projObs") ; + auto projObs = static_cast(pc.getObject("projObs")) ; RooArgSet* intObs = 0 ; Bool_t doScaling = pc.getInt("scaling") ; diff --git a/roofit/roofitcore/src/RooGlobalFunc.cxx b/roofit/roofitcore/src/RooGlobalFunc.cxx index fe33129c46ece..b2a24952932b9 100644 --- a/roofit/roofitcore/src/RooGlobalFunc.cxx +++ b/roofit/roofitcore/src/RooGlobalFunc.cxx @@ -209,9 +209,9 @@ namespace RooFit { RooCmdArg Minos(Bool_t flag) { return RooCmdArg("Minos",flag,0,0,0,0,0,0,0) ; } RooCmdArg Minos(const RooArgSet& minosArgs) { return RooCmdArg("Minos",kTRUE,0,0,0,0,0,&minosArgs,0) ; } RooCmdArg Minos(RooArgSet && minosArgs) { return Minos(RooCmdArg::take(std::move(minosArgs))); } - RooCmdArg ConditionalObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,0,0,0,0,&set) ; } + RooCmdArg ConditionalObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,&set) ; } RooCmdArg ConditionalObservables(RooArgSet && set) { return ConditionalObservables(RooCmdArg::take(std::move(set))) ; } - RooCmdArg ProjectedObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,0,0,0,0,&set) ; } + RooCmdArg ProjectedObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,&set) ; } RooCmdArg ProjectedObservables(RooArgSet && set) { return ProjectedObservables(RooCmdArg::take(std::move(set))) ; } RooCmdArg SplitRange(Bool_t flag) { return RooCmdArg("SplitRange",flag,0,0,0,0,0,0,0) ; } RooCmdArg SumCoefRange(const char* rangeName) { return RooCmdArg("SumCoefRange",0,0,0,0,rangeName,0,0,0) ; } From 6dc3c47ca97f8d0b3ab9266ae47cf4193b70292c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 17 May 2021 17:29:28 +0200 Subject: [PATCH 020/309] [json] provide workaround for TStyle::fLineStyle member it has similar name as field in TAttLine and produces duplicated members in JSON. This makes impossible to correctly read it back --- io/io/src/TBufferJSON.cxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/io/io/src/TBufferJSON.cxx b/io/io/src/TBufferJSON.cxx index 755afd86e0a9b..7be95121f9f53 100644 --- a/io/io/src/TBufferJSON.cxx +++ b/io/io/src/TBufferJSON.cxx @@ -1218,8 +1218,14 @@ void TBufferJSON::JsonStartElement(const TStreamerElement *elem, const TClass *b switch (special_kind) { case 0: - if (!base_class) - elem_name = elem->GetName(); + if (base_class) return; + elem_name = elem->GetName(); + if (strcmp(elem_name,"fLineStyle") == 0) + if ((strcmp(elem->GetTypeName(),"TString") == 0) && (strcmp(elem->GetFullName(),"fLineStyle[30]") == 0)) { + auto st1 = fStack.at(fStack.size() - 2).get(); + if (st1->IsStreamerInfo() && st1->fInfo && (strcmp(st1->fInfo->GetName(),"TStyle") == 0)) + elem_name = "fLineStyles"; + } break; case TClassEdit::kVector: elem_name = "fVector"; break; case TClassEdit::kList: elem_name = "fList"; break; From 1bf816c88398abe273eaa8d02e79d164e423e1a7 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 26 May 2021 20:12:40 +0200 Subject: [PATCH 021/309] [RF] Deprecate RooHashTable The `RooHashTable` can easily be replaced by a `std::unordered_map`, which is also a hash table. It is not necessary to have a hash table implementation in RooFit. For now, the `RooHashTable` is moved to RooFitLegacy with the intention of completeley removing it for ROOT 6.28. --- roofit/roofitcore/CMakeLists.txt | 4 ++-- roofit/roofitcore/inc/{ => RooFitLegacy}/RooHashTable.h | 7 +++---- roofit/roofitcore/src/{ => RooFitLegacy}/RooHashTable.cxx | 3 ++- roofit/roofitcore/src/RooLinkedList.cxx | 1 - 4 files changed, 7 insertions(+), 8 deletions(-) rename roofit/roofitcore/inc/{ => RooFitLegacy}/RooHashTable.h (96%) rename roofit/roofitcore/src/{ => RooFitLegacy}/RooHashTable.cxx (99%) diff --git a/roofit/roofitcore/CMakeLists.txt b/roofit/roofitcore/CMakeLists.txt index edc333038182f..864e12bcf2853 100644 --- a/roofit/roofitcore/CMakeLists.txt +++ b/roofit/roofitcore/CMakeLists.txt @@ -113,7 +113,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooGenProdProj.h RooGlobalFunc.h RooGrid.h - RooHashTable.h RooHistError.h RooHistFunc.h RooHist.h @@ -228,6 +227,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooBinSamplingPdf.h RooFitLegacy/RooCatTypeLegacy.h RooFitLegacy/RooCategorySharedProperties.h + RooFitLegacy/RooHashTable.h RooFitLegacy/RooNameSet.h RooFitLegacy/RooTreeData.h SOURCES @@ -331,7 +331,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore src/RooGenProdProj.cxx src/RooGlobalFunc.cxx src/RooGrid.cxx - src/RooHashTable.cxx src/RooHist.cxx src/RooHistError.cxx src/RooHistFunc.cxx @@ -441,6 +440,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore src/RooBinSamplingPdf.cxx src/RooFitLegacy/RooCatTypeLegacy.cxx src/RooFitLegacy/RooCategorySharedProperties.cxx + src/RooFitLegacy/RooHashTable.cxx src/RooFitLegacy/RooMultiCatIter.cxx src/RooFitLegacy/RooNameSet.cxx DICTIONARY_OPTIONS diff --git a/roofit/roofitcore/inc/RooHashTable.h b/roofit/roofitcore/inc/RooFitLegacy/RooHashTable.h similarity index 96% rename from roofit/roofitcore/inc/RooHashTable.h rename to roofit/roofitcore/inc/RooFitLegacy/RooHashTable.h index 4b1e1f75818fc..0dfa9409327d3 100644 --- a/roofit/roofitcore/inc/RooHashTable.h +++ b/roofit/roofitcore/inc/RooFitLegacy/RooHashTable.h @@ -19,6 +19,8 @@ #include "TObject.h" #include "TString.h" +#include + class RooAbsArg ; class RooLinkedList ; class RooLinkedListElem ; @@ -67,9 +69,6 @@ class RooHashTable : public TObject { RooLinkedList** _arr ; //! Array of linked lists storing elements in each slot ClassDef(RooHashTable,1) // Hash table -}; - - - +} R__SUGGEST_ALTERNATIVE("Please use std::unordered_map, which is also a hash table."); #endif diff --git a/roofit/roofitcore/src/RooHashTable.cxx b/roofit/roofitcore/src/RooFitLegacy/RooHashTable.cxx similarity index 99% rename from roofit/roofitcore/src/RooHashTable.cxx rename to roofit/roofitcore/src/RooFitLegacy/RooHashTable.cxx index effd87a6a8a9f..41f828dac7b16 100644 --- a/roofit/roofitcore/src/RooHashTable.cxx +++ b/roofit/roofitcore/src/RooFitLegacy/RooHashTable.cxx @@ -14,11 +14,12 @@ * listed in LICENSE (http://roofit.sourceforge.net/license.txt) * *****************************************************************************/ +#include "RooFitLegacy/RooHashTable.h" + #include "RooFit.h" #include "TMath.h" #include "TCollection.h" -#include "RooHashTable.h" #include "RooLinkedList.h" #include "RooAbsArg.h" #include "RooSetPair.h" diff --git a/roofit/roofitcore/src/RooLinkedList.cxx b/roofit/roofitcore/src/RooLinkedList.cxx index 703ac820ab23e..d00ac3fef9c30 100644 --- a/roofit/roofitcore/src/RooLinkedList.cxx +++ b/roofit/roofitcore/src/RooLinkedList.cxx @@ -31,7 +31,6 @@ Use RooAbsCollection derived objects for public use #include "RooFit.h" #include "RooLinkedListIter.h" -#include "RooHashTable.h" #include "RooAbsArg.h" #include "RooMsgService.h" From 9b66fdbe137f26929899fdd3b2e9ec6bad14f1e4 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Wed, 2 Jun 2021 08:05:16 +0200 Subject: [PATCH 022/309] [skip-ci] RBrowser doc (#8313) --- core/gui/src/TBrowser.cxx | 9 +++++++++ documentation/doxygen/images/v7_rbrowser.png | Bin 0 -> 122602 bytes gui/browserv7/src/RBrowser.cxx | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 documentation/doxygen/images/v7_rbrowser.png diff --git a/core/gui/src/TBrowser.cxx b/core/gui/src/TBrowser.cxx index 11ca682f4f6fc..9a1d4af5d9c39 100644 --- a/core/gui/src/TBrowser.cxx +++ b/core/gui/src/TBrowser.cxx @@ -20,6 +20,15 @@ will place all browsable objects in a new list and draws the contents of the selected class in the icon-box. And so on.... \image html base_browser.png + +\since **ROOT version 6.24/00** + +TBrowser invokes by default the Web-based %ROOT file browser RBrowser +To change this behaviour, and invoke the standard TBrowser, one should put +the following directive in the `.rootrc` file: +``` +Browser.Name: TRootBrowser +``` */ #include "TBrowser.h" diff --git a/documentation/doxygen/images/v7_rbrowser.png b/documentation/doxygen/images/v7_rbrowser.png new file mode 100644 index 0000000000000000000000000000000000000000..93c81d8612d049f35d64d062d03e3f099109392b GIT binary patch literal 122602 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

XuCCEg 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 JYWvYk{|kg?ZLR Date: Mon, 31 May 2021 18:59:23 +0200 Subject: [PATCH 023/309] fix memleak see https://github.com/root-project/root/issues/8297 --- core/thread/src/TThread.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/thread/src/TThread.cxx b/core/thread/src/TThread.cxx index b8c7d090c2732..42e7c1d3cd012 100644 --- a/core/thread/src/TThread.cxx +++ b/core/thread/src/TThread.cxx @@ -947,7 +947,10 @@ void TThread::Printf(const char *va_(fmt), ...) void *arr[2]; arr[1] = (void*) buf; - if (XARequest("PRTF", 2, arr, 0)) return; + if (XARequest("PRTF", 2, arr, 0)) { + delete [] buf; + return; + } printf("%s\n", buf); fflush(stdout); From b3ba1960fbc65d5627bb9be3d3585b246746c47c Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Tue, 1 Jun 2021 17:32:37 +0200 Subject: [PATCH 024/309] Resolve issue #8127 TGCommandLinePlugin autocomplete when single entry --- gui/gui/src/TGCommandPlugin.cxx | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/gui/gui/src/TGCommandPlugin.cxx b/gui/gui/src/TGCommandPlugin.cxx index 7f61a25c82242..34f054ebaf1d1 100644 --- a/gui/gui/src/TGCommandPlugin.cxx +++ b/gui/gui/src/TGCommandPlugin.cxx @@ -228,20 +228,33 @@ void TGCommandPlugin::HandleCommand() void TGCommandPlugin::HandleTab() { - std::string prompt = gInterpreter->GetPrompt(); std::string line = fCommandBuf->GetString(); - if (prompt.find("root") == std::string::npos) - prompt = "root []"; - prompt += " "; - prompt += line; - fStatus->AddLine(prompt.c_str()); - fStatus->ShowBottom(); std::vector result; size_t cur = line.length(); gInterpreter->CodeComplete(line, cur, result); - for (auto& res : result) { - fStatus->AddLine(res.c_str()); + if (result.size() == 1) { + // when there is only one result, complete the command line input + std::string found = result[0]; + std::string what = line; + size_t colon = line.find_last_of("::"); + if (colon != std::string::npos) + what = line.substr(colon+2); + size_t pos = found.find(what) + what.length(); + std::string suffix = found.substr(pos); + fCommand->AppendText(suffix.c_str()); + } else { + // otherwise print all results + std::string prompt = gInterpreter->GetPrompt(); + if (prompt.find("root") == std::string::npos) + prompt = "root []"; + prompt += " "; + prompt += line; + fStatus->AddLine(prompt.c_str()); fStatus->ShowBottom(); + for (auto& res : result) { + fStatus->AddLine(res.c_str()); + fStatus->ShowBottom(); + } } } From a26d3a0a12bebe1b3aa1c4bba17016466b198673 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 10:14:34 +0200 Subject: [PATCH 025/309] Fix gcc11 warning in TF2 - use of uninitialized variable --- hist/hist/src/TF2.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TF2.cxx b/hist/hist/src/TF2.cxx index b5108c4dfff33..aabe092909e5e 100644 --- a/hist/hist/src/TF2.cxx +++ b/hist/hist/src/TF2.cxx @@ -371,7 +371,7 @@ Double_t TF2::FindMinMax(Double_t *x, Bool_t findmax) const else { xxmin = x[0]; yymin = x[1]; - zzmin = function(xx); + zzmin = function(x); } xx[0] = xxmin; xx[1] = yymin; From bf4ccaeb55978eb291888d66310873eecd479e51 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 10:18:57 +0200 Subject: [PATCH 026/309] Fix gcc11 warning in TF3::FindMinMax - use of uninitialized variable --- hist/hist/src/TF3.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TF3.cxx b/hist/hist/src/TF3.cxx index 3ab98b1e4652c..d496fa82920fc 100644 --- a/hist/hist/src/TF3.cxx +++ b/hist/hist/src/TF3.cxx @@ -246,7 +246,7 @@ Double_t TF3::FindMinMax(Double_t *x, Bool_t findmax) const xxmin = x[0]; yymin = x[1]; zzmin = x[2]; - zzmin = function(xx); + zzmin = function(x); } xx[0] = xxmin; xx[1] = yymin; From a1b2f7e4b74aa7520c0702b178d17ffe00090308 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 11:02:06 +0200 Subject: [PATCH 027/309] Use nullptr in SafeDelete macro --- core/foundation/inc/ROOT/RConfig.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/foundation/inc/ROOT/RConfig.hxx b/core/foundation/inc/ROOT/RConfig.hxx index 3ae236eba00ed..484eea701ffb5 100644 --- a/core/foundation/inc/ROOT/RConfig.hxx +++ b/core/foundation/inc/ROOT/RConfig.hxx @@ -531,9 +531,9 @@ /*---- misc ------------------------------------------------------------------*/ #ifdef R__GNU -# define SafeDelete(p) { if (p) { delete p; p = 0; } } +# define SafeDelete(p) { if (p) { delete p; p = nullptr; } } #else -# define SafeDelete(p) { delete p; p = 0; } +# define SafeDelete(p) { delete p; p = nullptr; } #endif #ifdef __FAST_MATH__ From f13215bad77eb59177e726a91166bcf9a2d52bf1 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 11:02:59 +0200 Subject: [PATCH 028/309] Fix gcc11 warning in TGeoManager destructor --- geom/geom/src/TGeoManager.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geom/geom/src/TGeoManager.cxx b/geom/geom/src/TGeoManager.cxx index 17318c6edf93f..d4e617e673404 100644 --- a/geom/geom/src/TGeoManager.cxx +++ b/geom/geom/src/TGeoManager.cxx @@ -518,8 +518,8 @@ TGeoManager::~TGeoManager() if (fMaterials) {fMaterials->Delete(); SafeDelete(fMaterials);} SafeDelete(fElementTable); if (fMedia) {fMedia->Delete(); SafeDelete(fMedia);} - if (fHashVolumes) fHashVolumes->Clear("nodelete"); SafeDelete(fHashVolumes); - if (fHashGVolumes) fHashGVolumes->Clear("nodelete"); SafeDelete(fHashGVolumes); + if (fHashVolumes) { fHashVolumes->Clear("nodelete"); SafeDelete(fHashVolumes); } + if (fHashGVolumes) { fHashGVolumes->Clear("nodelete"); SafeDelete(fHashGVolumes); } if (fHashPNE) {fHashPNE->Delete(); SafeDelete(fHashPNE);} if (fArrayPNE) {delete fArrayPNE;} if (fVolumes) {fVolumes->Delete(); SafeDelete(fVolumes);} From a5d6869cc2125d362b8b28d0498f8f8054351243 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 11:29:35 +0200 Subject: [PATCH 029/309] Fix bug in TText::Copy fWcsTitle was copied wrongly --- graf2d/graf/src/TText.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graf2d/graf/src/TText.cxx b/graf2d/graf/src/TText.cxx index a7c73eff1afc1..5a3d264bbc0bf 100644 --- a/graf2d/graf/src/TText.cxx +++ b/graf2d/graf/src/TText.cxx @@ -112,9 +112,9 @@ void TText::Copy(TObject &obj) const TAttText::Copy(((TText&)obj)); if (((TText&)obj).fWcsTitle != NULL) { if (fWcsTitle != NULL) { - *reinterpret_cast(&((TText&)obj).fWcsTitle) = *reinterpret_cast(&fWcsTitle); + *reinterpret_cast(((TText&)obj).fWcsTitle) = *reinterpret_cast(fWcsTitle); } else { - delete reinterpret_cast(&((TText&)obj).fWcsTitle); + delete reinterpret_cast(((TText&)obj).fWcsTitle); ((TText&)obj).fWcsTitle = NULL; } } else { From 5b6f465ca3bb34ba08d3848eb0631d8e4199beab Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 11:31:57 +0200 Subject: [PATCH 030/309] Do not use NULL in TText --- graf2d/graf/src/TText.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/graf2d/graf/src/TText.cxx b/graf2d/graf/src/TText.cxx index 5a3d264bbc0bf..8fdf60386424b 100644 --- a/graf2d/graf/src/TText.cxx +++ b/graf2d/graf/src/TText.cxx @@ -110,15 +110,15 @@ void TText::Copy(TObject &obj) const ((TText&)obj).fY = fY; TNamed::Copy(obj); TAttText::Copy(((TText&)obj)); - if (((TText&)obj).fWcsTitle != NULL) { - if (fWcsTitle != NULL) { + if (((TText&)obj).fWcsTitle) { + if (fWcsTitle) { *reinterpret_cast(((TText&)obj).fWcsTitle) = *reinterpret_cast(fWcsTitle); } else { delete reinterpret_cast(((TText&)obj).fWcsTitle); - ((TText&)obj).fWcsTitle = NULL; + ((TText&)obj).fWcsTitle = nullptr; } } else { - if (fWcsTitle != NULL) { + if (fWcsTitle) { ((TText&)(obj)).fWcsTitle = new std::wstring(*reinterpret_cast(fWcsTitle)); } } @@ -129,10 +129,10 @@ void TText::Copy(TObject &obj) const const void *TText::GetWcsTitle(void) const { - if (fWcsTitle != NULL) { + if (fWcsTitle) { return reinterpret_cast(fWcsTitle)->c_str(); } else { - return NULL; + return nullptr; } } From d9912e1f532c996928fc2c8913c11f2f9c67d1ac Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Tue, 1 Jun 2021 16:45:44 +0200 Subject: [PATCH 031/309] [foundation] Protect against undefined _MSVC_LANG (issue #8267). --- core/foundation/inc/ROOT/RStringView.hxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/foundation/inc/ROOT/RStringView.hxx b/core/foundation/inc/ROOT/RStringView.hxx index cedd44d6635c0..63d998d1e1805 100644 --- a/core/foundation/inc/ROOT/RStringView.hxx +++ b/core/foundation/inc/ROOT/RStringView.hxx @@ -14,7 +14,13 @@ #include "RConfigure.h" -#if defined(R__HAS_STD_STRING_VIEW) || _MSVC_LANG >= 201703L || __cplusplus >= 201703L +#if defined(_MSVC_LANG) +# define R__MSVC_LANG _MSVC_LANG +#else +# define R__MSVC_LANG 0 +#endif + +#if defined(R__HAS_STD_STRING_VIEW) || R__MSVC_LANG >= 201703L || __cplusplus >= 201703L #include @@ -55,7 +61,7 @@ namespace std { #endif // ifdef else R__HAS_STD_STRING_VIEW -#if !(defined(R__HAS_OP_EQUAL_PLUS_STRING_VIEW) || _MSVC_LANG >= 201703L || __cplusplus >= 201703L) +#if !(defined(R__HAS_OP_EQUAL_PLUS_STRING_VIEW) || R__MSVC_LANG >= 201703L || __cplusplus >= 201703L) #include From 80d4d91065d4b03451b7c86c63e4f68f9625cbb3 Mon Sep 17 00:00:00 2001 From: Max Orok Date: Mon, 31 May 2021 08:41:56 -0400 Subject: [PATCH 032/309] [ntuple] Check TKey class name is RNTuple Fixes issue where TKeys with the same name as the requested RNTuple would be attempted to be parsed as an RNTuple, leading to internal parser assert failures later on. --- tree/ntuple/v7/src/RMiniFile.cxx | 5 ++++ tree/ntuple/v7/test/ntuple_minifile.cxx | 34 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/tree/ntuple/v7/src/RMiniFile.cxx b/tree/ntuple/v7/src/RMiniFile.cxx index 1d2179a93f5bc..6a5d0f831572b 100644 --- a/tree/ntuple/v7/src/RMiniFile.cxx +++ b/tree/ntuple/v7/src/RMiniFile.cxx @@ -961,6 +961,11 @@ ROOT::Experimental::Internal::RMiniFileReader::GetNTupleProper(std::string_view offset += key.GetHeaderSize(); ReadBuffer(&name, 1, offset); + ReadBuffer(&name, name.GetSize(), offset); + if (std::string_view(name.fData, name.fLName) != kNTupleClassName) { + offset = offsetNextKey; + continue; + } offset += name.GetSize(); ReadBuffer(&name, 1, offset); ReadBuffer(&name, name.GetSize(), offset); diff --git a/tree/ntuple/v7/test/ntuple_minifile.cxx b/tree/ntuple/v7/test/ntuple_minifile.cxx index 1b33bb5f693f4..08007ec3f9e72 100644 --- a/tree/ntuple/v7/test/ntuple_minifile.cxx +++ b/tree/ntuple/v7/test/ntuple_minifile.cxx @@ -173,6 +173,40 @@ TEST(MiniFile, Failures) } } +TEST(MiniFile, KeyClassName) +{ + FileRaii fileGuard("test_ntuple_minifile_key_class_name.root"); + auto file = std::make_unique(fileGuard.GetPath().c_str(), "RECREATE", "", 209); + { + auto tree = std::make_unique("Events", ""); + file->Write(); + } + file->Close(); + + try { + auto readerFail = RNTupleReader::Open("Events", fileGuard.GetPath()); + FAIL() << "RNTuple should only open Events key of type `RNTuple`"; + } catch (const RException &err) { + EXPECT_THAT(err.what(), testing::HasSubstr("no RNTuple named 'Events' in file")); + } +} + +TEST(MiniFile, DifferentTKeys) +{ + FileRaii fileGuard("test_ntuple_minifile_different_tkeys.root"); + auto file = std::make_unique(fileGuard.GetPath().c_str(), "RECREATE", "", 209); + { + auto tree = std::make_unique("SomeTTree", ""); + tree->Fill(); + auto ntuple = RNTupleWriter::Append(RNTupleModel::Create(), "Events", *file); + ntuple->Fill(); + file->Write(); + } + + file->Close(); + auto ntuple = RNTupleReader::Open("Events", fileGuard.GetPath()); + EXPECT_EQ(1, ntuple->GetNEntries()); +} TEST(MiniFile, FailOnForwardIncompatibility) { From 9084eee7ae8b088c2ca6a689d62e279b003b451d Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Wed, 5 May 2021 10:51:13 +0200 Subject: [PATCH 033/309] [mathcore] Update tests for modular arithmetic of RANLUX++ * Add a simple test for mulmod, a driver to call multiply9x9 and mod_m, which are tested separately. * Add explanations to test for minimum and maximum values of r in mod_m. --- math/mathcore/test/mulmod.icc | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/math/mathcore/test/mulmod.icc b/math/mathcore/test/mulmod.icc index 741a604eead27..db097a40f602d 100644 --- a/math/mathcore/test/mulmod.icc +++ b/math/mathcore/test/mulmod.icc @@ -70,10 +70,7 @@ TEST(multiply9x9, max) // and the following Python program: // >>> a = b = (1 << 576) - 1 // >>> mul = a * b - // >>> while mul > 0: - // ... print(hex(mul & 0xffffffffffffffff)) - // ... mul = mul >> 64 - // ... + // >>> print(hex(mul)) EXPECT_EQ(mul[0], 1); for (int i = 1; i < 9; i++) { EXPECT_EQ(mul[i], 0); @@ -181,6 +178,11 @@ TEST(mod_m, pattern) TEST(mod_m, r_min) { + // To make r = t_0 - (t_1 + t_2) + (t_3 + t_2) * 2 ** 240 minimal (and + // negative!), we need t_0 = 0, t_2 = max (because it also aliases the + // upper bits of t_1) and t_3 = 0 (it aliases the lower bits of t_1, but + // is multiplied with 2 ** 240 for the second, positive term). + uint64_t mul[18] = {0}; mul[14] = 0xffffffffffff0000; for (int i = 15; i < 18; i++) { @@ -204,6 +206,11 @@ TEST(mod_m, r_min) TEST(mod_m, r_max) { + // To make r = t_0 - (t_1 + t_2) + (t_3 + t_2) * 2 ** 240 maximal (and larger + // than 2 ** 576!), we need t_0 = max, t_2 = 0 (because it also aliases the + // upper bits of t_1) and t_3 = max (it aliases the lower bits of t_1, but is + // multiplied with 2 ** 240 for the second, positive term). + uint64_t mul[18] = {0}; for (int i = 0; i < 14; i++) { mul[i] = UINT64_MAX; @@ -223,6 +230,27 @@ TEST(mod_m, r_max) } } +TEST(mulmod, simple) +{ + uint64_t in1[9] = {0}; + uint64_t inout[9] = {0}; + in1[4] = (uint64_t(1) << 32); + inout[4] = (uint64_t(1) << 32); + // After multiplying the two values, (2 ** 288) * (2 ** 288) = 2 ** 576. + + mulmod(in1, inout); + + // The same result as mod_m::simple above: + // inout = 2 ** 576 - m = 2 ** 240 - 1, all first 240 bits set. + for (int i = 0; i < 3; i++) { + EXPECT_EQ(inout[i], 0xffffffffffffffff); + } + EXPECT_EQ(inout[3], 0x0000ffffffffffff); + for (int i = 4; i < 9; i++) { + EXPECT_EQ(inout[i], 0); + } +} + TEST(powermod, simple) { uint64_t base[9] = {0}; @@ -246,7 +274,7 @@ TEST(powermod, mod) powermod(base, res, 576); // The same result as mod_m::simple above: - // mod = 2 ** 576 - m = 2 ** 240 - 1, all first 240 bits set. + // res = 2 ** 576 - m = 2 ** 240 - 1, all first 240 bits set. for (int i = 0; i < 3; i++) { EXPECT_EQ(res[i], 0xffffffffffffffff); } From 42a224dee93b37a67323233ca51e162ac52f6bab Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 7 May 2021 16:03:21 +0200 Subject: [PATCH 034/309] [mathcore] Move RANLUX++ implementation to directory Split out addition and subtraction related functions to helpers.h, they will be re-used in future changes. Also add header guards and make the functions in mulmod.h static to avoid redefinition errors should the file be included into multiple TUs. --- math/mathcore/src/RanluxppEngineImpl.cxx | 2 +- math/mathcore/src/ranluxpp/helpers.h | 55 +++++++++++++++++++++++ math/mathcore/src/{ => ranluxpp}/mulmod.h | 51 +++++---------------- math/mathcore/test/mulmod.icc | 2 +- 4 files changed, 67 insertions(+), 43 deletions(-) create mode 100644 math/mathcore/src/ranluxpp/helpers.h rename math/mathcore/src/{ => ranluxpp}/mulmod.h (88%) diff --git a/math/mathcore/src/RanluxppEngineImpl.cxx b/math/mathcore/src/RanluxppEngineImpl.cxx index 05356e0fb94d3..53eaf11a3cce8 100644 --- a/math/mathcore/src/RanluxppEngineImpl.cxx +++ b/math/mathcore/src/RanluxppEngineImpl.cxx @@ -25,7 +25,7 @@ available at https://github.com/sibidanov/ranluxpp/. #include "Math/RanluxppEngine.h" -#include "mulmod.h" +#include "ranluxpp/mulmod.h" #include #include diff --git a/math/mathcore/src/ranluxpp/helpers.h b/math/mathcore/src/ranluxpp/helpers.h new file mode 100644 index 0000000000000..a2e299f642209 --- /dev/null +++ b/math/mathcore/src/ranluxpp/helpers.h @@ -0,0 +1,55 @@ +// @(#)root/mathcore:$Id$ +// Author: Jonas Hahnfeld 11/2020 + +/************************************************************************* + * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef RANLUXPP_HELPERS_H +#define RANLUXPP_HELPERS_H + +#include + +/// Compute `a + b` and set `overflow` accordingly. +static inline uint64_t add_overflow(uint64_t a, uint64_t b, unsigned &overflow) +{ + uint64_t add = a + b; + overflow = (add < a); + return add; +} + +/// Compute `a + b` and increment `carry` if there was an overflow +static inline uint64_t add_carry(uint64_t a, uint64_t b, unsigned &carry) +{ + unsigned overflow; + uint64_t add = add_overflow(a, b, overflow); + // Do NOT branch on overflow to avoid jumping code, just add 0 if there was + // no overflow. + carry += overflow; + return add; +} + +/// Compute `a - b` and set `overflow` accordingly +static inline uint64_t sub_overflow(uint64_t a, uint64_t b, unsigned &overflow) +{ + uint64_t sub = a - b; + overflow = (sub > a); + return sub; +} + +/// Compute `a - b` and increment `carry` if there was an overflow +static inline uint64_t sub_carry(uint64_t a, uint64_t b, unsigned &carry) +{ + unsigned overflow; + uint64_t sub = sub_overflow(a, b, overflow); + // Do NOT branch on overflow to avoid jumping code, just add 0 if there was + // no overflow. + carry += overflow; + return sub; +} + +#endif diff --git a/math/mathcore/src/mulmod.h b/math/mathcore/src/ranluxpp/mulmod.h similarity index 88% rename from math/mathcore/src/mulmod.h rename to math/mathcore/src/ranluxpp/mulmod.h index 6a661cba9a9f7..f5c1a83c3062c 100644 --- a/math/mathcore/src/mulmod.h +++ b/math/mathcore/src/ranluxpp/mulmod.h @@ -9,52 +9,19 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include - -/// Compute `a + b` and set `overflow` accordingly. -static inline uint64_t add_overflow(uint64_t a, uint64_t b, unsigned &overflow) -{ - uint64_t add = a + b; - overflow = (add < a); - return add; -} - -/// Compute `a + b` and increment `carry` if there was an overflow -static inline uint64_t add_carry(uint64_t a, uint64_t b, unsigned &carry) -{ - unsigned overflow; - uint64_t add = add_overflow(a, b, overflow); - // Do NOT branch on overflow to avoid jumping code, just add 0 if there was - // no overflow. - carry += overflow; - return add; -} +#ifndef RANLUXPP_MULMOD_H +#define RANLUXPP_MULMOD_H -/// Compute `a - b` and set `overflow` accordingly -static inline uint64_t sub_overflow(uint64_t a, uint64_t b, unsigned &overflow) -{ - uint64_t sub = a - b; - overflow = (sub > a); - return sub; -} +#include "helpers.h" -/// Compute `a - b` and increment `carry` if there was an overflow -static inline uint64_t sub_carry(uint64_t a, uint64_t b, unsigned &carry) -{ - unsigned overflow; - uint64_t sub = sub_overflow(a, b, overflow); - // Do NOT branch on overflow to avoid jumping code, just add 0 if there was - // no overflow. - carry += overflow; - return sub; -} +#include /// Multiply two 576 bit numbers, stored as 9 numbers of 64 bits each /// /// \param[in] in1 first factor as 9 numbers of 64 bits each /// \param[in] in2 second factor as 9 numbers of 64 bits each /// \param[out] out result with 18 numbers of 64 bits each -void multiply9x9(const uint64_t *in1, const uint64_t *in2, uint64_t *out) +static void multiply9x9(const uint64_t *in1, const uint64_t *in2, uint64_t *out) { uint64_t next = 0; unsigned nextCarry = 0; @@ -169,7 +136,7 @@ void multiply9x9(const uint64_t *in1, const uint64_t *in2, uint64_t *out) /// /// Note that this function does *not* return the smallest value congruent to /// the modulus, it only guarantees a value smaller than \f$ 2^{576} \$! -void mod_m(const uint64_t *mul, uint64_t *out) +static void mod_m(const uint64_t *mul, uint64_t *out) { uint64_t r[9] = {0}; @@ -314,7 +281,7 @@ void mod_m(const uint64_t *mul, uint64_t *out) /// /// \param[in] in1 first factor with 9 numbers of 64 bits each /// \param[inout] inout second factor and also the output of the same size -void mulmod(const uint64_t *in1, uint64_t *inout) +static void mulmod(const uint64_t *in1, uint64_t *inout) { uint64_t mul[2 * 9] = {0}; multiply9x9(in1, inout, mul); @@ -328,7 +295,7 @@ void mulmod(const uint64_t *in1, uint64_t *inout) /// \param[in] n exponent /// /// The arguments base and res may point to the same location. -void powermod(const uint64_t *base, uint64_t *res, uint64_t n) +static void powermod(const uint64_t *base, uint64_t *res, uint64_t n) { uint64_t fac[9] = {0}; fac[0] = base[0]; @@ -351,3 +318,5 @@ void powermod(const uint64_t *base, uint64_t *res, uint64_t n) mod_m(mul, fac); } } + +#endif diff --git a/math/mathcore/test/mulmod.icc b/math/mathcore/test/mulmod.icc index db097a40f602d..ac695ab0f8fb6 100644 --- a/math/mathcore/test/mulmod.icc +++ b/math/mathcore/test/mulmod.icc @@ -9,7 +9,7 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -#include "../src/mulmod.h" +#include "../src/ranluxpp/mulmod.h" #include "gtest/gtest.h" From 9cbb4c804811e9f67133fce529f7a94c6e81d36e Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Wed, 5 May 2021 12:52:13 +0200 Subject: [PATCH 035/309] [mathcore] Ensure full modulo operation in mod_m MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before mod_m only ensured that the result was smaller than 2 ** 576 to fit into the storage, but it could be greater or equal to the modulus. Update the correction term according to Lüscher. --- math/mathcore/src/RanluxppEngineImpl.cxx | 7 +++- math/mathcore/src/ranluxpp/mulmod.h | 18 +++++++-- math/mathcore/test/mulmod.icc | 51 ++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/math/mathcore/src/RanluxppEngineImpl.cxx b/math/mathcore/src/RanluxppEngineImpl.cxx index 53eaf11a3cce8..008dc2aa9b023 100644 --- a/math/mathcore/src/RanluxppEngineImpl.cxx +++ b/math/mathcore/src/RanluxppEngineImpl.cxx @@ -14,13 +14,18 @@ Implementation of the RANLUX++ generator RANLUX++ is an LCG equivalent of RANLUX using 576 bit numbers. -Described in +The idea of the generator (such as the initialization method) and the algorithm +for the modulo operation are described in A. Sibidanov, *A revision of the subtract-with-borrow random numbergenerators*, *Computer Physics Communications*, 221(2017), 299-303, preprint https://arxiv.org/pdf/1705.03123.pdf The code is loosely based on the Assembly implementation by A. Sibidanov available at https://github.com/sibidanov/ranluxpp/. + +Compared to the original generator, this implementation contains a fix to ensure +that the modulo operation of the LCG always returns the smallest value congruent +to the modulus (based on notes by M. Lüscher). */ #include "Math/RanluxppEngine.h" diff --git a/math/mathcore/src/ranluxpp/mulmod.h b/math/mathcore/src/ranluxpp/mulmod.h index f5c1a83c3062c..9ea0f34cdaa46 100644 --- a/math/mathcore/src/ranluxpp/mulmod.h +++ b/math/mathcore/src/ranluxpp/mulmod.h @@ -134,8 +134,7 @@ static void multiply9x9(const uint64_t *in1, const uint64_t *in2, uint64_t *out) /// /// \f$ m = 2^{576} - 2^{240} + 1 \f$ /// -/// Note that this function does *not* return the smallest value congruent to -/// the modulus, it only guarantees a value smaller than \f$ 2^{576} \$! +/// The result in out is guaranteed to be smaller than the modulus. static void mod_m(const uint64_t *mul, uint64_t *out) { uint64_t r[9] = {0}; @@ -220,7 +219,18 @@ static void mod_m(const uint64_t *mul, uint64_t *out) c += carry; // c = floor(r / 2 ** 576) has been computed along the way via the carry - // flags. Now to update r = r - c * m, it suffices to know c * (-2 ** 240 + 1) + // flags. Now if c = 0 and the value currently stored in r is greater or + // equal to m, we need cbar = 1 and subtract m, otherwise cbar = c. The + // value currently in r is greater or equal to m, if and only if one of + // the last 240 bits is set and the upper bits are all set. + bool greater_m = r[0] | r[1] | r[2] | (r[3] & 0x0000ffffffffffff); + greater_m &= (r[3] >> 48) == 0xffff; + for (int i = 4; i < 9; i++) { + greater_m &= (r[i] == UINT64_MAX); + } + c = c + (c == 0 && greater_m); + + // To update r = r - c * m, it suffices to know c * (-2 ** 240 + 1) // because the 2 ** 576 will cancel out. Also note that c may be zero, but // the operation is still performed to avoid branching. @@ -281,6 +291,8 @@ static void mod_m(const uint64_t *mul, uint64_t *out) /// /// \param[in] in1 first factor with 9 numbers of 64 bits each /// \param[inout] inout second factor and also the output of the same size +/// +/// The result in inout is guaranteed to be smaller than the modulus. static void mulmod(const uint64_t *in1, uint64_t *inout) { uint64_t mul[2 * 9] = {0}; diff --git a/math/mathcore/test/mulmod.icc b/math/mathcore/test/mulmod.icc index ac695ab0f8fb6..3b88b3ac08e8c 100644 --- a/math/mathcore/test/mulmod.icc +++ b/math/mathcore/test/mulmod.icc @@ -111,10 +111,8 @@ TEST(mod_m, modulus) mod_m(mul, mod); - // mod_m does not provide the smallest value, but just a value smaller than - // 2 ** 576 that is congruent to mul; in this case, mul itself. for (int i = 0; i < 9; i++) { - EXPECT_EQ(mod[i], mul[i]); + EXPECT_EQ(mod[i], 0); } } @@ -230,6 +228,8 @@ TEST(mod_m, r_max) } } +// The modulus m = 2 ** 576 - 2 ** 240 + 1. + TEST(mulmod, simple) { uint64_t in1[9] = {0}; @@ -251,6 +251,51 @@ TEST(mulmod, simple) } } +TEST(mulmod, modulus) +{ + // in1 = m = 2 ** 576 - 2 ** 240 + 1 + uint64_t in1[9] = {0}; + in1[0] = 1; + in1[3] = 0xffff000000000000; + for (int i = 4; i < 9; i++) { + in1[i] = 0xffffffffffffffff; + } + uint64_t inout[9] = {0}; + inout[0] = 1; + // After multiplying the two values, the result will be the modulus m. + + mulmod(in1, inout); + + // mulmod should provide the smallest value congruent to m; in this case 0. + for (int i = 0; i < 9; i++) { + EXPECT_EQ(inout[i], 0); + } +} + +TEST(mulmod, multiple_modulus) +{ + // in1 = m = 2 ** 576 - 2 ** 240 + 1 + uint64_t in1[9] = {0}; + in1[0] = 1; + in1[3] = 0xffff000000000000; + for (int i = 4; i < 9; i++) { + in1[i] = 0xffffffffffffffff; + } + uint64_t inout[9]; + for (int i = 0; i < 9; i++) { + inout[i] = 1; + } + // After multiplying the two values, the result will be a multiple of the + // modulus m. + + mulmod(in1, inout); + + // mulmod should provide the smallest value congruent to m; in this case 0. + for (int i = 0; i < 9; i++) { + EXPECT_EQ(inout[i], 0); + } +} + TEST(powermod, simple) { uint64_t base[9] = {0}; From 55173bd273fad28897c29bdd261b3868a6158de4 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Thu, 6 May 2021 09:50:09 +0200 Subject: [PATCH 036/309] RANLUX++: Convert LCG state to RANLUX numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just using bits from the LCG state introduces a bias because the number is guaranteed to be smaller than m and therefore not equally distributed over the whole range of 2 ** 576. Instead of storing the LCG state, store the RANLUX numbers and the carry bit and convert when needed according to notes by Lüscher. Refactor the computation of r to a common function used by both mod_m and to_ranlux. --- math/mathcore/src/RanluxppEngineImpl.cxx | 29 +- math/mathcore/src/ranluxpp/helpers.h | 101 ++++++ math/mathcore/src/ranluxpp/mulmod.h | 95 +----- math/mathcore/src/ranluxpp/ranlux_lcg.h | 92 ++++++ math/mathcore/test/CMakeLists.txt | 1 + math/mathcore/test/RanluxppEngine.cxx | 2 +- math/mathcore/test/ranlux_lcg.cxx | 400 +++++++++++++++++++++++ 7 files changed, 622 insertions(+), 98 deletions(-) create mode 100644 math/mathcore/src/ranluxpp/ranlux_lcg.h create mode 100644 math/mathcore/test/ranlux_lcg.cxx diff --git a/math/mathcore/src/RanluxppEngineImpl.cxx b/math/mathcore/src/RanluxppEngineImpl.cxx index 008dc2aa9b023..f8765d3fa89b2 100644 --- a/math/mathcore/src/RanluxppEngineImpl.cxx +++ b/math/mathcore/src/RanluxppEngineImpl.cxx @@ -25,12 +25,17 @@ available at https://github.com/sibidanov/ranluxpp/. Compared to the original generator, this implementation contains a fix to ensure that the modulo operation of the LCG always returns the smallest value congruent -to the modulus (based on notes by M. Lüscher). +to the modulus (based on notes by M. Lüscher). Also, the generator converts the +LCG state back to RANLUX numbers (implementation based on notes by M. Lüscher). +This avoids a bias in the generated numbers because the upper bits of the LCG +state, that is smaller than the modulus \f$ m = 2^{576} - 2^{240} + 1 \f$ (not +a power of 2!), have a higher probability of being 0 than 1. */ #include "Math/RanluxppEngine.h" #include "ranluxpp/mulmod.h" +#include "ranluxpp/ranlux_lcg.h" #include #include @@ -70,7 +75,8 @@ template class RanluxppEngineImpl { private: - uint64_t fState[9]; ///< State of the generator + uint64_t fState[9]; ///< RANLUX state of the generator + unsigned fCarry; ///< Carry bit of the RANLUX state int fPosition = 0; ///< Current position in bits static constexpr const uint64_t *kA = RanluxppData

::kA; @@ -79,7 +85,10 @@ class RanluxppEngineImpl { /// Produce next block of random bits void Advance() { - mulmod(kA, fState); + uint64_t lcg[9]; + to_lcg(fState, fCarry, lcg); + mulmod(kA, lcg); + to_ranlux(lcg, fState, fCarry); fPosition = 0; } @@ -110,9 +119,10 @@ class RanluxppEngineImpl { /// Initialize and seed the state of the generator void SetSeed(uint64_t s) { - fState[0] = 1; + uint64_t lcg[9]; + lcg[0] = 1; for (int i = 1; i < 9; i++) { - fState[i] = 0; + lcg[i] = 0; } uint64_t a_seed[9]; @@ -121,8 +131,9 @@ class RanluxppEngineImpl { powermod(a_seed, a_seed, uint64_t(1) << 48); // Skip another s states. powermod(a_seed, a_seed, s); - mulmod(a_seed, fState); + mulmod(a_seed, lcg); + to_ranlux(lcg, fState, fCarry); fPosition = 0; } @@ -145,7 +156,11 @@ class RanluxppEngineImpl { uint64_t a_skip[9]; powermod(kA, a_skip, skip + 1); - mulmod(a_skip, fState); + + uint64_t lcg[9]; + to_lcg(fState, fCarry, lcg); + mulmod(a_skip, lcg); + to_ranlux(lcg, fState, fCarry); // Potentially skip numbers in the freshly generated block. int remaining = n - skip * nPerState; diff --git a/math/mathcore/src/ranluxpp/helpers.h b/math/mathcore/src/ranluxpp/helpers.h index a2e299f642209..94f2da7474e58 100644 --- a/math/mathcore/src/ranluxpp/helpers.h +++ b/math/mathcore/src/ranluxpp/helpers.h @@ -52,4 +52,105 @@ static inline uint64_t sub_carry(uint64_t a, uint64_t b, unsigned &carry) return sub; } +/// Update r = r - (t1 + t2) + (t3 + t2) * b ** 10 +/// +/// This function also yields cbar = floor(r / m) as its return value (int64_t +/// because the value can be -1). With an initial value of r = t0, this can +/// be used for computing the remainder after division by m (see the function +/// mod_m in mulmod.h). The function to_ranlux passes r = 0 and uses only the +/// return value to obtain the decimal expansion after divison by m. +static inline int64_t compute_r(const uint64_t *upper, uint64_t *r) +{ + // Subtract t1 (24 * 24 = 576 bits) + unsigned carry = 0; + for (int i = 0; i < 9; i++) { + uint64_t r_i = r[i]; + r_i = sub_overflow(r_i, carry, carry); + + uint64_t t1_i = upper[i]; + r_i = sub_carry(r_i, t1_i, carry); + r[i] = r_i; + } + int64_t c = -((int64_t)carry); + + // Subtract t2 (only 240 bits, so need to extend) + carry = 0; + for (int i = 0; i < 9; i++) { + uint64_t r_i = r[i]; + r_i = sub_overflow(r_i, carry, carry); + + uint64_t t2_bits = 0; + if (i < 4) { + t2_bits += upper[i + 5] >> 16; + if (i < 3) { + t2_bits += upper[i + 6] << 48; + } + } + r_i = sub_carry(r_i, t2_bits, carry); + r[i] = r_i; + } + c -= carry; + + // r += (t3 + t2) * 2 ** 240 + carry = 0; + { + uint64_t r_3 = r[3]; + // 16 upper bits + uint64_t t2_bits = (upper[5] >> 16) << 48; + uint64_t t3_bits = (upper[0] << 48); + + r_3 = add_carry(r_3, t2_bits, carry); + r_3 = add_carry(r_3, t3_bits, carry); + + r[3] = r_3; + } + for (int i = 0; i < 3; i++) { + uint64_t r_i = r[i + 4]; + r_i = add_overflow(r_i, carry, carry); + + uint64_t t2_bits = (upper[5 + i] >> 32) + (upper[6 + i] << 32); + uint64_t t3_bits = (upper[i] >> 16) + (upper[1 + i] << 48); + + r_i = add_carry(r_i, t2_bits, carry); + r_i = add_carry(r_i, t3_bits, carry); + + r[i + 4] = r_i; + } + { + uint64_t r_7 = r[7]; + r_7 = add_overflow(r_7, carry, carry); + + uint64_t t2_bits = (upper[8] >> 32); + uint64_t t3_bits = (upper[3] >> 16) + (upper[4] << 48); + + r_7 = add_carry(r_7, t2_bits, carry); + r_7 = add_carry(r_7, t3_bits, carry); + + r[7] = r_7; + } + { + uint64_t r_8 = r[8]; + r_8 = add_overflow(r_8, carry, carry); + + uint64_t t3_bits = (upper[4] >> 16) + (upper[5] << 48); + + r_8 = add_carry(r_8, t3_bits, carry); + + r[8] = r_8; + } + c += carry; + + // c = floor(r / 2 ** 576) has been computed along the way via the carry + // flags. Now if c = 0 and the value currently stored in r is greater or + // equal to m, we need cbar = 1 and subtract m, otherwise cbar = c. The + // value currently in r is greater or equal to m, if and only if one of + // the last 240 bits is set and the upper bits are all set. + bool greater_m = r[0] | r[1] | r[2] | (r[3] & 0x0000ffffffffffff); + greater_m &= (r[3] >> 48) == 0xffff; + for (int i = 4; i < 9; i++) { + greater_m &= (r[i] == UINT64_MAX); + } + return c + (c == 0 && greater_m); +} + #endif diff --git a/math/mathcore/src/ranluxpp/mulmod.h b/math/mathcore/src/ranluxpp/mulmod.h index 9ea0f34cdaa46..dfac4e58679f4 100644 --- a/math/mathcore/src/ranluxpp/mulmod.h +++ b/math/mathcore/src/ranluxpp/mulmod.h @@ -137,98 +137,13 @@ static void multiply9x9(const uint64_t *in1, const uint64_t *in2, uint64_t *out) /// The result in out is guaranteed to be smaller than the modulus. static void mod_m(const uint64_t *mul, uint64_t *out) { - uint64_t r[9] = {0}; - - // r = t0 - t1 (24 * 24 = 576 bits) - unsigned carry = 0; - for (int i = 0; i < 9; i++) { - uint64_t t0_i = mul[i]; - uint64_t r_i = sub_overflow(t0_i, carry, carry); - - uint64_t t1_i = mul[i + 9]; - r_i = sub_carry(r_i, t1_i, carry); - r[i] = r_i; - } - int64_t c = -((int64_t)carry); - - // r -= t2 (only 240 bits, so need to extend) - carry = 0; + uint64_t r[9]; + // Assign r = t0 for (int i = 0; i < 9; i++) { - uint64_t r_i = r[i]; - r_i = sub_overflow(r_i, carry, carry); - - uint64_t t2_bits = 0; - if (i < 4) { - t2_bits += mul[i + 14] >> 16; - if (i < 3) { - t2_bits += mul[i + 15] << 48; - } - } - r_i = sub_carry(r_i, t2_bits, carry); - r[i] = r_i; - } - c -= carry; - - // r += (t3 + t2) * 2 ** 240 - carry = 0; - { - uint64_t r_3 = r[3]; - // 16 upper bits - uint64_t t2_bits = (mul[14] >> 16) << 48; - uint64_t t3_bits = (mul[9] << 48); - - r_3 = add_carry(r_3, t2_bits, carry); - r_3 = add_carry(r_3, t3_bits, carry); - - r[3] = r_3; + r[i] = mul[i]; } - for (int i = 0; i < 3; i++) { - uint64_t r_i = r[i + 4]; - r_i = add_overflow(r_i, carry, carry); - uint64_t t2_bits = (mul[14 + i] >> 32) + (mul[15 + i] << 32); - uint64_t t3_bits = (mul[9 + i] >> 16) + (mul[10 + i] << 48); - - r_i = add_carry(r_i, t2_bits, carry); - r_i = add_carry(r_i, t3_bits, carry); - - r[i + 4] = r_i; - } - { - uint64_t r_7 = r[7]; - r_7 = add_overflow(r_7, carry, carry); - - uint64_t t2_bits = (mul[17] >> 32); - uint64_t t3_bits = (mul[12] >> 16) + (mul[13] << 48); - - r_7 = add_carry(r_7, t2_bits, carry); - r_7 = add_carry(r_7, t3_bits, carry); - - r[7] = r_7; - } - { - uint64_t r_8 = r[8]; - r_8 = add_overflow(r_8, carry, carry); - - uint64_t t3_bits = (mul[13] >> 16) + (mul[14] << 48); - - r_8 = add_carry(r_8, t3_bits, carry); - - r[8] = r_8; - } - c += carry; - - // c = floor(r / 2 ** 576) has been computed along the way via the carry - // flags. Now if c = 0 and the value currently stored in r is greater or - // equal to m, we need cbar = 1 and subtract m, otherwise cbar = c. The - // value currently in r is greater or equal to m, if and only if one of - // the last 240 bits is set and the upper bits are all set. - bool greater_m = r[0] | r[1] | r[2] | (r[3] & 0x0000ffffffffffff); - greater_m &= (r[3] >> 48) == 0xffff; - for (int i = 4; i < 9; i++) { - greater_m &= (r[i] == UINT64_MAX); - } - c = c + (c == 0 && greater_m); + int64_t c = compute_r(mul + 9, r); // To update r = r - c * m, it suffices to know c * (-2 ** 240 + 1) // because the 2 ** 576 will cancel out. Also note that c may be zero, but @@ -257,7 +172,7 @@ static void mod_m(const uint64_t *mul, uint64_t *out) // (The assembly implementation shifts by 63, which gives the same result.) int64_t t1 = t2 >> 48; - carry = 0; + unsigned carry = 0; { uint64_t r_0 = r[0]; diff --git a/math/mathcore/src/ranluxpp/ranlux_lcg.h b/math/mathcore/src/ranluxpp/ranlux_lcg.h new file mode 100644 index 0000000000000..f2b6738d8aacd --- /dev/null +++ b/math/mathcore/src/ranluxpp/ranlux_lcg.h @@ -0,0 +1,92 @@ +// @(#)root/mathcore:$Id$ +// Author: Jonas Hahnfeld 05/2021 + +/************************************************************************* + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef RANLUXPP_RANLUX_LCG_H +#define RANLUXPP_RANLUX_LCG_H + +#include "helpers.h" + +#include + +/// Convert RANLUX numbers to an LCG state +/// +/// \param[in] ranlux the RANLUX numbers as 576 bits +/// \param[out] lcg the 576 bits of the LCG state, smaller than m +/// \param[in] c the carry bit of the RANLUX state +/// +/// \f$ m = 2^{576} - 2^{240} + 1 \f$ +static void to_lcg(const uint64_t *ranlux, unsigned c, uint64_t *lcg) +{ + unsigned carry = 0; + // Subtract the final 240 bits. + for (int i = 0; i < 9; i++) { + uint64_t ranlux_i = ranlux[i]; + uint64_t lcg_i = sub_overflow(ranlux_i, carry, carry); + + uint64_t bits = 0; + if (i < 4) { + bits += ranlux[i + 5] >> 16; + if (i < 3) { + bits += ranlux[i + 6] << 48; + } + } + lcg_i = sub_carry(lcg_i, bits, carry); + lcg[i] = lcg_i; + } + + // Add and propagate the carry bit. + for (int i = 0; i < 9; i++) { + lcg[i] = add_overflow(lcg[i], c, c); + } +} + +/// Convert an LCG state to RANLUX numbers +/// +/// \param[in] lcg the 576 bits of the LCG state, must be smaller than m +/// \param[out] ranlux the RANLUX numbers as 576 bits +/// \param[out] c the carry bit of the RANLUX state +/// +/// \f$ m = 2^{576} - 2^{240} + 1 \f$ +static void to_ranlux(const uint64_t *lcg, uint64_t *ranlux, unsigned &c_out) +{ + uint64_t r[9] = {0}; + int64_t c = compute_r(lcg, r); + + // ranlux = t1 + t2 + c + unsigned carry = 0; + for (int i = 0; i < 9; i++) { + uint64_t in_i = lcg[i]; + uint64_t tmp_i = add_overflow(in_i, carry, carry); + + uint64_t bits = 0; + if (i < 4) { + bits += lcg[i + 5] >> 16; + if (i < 3) { + bits += lcg[i + 6] << 48; + } + } + tmp_i = add_carry(tmp_i, bits, carry); + ranlux[i] = tmp_i; + } + + // If c = -1, we need to add it to all components. + int64_t c1 = c >> 1; + ranlux[0] = add_overflow(ranlux[0], c, carry); + for (int i = 1; i < 9; i++) { + uint64_t ranlux_i = ranlux[i]; + ranlux_i = add_overflow(ranlux_i, carry, carry); + ranlux_i = add_carry(ranlux_i, c1, carry); + } + + c_out = carry; +} + +#endif diff --git a/math/mathcore/test/CMakeLists.txt b/math/mathcore/test/CMakeLists.txt index f9f61ff5fb459..95af3ed733073 100644 --- a/math/mathcore/test/CMakeLists.txt +++ b/math/mathcore/test/CMakeLists.txt @@ -81,6 +81,7 @@ ROOT_ADD_GTEST(GradientFittingUnit testGradientFitting.cxx LIBRARIES Core MathCo ROOT_ADD_GTEST(MulmodUnitOpt mulmod_opt.cxx) ROOT_ADD_GTEST(MulmodUnitNoInt128 mulmod_noint128.cxx) +ROOT_ADD_GTEST(RanluxLCGUnit ranlux_lcg.cxx) ROOT_ADD_GTEST(RanluxppEngineTests RanluxppEngine.cxx LIBRARIES Core MathCore) diff --git a/math/mathcore/test/RanluxppEngine.cxx b/math/mathcore/test/RanluxppEngine.cxx index bfa3ee4d8b9d9..11d93b25cd8b2 100644 --- a/math/mathcore/test/RanluxppEngine.cxx +++ b/math/mathcore/test/RanluxppEngine.cxx @@ -15,7 +15,7 @@ using namespace ROOT::Math; -TEST(RanluxppEngine, random2048) +TEST(RanluxppEngine, DISABLED_random2048) { RanluxppEngine2048 rng(314159265); // Match the assembly implementation in skipping the first 11 numbers. diff --git a/math/mathcore/test/ranlux_lcg.cxx b/math/mathcore/test/ranlux_lcg.cxx new file mode 100644 index 0000000000000..31524bbfa8334 --- /dev/null +++ b/math/mathcore/test/ranlux_lcg.cxx @@ -0,0 +1,400 @@ +// @(#)root/mathcore:$Id$ +// Author: Jonas Hahnfeld 05/2021 + +/************************************************************************* + * Copyright (C) 1995-2021, 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 "../src/ranluxpp/ranlux_lcg.h" + +#include "gtest/gtest.h" + +#include + +TEST(to_lcg, zero) +{ + // RANLUX state with zero in all components. + uint64_t ranlux[9] = {0}; + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + for (int i = 0; i < 9; i++) { + EXPECT_EQ(lcg[i], 0); + } +} + +TEST(to_lcg, one) +{ + // RANLUX state with a one in the last component. + uint64_t ranlux[9] = {1, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 1); + for (int i = 1; i < 9; i++) { + EXPECT_EQ(lcg[i], 0); + } +} + +TEST(to_lcg, carry) +{ + // RANLUX state with zero in all components and the carry bit set. + uint64_t ranlux[9] = {0}; + unsigned c = 1; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + // Note that this state is the same as to_lcg::one above. When passed into + // the function to_ranlux, it will return the input state of to_lcg::one and + // not this one with the carry bit set. + EXPECT_EQ(lcg[0], 1); + for (int i = 1; i < 9; i++) { + EXPECT_EQ(lcg[i], 0); + } +} + +TEST(to_lcg, all_ones) +{ + // RANLUX state with a one in every component. + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + ranlux[i+0] = 1 + (1 << 24) + (uint64_t(1) << 48); + ranlux[i+1] = (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56); + ranlux[i+2] = (1 << 16) + (uint64_t(1) << 40); + } + unsigned c = 1; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 1); + EXPECT_EQ(lcg[1], 0); + EXPECT_EQ(lcg[2], 0); + EXPECT_EQ(lcg[3], 0x0001000000000000); + EXPECT_EQ(lcg[4], 0x0100000100000100); + EXPECT_EQ(lcg[5], 0x0000010000010000); + EXPECT_EQ(lcg[6], 0x0001000001000001); + EXPECT_EQ(lcg[7], 0x0100000100000100); + EXPECT_EQ(lcg[8], 0x0000010000010000); +} + +TEST(to_lcg, all_ones_alt) +{ + // The RANLUX state that the assembly version returns for the output of + // to_lcg::all_ones. + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + ranlux[i+0] = 1 + (1 << 24) + (uint64_t(1) << 48); + ranlux[i+1] = (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56); + ranlux[i+2] = (1 << 16) + (uint64_t(1) << 40); + } + ranlux[0]++; + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 1); + EXPECT_EQ(lcg[1], 0); + EXPECT_EQ(lcg[2], 0); + EXPECT_EQ(lcg[3], 0x0001000000000000); + EXPECT_EQ(lcg[4], 0x0100000100000100); + EXPECT_EQ(lcg[5], 0x0000010000010000); + EXPECT_EQ(lcg[6], 0x0001000001000001); + EXPECT_EQ(lcg[7], 0x0100000100000100); + EXPECT_EQ(lcg[8], 0x0000010000010000); +} + +TEST(to_lcg, all_ones_no_carry) +{ + // RANLUX state with a one in every component except the carry. + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + ranlux[i+0] = 1 + (1 << 24) + (uint64_t(1) << 48); + ranlux[i+1] = (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56); + ranlux[i+2] = (1 << 16) + (uint64_t(1) << 40); + } + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0); + EXPECT_EQ(lcg[1], 0); + EXPECT_EQ(lcg[2], 0); + EXPECT_EQ(lcg[3], 0x0001000000000000); + EXPECT_EQ(lcg[4], 0x0100000100000100); + EXPECT_EQ(lcg[5], 0x0000010000010000); + EXPECT_EQ(lcg[6], 0x0001000001000001); + EXPECT_EQ(lcg[7], 0x0100000100000100); + EXPECT_EQ(lcg[8], 0x0000010000010000); +} + +TEST(to_lcg, all_ones_no_carry_alt) +{ + // The RANLUX state that to_ranlux and the assembly version returns for the + // output of to_lcg::all_ones_no_carry. + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + ranlux[i+0] = 1 + (1 << 24) + (uint64_t(1) << 48); + ranlux[i+1] = (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56); + ranlux[i+2] = (1 << 16) + (uint64_t(1) << 40); + } + ranlux[0]--; + unsigned c = 1; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0); + EXPECT_EQ(lcg[1], 0); + EXPECT_EQ(lcg[2], 0); + EXPECT_EQ(lcg[3], 0x0001000000000000); + EXPECT_EQ(lcg[4], 0x0100000100000100); + EXPECT_EQ(lcg[5], 0x0000010000010000); + EXPECT_EQ(lcg[6], 0x0001000001000001); + EXPECT_EQ(lcg[7], 0x0100000100000100); + EXPECT_EQ(lcg[8], 0x0000010000010000); +} + +TEST(to_lcg, ascending) +{ + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + uint64_t ii = 8 * (i / 3); + ranlux[i+0] = (ii + 1) + ((ii + 2) << 24) + ((ii + 3) << 48); + ranlux[i+1] = ((ii + 4) << 8) + ((ii + 5) << 32) + ((ii + 6) << 56); + ranlux[i+2] = ((ii + 7) << 16) + ((ii + 8) << 40); + } + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0xfff1fffff1fffff2); + EXPECT_EQ(lcg[1], 0xf1fffff1fffff1ff); + EXPECT_EQ(lcg[2], 0xfffff1fffff1ffff); + EXPECT_EQ(lcg[3], 0x000afffff1fffff1); + EXPECT_EQ(lcg[4], 0x0e00000d00000c00); + EXPECT_EQ(lcg[5], 0x00001000000f0000); + EXPECT_EQ(lcg[6], 0x0013000012000011); + EXPECT_EQ(lcg[7], 0x1600001500001400); + EXPECT_EQ(lcg[8], 0x0000180000170000); +} + +TEST(to_lcg, ascending_alt) +{ + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + uint64_t ii = 8 * (i / 3); + ranlux[i+0] = (ii + 1) + ((ii + 2) << 24) + ((ii + 3) << 48); + ranlux[i+1] = ((ii + 4) << 8) + ((ii + 5) << 32) + ((ii + 6) << 56); + ranlux[i+2] = ((ii + 7) << 16) + ((ii + 8) << 40); + } + ranlux[0]--; + unsigned c = 1; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0xfff1fffff1fffff2); + EXPECT_EQ(lcg[1], 0xf1fffff1fffff1ff); + EXPECT_EQ(lcg[2], 0xfffff1fffff1ffff); + EXPECT_EQ(lcg[3], 0x000afffff1fffff1); + EXPECT_EQ(lcg[4], 0x0e00000d00000c00); + EXPECT_EQ(lcg[5], 0x00001000000f0000); + EXPECT_EQ(lcg[6], 0x0013000012000011); + EXPECT_EQ(lcg[7], 0x1600001500001400); + EXPECT_EQ(lcg[8], 0x0000180000170000); +} + +TEST(to_lcg, descending) +{ + uint64_t ranlux[9]; + for (int i = 0; i < 9; i += 3) { + uint64_t ii = 8 * (2 - i / 3); + ranlux[i+0] = (ii + 8) + ((ii + 7) << 24) + ((ii + 6) << 48); + ranlux[i+1] = ((ii + 5) << 8) + ((ii + 4) << 32) + ((ii + 3) << 56); + ranlux[i+2] = ((ii + 2) << 16) + ((ii + 1) << 40); + } + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0x000e00000e00000e); + EXPECT_EQ(lcg[1], 0x0e00000e00000e00); + EXPECT_EQ(lcg[2], 0x00000e00000e0000); + EXPECT_EQ(lcg[3], 0x000e00000e00000e); + EXPECT_EQ(lcg[4], 0x0b00000c00000d00); + EXPECT_EQ(lcg[5], 0x00000900000a0000); + EXPECT_EQ(lcg[6], 0x0006000007000008); + EXPECT_EQ(lcg[7], 0x0300000400000500); + EXPECT_EQ(lcg[8], 0x0000010000020000); +} + +TEST(to_lcg, max) +{ + uint64_t max = UINT64_MAX; + uint64_t ranlux[9] = {max, max, max, max, max, max, max, max, max}; + unsigned c = 0; + uint64_t lcg[9]; + + to_lcg(ranlux, c, lcg); + + EXPECT_EQ(lcg[0], 0); + EXPECT_EQ(lcg[1], 0); + EXPECT_EQ(lcg[2], 0); + EXPECT_EQ(lcg[3], 0xffff000000000000); + for (int i = 4; i < 9; i++) { + EXPECT_EQ(lcg[i], 0xffffffffffffffff); + } +} + +TEST(to_ranlux, zero) +{ + uint64_t lcg[9] = {0}; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + for (int i = 0; i < 9; i++) { + EXPECT_EQ(ranlux[i], 0); + } + EXPECT_EQ(c, 0); +} + +TEST(to_ranlux, one) +{ + uint64_t lcg[9] = {1, 0, 0, 0, 0, 0, 0, 0, 0}; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + EXPECT_EQ(ranlux[0], 1); + for (int i = 1; i < 9; i++) { + EXPECT_EQ(ranlux[i], 0); + } + EXPECT_EQ(c, 0); +} + +TEST(to_ranlux, all_ones) +{ + // See to_lcg::all_ones + uint64_t lcg[9] = { + 1, 0, 0, 0x0001000000000000, 0x0100000100000100, 0x0000010000010000, + 0x0001000001000001, 0x0100000100000100, 0x0000010000010000, + }; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + EXPECT_EQ(ranlux[0], 2 + (1 << 24) + (uint64_t(1) << 48)); + for (int i = 0; i < 9; i += 3) { + if (i != 0) { + EXPECT_EQ(ranlux[i+0], 1 + (1 << 24) + (uint64_t(1) << 48)); + } + EXPECT_EQ(ranlux[i+1], (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56)); + EXPECT_EQ(ranlux[i+2], (1 << 16) + (uint64_t(1) << 40)); + } + EXPECT_EQ(c, 0); +} + +TEST(to_ranlux, all_ones_no_carry) +{ + // See to_lcg::all_ones_no_carry and to_lcg::all_ones_no_carry_alt + uint64_t lcg[9] = { + 0, 0, 0, 0x0001000000000000, 0x0100000100000100, 0x0000010000010000, + 0x0001000001000001, 0x0100000100000100, 0x0000010000010000, + }; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + EXPECT_EQ(ranlux[0], (1 << 24) + (uint64_t(1) << 48)); + for (int i = 0; i < 9; i += 3) { + if (i != 0) { + EXPECT_EQ(ranlux[i+0], 1 + (1 << 24) + (uint64_t(1) << 48)); + } + EXPECT_EQ(ranlux[i+1], (1 << 8) + (uint64_t(1) << 32) + (uint64_t(1) << 56)); + EXPECT_EQ(ranlux[i+2], (1 << 16) + (uint64_t(1) << 40)); + } + EXPECT_EQ(c, 1); +} + +TEST(to_ranlux, ascending) +{ + // See to_lcg::ascending and to_lcg::ascending_alt + uint64_t lcg[9] = { + 0xfff1fffff1fffff2, 0xf1fffff1fffff1ff, 0xfffff1fffff1ffff, + 0x000afffff1fffff1, 0x0e00000d00000c00, 0x00001000000f0000, + 0x0013000012000011, 0x1600001500001400, 0x0000180000170000, + }; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + EXPECT_EQ(ranlux[0], (2 << 24) + (uint64_t(3) << 48)); + for (int i = 0; i < 9; i += 3) { + int ii = 8 * (i / 3); + if (i != 0) { + EXPECT_EQ(ranlux[i+0], (ii + 1) + ((ii + 2) << 24) + (uint64_t(ii + 3) << 48)); + } + EXPECT_EQ(ranlux[i+1], ((ii + 4) << 8) + (uint64_t(ii + 5) << 32) + (uint64_t(ii + 6) << 56)); + EXPECT_EQ(ranlux[i+2], ((ii + 7) << 16) + (uint64_t(ii + 8) << 40)); + } + EXPECT_EQ(c, 1); +} + +TEST(to_ranlux, descending) +{ + // See to_lcg::decending + uint64_t lcg[9] = { + 0x000e00000e00000e, 0x0e00000e00000e00, 0x00000e00000e0000, + 0x000e00000e00000e, 0x0b00000c00000d00, 0x00000900000a0000, + 0x0006000007000008, 0x0300000400000500, 0x0000010000020000, + }; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + for (int i = 0; i < 9; i += 3) { + uint64_t ii = 8 * (2 - i / 3); + EXPECT_EQ(ranlux[i+0], (ii + 8) + ((ii + 7) << 24) + ((ii + 6) << 48)); + EXPECT_EQ(ranlux[i+1], ((ii + 5) << 8) + ((ii + 4) << 32) + ((ii + 3) << 56)); + EXPECT_EQ(ranlux[i+2], ((ii + 2) << 16) + ((ii + 1) << 40)); + } + EXPECT_EQ(c, 0); +} + +TEST(to_ranlux, max) +{ + // See to_lcg::max + uint64_t max = UINT64_MAX; + uint64_t lcg[9] = {0, 0, 0, 0xffff000000000000, max, max, max, max, max}; + uint64_t ranlux[9]; + unsigned c = 0; + + to_ranlux(lcg, ranlux, c); + + EXPECT_EQ(ranlux[0], max - 1); + for (int i = 1; i < 9; i++) { + EXPECT_EQ(ranlux[i], max); + } + EXPECT_EQ(c, 1); +} From ee0ba46eadb889c8a05274e1b7f5ea68c590b2ea Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Mon, 31 May 2021 12:11:27 +0200 Subject: [PATCH 037/309] RANLUX++: Extract only 48 bits per number This restores the connection to the theoretical properties when understanding the original subtract-with-borrow recursion as a dynamical system. --- math/mathcore/inc/Math/RanluxppEngine.h | 6 ++--- math/mathcore/src/RanluxppEngineImpl.cxx | 30 ++++++++++----------- math/mathcore/test/RanluxppEngine.cxx | 34 ++++++++++++++---------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/math/mathcore/inc/Math/RanluxppEngine.h b/math/mathcore/inc/Math/RanluxppEngine.h index f6d893a6d7d6f..bfef96bc7735c 100644 --- a/math/mathcore/inc/Math/RanluxppEngine.h +++ b/math/mathcore/inc/Math/RanluxppEngine.h @@ -27,17 +27,17 @@ template class RanluxppEngine final : public TRandomEngine { private: - std::unique_ptr> fImpl; + std::unique_ptr> fImpl; public: RanluxppEngine(uint64_t seed = 314159265); virtual ~RanluxppEngine(); - /// Generate a double-precision random number with 52 bits of randomness + /// Generate a double-precision random number with 48 bits of randomness double Rndm() override; /// Generate a double-precision random number (non-virtual method) double operator()(); - /// Generate a random integer value with 52 bits + /// Generate a random integer value with 48 bits uint64_t IntRndm(); /// Initialize and seed the state of the generator diff --git a/math/mathcore/src/RanluxppEngineImpl.cxx b/math/mathcore/src/RanluxppEngineImpl.cxx index f8765d3fa89b2..83ecbd7f576d3 100644 --- a/math/mathcore/src/RanluxppEngineImpl.cxx +++ b/math/mathcore/src/RanluxppEngineImpl.cxx @@ -29,7 +29,11 @@ to the modulus (based on notes by M. Lüscher). Also, the generator converts the LCG state back to RANLUX numbers (implementation based on notes by M. Lüscher). This avoids a bias in the generated numbers because the upper bits of the LCG state, that is smaller than the modulus \f$ m = 2^{576} - 2^{240} + 1 \f$ (not -a power of 2!), have a higher probability of being 0 than 1. +a power of 2!), have a higher probability of being 0 than 1. And finally, this +implementation draws 48 random bits for each generated floating point number +(instead of 52 bits as in the original generator) to maintain the theoretical +properties from understanding the original transition function of RANLUX as a +chaotic dynamical system. */ #include "Math/RanluxppEngine.h" @@ -116,6 +120,14 @@ class RanluxppEngineImpl { return bits; } + /// Return a floating point number, converted from the next random bits. + double NextRandomFloat() + { + static constexpr double div = 1.0 / (uint64_t(1) << w); + uint64_t bits = NextRandomBits(); + return bits * div; + } + /// Initialize and seed the state of the generator void SetSeed(uint64_t s) { @@ -171,7 +183,7 @@ class RanluxppEngineImpl { }; template -RanluxppEngine

::RanluxppEngine(uint64_t seed) : fImpl(new RanluxppEngineImpl<52, p>) +RanluxppEngine

::RanluxppEngine(uint64_t seed) : fImpl(new RanluxppEngineImpl<48, p>) { fImpl->SetSeed(seed); } @@ -188,19 +200,7 @@ double RanluxppEngine

::Rndm() template double RanluxppEngine

::operator()() { - // Get 52 bits of randomness. - uint64_t bits = fImpl->NextRandomBits(); - - // Construct the double in [1, 2), using the random bits as mantissa. - static constexpr uint64_t exp = 0x3ff0000000000000; - union { - double dRandom; - uint64_t iRandom; - }; - iRandom = exp | bits; - - // Shift to the right interval of [0, 1). - return dRandom - 1; + return fImpl->NextRandomFloat(); } template diff --git a/math/mathcore/test/RanluxppEngine.cxx b/math/mathcore/test/RanluxppEngine.cxx index 11d93b25cd8b2..258d90a055a7a 100644 --- a/math/mathcore/test/RanluxppEngine.cxx +++ b/math/mathcore/test/RanluxppEngine.cxx @@ -9,34 +9,40 @@ * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ +// This test uses EXPECT_EQ also for floating point numbers - the expected +// values are entered with enough digits to ensure binary equality. + #include "Math/RanluxppEngine.h" #include "gtest/gtest.h" using namespace ROOT::Math; -TEST(RanluxppEngine, DISABLED_random2048) +TEST(RanluxppEngine, random2048) { RanluxppEngine2048 rng(314159265); - // Match the assembly implementation in skipping the first 11 numbers. - rng.Skip(11); - // Values extracted from the assembly implementation. - EXPECT_EQ(rng.IntRndm(), 1357063655714534); - EXPECT_DOUBLE_EQ(rng.Rndm(), 0.500504017418743); + // The following values were obtained without skipping. + + EXPECT_EQ(rng.IntRndm(), 39378223178113); + EXPECT_EQ(rng.Rndm(), 0.57072241146576274673); // Skip ahead in block. - rng.Skip(2); - EXPECT_EQ(rng.IntRndm(), 160414309741165); - EXPECT_DOUBLE_EQ(rng.Rndm(), 0.9422050833832005); + rng.Skip(8); + EXPECT_EQ(rng.IntRndm(), 52221857391813); + EXPECT_EQ(rng.Rndm(), 0.16812543081078956675); + + // The next call needs to advance the state. + EXPECT_EQ(rng.IntRndm(), 185005245121693); + EXPECT_EQ(rng.Rndm(), 0.28403302782895423206); // Skip ahead to start of next block. - rng.Skip(5); - EXPECT_EQ(rng.IntRndm(), 911953872946889); - EXPECT_DOUBLE_EQ(rng.Rndm(), 0.7498142796273863); + rng.Skip(10); + EXPECT_EQ(rng.IntRndm(), 89237874214503); + EXPECT_EQ(rng.Rndm(), 0.79969842495805920635); // Skip ahead across blocks. rng.Skip(42); - EXPECT_EQ(rng.IntRndm(), 4265826975858336); - EXPECT_DOUBLE_EQ(rng.Rndm(), 0.472544363223621); + EXPECT_EQ(rng.IntRndm(), 49145148745150); + EXPECT_EQ(rng.Rndm(), 0.74670661284082484599); } From 247ff7873d8e1fdd010f4755533e54173cb2926b Mon Sep 17 00:00:00 2001 From: iarspider Date: Wed, 5 May 2021 14:50:18 +0200 Subject: [PATCH 038/309] Fix FindOracle.cmake to find version 21.x Notice: I did not test Oracle functionality with 21.x --- cmake/modules/FindOracle.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindOracle.cmake b/cmake/modules/FindOracle.cmake index e3ea87da5cd95..e86364bdbd7d3 100644 --- a/cmake/modules/FindOracle.cmake +++ b/cmake/modules/FindOracle.cmake @@ -55,7 +55,7 @@ FIND_LIBRARY( ) FIND_LIBRARY( ORACLE_LIBRARY_LNNZ - NAMES libnnz10 nnz10 libnnz11 nnz11 libnnz12 nnz12 nnz18 nnz19 ociw32 + NAMES libnnz10 nnz10 libnnz11 nnz11 libnnz12 nnz12 nnz18 nnz19 nnz21 ociw32 PATHS ${ORACLE_LIB_LOCATION} ) From 2cf286ef2c8a862dc30dc706ed88456d13c66b9a Mon Sep 17 00:00:00 2001 From: SpectreVert Date: Tue, 25 May 2021 13:53:08 +0200 Subject: [PATCH 039/309] [cmake] fix #7009 escape characters in regex > git clone git@github.com:SpectreVert/root.git root_src+tag > cd root_src+tag > mkdir compiled && cd compiled && cmake .. # should work as intented now --- cmake/modules/RootMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 6e28c5e2c9982..83f30cd876536 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -300,13 +300,13 @@ function(ROOT_GENERATE_DICTIONARY dictionary) if(NOT ${dir} MATCHES "^[$]") list(APPEND incdirs ${dir}) endif() - if(${dir} MATCHES "^${CMAKE_SOURCE_DIR}") + string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" tmp_src_dir ${CMAKE_SOURCE_DIR}) + if(${dir} MATCHES "^${tmp_src_dir}") list(APPEND headerdirs ${dir}) endif() endforeach() endif() - # if (cxxmodules OR runtime_cxxmodules) # Comments from Vassil: # FIXME: We prepend ROOTSYS/include because if we have built a module From ed2b3c315f5a2405bd01a624a1051da4e3793ece Mon Sep 17 00:00:00 2001 From: SpectreVert Date: Tue, 1 Jun 2021 10:29:05 +0200 Subject: [PATCH 040/309] Remove regex matching to avoid escaping --- cmake/modules/RootMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 83f30cd876536..2b85d5637172e 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -300,8 +300,8 @@ function(ROOT_GENERATE_DICTIONARY dictionary) if(NOT ${dir} MATCHES "^[$]") list(APPEND incdirs ${dir}) endif() - string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" tmp_src_dir ${CMAKE_SOURCE_DIR}) - if(${dir} MATCHES "^${tmp_src_dir}") + string(FIND ${dir} ${CMAKE_SOURCE_DIR} res) + if(${res} GREATER -1) list(APPEND headerdirs ${dir}) endif() endforeach() From ab85e6c70b5eea8a0f94539c89971eb6920c5810 Mon Sep 17 00:00:00 2001 From: SpectreVert Date: Tue, 1 Jun 2021 11:17:48 +0200 Subject: [PATCH 041/309] Check if match is done at start of directory name --- cmake/modules/RootMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 2b85d5637172e..10c8266ee7e96 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -300,8 +300,8 @@ function(ROOT_GENERATE_DICTIONARY dictionary) if(NOT ${dir} MATCHES "^[$]") list(APPEND incdirs ${dir}) endif() - string(FIND ${dir} ${CMAKE_SOURCE_DIR} res) - if(${res} GREATER -1) + string(FIND ${dir} "${CMAKE_SOURCE_DIR}" src_dir_in_dir) + if(${src_dir_in_dir} EQUAL 0) list(APPEND headerdirs ${dir}) endif() endforeach() From 80abb2fca59152c22d7eed466a6773feb7d07aa9 Mon Sep 17 00:00:00 2001 From: SpectreVert Date: Tue, 1 Jun 2021 12:04:04 +0200 Subject: [PATCH 042/309] Replace regex escaping/matching with string(FIND) --- cmake/modules/RootMacros.cmake | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 10c8266ee7e96..e2a1f736dbe12 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -410,14 +410,14 @@ function(ROOT_GENERATE_DICTIONARY dictionary) else() set(incdirs_in_build) set(incdirs_in_prefix ${headerdirs_dflt}) - string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" _source_dir "${CMAKE_SOURCE_DIR}") - string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" _binary_dir "${CMAKE_BINARY_DIR}") - string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" _curr_binary_dir "${CMAKE_CURRENT_BINARY_DIR}") foreach(incdir ${incdirs}) + string(FIND ${incdir} "${CMAKE_SOURCE_DIR}" src_dir_in_dir) + string(FIND ${incdir} "${CMAKE_BINARY_DIR}" bin_dir_in_dir) + string(FIND ${incdir} "${CMAKE_CURRENT_BINARY_DIR}" cur_dir_in_dir) if(NOT IS_ABSOLUTE ${incdir} - OR ${incdir} MATCHES "^${_source_dir}" - OR ${incdir} MATCHES "^${_binary_dir}" - OR ${incdir} MATCHES "^${_curr_binary_dir}") + OR ${src_dir_in_dir} EQUAL 0 + OR ${bin_dir_in_dir} EQUAL 0 + OR ${cur_dir_in_dir} EQUAL 0) list(APPEND incdirs_in_build ${incdir}) else() list(APPEND incdirs_in_prefix ${incdir}) @@ -1054,11 +1054,11 @@ function(ROOT_OBJECT_LIBRARY library) set(obj ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.build/${CMAKE_CFG_INTDIR}/${library}.build/Objects-normal/x86_64/${name}${CMAKE_CXX_OUTPUT_EXTENSION}) else() if(IS_ABSOLUTE ${s}) - string(REGEX REPLACE "([][.?*+|()$^-])" "\\\\\\1" escaped_source_dir "${CMAKE_CURRENT_SOURCE_DIR}") - string(REGEX REPLACE "([][.?*+|()$^-])" "\\\\\\1" escaped_binary_dir "${CMAKE_CURRENT_BINARY_DIR}") - if(${s} MATCHES "^${escaped_source_dir}") + string(FIND ${s} "${CMAKE_CURRENT_SOURCE_DIR}" src_dir_in_src) + string(FIND ${s} "${CMAKE_CURRENT_BINARY_DIR}" bin_dir_in_src) + if(${src_dir_in_src} EQUAL 0) string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${library}.dir src ${s}) - elseif(${s} MATCHES "^${escaped_binary_dir}") + elseif(${bin_dir_in_src} EQUAL 0) string(REPLACE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${library}.dir src ${s}) else() #message(WARNING "Unknown location of source ${s} for object library ${library}") From 5d0cd9a918ff1896e30e0b4ff2655c40a125d1ea Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Thu, 3 Jun 2021 14:34:04 +0200 Subject: [PATCH 043/309] [Windows] Fix fatal error C1001: Internal compiler error (#8327) * [Windows] Fix fatal error C1001: Internal compiler error After updating Visual Studio 2019 to the version `16.10.0`, there is a `fatal error C1001: Internal compiler error` when compiling `G__MathCore.cxx` See the bug report at Microsoft: [[v16.10.0] Fatal error C1001: Internal compiler error](https://developercommunity.visualstudio.com/t/v16100-fatal-error-c1001-internal-compiler-error/1437980?from=email&viewtype=all) And the proposed workaround: 1. Remove the `auto` return type from `FunctorGradHandler::Clone()`. This function is the cause of the ICE and replacing `auto` with `ImplFunc*` will resolve the issue. 2. Only if fixing the source is not an option, add `/d1deducedReturnEncoding-` to your build. This will disable the recent compiler work around deduced return types. Keep in mind that this option should only be used as a last resort because it is not a permanent switch. Interestingly enough, the `auto` return type was introduced as a workaround for another compiler error with `VS 2019 (16.4.3)` * Remove one useless version check --- math/mathcore/inc/Math/Functor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/mathcore/inc/Math/Functor.h b/math/mathcore/inc/Math/Functor.h index 864e86ec7622e..bcb8e120406b4 100644 --- a/math/mathcore/inc/Math/Functor.h +++ b/math/mathcore/inc/Math/Functor.h @@ -178,7 +178,7 @@ class FunctorGradHandler : public ParentFunctor::Impl { ImplFunc * Copy() const { return new FunctorGradHandler(*this); } // clone of the function handler (use copy-ctor) -#if defined(_MSC_VER) && !defined(__CLING__) +#if defined(_MSC_VER) && (_MSC_VER < 1929) && !defined(__CLING__) // FIXME: this is a work-around for a compiler error with VS 2019 (16.4.3) // try to remove this #ifdef when updating Visual Studio auto Clone() const { return Copy(); } From 1f5378d3b0c41ca6c116a163b465c5c1a745a1b7 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Mon, 31 May 2021 15:32:43 +0200 Subject: [PATCH 044/309] [ntuple] Factor out common code used in the commit/load of pages Parts of the code to commit/load pages is used in the sealed pages path. Factor this out. Specifically, this affects common code in: - `CommitPageImpl` and `CommitSealedPageImpl`. - `PopulatePageFromCluster()` and `LoadSealedPage()`. Locating the RPageInfo from the cluster index is now a member function of RPageRange. --- tree/ntuple/v7/inc/ROOT/RNTupleDescriptor.hxx | 12 ++++ tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx | 3 + tree/ntuple/v7/src/RNTupleDescriptor.cxx | 21 ++++++ tree/ntuple/v7/src/RPageStorageDaos.cxx | 22 ++---- tree/ntuple/v7/src/RPageStorageFile.cxx | 72 ++++++------------- 5 files changed, 61 insertions(+), 69 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleDescriptor.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleDescriptor.hxx index f9dcc7de64fa8..01805d9480cb9 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleDescriptor.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleDescriptor.hxx @@ -216,6 +216,15 @@ public: return fNElements == other.fNElements && fLocator == other.fLocator; } }; + struct RPageInfoExtended : RPageInfo { + /// Index (in cluster) of the first element in page. + RClusterSize::ValueType fFirstInPage; + /// Page number in the corresponding RPageRange. + NTupleSize_t fPageNo; + + RPageInfoExtended(const RPageInfo &pi, RClusterSize::ValueType i, NTupleSize_t n) + : RPageInfo(pi), fFirstInPage(i), fPageNo(n) {} + }; RPageRange() = default; RPageRange(const RPageRange &other) = delete; @@ -230,6 +239,9 @@ public: return clone; } + /// Find the page in the RPageRange that contains the given element. The element must exist. + RPageInfoExtended Find(RClusterSize::ValueType idxInCluster) const; + DescriptorId_t fColumnId = kInvalidDescriptorId; std::vector fPageInfos; diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx index f79ca44baa1cc..50ce852529e5f 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx @@ -70,6 +70,9 @@ private: std::uint64_t fClusterMaxOffset = 0; RPageSinkFile(std::string_view ntupleName, const RNTupleWriteOptions &options); + RClusterDescriptor::RLocator WriteSealedPage(const RPageStorage::RSealedPage &sealedPage, + std::size_t bytesPacked); + protected: void CreateImpl(const RNTupleModel &model) final; RClusterDescriptor::RLocator CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) final; diff --git a/tree/ntuple/v7/src/RNTupleDescriptor.cxx b/tree/ntuple/v7/src/RNTupleDescriptor.cxx index 6f3541af19e2b..df806ac225519 100644 --- a/tree/ntuple/v7/src/RNTupleDescriptor.cxx +++ b/tree/ntuple/v7/src/RNTupleDescriptor.cxx @@ -457,6 +457,27 @@ bool ROOT::Experimental::RColumnDescriptor::operator==(const RColumnDescriptor & //////////////////////////////////////////////////////////////////////////////// +ROOT::Experimental::RClusterDescriptor::RPageRange::RPageInfoExtended +ROOT::Experimental::RClusterDescriptor::RPageRange::Find(ROOT::Experimental::RClusterSize::ValueType idxInCluster) const +{ + // TODO(jblomer): binary search + RPageInfo pageInfo; + decltype(idxInCluster) firstInPage = 0; + NTupleSize_t pageNo = 0; + for (const auto &pi : fPageInfos) { + if (firstInPage + pi.fNElements > idxInCluster) { + pageInfo = pi; + break; + } + firstInPage += pi.fNElements; + ++pageNo; + } + R__ASSERT(firstInPage <= idxInCluster); + R__ASSERT((firstInPage + pageInfo.fNElements) > idxInCluster); + return RPageInfoExtended{pageInfo, firstInPage, pageNo}; +} + + bool ROOT::Experimental::RClusterDescriptor::operator==(const RClusterDescriptor &other) const { return fClusterId == other.fClusterId && diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index d054051778326..f9127aa8314b3 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -327,22 +327,8 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceDaos::P { const auto columnId = columnHandle.fId; const auto clusterId = clusterDescriptor.GetId(); - const auto &pageRange = clusterDescriptor.GetPageRange(columnId); - - // TODO(jblomer): binary search - RClusterDescriptor::RPageRange::RPageInfo pageInfo; - decltype(idxInCluster) firstInPage = 0; - NTupleSize_t pageNo = 0; - for (const auto &pi : pageRange.fPageInfos) { - if (firstInPage + pi.fNElements > idxInCluster) { - pageInfo = pi; - break; - } - firstInPage += pi.fNElements; - ++pageNo; - } - R__ASSERT(firstInPage <= idxInCluster); - R__ASSERT((firstInPage + pageInfo.fNElements) > idxInCluster); + + auto pageInfo = clusterDescriptor.GetPageRange(columnId).Find(idxInCluster); const auto element = columnHandle.fColumn->GetElement(); const auto elementSize = element->GetSize(); @@ -368,7 +354,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceDaos::P if (!cachedPage.IsNull()) return cachedPage; - ROnDiskPage::Key key(columnId, pageNo); + ROnDiskPage::Key key(columnId, pageInfo.fPageNo); auto onDiskPage = fCurrentCluster->GetOnDiskPage(key); R__ASSERT(onDiskPage && (bytesOnStorage == onDiskPage->GetSize())); sealedPageBuffer = onDiskPage->GetAddress(); @@ -383,7 +369,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceDaos::P const auto indexOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex; auto newPage = fPageAllocator->NewPage(columnId, pageBuffer.release(), elementSize, pageInfo.fNElements); - newPage.SetWindow(indexOffset + firstInPage, RPage::RClusterInfo(clusterId, indexOffset)); + newPage.SetWindow(indexOffset + pageInfo.fFirstInPage, RPage::RClusterInfo(clusterId, indexOffset)); fPagePool->RegisterPage(newPage, RPageDeleter([](const RPage &page, void * /*userData*/) { diff --git a/tree/ntuple/v7/src/RPageStorageFile.cxx b/tree/ntuple/v7/src/RPageStorageFile.cxx index 543963d898f99..905263bc6e0b7 100644 --- a/tree/ntuple/v7/src/RPageStorageFile.cxx +++ b/tree/ntuple/v7/src/RPageStorageFile.cxx @@ -102,14 +102,11 @@ void ROOT::Experimental::Detail::RPageSinkFile::CreateImpl(const RNTupleModel & } -ROOT::Experimental::RClusterDescriptor::RLocator -ROOT::Experimental::Detail::RPageSinkFile::CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) +inline ROOT::Experimental::RClusterDescriptor::RLocator +ROOT::Experimental::Detail::RPageSinkFile::WriteSealedPage( + const RPageStorage::RSealedPage &sealedPage, std::size_t bytesPacked) { - auto element = columnHandle.fColumn->GetElement(); - auto sealedPage = SealPage(page, *element, fOptions.GetCompression()); - - auto offsetData = fWriter->WriteBlob( - sealedPage.fBuffer, sealedPage.fSize, element->GetPackedSize(page.GetNElements())); + const auto offsetData = fWriter->WriteBlob(sealedPage.fBuffer, sealedPage.fSize, bytesPacked); fClusterMinOffset = std::min(offsetData, fClusterMinOffset); fClusterMaxOffset = std::max(offsetData + sealedPage.fSize, fClusterMaxOffset); @@ -121,22 +118,25 @@ ROOT::Experimental::Detail::RPageSinkFile::CommitPageImpl(ColumnHandle_t columnH } +ROOT::Experimental::RClusterDescriptor::RLocator +ROOT::Experimental::Detail::RPageSinkFile::CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) +{ + auto element = columnHandle.fColumn->GetElement(); + auto sealedPage = SealPage(page, *element, fOptions.GetCompression()); + + return WriteSealedPage(sealedPage, element->GetPackedSize(page.GetNElements())); +} + + ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkFile::CommitSealedPageImpl( DescriptorId_t columnId, const RPageStorage::RSealedPage &sealedPage) { const auto bitsOnStorage = RColumnElementBase::GetBitsOnStorage( fDescriptorBuilder.GetDescriptor().GetColumnDescriptor(columnId).GetModel().GetType()); - const auto bytesPacked = (bitsOnStorage * sealedPage.fNElements + 7) / 8; - const auto offsetData = fWriter->WriteBlob(sealedPage.fBuffer, sealedPage.fSize, bytesPacked); - fClusterMinOffset = std::min(offsetData, fClusterMinOffset); - fClusterMaxOffset = std::max(offsetData + sealedPage.fSize, fClusterMaxOffset); - RClusterDescriptor::RLocator result; - result.fPosition = offsetData; - result.fBytesOnStorage = sealedPage.fSize; - return result; + return WriteSealedPage(sealedPage, bytesPacked); } @@ -340,25 +340,9 @@ void ROOT::Experimental::Detail::RPageSourceFile::LoadSealedPage( DescriptorId_t columnId, const RClusterIndex &clusterIndex, RSealedPage &sealedPage) { const auto clusterId = clusterIndex.GetClusterId(); - const auto index = clusterIndex.GetIndex(); - const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId); - const auto &pageRange = clusterDescriptor.GetPageRange(columnId); - - // TODO(jblomer): binary search - RClusterDescriptor::RPageRange::RPageInfo pageInfo; - std::uint32_t firstInPage = 0; - NTupleSize_t pageNo = 0; - for (const auto &pi : pageRange.fPageInfos) { - if (firstInPage + pi.fNElements > index) { - pageInfo = pi; - break; - } - firstInPage += pi.fNElements; - ++pageNo; - } - R__ASSERT(firstInPage <= index); - R__ASSERT((firstInPage + pageInfo.fNElements) > index); + + auto pageInfo = clusterDescriptor.GetPageRange(columnId).Find(clusterIndex.GetIndex()); const auto bytesOnStorage = pageInfo.fLocator.fBytesOnStorage; sealedPage.fSize = bytesOnStorage; @@ -372,22 +356,8 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::P { const auto columnId = columnHandle.fId; const auto clusterId = clusterDescriptor.GetId(); - const auto &pageRange = clusterDescriptor.GetPageRange(columnId); - - // TODO(jblomer): binary search - RClusterDescriptor::RPageRange::RPageInfo pageInfo; - decltype(idxInCluster) firstInPage = 0; - NTupleSize_t pageNo = 0; - for (const auto &pi : pageRange.fPageInfos) { - if (firstInPage + pi.fNElements > idxInCluster) { - pageInfo = pi; - break; - } - firstInPage += pi.fNElements; - ++pageNo; - } - R__ASSERT(firstInPage <= idxInCluster); - R__ASSERT((firstInPage + pageInfo.fNElements) > idxInCluster); + + auto pageInfo = clusterDescriptor.GetPageRange(columnId).Find(idxInCluster); const auto element = columnHandle.fColumn->GetElement(); const auto elementSize = element->GetSize(); @@ -412,7 +382,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::P if (!cachedPage.IsNull()) return cachedPage; - ROnDiskPage::Key key(columnId, pageNo); + ROnDiskPage::Key key(columnId, pageInfo.fPageNo); auto onDiskPage = fCurrentCluster->GetOnDiskPage(key); R__ASSERT(onDiskPage && (bytesOnStorage == onDiskPage->GetSize())); sealedPageBuffer = onDiskPage->GetAddress(); @@ -427,7 +397,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::P const auto indexOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex; auto newPage = fPageAllocator->NewPage(columnId, pageBuffer.release(), elementSize, pageInfo.fNElements); - newPage.SetWindow(indexOffset + firstInPage, RPage::RClusterInfo(clusterId, indexOffset)); + newPage.SetWindow(indexOffset + pageInfo.fFirstInPage, RPage::RClusterInfo(clusterId, indexOffset)); fPagePool->RegisterPage(newPage, RPageDeleter([](const RPage &page, void * /*userData*/) { From 8bff69247097f4e7fc215d09026354e7791e3134 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Mon, 31 May 2021 16:04:15 +0200 Subject: [PATCH 045/309] [ntuple,daos] Support load/store of sealed pages in DAOS --- tree/ntuple/v7/src/RPageStorageDaos.cxx | 36 ++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index f9127aa8314b3..71e969b85c1a6 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -145,6 +145,14 @@ ROOT::Experimental::Detail::RPageSinkDaos::CommitPageImpl(ColumnHandle_t columnH auto element = columnHandle.fColumn->GetElement(); auto sealedPage = SealPage(page, *element, fOptions.GetCompression()); + return CommitSealedPageImpl(columnHandle.fId, sealedPage); +} + + +ROOT::Experimental::RClusterDescriptor::RLocator +ROOT::Experimental::Detail::RPageSinkDaos::CommitSealedPageImpl( + DescriptorId_t /*columnId*/, const RPageStorage::RSealedPage &sealedPage) +{ auto offsetData = std::get<0>(fDaosContainer->WriteObject(sealedPage.fBuffer, sealedPage.fSize, kDistributionKey, @@ -157,17 +165,6 @@ ROOT::Experimental::Detail::RPageSinkDaos::CommitPageImpl(ColumnHandle_t columnH } -ROOT::Experimental::RClusterDescriptor::RLocator -ROOT::Experimental::Detail::RPageSinkDaos::CommitSealedPageImpl( - DescriptorId_t columnId, const RPageStorage::RSealedPage &sealedPage) -{ - /// TODO(jalopezg): this will be addressed in a different pull request. - (void)columnId; - (void)sealedPage; - return {}; -} - - // TODO(jalopezg): the current byte range arithmetic makes little sense for the // object store. We might find out, however, that there are native ways to group // clusters in DAOS. @@ -316,10 +313,19 @@ ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceDao void ROOT::Experimental::Detail::RPageSourceDaos::LoadSealedPage( DescriptorId_t columnId, const RClusterIndex &clusterIndex, RSealedPage &sealedPage) { - /// TODO(jalopezg): this will be addressed in a different pull request. - (void)columnId; - (void)clusterIndex; - (void)sealedPage; + const auto clusterId = clusterIndex.GetClusterId(); + const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId); + + auto pageInfo = clusterDescriptor.GetPageRange(columnId).Find(clusterIndex.GetIndex()); + + const auto bytesOnStorage = pageInfo.fLocator.fBytesOnStorage; + sealedPage.fSize = bytesOnStorage; + sealedPage.fNElements = pageInfo.fNElements; + if (sealedPage.fBuffer) { + fDaosContainer->ReadObject({static_cast(pageInfo.fLocator.fPosition), 0}, + const_cast(sealedPage.fBuffer), bytesOnStorage, + kDistributionKey, kAttributeKey); + } } ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceDaos::PopulatePageFromCluster( From c4a755661bf42d54c43a1bb24e8c9e34a1a529a5 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 2 Jun 2021 10:42:59 +0200 Subject: [PATCH 046/309] [DF] Add test for Foreach with mutable lambdas --- tree/dataframe/test/dataframe_interface.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tree/dataframe/test/dataframe_interface.cxx b/tree/dataframe/test/dataframe_interface.cxx index 354b0b4dc7b70..b2d14f416d5f7 100644 --- a/tree/dataframe/test/dataframe_interface.cxx +++ b/tree/dataframe/test/dataframe_interface.cxx @@ -749,3 +749,10 @@ TEST(RDataFrameInterface, StressShortSyntaxForCollectionSizes) auto c = df.Count().GetValue(); EXPECT_EQ(c, 42ull); } + +TEST(RDataFrameInterface, MutableForeach) +{ + int i = 0; + ROOT::RDataFrame(10).Foreach([&](ULong64_t) mutable { ++i; }, {"rdfentry_"}); + EXPECT_EQ(i, 10); +} From 6832151a556172150d53ba13c89e5ae77a80483a Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 2 Jun 2021 10:46:32 +0200 Subject: [PATCH 047/309] [DF] Fix compilation of Foreach with mutable lambdas This fixes #8317. --- tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx index c5d6532d06545..591882e77ed1c 100644 --- a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx @@ -533,7 +533,7 @@ struct RMinReturnType { template std::function AddSlotParameter(F &f, TypeList) { - return [f](unsigned int, Args... a) -> R { return f(a...); }; + return [f](unsigned int, Args... a) mutable -> R { return f(a...); }; } template From 0e171a4e1d740a069a0ebfd14551a1aec423ad13 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 11:54:12 +0200 Subject: [PATCH 048/309] Fix gcc11 warnings in TASImage gcc11 complains about non-initialized variable, just make it happy. --- graf2d/asimage/src/TASImage.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index 8c47db7a9c501..23f9d96f4beac 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -5486,6 +5486,9 @@ void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col, del = kTRUE; } + ET.scanlines.next = nullptr; // to avoid compiler warnings + ET.ymin = ET.ymax = 0; // to avoid compiler warnings + ptsOut = firstPoint; width = firstWidth; CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock); @@ -5586,6 +5589,9 @@ void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, TImage *tile) pETEs = new EdgeTableEntry[count]; + ET.scanlines.next = nullptr; // to avoid compiler warnings + ET.ymin = ET.ymax = 0; // to avoid compiler warnings + ptsOut = firstPoint; width = firstWidth; CreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock); From 054ec8684aa419f2458150c08635aa8c0f3623bf Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 12:03:10 +0200 Subject: [PATCH 049/309] Provide initializer for RealInfo_t members in TGNumberEntry.cxx gcc11 complains that some values may be used uninitialized --- gui/gui/src/TGNumberEntry.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gui/gui/src/TGNumberEntry.cxx b/gui/gui/src/TGNumberEntry.cxx index 8cca9dc13e882..49aeddbf08726 100644 --- a/gui/gui/src/TGNumberEntry.cxx +++ b/gui/gui/src/TGNumberEntry.cxx @@ -111,13 +111,13 @@ enum ERealStyle { // Style of real //////////////////////////////////////////////////////////////////////////////// struct RealInfo_t { - ERealStyle fStyle; // Style of real - Int_t fFracDigits; // Number of fractional digits - Int_t fFracBase; // Base of fractional digits - Int_t fIntNum; // Integer number - Int_t fFracNum; // Fraction - Int_t fExpoNum; // Exponent - Int_t fSign; // Sign + ERealStyle fStyle{kRSInt}; // Style of real + Int_t fFracDigits{0}; // Number of fractional digits + Int_t fFracBase{0}; // Base of fractional digits + Int_t fIntNum{0}; // Integer number + Int_t fFracNum{0}; // Fraction + Int_t fExpoNum{0}; // Exponent + Int_t fSign{0}; // Sign }; //////////////////////////////////////////////////////////////////////////////// From 9228c266830d2b25af669dce6a178a7a70d5c9ab Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 12:16:11 +0200 Subject: [PATCH 050/309] Fix warning about strcpy in TGTextLine constructor --- gui/gui/src/TGText.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gui/gui/src/TGText.cxx b/gui/gui/src/TGText.cxx index 7e9dbf316f3f1..cc1464766819e 100644 --- a/gui/gui/src/TGText.cxx +++ b/gui/gui/src/TGText.cxx @@ -71,8 +71,7 @@ TGTextLine::TGTextLine(const char *string) if (string) { fLength = strlen(string); fString = new char[fLength+1]; - strncpy(fString, string, fLength); - fString[fLength] = 0; + strlcpy(fString, string, fLength+1); } else { fLength = 0; fString = 0; From 4f8bc5a804f33eb77f3e638adbe7dd5ee775cb6d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 2 Jun 2021 12:19:18 +0200 Subject: [PATCH 051/309] Fix bug in TGTextLine::GetText Wrong check for length was performed --- gui/gui/src/TGText.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/gui/src/TGText.cxx b/gui/gui/src/TGText.cxx index cc1464766819e..04ea45eb1345c 100644 --- a/gui/gui/src/TGText.cxx +++ b/gui/gui/src/TGText.cxx @@ -187,7 +187,7 @@ char *TGTextLine::GetText(ULong_t pos, ULong_t length) return 0; } - if (pos + length > (ULong_t)fString) { + if (pos + length > fLength) { length = fLength - pos; } From b1a9bab66c1314b7f1ce16219a17fa2be77ab29c Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Tue, 1 Jun 2021 19:14:32 +0200 Subject: [PATCH 052/309] [tree] Print error in case of branch kind mismatch in CopyAddresses TTree::CopyAddresses has the built-in pre-condition that the input and output branches are of the same kind. Clones might be added, however, for which the pre-condition is violated. This is currently the case, for example, with certain usages of RDataFrame::Snapshot, which might create an output branch that is a simple TBranch while the input branch is e.g. a TBranchElement. This results in wrong data being written out. With this patch we detect this case and complain. A proper fix will be proposed soon. The issue is tracked as #8295. --- tree/tree/src/TTree.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 93f2dcbba64cf..7af2c7b9b8e37 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -3361,6 +3361,13 @@ void TTree::CopyAddresses(TTree* tree, Bool_t undo) tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress()); TBranch* br = tree->GetBranch(branch->GetName()); if (br) { + if (br->IsA() != branch->IsA()) { + Error( + "CopyAddresses", + "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'", + tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(), + br->IsA()->GetName()); + } // The copy does not own any object allocated by SetAddress(). // FIXME: We do too much here, br may not be a top-level branch. if (br->InheritsFrom(TBranchElement::Class())) { From 68547d05b88fe46d4c61eed3347b2a3535734b79 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Fri, 4 Jun 2021 10:00:37 +0200 Subject: [PATCH 053/309] Better fix for Windows See the bug report at Microsoft: [Problem with how the compiler generates covariant virtual functions](https://developercommunity.visualstudio.com/t/Problem-with-how-the-compiler-generates/1441440) And the proposed workaround: >It turns out to be a problem with how the compiler generates the covariant virtual function `Clone` in `FunctorGradHandler`. To address the issue just use the original return type of the virtual base: >``` >template >class FunctorGradHandler : public ParentFunctor::Impl { >... > typename ParentFunctor::ImplBase* Clone() const { return Copy(); } >... >}; >``` > This should avoid the need for the compiler to generate the problematic covariant function. --- math/mathcore/inc/Math/Functor.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/math/mathcore/inc/Math/Functor.h b/math/mathcore/inc/Math/Functor.h index bcb8e120406b4..43214aa8d2190 100644 --- a/math/mathcore/inc/Math/Functor.h +++ b/math/mathcore/inc/Math/Functor.h @@ -178,10 +178,12 @@ class FunctorGradHandler : public ParentFunctor::Impl { ImplFunc * Copy() const { return new FunctorGradHandler(*this); } // clone of the function handler (use copy-ctor) -#if defined(_MSC_VER) && (_MSC_VER < 1929) && !defined(__CLING__) - // FIXME: this is a work-around for a compiler error with VS 2019 (16.4.3) - // try to remove this #ifdef when updating Visual Studio - auto Clone() const { return Copy(); } +#ifdef _MSC_VER + // FIXME: this is a work-around for a a problem with how the compiler + // generates the covariant virtual function "Clone". To address the + // issue just use the original return type of the virtual base class. + // Try to remove this #ifdef when updating Visual Studio + typename ParentFunctor::ImplBase* Clone() const { return Copy(); } #else BaseFunc * Clone() const { return Copy(); } #endif From 3cfb202b03358ebf2d1c4ab0a63f9df2e2e07d17 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 3 Jun 2021 18:38:32 +0200 Subject: [PATCH 054/309] [graf2d] Remove code that forced a segfault if gDebug == gVirtualX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc11 warns about the intentionally broken code: ``` ../io/io/src/TMapFile.cxx:1153:54: note: returned from ‘static void* TObject::operator new(size_t)’ [960/2325] Building CXX object graf2d/x11/CMakeFiles/GX11.dir/src/GX11Gui.cxx.o ../graf2d/x11/src/GX11Gui.cxx: In function ‘Int_t RootX11ErrorHandler(Display*, XErrorEvent*)’: ../graf2d/x11/src/GX11Gui.cxx:179:14: warning: ‘void operator delete(void*, std::size_t)’ called on a pointer to an unallocated object ‘1’ [-Wfree-nonheap-object] 179 | delete kil; | ^~~ ``` --- graf2d/x11/src/GX11Gui.cxx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/graf2d/x11/src/GX11Gui.cxx b/graf2d/x11/src/GX11Gui.cxx index e131cdb26c4ad..413ea8c9d40ad 100644 --- a/graf2d/x11/src/GX11Gui.cxx +++ b/graf2d/x11/src/GX11Gui.cxx @@ -170,16 +170,6 @@ static Int_t RootX11ErrorHandler(Display *disp, XErrorEvent *err) char msg[80]; XGetErrorText(disp, err->error_code, msg, 80); - // force segV. to allow backtracing the error with gdb - if (gDebug == (Long_t)gVirtualX) { - gSystem->ProcessEvents(); - ::Error("RootX11ErrorHandler", "%s (XID: %u, XREQ: %u)", msg, - (UInt_t)err->resourceid, err->request_code); - int *kil = (int*)1; - delete kil; - return 0; - } - if (!err->resourceid) return 0; TObject *w = (TObject *)gROOT->ProcessLineFast(Form("gClient ? gClient->GetWindowById(%lu) : 0", From 66b3edba31dc365cbb86efa64ab0a1537e4aa068 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 3 Jun 2021 18:51:07 +0200 Subject: [PATCH 055/309] [io] Overload `new` as well as `delete` for TMapFile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following gcc11 warnings: ``` [433/2325] Building CXX object io/io/CMakeFiles/RIO.dir/src/TMapFile.cxx.o ../io/io/src/TMapFile.cxx: In constructor ‘TMapFile::TMapFile(const char*, const char*, Option_t*, Int_t, TMapFile*&)’: ../io/io/src/TMapFile.cxx:424:45: warning: ‘static void TMapFile::operator delete(void*)’ called on pointer returned from a mismatched allocation function [-Wmismatched-new-delete] 424 | TMapFile *mf = new TMapFile(*mapfil); | ^ ``` --- io/io/inc/TMapFile.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/io/io/inc/TMapFile.h b/io/io/inc/TMapFile.h index 936bf43d0f457..c9fbb13f965d3 100644 --- a/io/io/inc/TMapFile.h +++ b/io/io/inc/TMapFile.h @@ -77,6 +77,10 @@ friend class TMapRec; // Should both be protected (waiting for cint) virtual ~TMapFile(); + void *operator new(size_t sz) { return TObject::operator new(sz); } + void *operator new[](size_t sz) { return TObject::operator new[](sz); } + void *operator new(size_t sz, void *vp) { return TObject::operator new(sz, vp); } + void *operator new[](size_t sz, void *vp) { return TObject::operator new[](sz, vp); } void operator delete(void *vp); void Browse(TBrowser *b); From 874758f2df01332055a966173a88f0edd733d121 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 3 Jun 2021 19:09:00 +0200 Subject: [PATCH 056/309] [graf3d] Fix definition of gluTessVertex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the mismatch pointed out by this gcc11 warning: ``` [8203/8650] Building C object graf3d/eve7/CMakeFiles/ROOTEve.dir/glu/tess.c.o ../graf3d/eve7/glu/tess.c:425:46: warning: argument 2 of type ‘GLdouble[3]’ {aka ‘double[3]’} with mismatched bound [-Warray-parameter=] 425 | gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) | ~~~~~~~~~^~~~~~~~~ In file included from ../graf3d/eve7/glu/tess.h:38, from ../graf3d/eve7/glu/tess.c:40: ../graf3d/eve7/glu/GL_glu.h:372:69: note: previously declared as ‘GLdouble *’ {aka ‘double *’} 372 | GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data); | ~~~~~~~~~~^~~~~~~~ ``` --- graf3d/eve7/glu/tess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graf3d/eve7/glu/tess.c b/graf3d/eve7/glu/tess.c index a9dd77bba45f2..46e7a43702337 100644 --- a/graf3d/eve7/glu/tess.c +++ b/graf3d/eve7/glu/tess.c @@ -422,7 +422,7 @@ static int EmptyCache( GLUtesselator *tess ) void GLAPIENTRY -gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +gluTessVertex( GLUtesselator *tess, GLdouble *coords, void *data ) { int i, tooLarge = FALSE; GLdouble x, clamped[3]; From 20101d17ba2cf7c74e601be5c94602a9611c2b1d Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 4 Jun 2021 12:08:23 +0200 Subject: [PATCH 057/309] [tree] Sync argument name between header and source This also resolves a gcc11 warning due to `destructor` shadowing a global typedef in a Python header. --- tree/tree/inc/TLeaf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/tree/inc/TLeaf.h b/tree/tree/inc/TLeaf.h index 236dab417e48d..4608fc470f279 100644 --- a/tree/tree/inc/TLeaf.h +++ b/tree/tree/inc/TLeaf.h @@ -155,7 +155,7 @@ class TLeaf : public TNamed { virtual void ReadValue(std::istream & /*s*/, Char_t /*delim*/ = ' ') { Error("ReadValue", "Not implemented!"); } - Int_t ResetAddress(void *add, Bool_t destructor = kFALSE); + Int_t ResetAddress(void *add, Bool_t calledFromDestructor = kFALSE); virtual void SetAddress(void *add = 0); virtual void SetBranch(TBranch *branch) { fBranch = branch; } virtual void SetLeafCount(TLeaf *leaf); From 248782ae4135389a1476fbde801786dc3a58522c Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 4 Jun 2021 15:32:11 +0200 Subject: [PATCH 058/309] [skip-ci] Make sure the link to RBrowser is working. (#8339) --- core/gui/src/TBrowser.cxx | 2 +- documentation/doxygen/images/v7_rbrowser.png | Bin 122602 -> 122566 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/gui/src/TBrowser.cxx b/core/gui/src/TBrowser.cxx index 9a1d4af5d9c39..aaebe03679ef0 100644 --- a/core/gui/src/TBrowser.cxx +++ b/core/gui/src/TBrowser.cxx @@ -23,7 +23,7 @@ contents of the selected class in the icon-box. And so on.... \since **ROOT version 6.24/00** -TBrowser invokes by default the Web-based %ROOT file browser RBrowser +TBrowser invokes by default the Web-based %ROOT file browser [RBrowser](\ref ROOT::Experimental::RBrowser) To change this behaviour, and invoke the standard TBrowser, one should put the following directive in the `.rootrc` file: ``` diff --git a/documentation/doxygen/images/v7_rbrowser.png b/documentation/doxygen/images/v7_rbrowser.png index 93c81d8612d049f35d64d062d03e3f099109392b..f83f27889c2c8ae3a51a9dbb6894f86a1b0b40fe 100644 GIT binary patch delta 90736 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 delta 91075 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 Date: Thu, 3 Jun 2021 17:58:21 +0200 Subject: [PATCH 059/309] [DF] Prefer GetEntriesUnsafe when we know there are no races --- tree/dataframe/src/RDFUtils.cxx | 2 +- tree/dataframe/src/RLoopManager.cxx | 2 +- tree/dataframe/src/RRootDS.cxx | 2 +- tree/dataframe/test/datasource_more.cxx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tree/dataframe/src/RDFUtils.cxx b/tree/dataframe/src/RDFUtils.cxx index 0f83f900cf4d8..6ed36c36a2b08 100644 --- a/tree/dataframe/src/RDFUtils.cxx +++ b/tree/dataframe/src/RDFUtils.cxx @@ -203,7 +203,7 @@ std::string GetBranchOrLeafTypeName(TTree &t, const std::string &colName) } return be->GetClassName(); } - } else if (branch->IsA() == TBranch::Class() && branch->GetListOfLeaves()->GetEntries() == 1) { + } else if (branch->IsA() == TBranch::Class() && branch->GetListOfLeaves()->GetEntriesUnsafe() == 1) { // normal branch (not a TBranchElement): if it has only one leaf, we pick the type of the leaf: // RDF and TTreeReader allow referring to branch.leaf as just branch if branch has only one leaf leaf = static_cast(branch->GetListOfLeaves()->UncheckedAt(0)); diff --git a/tree/dataframe/src/RLoopManager.cxx b/tree/dataframe/src/RLoopManager.cxx index 58288b4b1ba46..65cb3b06ede67 100644 --- a/tree/dataframe/src/RLoopManager.cxx +++ b/tree/dataframe/src/RLoopManager.cxx @@ -149,7 +149,7 @@ static void GetBranchNamesImpl(TTree &t, std::set &bNamesReg, Colum if (branch->IsA() == TBranch::Class()) { // Leaf list auto listOfLeaves = branch->GetListOfLeaves(); - if (listOfLeaves->GetEntries() == 1) { + if (listOfLeaves->GetEntriesUnsafe() == 1) { auto leaf = static_cast(listOfLeaves->UncheckedAt(0)); UpdateList(bNamesReg, bNames, branchName, friendName, foundLeaves, leaf, allowDuplicates); } diff --git a/tree/dataframe/src/RRootDS.cxx b/tree/dataframe/src/RRootDS.cxx index e9736f8c0d346..9f4da07cd1eec 100644 --- a/tree/dataframe/src/RRootDS.cxx +++ b/tree/dataframe/src/RRootDS.cxx @@ -52,7 +52,7 @@ RRootDS::RRootDS(std::string_view treeName, std::string_view fileNameGlob) fModelChain.Add(fFileNameGlob.c_str()); const TObjArray &lob = *fModelChain.GetListOfBranches(); - fListOfBranches.resize(lob.GetEntries()); + fListOfBranches.resize(lob.GetEntriesUnsafe()); TIterCategory iter(&lob); std::transform(iter.Begin(), iter.End(), fListOfBranches.begin(), [](TObject *o) { return o->GetName(); }); diff --git a/tree/dataframe/test/datasource_more.cxx b/tree/dataframe/test/datasource_more.cxx index cd83f6da188a2..1253e15eaaaed 100644 --- a/tree/dataframe/test/datasource_more.cxx +++ b/tree/dataframe/test/datasource_more.cxx @@ -58,7 +58,7 @@ TEST(RArraysDS, SnapshotAndShortSyntaxForCollectionSizes) TFile f(fname); auto *t = f.Get("t"); auto *blist = t->GetListOfBranches(); - EXPECT_EQ(blist->GetEntries(), 1u); + EXPECT_EQ(blist->GetEntriesUnsafe(), 1u); EXPECT_STREQ(blist->At(0)->GetName(), "var"); f.Close(); // Windows does not allow deletion/recreation of files that are still in use. From 31154cae7e94e1bca43cea888c7abd910284aed4 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Fri, 4 Jun 2021 13:20:58 +0200 Subject: [PATCH 060/309] Workaround for MS compiler bug This is a workaround for the issue reported as [Another fatal error C1001: Internal compiler error](https://developercommunity.visualstudio.com/t/another-fatal-error-c1001-internal-compiler-error/1441527) --- tree/dataframe/test/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tree/dataframe/test/CMakeLists.txt b/tree/dataframe/test/CMakeLists.txt index f1dc54dc771fd..fd2b7322ff699 100644 --- a/tree/dataframe/test/CMakeLists.txt +++ b/tree/dataframe/test/CMakeLists.txt @@ -43,6 +43,11 @@ if (imt) ROOT_ADD_GTEST(dataframe_concurrency dataframe_concurrency.cxx LIBRARIES ROOTDataFrame) endif() +if (MSVC) + # TODO: remove this workaround for MS compiler bug #1441527 once fixed + string(REPLACE "-Od -Z7" "-O2" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "-Z7" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +endif() ROOT_ADD_GTEST(datasource_more datasource_more.cxx LIBRARIES ROOTDataFrame) # TODO: RRootDS is in the process of being hidden from users, and it's currently deprecated. # Re-enable these tests after moving RRootDS to the internal namespace From eb0109666774deaa61306d9b482c6a5f0906def9 Mon Sep 17 00:00:00 2001 From: Matevz Tadel Date: Fri, 21 May 2021 15:14:04 -0700 Subject: [PATCH 061/309] REveProjectionManager - rename UpdateDependentElsAndScenes to UpdateDependentElements, remove scene update part as it is not needed with REve stamping. --- .../eve7/inc/ROOT/REveProjectionManager.hxx | 2 +- graf3d/eve7/src/REveProjectionManager.cxx | 27 +++++-------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveProjectionManager.hxx b/graf3d/eve7/inc/ROOT/REveProjectionManager.hxx index 56129240b69fe..625e9e357b948 100644 --- a/graf3d/eve7/inc/ROOT/REveProjectionManager.hxx +++ b/graf3d/eve7/inc/ROOT/REveProjectionManager.hxx @@ -44,7 +44,7 @@ protected: Bool_t fImportEmpty{kFALSE}; // import sub-trees with no projectable elements virtual Bool_t ShouldImport(REveElement *el); - virtual void UpdateDependentElsAndScenes(REveElement *root); + virtual void UpdateDependentElements(REveElement *root); public: REveProjectionManager(REveProjection::EPType_e type = REveProjection::kPT_Unknown); diff --git a/graf3d/eve7/src/REveProjectionManager.cxx b/graf3d/eve7/src/REveProjectionManager.cxx index a6a5cc60774ff..105d57a74d329 100644 --- a/graf3d/eve7/src/REveProjectionManager.cxx +++ b/graf3d/eve7/src/REveProjectionManager.cxx @@ -160,30 +160,15 @@ Bool_t REveProjectionManager::ShouldImport(REveElement *el) } //////////////////////////////////////////////////////////////////////////////// -/// Update dependent elements' bounding box and mark scenes -/// containing element root or its children as requiring a repaint. +/// Update dependent elements' bounding boxes. -void REveProjectionManager::UpdateDependentElsAndScenes(REveElement * /*root*/) +void REveProjectionManager::UpdateDependentElements(REveElement * /*root*/) { for (auto &d: fDependentEls) { TAttBBox* bbox = dynamic_cast(d); if (bbox) bbox->ComputeBBox(); } - - static int warn_count = 0; - if (++warn_count <= 5) - Warning("REveProjectionManager::UpdateDependentElsAndScenes", - "Figure out if scene stamping is still needed."); - /* - List_t scenes; - root->CollectScenes(scenes); - if (root == this) - for (auto &n : fNieces) - n->CollectScenes(scenes); - - REX::gEve->ScenesChanged(scenes); - */ } //////////////////////////////////////////////////////////////////////////////// @@ -259,7 +244,7 @@ REveElement* REveProjectionManager::ImportElements(REveElement* el, AssertBBoxExtents(0.1); StampTransBBox(); - UpdateDependentElsAndScenes(new_el); + UpdateDependentElements(new_el); if (ext_list) AddNiece(new_el); @@ -291,7 +276,7 @@ REveElement* REveProjectionManager::SubImportElements(REveElement* el, AssertBBoxExtents(0.1); StampTransBBox(); - UpdateDependentElsAndScenes(new_el); + UpdateDependentElements(new_el); } return new_el; } @@ -326,7 +311,7 @@ Int_t REveProjectionManager::SubImportChildren(REveElement* el, REveElement* pro AssertBBoxExtents(0.1); StampTransBBox(); - UpdateDependentElsAndScenes(proj_parent); + UpdateDependentElements(proj_parent); } return (Int_t) new_els.size(); } @@ -370,7 +355,7 @@ void REveProjectionManager::ProjectChildren() AssertBBoxExtents(0.1); StampTransBBox(); - UpdateDependentElsAndScenes(this); + UpdateDependentElements(this); } //////////////////////////////////////////////////////////////////////////////// From 358c43727dcca27faa0fc439cb4dcc1af49b71e0 Mon Sep 17 00:00:00 2001 From: alja Date: Tue, 25 May 2021 11:29:34 -0700 Subject: [PATCH 062/309] Add missing initialization --- graf3d/eve7/inc/ROOT/REveDataProxyBuilderBase.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveDataProxyBuilderBase.hxx b/graf3d/eve7/inc/ROOT/REveDataProxyBuilderBase.hxx index 7b01002d765cd..e4a82abf21710 100644 --- a/graf3d/eve7/inc/ROOT/REveDataProxyBuilderBase.hxx +++ b/graf3d/eve7/inc/ROOT/REveDataProxyBuilderBase.hxx @@ -89,9 +89,9 @@ protected: private: REveDataCollection *m_collection{nullptr}; - float m_layer; - bool m_haveWindow; - bool m_modelsChanged; + float m_layer{0.}; + bool m_haveWindow{false}; + bool m_modelsChanged{false}; }; } // namespace Experimental From c97dce3df8303cd30b9fb385d7cc5f6fca1d5f0d Mon Sep 17 00:00:00 2001 From: alja Date: Thu, 27 May 2021 13:35:16 -0700 Subject: [PATCH 063/309] Check validity of function --- graf3d/eve7/inc/ROOT/REveDataTable.hxx | 2 ++ graf3d/eve7/src/REveDataTable.cxx | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveDataTable.hxx b/graf3d/eve7/inc/ROOT/REveDataTable.hxx index 969d5a2dee1c7..ae9606d42a4c8 100644 --- a/graf3d/eve7/inc/ROOT/REveDataTable.hxx +++ b/graf3d/eve7/inc/ROOT/REveDataTable.hxx @@ -59,6 +59,7 @@ public: std::function fBoolFoo; std::function fStringFoo; + public: REveDataColumn(const std::string& n = "REveDataColumn", const std::string& t = ""); virtual ~REveDataColumn() {} @@ -69,6 +70,7 @@ public: void SetPrecision(Int_t prec); std::string EvalExpr(void *iptr) const; + bool hasValidExpression() const; }; diff --git a/graf3d/eve7/src/REveDataTable.cxx b/graf3d/eve7/src/REveDataTable.cxx index 52800a464f882..38591287b7919 100644 --- a/graf3d/eve7/src/REveDataTable.cxx +++ b/graf3d/eve7/src/REveDataTable.cxx @@ -73,14 +73,17 @@ Int_t REveDataTable::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) return ret; } -void REveDataTable::AddNewColumn(const std::string& expr, const std::string& title, int prec) +void REveDataTable::AddNewColumn(const std::string &expr, const std::string &title, int prec) { auto c = new REveDataColumn(title); - AddElement(c); c->SetExpressionAndType(expr, REveDataColumn::FT_Double); c->SetPrecision(prec); + gROOT->ProcessLine(c->GetFunctionExpressionString().c_str()); - StampObjProps(); + if (c->hasValidExpression()) { + AddElement(c); + StampObjProps(); + } } //============================================================================== @@ -130,7 +133,8 @@ std::string REveDataColumn::GetFunctionExpressionString() const } std::stringstream s; - s << "*((std::function<" << rtyp << "(" << fClassType->GetName() << "*)>*)" << std::hex << std::showbase << (size_t)fooptr + s << " *((std::function<" << rtyp << "(" << fClassType->GetName() << "*)>*)" + << std::hex << std::showbase << (size_t)fooptr << ") = [](" << fClassType->GetName() << "* p){" << fClassType->GetName() << " &i=*p; return (" << fExpression.Data() << "); };"; @@ -138,11 +142,17 @@ std::string REveDataColumn::GetFunctionExpressionString() const return s.str(); } +//______________________________________________________________________________ +bool REveDataColumn::hasValidExpression() const +{ + return (fDoubleFoo || fBoolFoo || fStringFoo); +} + //______________________________________________________________________________ std::string REveDataColumn::EvalExpr(void *iptr) const { - if (!(fDoubleFoo || fBoolFoo || fStringFoo)) - gROOT->ProcessLine(GetFunctionExpressionString().c_str()); + if (!hasValidExpression()) + return "ErrFunc"; switch (fType) { @@ -161,5 +171,5 @@ std::string REveDataColumn::EvalExpr(void *iptr) const return fStringFoo(iptr); } } - return "XYZ"; + return "Nn"; } From 16734adcb4934e493db68e0c52fff8d922d95c40 Mon Sep 17 00:00:00 2001 From: alja Date: Thu, 27 May 2021 14:06:22 -0700 Subject: [PATCH 064/309] Check valid function pointer in ApplyFilter() --- graf3d/eve7/src/REveDataCollection.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graf3d/eve7/src/REveDataCollection.cxx b/graf3d/eve7/src/REveDataCollection.cxx index c00d96010f9f6..8c877362b0da4 100644 --- a/graf3d/eve7/src/REveDataCollection.cxx +++ b/graf3d/eve7/src/REveDataCollection.cxx @@ -274,6 +274,9 @@ void REveDataCollection::SetFilterExpr(const char* filter) void REveDataCollection::ApplyFilter() { + if (!fFilterFoo) + return; + Ids_t ids; int idx = 0; for (auto &ii : fItemList->fItems) From a9c61d56afd70b74425779f330a4ec2cc581bb0b Mon Sep 17 00:00:00 2001 From: alja Date: Thu, 3 Jun 2021 15:01:17 -0700 Subject: [PATCH 065/309] Handle RFileDialog requests in REveManager::WindowData() --- graf3d/eve7/src/REveManager.cxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/graf3d/eve7/src/REveManager.cxx b/graf3d/eve7/src/REveManager.cxx index 291260dc93af5..23aa806dc5024 100644 --- a/graf3d/eve7/src/REveManager.cxx +++ b/graf3d/eve7/src/REveManager.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "TGeoManager.h" @@ -787,8 +788,8 @@ void REveManager::WindowData(unsigned connid, const std::string &arg) return; } // client status data - if (arg.compare("__REveDoneChanges") == 0) { - + if (arg.compare("__REveDoneChanges") == 0) + { std::unique_lock lock(fServerState.fMutex); for (auto &conn : fConnList) { @@ -805,6 +806,11 @@ void REveManager::WindowData(unsigned connid, const std::string &arg) return; } + else if (arg.compare( 0, 10, "FILEDIALOG") == 0) + { + RFileDialog::Embedded(fWebWindow, arg); + return; + } nlohmann::json cj = nlohmann::json::parse(arg); if (gDebug > 0) From da1362236173a0d66fe691980bc14b1ea8033c17 Mon Sep 17 00:00:00 2001 From: Oksana Shadura Date: Fri, 4 Jun 2021 16:48:00 +0200 Subject: [PATCH 066/309] Remove not needed fatal message (fixing ##8280) --- CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9843f76e37202..0615ee50b61f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -649,11 +649,10 @@ if(testing) endif() endif() -if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10.0") - if (${CMAKE_MINIMUM_REQUIRED_VERSION} VERSION_GREATER_EQUAL "3.10.0") - message(FATAL_ERROR "Remove this condition") - endif() +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10.0") cmake_host_system_information(RESULT PROCESSOR QUERY PROCESSOR_DESCRIPTION) +else() + set(PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR}) endif() message(STATUS "ROOT Configuration \n From 27cd610c864a07bdd2b883d5e109df9bed1e73e0 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 4 Jun 2021 12:37:09 +0200 Subject: [PATCH 067/309] [DF] Use a RAII object to make sure to always run CleanUpTask Before this patch we skipped running CleanUpTask if the status of the TTreeReader after a single-thread event loop over ROOT data encountered an error. --- tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx | 2 ++ tree/dataframe/src/RLoopManager.cxx | 33 +++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx b/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx index c92083f89c4f4..ab2b438538e17 100644 --- a/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx @@ -95,6 +95,8 @@ class RLoopManager : public RNodeBase { } }; + friend struct RCallCleanUpTask; + std::vector fBookedActions; ///< Non-owning pointers to actions to be run std::vector fRunActions; ///< Non-owning pointers to actions already run std::vector fBookedFilters; diff --git a/tree/dataframe/src/RLoopManager.cxx b/tree/dataframe/src/RLoopManager.cxx index 65cb3b06ede67..04cf99601e6d1 100644 --- a/tree/dataframe/src/RLoopManager.cxx +++ b/tree/dataframe/src/RLoopManager.cxx @@ -294,6 +294,21 @@ DatasetLogInfo TreeDatasetLogInfo(const TTreeReader &r, unsigned int slot) } // anonymous namespace +namespace ROOT { +namespace Detail { +namespace RDF { + +/// A RAII object that calls RLoopManager::CleanUpTask at destruction +struct RCallCleanUpTask { + RLoopManager &fLoopManager; + unsigned int fArg; + ~RCallCleanUpTask() { fLoopManager.CleanUpTask(fArg); } +}; + +} // namespace RDF +} // namespace Detail +} // namespace ROOT + /////////////////////////////////////////////////////////////////////////////// /// Get all the branches names, including the ones of the friend trees ColumnNames_t ROOT::Internal::RDF::GetBranchNames(TTree &t, bool allowDuplicates) @@ -359,6 +374,7 @@ void RLoopManager::RunEmptySourceMT() auto genFunction = [this, &slotStack](const std::pair &range) { RSlotRAII slotRAII(slotStack); auto slot = slotRAII.fSlot; + RCallCleanUpTask cleanup{*this, slot}; InitNodeSlots(nullptr, slot); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing({"an empty source", range.first, range.second, slot}); try { @@ -366,12 +382,10 @@ void RLoopManager::RunEmptySourceMT() RunAndCheckFilters(slot, currEntry); } } catch (...) { - CleanUpTask(slot); // Error might throw in experiment frameworks like CMSSW std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } - CleanUpTask(slot); }; ROOT::TThreadExecutor pool; @@ -385,16 +399,15 @@ void RLoopManager::RunEmptySource() { InitNodeSlots(nullptr, 0); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing({"an empty source", 0, fNEmptyEntries, 0u}); + RCallCleanUpTask cleanup{*this, 0u}; try { for (ULong64_t currEntry = 0; currEntry < fNEmptyEntries && fNStopsReceived < fNChildren; ++currEntry) { RunAndCheckFilters(0, currEntry); } } catch (...) { - CleanUpTask(0u); std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } - CleanUpTask(0u); } /// Run event loop over one or multiple ROOT files, in parallel. @@ -410,6 +423,7 @@ void RLoopManager::RunTreeProcessorMT() tp->Process([this, &slotStack, &entryCount](TTreeReader &r) -> void { RSlotRAII slotRAII(slotStack); auto slot = slotRAII.fSlot; + RCallCleanUpTask cleanup{*this, slot}; InitNodeSlots(&r, slot); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing(TreeDatasetLogInfo(r, slot)); const auto entryRange = r.GetEntriesRange(); // we trust TTreeProcessorMT to call SetEntriesRange @@ -421,11 +435,9 @@ void RLoopManager::RunTreeProcessorMT() RunAndCheckFilters(slot, count++); } } catch (...) { - CleanUpTask(slot); std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } - CleanUpTask(slot); }); #endif // no-op otherwise (will not be called) } @@ -436,6 +448,7 @@ void RLoopManager::RunTreeReader() TTreeReader r(fTree.get(), fTree->GetEntryList()); if (0 == fTree->GetEntriesFast()) return; + RCallCleanUpTask cleanup{*this, 0u}; InitNodeSlots(&r, 0); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing(TreeDatasetLogInfo(r, 0u)); @@ -446,7 +459,6 @@ void RLoopManager::RunTreeReader() RunAndCheckFilters(0, r.GetCurrentEntry()); } } catch (...) { - CleanUpTask(0u); std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } @@ -455,7 +467,6 @@ void RLoopManager::RunTreeReader() throw std::runtime_error("An error was encountered while processing the data. TTreeReader status code is: " + std::to_string(r.GetEntryStatus())); } - CleanUpTask(0u); } /// Run event loop over data accessed through a DataSource, in sequence. @@ -467,6 +478,7 @@ void RLoopManager::RunDataSource() while (!ranges.empty() && fNStopsReceived < fNChildren) { InitNodeSlots(nullptr, 0u); fDataSource->InitSlot(0u, 0ull); + RCallCleanUpTask cleanup{*this, 0u}; try { for (const auto &range : ranges) { const auto start = range.first; @@ -479,11 +491,9 @@ void RLoopManager::RunDataSource() } } } catch (...) { - CleanUpTask(0u); std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } - CleanUpTask(0u); fDataSource->FinaliseSlot(0u); ranges = fDataSource->GetEntryRanges(); } @@ -503,6 +513,7 @@ void RLoopManager::RunDataSourceMT() RSlotRAII slotRAII(slotStack); const auto slot = slotRAII.fSlot; InitNodeSlots(nullptr, slot); + RCallCleanUpTask cleanup{*this, slot}; fDataSource->InitSlot(slot, range.first); const auto start = range.first; const auto end = range.second; @@ -514,11 +525,9 @@ void RLoopManager::RunDataSourceMT() } } } catch (...) { - CleanUpTask(slot); std::cerr << "RDataFrame::Run: event loop was interrupted\n"; throw; } - CleanUpTask(slot); fDataSource->FinaliseSlot(slot); }; From 378872d7a0bef1a14dea2309c12f10b166685c71 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 4 Jun 2021 15:39:02 +0200 Subject: [PATCH 068/309] [json] support utf-8 codes when writing const char* When found special codes which correspond to utf8 coding, convert them to string like \u0444. Let use non-latine symbols in ROOT7 graphics --- io/io/src/TBufferJSON.cxx | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/io/io/src/TBufferJSON.cxx b/io/io/src/TBufferJSON.cxx index 7be95121f9f53..e588fde90cf0f 100644 --- a/io/io/src/TBufferJSON.cxx +++ b/io/io/src/TBufferJSON.cxx @@ -4030,10 +4030,9 @@ void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * len = strlen(value); for (Int_t n = 0; n < len; n++) { - char c = value[n]; - if (c == 0) - break; + unsigned char c = value[n]; switch (c) { + case 0: n = len; break; case '\n': fValue.Append("\\n"); break; case '\t': fValue.Append("\\t"); break; case '\"': fValue.Append("\\\""); break; @@ -4043,10 +4042,26 @@ void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * case '\r': fValue.Append("\\r"); break; case '/': fValue.Append("\\/"); break; default: - if ((c > 31) && (c < 127)) + if (c < 31) { + fValue.Append(TString::Format("\\u%04x", (unsigned)c)); + } else if (c < 0x80) { fValue.Append(c); - else + } else if ((n < len - 1) && ((c & 0xe0) == 0xc0) && ((value[n+1] & 0xc0) == 0x80)) { + unsigned code = ((unsigned)value[n+1] & 0x3f) | (((unsigned) c & 0x1f) << 6); + fValue.Append(TString::Format("\\u%04x", code)); + n++; + } else if ((n < len - 2) && ((c & 0xf0) == 0xe0) && ((value[n+1] & 0xc0) == 0x80) && ((value[n+2] & 0xc0) == 0x80)) { + unsigned code = ((unsigned)value[n+2] & 0x3f) | (((unsigned) value[n+1] & 0x3f) << 6) | (((unsigned) c & 0x0f) << 12); + fValue.Append(TString::Format("\\u%04x", code)); + n+=2; + } else if ((n < len - 3) && ((c & 0xf8) == 0xf0) && ((value[n+1] & 0xc0) == 0x80) && ((value[n+2] & 0xc0) == 0x80) && ((value[n+3] & 0xc0) == 0x80)) { + unsigned code = ((unsigned)value[n+3] & 0x3f) | (((unsigned) value[n+2] & 0x3f) << 6) | (((unsigned) value[n+1] & 0x3f) << 12) | (((unsigned) c & 0x07) << 18); + // TODO: no idea how to add codes which are higher then 0xFFFF + fValue.Append(TString::Format("\\u%04x\\u%04x", code & 0xffff, code >> 16)); + n+=3; + } else { fValue.Append(TString::Format("\\u%04x", (unsigned)c)); + } } } From 941e9dbb70b7a94d974cf7c249e1fc992f03ebb4 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 4 Jun 2021 19:25:42 +0200 Subject: [PATCH 069/309] [json] add utf8 testing for TBufferJSON Checks that creating and parsing JSON with UTF-8 characters works properly --- io/io/test/CMakeLists.txt | 1 + io/io/test/TBufferJSONTests.cxx | 49 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 io/io/test/TBufferJSONTests.cxx diff --git a/io/io/test/CMakeLists.txt b/io/io/test/CMakeLists.txt index 9ffc951a8a652..3fb1e0367c918 100644 --- a/io/io/test/CMakeLists.txt +++ b/io/io/test/CMakeLists.txt @@ -7,6 +7,7 @@ ROOT_ADD_GTEST(RRawFile RRawFile.cxx LIBRARIES RIO) ROOT_ADD_GTEST(TFile TFileTests.cxx LIBRARIES RIO) ROOT_ADD_GTEST(TBufferMerger TBufferMerger.cxx LIBRARIES RIO Imt Tree) +ROOT_ADD_GTEST(TBufferJSON TBufferJSONTests.cxx LIBRARIES RIO) ROOT_ADD_GTEST(TFileMerger TFileMergerTests.cxx LIBRARIES RIO Tree) ROOT_ADD_GTEST(TROMemFile TROMemFileTests.cxx LIBRARIES RIO Tree) if(uring AND NOT DEFINED ENV{ROOTTEST_IGNORE_URING}) diff --git a/io/io/test/TBufferJSONTests.cxx b/io/io/test/TBufferJSONTests.cxx new file mode 100644 index 0000000000000..c874c89cd5e16 --- /dev/null +++ b/io/io/test/TBufferJSONTests.cxx @@ -0,0 +1,49 @@ +#include "TBufferJSON.h" +#include "TNamed.h" +#include + +#include "gtest/gtest.h" + +// check utf8 coding with two bytes - most frequent usecase +TEST(TBufferJSON, utf8_2) +{ + std::string str0 = u8"test \u0444"; // this should be cyrillic letter f + + auto len0 = str0.length(); + + EXPECT_EQ(len0, 7); + + EXPECT_EQ((unsigned char) str0[len0-2], 0xd1); // utf8 coding for \u0444 + EXPECT_EQ((unsigned char) str0[len0-1], 0x84); // utf8 coding for \u0444 + + TNamed named0("name", str0.c_str()); + + auto json = TBufferJSON::ToJSON(&named0); + + auto named1 = TBufferJSON::FromJSON(json.Data()); + + EXPECT_EQ(str0, named1->GetTitle()); +} + +// check utf8 coding with three bytes +TEST(TBufferJSON, utf8_3) +{ + std::string str0 = u8"test \u7546"; // no idea that + + auto len0 = str0.length(); + + EXPECT_EQ(len0, 8); + + EXPECT_EQ((unsigned char) str0[len0-3], 0xe7); + EXPECT_EQ((unsigned char) str0[len0-2], 0x95); + EXPECT_EQ((unsigned char) str0[len0-1], 0x86); + + TNamed named0("name", str0.c_str()); + + auto json = TBufferJSON::ToJSON(&named0); + + auto named1 = TBufferJSON::FromJSON(json.Data()); + + EXPECT_EQ(str0, named1->GetTitle()); +} + From 1ca221f010fdcfb6249ae7b1cac77fbe29b86214 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Mon, 7 Jun 2021 11:02:48 +0200 Subject: [PATCH 070/309] [io] Avoid nullptr deref when printing warning in TStreamerInfo --- io/io/src/TStreamerInfo.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index d545ab7be8e39..a026635890668 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -1109,12 +1109,12 @@ void TStreamerInfo::BuildCheck(TFile *file /* = 0 */, Bool_t load /* = kTRUE */) fClassVersion, GetName(), GetName(), GetName(), fClassVersion); } else { Warning("BuildCheck", "\n\ - The StreamerInfo from %s does not match existing one (%s:%d)\n\ + The StreamerInfo does not match existing one (%s:%d)\n\ The existing one has not been used yet and will be discarded.\n\ Reading should work properly, however writing object of\n\ type %s will not work properly. Most likely the version number\n\ of the class was not properly updated [See ClassDef(%s,%d)].", - file->GetName(), GetName(), fClassVersion, GetName(), GetName(), fClassVersion); + GetName(), fClassVersion, GetName(), GetName(), fClassVersion); } } } From 1c38aa09082f7d18bfcfc128e94f43fd0bc7bc94 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 4 Jun 2021 20:33:07 +0200 Subject: [PATCH 071/309] Test if json_fwd.hpp exists On some platforms external nlohmann/json.hpp installed without such special include. In this case full version has to be used. Provide special define when compile EVE7 which indicates if json_fwd.hpp can be used. In the macros such define is not exported and therefore full version of nlohmann/json.hpp will be used. --- graf3d/eve7/CMakeLists.txt | 15 +++++++++++++++ graf3d/eve7/inc/ROOT/REveElement.hxx | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/graf3d/eve7/CMakeLists.txt b/graf3d/eve7/CMakeLists.txt index 3ef416f52f366..42ba9db04bf7e 100644 --- a/graf3d/eve7/CMakeLists.txt +++ b/graf3d/eve7/CMakeLists.txt @@ -135,8 +135,23 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTEve if(builtin_nlohmannjson) target_include_directories(ROOTEve PRIVATE ${CMAKE_SOURCE_DIR}/builtins) + target_compile_definitions(ROOTEve INTERFACE NLOHMANN_JSON_PROVIDES_FWD_HPP) else() target_link_libraries(ROOTEve PUBLIC nlohmann_json::nlohmann_json) + + get_target_property(inc_dirs nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) + foreach(dir ${inc_dirs}) + if(EXISTS "${dir}/nlohmann/json_fwd.hpp") + set(found_fwd true) + endif() + endforeach() + + if(found_fwd) + target_compile_definitions(ROOTEve INTERFACE NLOHMANN_JSON_PROVIDES_FWD_HPP) + else() + message("-- missing nlohmann/json_fwd.hpp required by eve7") + endif() + endif() # this is required for glew diff --git a/graf3d/eve7/inc/ROOT/REveElement.hxx b/graf3d/eve7/inc/ROOT/REveElement.hxx index d31ba22b6516b..b57ed22b2118a 100644 --- a/graf3d/eve7/inc/ROOT/REveElement.hxx +++ b/graf3d/eve7/inc/ROOT/REveElement.hxx @@ -18,7 +18,11 @@ #include +#ifdef NLOHMANN_JSON_PROVIDES_FWD_HPP #include +#else +#include +#endif class TGeoMatrix; From 47bd4c001c6d83765a70c262ee81a0d09c3d1b46 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 7 Jun 2021 11:59:55 +0200 Subject: [PATCH 072/309] [reve] provide REveRGBAPalette::OnZeroRefCount() implementation When using default REveRefCnt implementation, wrong **this** value used with delete operator because of double inheritance --- graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx b/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx index c48454b17dae2..788491df79f1a 100644 --- a/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx +++ b/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx @@ -152,6 +152,8 @@ public: void SetOverColorPixel(Pixel_t pix); void SetOverColorRGBA(UChar_t r, UChar_t g, UChar_t b, UChar_t a=255); + virtual void OnZeroRefCount() { delete this; } + // ================================================================ ClassDef(REveRGBAPalette, 0); // A generic, speed-optimised mapping from value to RGBA color supporting different wrapping and range truncation modes. From dd36f6353301e975223748e86f3e26fc5953affe Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 7 Jun 2021 12:04:03 +0200 Subject: [PATCH 073/309] [reve] exclude TObject from REveRGBAPalette parent classes No longer required --- graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx | 15 ++++----------- graf3d/eve7/src/REveRGBAPalette.cxx | 2 -- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx b/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx index 788491df79f1a..be5c2e5605b14 100644 --- a/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx +++ b/graf3d/eve7/inc/ROOT/REveRGBAPalette.hxx @@ -14,15 +14,12 @@ #include "ROOT/REveUtil.hxx" -#include "TObject.h" - #include "TMath.h" namespace ROOT { namespace Experimental { -class REveRGBAPalette : public TObject, - public REveRefCnt +class REveRGBAPalette : public REveRefCnt { friend class REveRGBAPaletteEditor; friend class REveRGBAPaletteSubEditor; @@ -33,8 +30,8 @@ public: enum ELimitAction_e { kLA_Cut, kLA_Mark, kLA_Clip, kLA_Wrap }; private: - REveRGBAPalette(const REveRGBAPalette&); // Not implemented - REveRGBAPalette& operator=(const REveRGBAPalette&); // Not implemented + REveRGBAPalette(const REveRGBAPalette&) = delete; + REveRGBAPalette& operator=(const REveRGBAPalette&) = delete; protected: Double_t fUIf; // UI representation calculated as: d = fUIf*i + fUIc @@ -152,14 +149,10 @@ public: void SetOverColorPixel(Pixel_t pix); void SetOverColorRGBA(UChar_t r, UChar_t g, UChar_t b, UChar_t a=255); - virtual void OnZeroRefCount() { delete this; } - - // ================================================================ + void OnZeroRefCount() override { delete this; } - ClassDef(REveRGBAPalette, 0); // A generic, speed-optimised mapping from value to RGBA color supporting different wrapping and range truncation modes. }; - /******************************************************************************/ // Inlines for REveRGBAPalette /******************************************************************************/ diff --git a/graf3d/eve7/src/REveRGBAPalette.cxx b/graf3d/eve7/src/REveRGBAPalette.cxx index 74b61783da3fb..bb900a348484d 100644 --- a/graf3d/eve7/src/REveRGBAPalette.cxx +++ b/graf3d/eve7/src/REveRGBAPalette.cxx @@ -34,7 +34,6 @@ ClassImp(REveRGBAPalette); /// Constructor. REveRGBAPalette::REveRGBAPalette() : - TObject(), REveRefCnt(), fUIf(1), fUIc(0), @@ -67,7 +66,6 @@ REveRGBAPalette::REveRGBAPalette() : REveRGBAPalette::REveRGBAPalette(Int_t min, Int_t max, Bool_t interp, Bool_t showdef, Bool_t fixcolrng) : - TObject(), REveRefCnt(), fUIf(1), fUIc(0), From 3f14846242f8339082523bcbe87542c786552db7 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 7 Jun 2021 12:12:12 +0200 Subject: [PATCH 074/309] [reve] provide also REveFrameBox::OnZeroRefCount Only final class can make proper "delete this" call --- graf3d/eve7/inc/ROOT/REveFrameBox.hxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveFrameBox.hxx b/graf3d/eve7/inc/ROOT/REveFrameBox.hxx index 5f478252cb731..4035f19f1de6d 100644 --- a/graf3d/eve7/inc/ROOT/REveFrameBox.hxx +++ b/graf3d/eve7/inc/ROOT/REveFrameBox.hxx @@ -23,8 +23,8 @@ public: enum EFrameType_e { kFT_None, kFT_Quad, kFT_Box }; private: - REveFrameBox(const REveFrameBox&); // Not implemented - REveFrameBox& operator=(const REveFrameBox&); // Not implemented + REveFrameBox(const REveFrameBox&) = delete; + REveFrameBox& operator=(const REveFrameBox&) = delete; protected: EFrameType_e fFrameType; @@ -85,6 +85,8 @@ public: Bool_t GetDrawBack() const { return fDrawBack; } void SetDrawBack(Bool_t f) { fDrawBack = f; } + void OnZeroRefCount() override { delete this; } + }; } // namespace Experimental From 7e92c386c2954241844bf4f1a0370c77509510a1 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 7 Jun 2021 12:17:05 +0200 Subject: [PATCH 075/309] [reve] make REveRefCnt::OnZeroRefCount() abstract To ensure that all derived classes properly implement it --- graf3d/eve7/inc/ROOT/REveUtil.hxx | 16 ++++++++-------- graf3d/eve7/src/REveUtil.cxx | 29 ----------------------------- 2 files changed, 8 insertions(+), 37 deletions(-) diff --git a/graf3d/eve7/inc/ROOT/REveUtil.hxx b/graf3d/eve7/inc/ROOT/REveUtil.hxx index 8ad8b2aff2e7f..01f74de3c95a2 100644 --- a/graf3d/eve7/inc/ROOT/REveUtil.hxx +++ b/graf3d/eve7/inc/ROOT/REveUtil.hxx @@ -101,6 +101,9 @@ public: class REveRefCnt { + REveRefCnt(const REveRefCnt &) = delete; + REveRefCnt &operator=(const REveRefCnt &) = delete; + protected: Int_t fRefCount{0}; @@ -108,9 +111,6 @@ public: REveRefCnt() = default; virtual ~REveRefCnt() {} - REveRefCnt(const REveRefCnt &) : fRefCount(0) {} - REveRefCnt &operator=(const REveRefCnt &) { return *this; } - void IncRefCount() { ++fRefCount; } void DecRefCount() { @@ -118,7 +118,7 @@ public: OnZeroRefCount(); } - virtual void OnZeroRefCount() { delete this; } + virtual void OnZeroRefCount() = 0; }; //////////////////////////////////////////////////////////////////////////////// @@ -128,18 +128,18 @@ public: class REveRefBackPtr : public REveRefCnt { + REveRefBackPtr(const REveRefBackPtr &) = delete; + REveRefBackPtr &operator=(const REveRefBackPtr &) = delete; + protected: typedef std::map RefMap_t; RefMap_t fBackRefs; public: - REveRefBackPtr(); + REveRefBackPtr() = default; virtual ~REveRefBackPtr(); - REveRefBackPtr(const REveRefBackPtr &); - REveRefBackPtr &operator=(const REveRefBackPtr &); - using REveRefCnt::DecRefCount; using REveRefCnt::IncRefCount; virtual void IncRefCount(REveElement *re); diff --git a/graf3d/eve7/src/REveUtil.cxx b/graf3d/eve7/src/REveUtil.cxx index 4669d2c091328..b01877c618461 100644 --- a/graf3d/eve7/src/REveUtil.cxx +++ b/graf3d/eve7/src/REveUtil.cxx @@ -383,15 +383,6 @@ Base-class for reference-counted objects with reverse references to REveElement objects. */ -//////////////////////////////////////////////////////////////////////////////// -/// Default constructor. - -REveRefBackPtr::REveRefBackPtr() : - REveRefCnt(), - fBackRefs() -{ -} - //////////////////////////////////////////////////////////////////////////////// /// Destructor. Noop, should complain if back-ref list is not empty. @@ -400,26 +391,6 @@ REveRefBackPtr::~REveRefBackPtr() // !!! Complain if list not empty. } -//////////////////////////////////////////////////////////////////////////////// -/// Copy constructor. New copy starts with zero reference count and -/// empty back-reference list. - -REveRefBackPtr::REveRefBackPtr(const REveRefBackPtr&) : - REveRefCnt(), - fBackRefs() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -/// Assignment operator. Reference count and back-reference -/// information is not assigned as these object hold pointers to a -/// specific object. - -REveRefBackPtr& REveRefBackPtr::operator=(const REveRefBackPtr&) -{ - return *this; -} - //////////////////////////////////////////////////////////////////////////////// /// Increase reference count and add re to the list of back-references. From 5d20599d462bff98fe05723015a106c63de1c2b6 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 7 Jun 2021 12:21:57 +0200 Subject: [PATCH 076/309] [eve] provide OnZeroRefCount() in derived from TEveRefCnt classes Fixing same kind of error as in REve classes, but do not declare method in base class as abstract --- graf3d/eve/inc/TEveFrameBox.h | 2 ++ graf3d/eve/inc/TEveRGBAPalette.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/graf3d/eve/inc/TEveFrameBox.h b/graf3d/eve/inc/TEveFrameBox.h index a0abbcf284b2e..cd8c05882e461 100644 --- a/graf3d/eve/inc/TEveFrameBox.h +++ b/graf3d/eve/inc/TEveFrameBox.h @@ -85,6 +85,8 @@ class TEveFrameBox : public TObject, public TEveRefBackPtr Bool_t GetDrawBack() const { return fDrawBack; } void SetDrawBack(Bool_t f) { fDrawBack = f; } + virtual void OnZeroRefCount() { delete this; } + ClassDef(TEveFrameBox, 0); // Description of a 2D or 3D frame that can be used to visually group a set of objects. }; diff --git a/graf3d/eve/inc/TEveRGBAPalette.h b/graf3d/eve/inc/TEveRGBAPalette.h index 96b046f3ca829..e9a77af50e107 100644 --- a/graf3d/eve/inc/TEveRGBAPalette.h +++ b/graf3d/eve/inc/TEveRGBAPalette.h @@ -151,6 +151,8 @@ class TEveRGBAPalette : public TObject, void SetOverColorPixel(Pixel_t pix); void SetOverColorRGBA(UChar_t r, UChar_t g, UChar_t b, UChar_t a=255); + virtual void OnZeroRefCount() { delete this; } + // ================================================================ void MinMaxValChanged(); // *SIGNAL* From 474d83387163176aaf73c9987fec1a5cb2f278da Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Tue, 8 Jun 2021 02:46:18 +0200 Subject: [PATCH 077/309] Add TTreeProcessorMP to LinkDef This fixes test failure: 745/1157 Test #729: tutorial-multicore-mp102_readNtuplesFillHistosAndFit ................***Failed 1.55 sec Processing /builddir/build/BUILD/root-6.25.01/tutorials/multicore/mp102_readNtuplesFillHistosAndFit.C... IncrementalExecutor::executeFunction: symbol '_ZN4ROOT16TTreeProcessorMPC1Ej' unresolved while linking [cling interface function]! You are probably missing the definition of ROOT::TTreeProcessorMP::TTreeProcessorMP(unsigned int) Maybe you need to load the corresponding shared library? IncrementalExecutor::executeFunction: symbol '_ZN4ROOT16TTreeProcessorMP11ReplyToIdleEP7TSocket' unresolved while linking [cling interface function]! You are probably missing the definition of ROOT::TTreeProcessorMP::ReplyToIdle(TSocket*) Maybe you need to load the corresponding shared library? CMake Error at /builddir/build/BUILD/root-6.25.01/x86_64-redhat-linux-gnu/RootTestDriver.cmake:237 (message): error code: 1 --- tree/treeplayer/inc/LinkDef.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/treeplayer/inc/LinkDef.h b/tree/treeplayer/inc/LinkDef.h index e7fdd7c9bf3a7..d195536a40e42 100644 --- a/tree/treeplayer/inc/LinkDef.h +++ b/tree/treeplayer/inc/LinkDef.h @@ -30,6 +30,7 @@ #pragma link C++ class TSimpleAnalysis+; #ifndef _MSC_VER #pragma link C++ class TMPWorkerTree+; +#pragma link C++ class ROOT::TTreeProcessorMP-; #endif #ifdef R__USE_IMT #pragma link C++ class ROOT::TTreeProcessorMT-; From e8ac18967f342aefb4d2eecc75d7a3ac920aff31 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 7 Jun 2021 19:08:46 +0200 Subject: [PATCH 078/309] [RF] Set plot norm variables in RooAbsPdf::plotOn before using them The first call to `frame->updateNormVars(*frame->getPlotVar())` should be made before the first call to `frame->getNormVars()` in the `RooAbsPdf::plotOn` function. This fixes the Jira issue ROOT-5529. --- roofit/roofitcore/src/RooAbsPdf.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/roofit/roofitcore/src/RooAbsPdf.cxx b/roofit/roofitcore/src/RooAbsPdf.cxx index 9b67ce5ca5db6..b6476161f2524 100644 --- a/roofit/roofitcore/src/RooAbsPdf.cxx +++ b/roofit/roofitcore/src/RooAbsPdf.cxx @@ -2970,6 +2970,7 @@ RooPlot* RooAbsPdf::plotOn(RooPlot* frame, RooLinkedList& cmdList) const << "): ERROR the 'Expected' scale option can only be used on extendable PDFs" << endl ; return frame ; } + frame->updateNormVars(*frame->getPlotVar()) ; nExpected = expectedEvents(frame->getNormVars()) ; } @@ -3185,6 +3186,7 @@ RooPlot* RooAbsPdf::plotOn(RooPlot *frame, PlotOpt o) const << "): ERROR the 'Expected' scale option can only be used on extendable PDFs" << endl ; return frame ; } + frame->updateNormVars(*frame->getPlotVar()) ; nExpected = expectedEvents(frame->getNormVars()) ; } From cff4b09d1505cca387458028478cc4e8fdb4c11e Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 8 Jun 2021 02:14:25 +0200 Subject: [PATCH 079/309] [RF] Handle nullptr or empty norm set ambiguity in RooAbsReal::getVal The downsteam code, -- like RooAddPdf::getValV for example -- assume that a nullptr is passed when no normalization is requested. The case of an empty norm set is not handled correctly in RooAddPdf::getValV, leading to wrong results. However, some calling code passes an empty norm set to RooAbsReal::getVal instead of a `nullptr` in an attempt to disable normalization. This commit suggests to solve this ambiguity at the highest possible level: right at the beginning of RooAbsReal::getVal. If the normalization set is empty, the pointer pointing to it will be set to `nullptr`. This fixes issue #8307. --- roofit/roofitcore/inc/RooAbsReal.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/roofit/roofitcore/inc/RooAbsReal.h b/roofit/roofitcore/inc/RooAbsReal.h index 465407e5325b2..53eb63fea1119 100644 --- a/roofit/roofitcore/inc/RooAbsReal.h +++ b/roofit/roofitcore/inc/RooAbsReal.h @@ -89,6 +89,14 @@ class RooAbsReal : public RooAbsArg { /// These are integrated over their current ranges to compute the normalisation constant, /// and the unnormalised result is divided by this value. inline Double_t getVal(const RooArgSet* normalisationSet = nullptr) const { + // Sometimes, the calling code uses an empty RooArgSet to request evaluation + // without normalization set instead of following the `nullptr` convention. + // To remove this ambiguity which might not always be correctly handled in + // downstream code, we set `normalisationSet` to nullptr if it is pointing + // to an empty set. + if(normalisationSet && normalisationSet->empty()) { + normalisationSet = nullptr; + } #ifdef ROOFIT_CHECK_CACHED_VALUES return _DEBUG_getVal(normalisationSet); #else @@ -103,7 +111,13 @@ class RooAbsReal : public RooAbsArg { } /// Like getVal(const RooArgSet*), but always requires an argument for normalisation. - inline Double_t getVal(const RooArgSet& normalisationSet) const { return _fast ? _value : getValV(&normalisationSet) ; } + inline Double_t getVal(const RooArgSet& normalisationSet) const { + // Sometimes, the calling code uses an empty RooArgSet to request evaluation + // without normalization set instead of following the `nullptr` convention. + // To remove this ambiguity which might not always be correctly handled in + // downstream code, we set `normalisationSet` to nullptr if it is an empty set. + return _fast ? _value : getValV(normalisationSet.empty() ? nullptr : &normalisationSet) ; + } virtual Double_t getValV(const RooArgSet* normalisationSet = nullptr) const ; From 2029decb99436a2160fd88b8db460ec52efda6e5 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 8 Jun 2021 02:21:59 +0200 Subject: [PATCH 080/309] [RF] Add unit test for RooSimultaneous that covers #8307 --- roofit/roofitcore/test/CMakeLists.txt | 1 + .../roofitcore/test/testRooSimultaneous.cxx | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 roofit/roofitcore/test/testRooSimultaneous.cxx diff --git a/roofit/roofitcore/test/CMakeLists.txt b/roofit/roofitcore/test/CMakeLists.txt index 7b55450808091..85e69a85a6afc 100644 --- a/roofit/roofitcore/test/CMakeLists.txt +++ b/roofit/roofitcore/test/CMakeLists.txt @@ -37,4 +37,5 @@ if(NOT MSVC OR win_broken_tests) endif() ROOT_ADD_GTEST(testRooProductPdf testRooProductPdf.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testNaNPacker testNaNPacker.cxx LIBRARIES RooFitCore) +ROOT_ADD_GTEST(testRooSimultaneous testRooSimultaneous.cxx LIBRARIES RooFitCore RooFit) diff --git a/roofit/roofitcore/test/testRooSimultaneous.cxx b/roofit/roofitcore/test/testRooSimultaneous.cxx new file mode 100644 index 0000000000000..1d9afb7b9297c --- /dev/null +++ b/roofit/roofitcore/test/testRooSimultaneous.cxx @@ -0,0 +1,49 @@ +// Tests for the RooSimultaneous +// Authors: Jonas Rembser, CERN 06/2021 + +#include "RooAddPdf.h" +#include "RooConstVar.h" +#include "RooCategory.h" +#include "RooDataSet.h" +#include "RooGaussian.h" +#include "RooRealVar.h" +#include "RooSimultaneous.h" +#include "RooProdPdf.h" + +#include "gtest/gtest.h" + +#include + +/// GitHub issue #8307. +/// A likelihood with a model wrapped in a RooSimultaneous ith one category +/// should give the same results as the likelihood with the model directly. +TEST(RooSimultaneous, ImportFromTreeWithCut) +{ + using namespace RooFit; + + RooRealVar x("x", "x", 0, 10); + RooRealVar mean("mean", "mean", 1., 0, 10); + RooRealVar width("width", "width", 1, 0.1, 10); + RooRealVar nsig("nsig", "nsig", 500, 100, 1000); + + RooGaussian gauss1("gauss1", "gauss1", x, mean, width); + RooGaussian fconstraint("fconstraint", "fconstraint", mean, RooConst(2.0), RooConst(0.2)); + + RooAddPdf model("model", "model", RooArgList(gauss1), RooArgList(nsig)); + RooProdPdf modelConstrained("modelConstrained", "modelConstrained", RooArgSet(model, fconstraint)); + + RooCategory cat("cat", "cat"); + cat.defineType("physics"); + + RooSimultaneous modelSim("modelSim", "modelSim", RooArgList{modelConstrained}, cat); + + std::unique_ptr data{model.generate(x)}; + RooDataSet combData("combData", "combData", x, Index(cat), Import("physics", *data)); + + RooArgSet constraints{fconstraint}; + + std::unique_ptr nllDirect{modelConstrained.createNLL(combData, Constrain(constraints))}; + std::unique_ptr nllSimWrapped{modelSim.createNLL(combData, Constrain(constraints))}; + + EXPECT_FLOAT_EQ(nllDirect->getVal(), nllSimWrapped->getVal()); +} From 3c63384568ca255e934f15f797b1201895527b21 Mon Sep 17 00:00:00 2001 From: YuryYury Date: Sun, 6 Jun 2021 23:01:02 +0300 Subject: [PATCH 081/309] Cosmetic changes in ALittleC++.md for better readability Cosmetic changes --- documentation/users-guide/ALittleC++.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/users-guide/ALittleC++.md b/documentation/users-guide/ALittleC++.md index 99b508a7a58ed..bd09d528d6dc6 100644 --- a/documentation/users-guide/ALittleC++.md +++ b/documentation/users-guide/ALittleC++.md @@ -68,10 +68,10 @@ build and draw a line, we have to do: l.Draw(); ``` -The first line builds the object `l `by calling its constructor. The +The first line builds the object `l` by calling its constructor. The second line calls the **`TLine`**`::Draw()` method of this object. You don't need to pass any parameters to this method since it applies to -the object l, which knows the coordinates of the line. These are +the object `l`, which knows the coordinates of the line. These are internal variables `x1`, `y1`, `x2`, `y2` that were initialized by the constructor. From 01c1c76911cf5cd3c43db8fb61e9a0eda328d052 Mon Sep 17 00:00:00 2001 From: YuryYury Date: Sun, 6 Jun 2021 22:34:55 +0300 Subject: [PATCH 082/309] Fixing a typo in FittingHistograms.md Adding a missing closing double quote. --- documentation/users-guide/FittingHistograms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/users-guide/FittingHistograms.md b/documentation/users-guide/FittingHistograms.md index d5d3e07adc52e..79ad9fc3d6eac 100644 --- a/documentation/users-guide/FittingHistograms.md +++ b/documentation/users-guide/FittingHistograms.md @@ -137,7 +137,7 @@ The list of pre-defined functions that can be used with the `Fit` method is the - "`landau`" Landau function with mean and sigma. This function has been adapted from the `CERNLIB` routine `G110 denlan` (see `TMath::Landau`). -- "`gausn` Normalized form of the gaussian function with 3 parameters +- "`gausn`" Normalized form of the gaussian function with 3 parameters `f(x) = p0*exp(-0.5*((x-p1)/p2)^2)/(p2 *sqrt(2PI))` From 5cb45ede9f077fe48ad542903d2590c1b03609f8 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 4 Jun 2021 18:58:00 +0200 Subject: [PATCH 083/309] [DF] Fix Book with helper that takes no columns Recent changes that added support for jitted Book actions broke the edge case in which the action helper takes no columns: `df.Book(Helper{}, {})` now means "jit this action" rather than "this action does not take any columns". With this patch, we resolve this ambiguity at runtime by looking at the list of column names. A helper type is used to make sure that compilation is fine in all cases. --- tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index 348bb77063452..ba1e54f72150c 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -2426,7 +2426,12 @@ public: auto hPtr = std::make_shared(std::forward(helper)); auto resPtr = hPtr->GetResultPtr(); - return CreateAction(columns, resPtr, hPtr, columns.size()); + if (std::is_same::value && columns.empty()) { + return CallCreateActionWithoutColsIfPossible(resPtr, hPtr, TTraits::TypeList{}); + } else { + return CreateAction(columns, resPtr, hPtr, + columns.size()); + } } //////////////////////////////////////////////////////////////////////////// @@ -2729,6 +2734,25 @@ private: return cachedRDF; } + template + auto CallCreateActionWithoutColsIfPossible(const std::shared_ptr &resPtr, + const std::shared_ptr &hPtr, + TTraits::TypeList) + -> decltype(hPtr->Exec(0u), RResultPtr{}) + { + return CreateAction(/*columns=*/{}, resPtr, hPtr, 0u); + } + + template + RResultPtr + CallCreateActionWithoutColsIfPossible(const std::shared_ptr &, Others...) + { + throw std::logic_error(std::string("An action was booked with no input columns, but the action requires " + "columns! The action helper type was ") + + typeid(Helper).name()); + return {}; + } + protected: RInterface(const std::shared_ptr &proxied, RLoopManager &lm, const RDFInternal::RBookedDefines &columns, RDataSource *ds) From 5ab00fc8abe4b18987971d4cef28ab609eee893d Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Mon, 7 Jun 2021 11:30:11 +0200 Subject: [PATCH 084/309] [DF] Add test for Book with a helper that reads no columns --- tree/dataframe/test/CounterHelper.h | 27 +++++++++++++++++++++ tree/dataframe/test/dataframe_interface.cxx | 9 +++++++ 2 files changed, 36 insertions(+) create mode 100644 tree/dataframe/test/CounterHelper.h diff --git a/tree/dataframe/test/CounterHelper.h b/tree/dataframe/test/CounterHelper.h new file mode 100644 index 0000000000000..17c1bb863bc86 --- /dev/null +++ b/tree/dataframe/test/CounterHelper.h @@ -0,0 +1,27 @@ +#ifndef ROOT_RDF_COUNTERHELPER +#define ROOT_RDF_COUNTERHELPER + +#include + +#include +#include +#include + +class CounterHelper : public ROOT::Detail::RDF::RActionImpl { + std::shared_ptr fNCalls; // final result +public: + CounterHelper() : fNCalls(std::make_shared(0u)) {} + CounterHelper(CounterHelper &&) = default; + CounterHelper(const CounterHelper &) = delete; + + using Result_t = std::atomic_uint; + std::shared_ptr GetResultPtr() const { return fNCalls; } + void Initialize() {} + void InitTask(TTreeReader *, unsigned int) {} + void Exec(unsigned int) { ++(*fNCalls); } + void Finalize() {} + + std::string GetActionName() { return "ThreadSafeCounter"; } +}; + +#endif diff --git a/tree/dataframe/test/dataframe_interface.cxx b/tree/dataframe/test/dataframe_interface.cxx index b2d14f416d5f7..9638c00025826 100644 --- a/tree/dataframe/test/dataframe_interface.cxx +++ b/tree/dataframe/test/dataframe_interface.cxx @@ -1,3 +1,6 @@ +#include "CounterHelper.h" +#include "MaxSlotHelper.h" + #include "ROOT/RCsvDS.hxx" #include "ROOT/RDataFrame.hxx" #include "ROOT/RStringView.hxx" @@ -756,3 +759,9 @@ TEST(RDataFrameInterface, MutableForeach) ROOT::RDataFrame(10).Foreach([&](ULong64_t) mutable { ++i; }, {"rdfentry_"}); EXPECT_EQ(i, 10); } + +TEST(RDataFrameInterface, BookWithoutColumns) +{ + EXPECT_EQ(ROOT::RDataFrame(3).Book<>(CounterHelper()).GetValue(), 3); + EXPECT_THROW(ROOT::RDataFrame(3).Book(MaxSlotHelper(1u)), std::logic_error); +} From 0c06dfe9b157feaca0a9a035788af3412a0bde71 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 4 Jun 2021 09:24:12 +0200 Subject: [PATCH 085/309] [rbox] use directly border and fill attributes No need for intermediate RAttrBox, which makes syntax too long --- graf2d/gpadv7/test/attribute.cxx | 80 +++++++++++++------------ graf2d/gpadv7/test/rstyle.cxx | 18 +++--- graf2d/primitivesv7/inc/ROOT/RBox.hxx | 22 +++---- graf2d/primitivesv7/test/primitives.cxx | 14 ++--- tutorials/v7/box.cxx | 30 +++++----- tutorials/v7/draw_frame.cxx | 4 +- 6 files changed, 88 insertions(+), 80 deletions(-) diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index 308870541c156..36933827f778c 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -1,23 +1,29 @@ #include "gtest/gtest.h" #include "ROOT/RAttrText.hxx" -#include "ROOT/RAttrBox.hxx" - +#include "ROOT/RAttrFill.hxx" +#include "ROOT/RAttrLine.hxx" using namespace ROOT::Experimental; class CustomAttrs : public RAttrBase { - RAttrBox fAttrBox{this, "box"}; - RAttrText fAttrText{this, "text"}; + RAttrLine fAttrLine{this, "line"}; ///AddBlock("custom").AddDouble("line_width", 2.); - style->AddBlock("#customid").AddInt("box_fill_style", 5); + style->AddBlock("#customid").AddInt("fill_style", 5); style->AddBlock(".custom_class").AddDouble("text_size", 3.); @@ -61,7 +61,7 @@ TEST(RStyleTest, CreateStyle) EXPECT_DOUBLE_EQ(drawable.GetAttrLine().GetWidth(), 2.); - EXPECT_EQ(drawable.AttrBox().GetAttrFill().GetStyle(), 5); + EXPECT_EQ(drawable.GetAttrFill().GetStyle(), 5); EXPECT_DOUBLE_EQ(drawable.GetAttrText().GetSize(), 3.); } @@ -70,7 +70,7 @@ TEST(RStyleTest, CreateStyle) TEST(RStyleTest, CreateCss) { auto style = RStyle::Parse(" custom { line_width: 2; line_color: red; }" - " #customid { box_fill_style: 5; }" + " #customid { fill_style: 5; }" " .custom_class { text_size: 3; }"); ASSERT_NE(style, nullptr); @@ -85,7 +85,7 @@ TEST(RStyleTest, CreateCss) EXPECT_EQ(drawable.GetAttrLine().GetColor(), RColor::kRed); - EXPECT_EQ(drawable.AttrBox().GetAttrFill().GetStyle(), 5); + EXPECT_EQ(drawable.GetAttrFill().GetStyle(), 5); EXPECT_DOUBLE_EQ(drawable.GetAttrText().GetSize(), 3.); } diff --git a/graf2d/primitivesv7/inc/ROOT/RBox.hxx b/graf2d/primitivesv7/inc/ROOT/RBox.hxx index eb6c86303faef..405aeb63a1b59 100644 --- a/graf2d/primitivesv7/inc/ROOT/RBox.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RBox.hxx @@ -10,7 +10,8 @@ #define ROOT7_RBox #include -#include +#include +#include #include #include @@ -30,8 +31,9 @@ namespace Experimental { class RBox : public RDrawable, public RAttrOnFrame { - RPadPos fP1, fP2; ///< box corners coordinates - RAttrBox fAttrBox{this, "box"}; ///(RPadPos(0.1_normal, 0.3_normal), RPadPos(0.3_normal,0.6_normal)); - box->AttrBox().AttrBorder().SetColor(RColor::kRed).SetWidth(5.).SetStyle(7); - box->AttrBox().AttrFill().SetColor(RColor::kBlue).SetStyle(6); + box->AttrBorder().SetColor(RColor::kRed).SetWidth(5.).SetStyle(7); + box->AttrFill().SetColor(RColor::kBlue).SetStyle(6); EXPECT_EQ(canv.NumPrimitives(), 1u); - EXPECT_EQ(box->GetAttrBox().GetAttrBorder().GetColor(), RColor::kRed); - EXPECT_DOUBLE_EQ(box->GetAttrBox().GetAttrBorder().GetWidth(), 5.); - EXPECT_EQ(box->GetAttrBox().GetAttrBorder().GetStyle(), 7); + EXPECT_EQ(box->GetAttrBorder().GetColor(), RColor::kRed); + EXPECT_DOUBLE_EQ(box->GetAttrBorder().GetWidth(), 5.); + EXPECT_EQ(box->GetAttrBorder().GetStyle(), 7); - EXPECT_EQ(box->GetAttrBox().GetAttrFill().GetColor(), RColor::kBlue); - EXPECT_EQ(box->GetAttrBox().GetAttrFill().GetStyle(), 6); + EXPECT_EQ(box->GetAttrFill().GetColor(), RColor::kBlue); + EXPECT_EQ(box->GetAttrFill().GetStyle(), 6); } // Test RLine API diff --git a/tutorials/v7/box.cxx b/tutorials/v7/box.cxx index 5d0b300ad4f73..1fa0f4d3dfd63 100644 --- a/tutorials/v7/box.cxx +++ b/tutorials/v7/box.cxx @@ -16,35 +16,35 @@ #include "ROOT/RCanvas.hxx" #include "ROOT/RColor.hxx" #include "ROOT/RBox.hxx" -#include +#include "ROOT/RPadPos.hxx" void box() { using namespace ROOT::Experimental; // Create a canvas to be displayed. - auto canvas = RCanvas::Create("Canvas Title"); + auto canvas = RCanvas::Create("RBox drawing"); - auto Box1 = canvas->Draw(RPadPos(0.1_normal, 0.3_normal), RPadPos(0.3_normal,0.6_normal)); + auto box1 = canvas->Draw(RPadPos(0.1_normal, 0.3_normal), RPadPos(0.3_normal,0.6_normal)); RColor Color1(0, 255, 0, 0.5); // 50% opaque RColor Color2(0, 0, 255, 0.7); // 70% opaque - Box1->AttrBox().AttrBorder().SetColor(Color1).SetWidth(5); - Box1->AttrBox().AttrFill().SetColor(RColor::kRed); + box1->AttrBorder().SetColor(Color1).SetWidth(5); + box1->AttrFill().SetColor(RColor::kRed); - auto Box2 = canvas->Draw(RPadPos(0.4_normal, 0.2_normal), RPadPos(0.6_normal,0.7_normal)); - Box2->AttrBox().AttrBorder().SetColor(Color2).SetStyle(2).SetWidth(10); - Box2->AttrBox().AttrFill().SetColor(RColor::kGreen); + auto box2 = canvas->Draw(RPadPos(0.4_normal, 0.2_normal), RPadPos(0.6_normal,0.7_normal)); + box2->AttrBorder().SetColor(Color2).SetStyle(2).SetWidth(10); + box2->AttrFill().SetColor(RColor::kGreen); - auto Box3 = canvas->Draw(RPadPos(0.7_normal, 0.4_normal), RPadPos(0.9_normal,0.6_normal)); - Box3->AttrBox().AttrBorder().SetWidth(3); - Box3->AttrBox().AttrFill().SetColor(RColor::kBlue); + auto box3 = canvas->Draw(RPadPos(0.7_normal, 0.4_normal), RPadPos(0.9_normal,0.6_normal)); + box3->AttrBorder().SetWidth(3); + box3->AttrFill().SetColor(RColor::kBlue); - auto Box4 = canvas->Draw(RPadPos(0.7_normal, 0.7_normal), RPadPos(0.9_normal,0.9_normal)); - Box4->AttrBox().AttrBorder().SetWidth(3); + auto box4 = canvas->Draw(RPadPos(0.7_normal, 0.7_normal), RPadPos(0.9_normal,0.9_normal)); + box4->AttrBorder().SetWidth(3); - auto Box5 = canvas->Draw(RPadPos(0.7_normal, 0.1_normal), RPadPos(0.9_normal,0.3_normal)); - Box5->AttrBox().AttrBorder().SetWidth(3); + auto box5 = canvas->Draw(RPadPos(0.7_normal, 0.1_normal), RPadPos(0.9_normal,0.3_normal)); + box5->AttrBorder().SetWidth(3); canvas->Show(); } diff --git a/tutorials/v7/draw_frame.cxx b/tutorials/v7/draw_frame.cxx index 5ad79f0b6500d..4b6f5d95904c7 100644 --- a/tutorials/v7/draw_frame.cxx +++ b/tutorials/v7/draw_frame.cxx @@ -91,7 +91,7 @@ void draw_frame() // draw box before line at same position as line ending with 40x40 px size and clipping on auto box4 = canvas->Draw(RPadPos(80_user - 20_px, 80_user - 20_px), RPadPos(80_user + 20_px, 80_user + 20_px)); - box4->AttrBox().AttrFill().SetColor(RColor::kBlue); + box4->AttrFill().SetColor(RColor::kBlue); box4->SetClipping(true); // or via CSS "clipping: true;" box4->SetOnFrame(true); // or via CSS "onframe: true;" @@ -106,7 +106,7 @@ void draw_frame() // draw box before line at same position as line ending with 40x40 px size auto box5 = canvas->Draw(RPadPos(80_user - 20_px, 20_user - 20_px), RPadPos(80_user + 20_px, 20_user + 20_px)); - box5->AttrBox().AttrFill().SetColor(RColor::kYellow); + box5->AttrFill().SetColor(RColor::kYellow); box5->SetOnFrame(true); // or via CSS "onframe: true;" // draw line in the frame, but disable default cutting by the frame borders From 424b68dec6097a19c874f9cb2c802ef417c3fac8 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 8 Jun 2021 09:24:20 +0200 Subject: [PATCH 086/309] [rcanvas] provide onframe/clipping attributes directly to drawables Do not use RAttrOnFrame class which just contains these both values --- graf2d/primitivesv7/inc/ROOT/RBox.hxx | 21 ++++++++++++++------- graf2d/primitivesv7/inc/ROOT/RLine.hxx | 18 ++++++++++++------ graf2d/primitivesv7/inc/ROOT/RMarker.hxx | 24 ++++++++++++++++-------- graf2d/primitivesv7/inc/ROOT/RText.hxx | 19 +++++++++++++------ 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/graf2d/primitivesv7/inc/ROOT/RBox.hxx b/graf2d/primitivesv7/inc/ROOT/RBox.hxx index 405aeb63a1b59..7342946d902be 100644 --- a/graf2d/primitivesv7/inc/ROOT/RBox.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RBox.hxx @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -29,18 +28,20 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RBox : public RDrawable, public RAttrOnFrame { +class RBox : public RDrawable { - RPadPos fP1, fP2; ///< box corners coordinates - RAttrLine fAttrBorder{this, "border"}; /// fOnFrame{this, "onframe", false}; /// fClipping{this, "clipping", false}; /// #include -#include #include namespace ROOT { @@ -26,13 +25,14 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RLine : public RDrawable, public RAttrOnFrame { - - RPadPos fP1, fP2; ///< line begin/end - RAttrLine fAttrLine{this, "line"}; /// fOnFrame{this, "onframe", false}; /// fClipping{this, "clipping", false}; /// #include -#include #include #include @@ -27,13 +26,15 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RMarker : public RDrawable, public RAttrOnFrame { +class RMarker : public RDrawable { - RPadPos fP; ///< position - RAttrMarker fMarkerAttr{this, "marker"}; /// fOnFrame{this, "onframe", false}; /// fClipping{this, "clipping", false}; /// #include -#include #include #include @@ -28,14 +27,16 @@ namespace Experimental { welcome! */ -class RText : public RDrawable, public RAttrOnFrame { +class RText : public RDrawable { - std::string fText; ///< text to display - RPadPos fPos; ///< position - RAttrText fAttrText{this, "text"}; /// fOnFrame{this, "onframe", false}; /// fClipping{this, "clipping", false}; /// Date: Tue, 8 Jun 2021 09:34:00 +0200 Subject: [PATCH 087/309] [rcanvas] remove no-longer used RAttrBox and RAttrOnFrame classes --- graf2d/gpadv7/CMakeLists.txt | 2 -- graf2d/gpadv7/inc/LinkDef.h | 2 -- graf2d/gpadv7/inc/ROOT/RAttrBox.hxx | 46 ------------------------- graf2d/gpadv7/inc/ROOT/RAttrOnFrame.hxx | 44 ----------------------- 4 files changed, 94 deletions(-) delete mode 100644 graf2d/gpadv7/inc/ROOT/RAttrBox.hxx delete mode 100644 graf2d/gpadv7/inc/ROOT/RAttrOnFrame.hxx diff --git a/graf2d/gpadv7/CMakeLists.txt b/graf2d/gpadv7/CMakeLists.txt index 5cde23d1e2e27..944be3802cd9d 100644 --- a/graf2d/gpadv7/CMakeLists.txt +++ b/graf2d/gpadv7/CMakeLists.txt @@ -19,11 +19,9 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGpadv7 ROOT/RAttrMap.hxx ROOT/RAttrBase.hxx ROOT/RAttrAxis.hxx - ROOT/RAttrBox.hxx ROOT/RAttrLine.hxx ROOT/RAttrFill.hxx ROOT/RAttrMarker.hxx - ROOT/RAttrOnFrame.hxx ROOT/RAttrMargins.hxx ROOT/RAttrText.hxx ROOT/RAttrValue.hxx diff --git a/graf2d/gpadv7/inc/LinkDef.h b/graf2d/gpadv7/inc/LinkDef.h index e972937740c5e..135d468ddb900 100644 --- a/graf2d/gpadv7/inc/LinkDef.h +++ b/graf2d/gpadv7/inc/LinkDef.h @@ -76,11 +76,9 @@ #pragma link C++ class ROOT::Experimental::RAttrValue+; #pragma link C++ class ROOT::Experimental::RAttrValue+; #pragma link C++ class ROOT::Experimental::RAttrValue+; -#pragma link C++ class ROOT::Experimental::RAttrOnFrame+; #pragma link C++ class ROOT::Experimental::RAttrFill+; #pragma link C++ class ROOT::Experimental::RAttrLine+; -#pragma link C++ class ROOT::Experimental::RAttrBox+; #pragma link C++ class ROOT::Experimental::RAttrMarker+; #pragma link C++ class ROOT::Experimental::RAttrText+; #pragma link C++ class ROOT::Experimental::RAttrAxis+; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBox.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBox.hxx deleted file mode 100644 index bcc15702059d7..0000000000000 --- a/graf2d/gpadv7/inc/ROOT/RAttrBox.hxx +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT7_RAttrBox -#define ROOT7_RAttrBox - -#include -#include -#include - -namespace ROOT { -namespace Experimental { - -/** \class RAttrBox -\ingroup GpadROOT7 -\author Axel Naumann -\date 2018-10-17 -\brief Drawing attributes for a box: rectangular lines with size and position. -\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! -*/ - -class RAttrBox : public RAttrBase { - - RAttrLine fAttrBorder{this, "border"}; /// - -namespace ROOT { -namespace Experimental { - -/** \class RAttrOnFrame -\ingroup GpadROOT7 -\author Sergey Linev -\date 2021-05-06 -\brief Class which add onframe property for drawable, used when drawable can be drawn on frame or outside frame -\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! -*/ - -class RAttrOnFrame { - - RAttrValue fOnFrame; /// fClipping; /// Date: Tue, 8 Jun 2021 10:28:41 +0200 Subject: [PATCH 088/309] [rcanvas] enforce naming convention for attributes access Always define const/non-const methods like: RAttrLine &AttrLine() { return fAttrLine; } const RAttrLine &AttrLine() const { return fAttrLine; } Do not provide extra setter methods for attribute classes --- graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx | 3 +- graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrText.hxx | 9 ++-- graf2d/gpadv7/inc/ROOT/RAxisDrawable.hxx | 3 +- graf2d/gpadv7/inc/ROOT/RFrame.hxx | 28 ++++------- graf2d/gpadv7/inc/ROOT/RPad.hxx | 3 +- graf2d/gpadv7/inc/ROOT/RPave.hxx | 9 ++-- graf2d/gpadv7/src/RFrame.cxx | 6 +-- graf2d/gpadv7/test/attribute.cxx | 37 +++++++-------- graf2d/gpadv7/test/rpave.cxx | 8 ++-- graf2d/gpadv7/test/rstyle.cxx | 44 ++++++++--------- graf2d/primitivesv7/inc/ROOT/RBox.hxx | 6 +-- graf2d/primitivesv7/inc/ROOT/RFrameTitle.hxx | 7 +-- graf2d/primitivesv7/inc/ROOT/RLine.hxx | 7 +-- graf2d/primitivesv7/inc/ROOT/RMarker.hxx | 7 +-- graf2d/primitivesv7/inc/ROOT/RText.hxx | 7 +-- graf2d/primitivesv7/test/primitives.cxx | 50 ++++++++++---------- hist/histdrawv7/inc/ROOT/RHistDrawable.hxx | 26 +++++----- tutorials/v7/draw_frame.cxx | 4 +- tutorials/v7/draw_rh2_colz.cxx | 2 +- tutorials/v7/draw_rh2_large.cxx | 2 +- tutorials/v7/draw_rh3_large.cxx | 2 +- tutorials/v7/draw_symlog.cxx | 2 +- 23 files changed, 113 insertions(+), 161 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx index 8995f1ec0774d..726668ecbba94 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx @@ -113,8 +113,7 @@ class RAttrAxis : public RAttrBase { fTimeFormat.Clear(); } - const RAttrLine &GetAttrLine() const { return fAttrLine; } - RAttrAxis &SetAttrLine(const RAttrLine &line) { fAttrLine = line; return *this; } + const RAttrLine &AttrLine() const { return fAttrLine; } RAttrLine &AttrLine() { return fAttrLine; } RAttrAxis &SetEndingSize(const RPadLength &sz) { fEndingSize = sz; return *this; } diff --git a/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx b/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx index 6fd5986cbc375..7c9ad60337d5e 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx @@ -32,7 +32,7 @@ class RAttrMargins : public RAttrBase { RAttrValue fBottom{this, "bottom", 0._normal}; RAttrValue fAll{this, "all", 0._normal}; - R__ATTR_CLASS(RAttrMargins, "margin"); + R__ATTR_CLASS(RAttrMargins, "margins"); public: diff --git a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx index ed635d1538bf3..af203229f9c1c 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx @@ -47,6 +47,10 @@ class RAttrText : public RAttrBase { RAttrText &SetAlign(int align) { fAlign = align; return *this; } int GetAlign() const { return fAlign; } + ///The color of the text. + RAttrText &SetColor(const RColor &color) { fColor = color; return *this; } + RColor GetColor() const { return fColor; } + ///Set text font by id as usually handled in the ROOT, set number between 1 and 15 RAttrText &SetFont(int font) { @@ -109,11 +113,6 @@ class RAttrText : public RAttrBase { } std::string GetFontWeight() const { return fFontWeight; } - - ///The color of the text. - RAttrText &SetColor(const RColor &color) { fColor = color; return *this; } - RColor GetColor() const { return fColor; } - }; diff --git a/graf2d/gpadv7/inc/ROOT/RAxisDrawable.hxx b/graf2d/gpadv7/inc/ROOT/RAxisDrawable.hxx index 34081ba884f7f..26bb8291eb02b 100644 --- a/graf2d/gpadv7/inc/ROOT/RAxisDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAxisDrawable.hxx @@ -55,8 +55,7 @@ public: const RPadPos& GetPos() const { return fPos; } const RPadLength& GetLength() const { return fLength; } - const RAttrAxis &GetAttrAxis() const { return fAttrAxis; } - RAxisDrawableBase &SetAttrAxis(const RAttrAxis &attr) { fAttrAxis = attr; return *this; } + const RAttrAxis &AttrAxis() const { return fAttrAxis; } RAttrAxis &AttrAxis() { return fAttrAxis; } }; diff --git a/graf2d/gpadv7/inc/ROOT/RFrame.hxx b/graf2d/gpadv7/inc/ROOT/RFrame.hxx index c9eaff499630b..6452142c4e06b 100644 --- a/graf2d/gpadv7/inc/ROOT/RFrame.hxx +++ b/graf2d/gpadv7/inc/ROOT/RFrame.hxx @@ -144,7 +144,7 @@ public: }; private: - RAttrMargins fMargins{this, "margin"}; ///second; } else { - GetAxisRanges(0, GetAttrX(), ranges); - GetAxisRanges(1, GetAttrY(), ranges); - GetAxisRanges(2, GetAttrZ(), ranges); + GetAxisRanges(0, AttrX(), ranges); + GetAxisRanges(1, AttrY(), ranges); + GetAxisRanges(2, AttrZ(), ranges); } } diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index 36933827f778c..e86280650cc47 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -17,16 +17,13 @@ class CustomAttrs : public RAttrBase { R__ATTR_CLASS(CustomAttrs, "custom"); - const RAttrLine &GetAttrLine() const { return fAttrLine; } - CustomAttrs &SetAttrLine(const RAttrLine &line) { fAttrLine = line; return *this; } + const RAttrLine &AttrLine() const { return fAttrLine; } RAttrLine &AttrLine() { return fAttrLine; } - const RAttrFill &GetAttrFill() const { return fAttrFill; } - CustomAttrs &SetAttrFill(const RAttrFill &fill) { fAttrFill = fill; return *this; } + const RAttrFill &AttrFill() const { return fAttrFill; } RAttrFill &AttrFill() { return fAttrFill; } - const RAttrText &GetAttrText() const { return fAttrText; } - CustomAttrs &SetAttrText(const RAttrText &txt) { fAttrText = txt; return *this; } + const RAttrText &AttrText() const { return fAttrText; } RAttrText &AttrText() { return fAttrText; } double GetDirect(const std::string &name) const { return GetValue(name); } @@ -54,18 +51,18 @@ TEST(OptsTest, AttribVals) { CustomAttrs attrs; attrs.AttrText().SetColor(RColor::kBlue); - auto &border = attrs.AttrLine(); - border.SetWidth(42.); + auto &line = attrs.AttrLine(); + line.SetWidth(42.); { // Value was set on this attr, not coming from style: - EXPECT_FLOAT_EQ(attrs.GetAttrLine().GetWidth(), 42.f); - EXPECT_FLOAT_EQ(border.GetWidth(), 42.f); + EXPECT_FLOAT_EQ(attrs.AttrLine().GetWidth(), 42.f); + EXPECT_FLOAT_EQ(line.GetWidth(), 42.f); } { // Value was set on this attr, not coming from style: - EXPECT_EQ(attrs.GetAttrText().GetColor(), RColor::kBlue); + EXPECT_EQ(attrs.AttrText().GetColor(), RColor::kBlue); } } @@ -117,8 +114,8 @@ TEST(OptsTest, AttribAssign) { CustomAttrs attrs2; // deep copy - independent from origin - auto attrLine1 = attrs1.GetAttrLine(); - auto attrLine2 = attrs2.GetAttrLine(); + auto attrLine1 = attrs1.AttrLine(); + auto attrLine2 = attrs2.AttrLine(); EXPECT_EQ(attrLine2, attrLine1); EXPECT_EQ(attrLine1, attrLine2); @@ -131,20 +128,20 @@ TEST(OptsTest, AttribAssign) { EXPECT_EQ(attrLine1, attrLine2); // But original attributes now differ - EXPECT_NE(attrs1.GetAttrLine(), attrLine1); - EXPECT_NE(attrs2.GetAttrLine(), attrLine2); + EXPECT_NE(attrs1.AttrLine(), attrLine1); + EXPECT_NE(attrs2.AttrLine(), attrLine2); EXPECT_FLOAT_EQ(attrLine1.GetWidth(), 42.); EXPECT_FLOAT_EQ(attrLine2.GetWidth(), 42.); // default width return 1 - EXPECT_FLOAT_EQ(attrs1.GetAttrLine().GetWidth(), 1.); - EXPECT_FLOAT_EQ(attrs2.GetAttrLine().GetWidth(), 1.); + EXPECT_FLOAT_EQ(attrs1.AttrLine().GetWidth(), 1.); + EXPECT_FLOAT_EQ(attrs2.AttrLine().GetWidth(), 1.); // Are the two attributes disconnected? attrLine2.SetWidth(3.); - EXPECT_EQ(attrs1.GetAttrLine(), attrs2.GetAttrLine()); + EXPECT_EQ(attrs1.AttrLine(), attrs2.AttrLine()); EXPECT_FLOAT_EQ(attrLine1.GetWidth(), 42.); EXPECT_FLOAT_EQ(attrLine2.GetWidth(), 3.); - EXPECT_FLOAT_EQ(attrs1.GetAttrLine().GetWidth(), 1.); - EXPECT_FLOAT_EQ(attrs2.GetAttrLine().GetWidth(), 1.); + EXPECT_FLOAT_EQ(attrs1.AttrLine().GetWidth(), 1.); + EXPECT_FLOAT_EQ(attrs2.AttrLine().GetWidth(), 1.); } diff --git a/graf2d/gpadv7/test/rpave.cxx b/graf2d/gpadv7/test/rpave.cxx index 4293a3f087024..9edbc2423e1b0 100644 --- a/graf2d/gpadv7/test/rpave.cxx +++ b/graf2d/gpadv7/test/rpave.cxx @@ -27,11 +27,11 @@ TEST(Primitives, RPave) // when adding pave, RFrame is automatically created EXPECT_EQ(canv.NumPrimitives(), 2u); - EXPECT_EQ(pave->GetAttrBorder().GetColor(), RColor::kRed); - EXPECT_EQ(pave->GetAttrBorder().GetWidth(), 3); + EXPECT_EQ(pave->AttrBorder().GetColor(), RColor::kRed); + EXPECT_EQ(pave->AttrBorder().GetWidth(), 3); - EXPECT_EQ(pave->GetAttrFill().GetColor(), RColor::kBlue); - EXPECT_EQ(pave->GetAttrFill().GetStyle(), 3003); + EXPECT_EQ(pave->AttrFill().GetColor(), RColor::kBlue); + EXPECT_EQ(pave->AttrFill().GetStyle(), 3003); EXPECT_EQ(pave->GetCornerX(), 0.03_normal); EXPECT_EQ(pave->GetWidth(), 0.4_normal); diff --git a/graf2d/gpadv7/test/rstyle.cxx b/graf2d/gpadv7/test/rstyle.cxx index 1d67ccecacbb0..3cb361ef7a03d 100644 --- a/graf2d/gpadv7/test/rstyle.cxx +++ b/graf2d/gpadv7/test/rstyle.cxx @@ -16,29 +16,25 @@ using namespace ROOT::Experimental; class CustomDrawable : public RDrawable { - RAttrLine fAttrLine{this, "line"}; ///GetAttrBorder().GetColor(), RColor::kRed); - EXPECT_DOUBLE_EQ(box->GetAttrBorder().GetWidth(), 5.); - EXPECT_EQ(box->GetAttrBorder().GetStyle(), 7); + EXPECT_EQ(box->AttrBorder().GetColor(), RColor::kRed); + EXPECT_DOUBLE_EQ(box->AttrBorder().GetWidth(), 5.); + EXPECT_EQ(box->AttrBorder().GetStyle(), 7); - EXPECT_EQ(box->GetAttrFill().GetColor(), RColor::kBlue); - EXPECT_EQ(box->GetAttrFill().GetStyle(), 6); + EXPECT_EQ(box->AttrFill().GetColor(), RColor::kBlue); + EXPECT_EQ(box->AttrFill().GetStyle(), 6); } // Test RLine API @@ -39,9 +39,9 @@ TEST(Primitives, RLine) EXPECT_EQ(canv.NumPrimitives(), 1u); - EXPECT_EQ(line->GetAttrLine().GetColor(), RColor::kRed); - EXPECT_DOUBLE_EQ(line->GetAttrLine().GetWidth(), 5.); - EXPECT_EQ(line->GetAttrLine().GetStyle(), 7); + EXPECT_EQ(line->AttrLine().GetColor(), RColor::kRed); + EXPECT_DOUBLE_EQ(line->AttrLine().GetWidth(), 5.); + EXPECT_EQ(line->AttrLine().GetStyle(), 7); } // Test RMarker API @@ -54,9 +54,9 @@ TEST(Primitives, RMarker) EXPECT_EQ(canv.NumPrimitives(), 1u); - EXPECT_EQ(marker->GetAttrMarker().GetColor(), RColor::kGreen); - EXPECT_DOUBLE_EQ(marker->GetAttrMarker().GetSize(), 2.5); - EXPECT_EQ(marker->GetAttrMarker().GetStyle(), 7); + EXPECT_EQ(marker->AttrMarker().GetColor(), RColor::kGreen); + EXPECT_DOUBLE_EQ(marker->AttrMarker().GetSize(), 2.5); + EXPECT_EQ(marker->AttrMarker().GetStyle(), 7); } // Test RText API @@ -71,11 +71,11 @@ TEST(Primitives, RText) EXPECT_EQ(canv.NumPrimitives(), 1u); EXPECT_EQ(text->GetText(), "Hello World"); - EXPECT_EQ(text->GetAttrText().GetColor(), RColor::kBlack); - EXPECT_DOUBLE_EQ(text->GetAttrText().GetSize(), 12.5); - EXPECT_DOUBLE_EQ(text->GetAttrText().GetAngle(), 90.); - EXPECT_EQ(text->GetAttrText().GetAlign(), 13); - EXPECT_EQ(text->GetAttrText().GetFontFamily(), "Arial"); + EXPECT_EQ(text->AttrText().GetColor(), RColor::kBlack); + EXPECT_DOUBLE_EQ(text->AttrText().GetSize(), 12.5); + EXPECT_DOUBLE_EQ(text->AttrText().GetAngle(), 90.); + EXPECT_EQ(text->AttrText().GetAlign(), 13); + EXPECT_EQ(text->AttrText().GetFontFamily(), "Arial"); } // Test RLegend API @@ -101,7 +101,7 @@ TEST(Primitives, RLegend) EXPECT_EQ(legend->NumEntries(), 3u); EXPECT_EQ(legend->GetTitle(), "Legend title"); - EXPECT_EQ(legend->GetAttrFill().GetColor(), RColor::kWhite); + EXPECT_EQ(legend->AttrFill().GetColor(), RColor::kWhite); } // Test RPaveText API @@ -126,15 +126,15 @@ TEST(Primitives, RPaveText) EXPECT_EQ(text->GetLine(1), "Second line"); EXPECT_EQ(text->GetLine(2), "Third line"); - EXPECT_EQ(text->GetAttrText().GetColor(), RColor::kBlack); - EXPECT_DOUBLE_EQ(text->GetAttrText().GetSize(), 12); - EXPECT_EQ(text->GetAttrText().GetAlign(), 13); - EXPECT_EQ(text->GetAttrText().GetFontFamily(), "Times New Roman"); + EXPECT_EQ(text->AttrText().GetColor(), RColor::kBlack); + EXPECT_DOUBLE_EQ(text->AttrText().GetSize(), 12); + EXPECT_EQ(text->AttrText().GetAlign(), 13); + EXPECT_EQ(text->AttrText().GetFontFamily(), "Times New Roman"); - EXPECT_EQ(text->GetAttrBorder().GetColor(), RColor::kRed); - EXPECT_EQ(text->GetAttrBorder().GetWidth(), 3); + EXPECT_EQ(text->AttrBorder().GetColor(), RColor::kRed); + EXPECT_EQ(text->AttrBorder().GetWidth(), 3); - EXPECT_EQ(text->GetAttrFill().GetColor(), RColor::kBlue); - EXPECT_EQ(text->GetAttrFill().GetStyle(), 3003); + EXPECT_EQ(text->AttrFill().GetColor(), RColor::kBlue); + EXPECT_EQ(text->AttrFill().GetStyle(), 3003); } diff --git a/hist/histdrawv7/inc/ROOT/RHistDrawable.hxx b/hist/histdrawv7/inc/ROOT/RHistDrawable.hxx index a551c9265de9d..07962a7f6ff51 100644 --- a/hist/histdrawv7/inc/ROOT/RHistDrawable.hxx +++ b/hist/histdrawv7/inc/ROOT/RHistDrawable.hxx @@ -35,13 +35,13 @@ namespace ROOT { namespace Experimental { class RHistDrawableBase : public RDrawable { - RAttrValue fKind{this, "kind", ""}; /// fSub{this, "sub", -1}; /// fOptimize{this, "optimize", false}; /// fKind{this, "kind", ""}; /// fSub{this, "sub", -1}; /// fOptimize{this, "optimize", false}; ///AttrFill().SetColor(RColor::kBlue); frame->AttrBorder().SetColor(RColor::kBlue); frame->AttrBorder().SetWidth(3); - frame->Margins().SetTop(0.25_normal); - frame->Margins().SetAll(0.2_normal); + frame->AttrMargins().SetTop(0.25_normal); + frame->AttrMargins().SetAll(0.2_normal); // let frame draw axes without need of any histogram frame->SetDrawAxes(true); diff --git a/tutorials/v7/draw_rh2_colz.cxx b/tutorials/v7/draw_rh2_colz.cxx index 26ea048b96291..b2620a6a15c33 100644 --- a/tutorials/v7/draw_rh2_colz.cxx +++ b/tutorials/v7/draw_rh2_colz.cxx @@ -49,7 +49,7 @@ void draw_rh2_colz() auto frame = canvas->GetOrCreateFrame(); // should we made special style for frame with palette? - frame->Margins().SetRight(0.2_normal); + frame->AttrMargins().SetRight(0.2_normal); frame->SetGridX(false).SetGridY(false); diff --git a/tutorials/v7/draw_rh2_large.cxx b/tutorials/v7/draw_rh2_large.cxx index 8c420c84ec574..b48e8a0805de9 100644 --- a/tutorials/v7/draw_rh2_large.cxx +++ b/tutorials/v7/draw_rh2_large.cxx @@ -51,7 +51,7 @@ void draw_rh2_large() auto frame = canvas->GetOrCreateFrame(); // should we made special style for frame with palette? - // frame->Margins().SetRight(0.2_normal); + // frame->AttrMargins().SetRight(0.2_normal); frame->SetGridX(false).SetGridY(false); frame->AttrX().SetZoom(nbins*0.2, nbins*0.8); diff --git a/tutorials/v7/draw_rh3_large.cxx b/tutorials/v7/draw_rh3_large.cxx index a4586ec8852c3..b7e80f92c8a85 100644 --- a/tutorials/v7/draw_rh3_large.cxx +++ b/tutorials/v7/draw_rh3_large.cxx @@ -53,7 +53,7 @@ void draw_rh3_large() auto frame = canvas->GetOrCreateFrame(); // should we made special style for frame with palette? - // frame->Margins().SetRight(0.2_normal); + // frame->AttrMargins().SetRight(0.2_normal); frame->AttrX().SetZoom(nbins*0.1, nbins*0.9); frame->AttrY().SetZoom(nbins*0.1, nbins*0.9); diff --git a/tutorials/v7/draw_symlog.cxx b/tutorials/v7/draw_symlog.cxx index 5a16209f17dcb..9b831f4c2bf10 100644 --- a/tutorials/v7/draw_symlog.cxx +++ b/tutorials/v7/draw_symlog.cxx @@ -27,7 +27,7 @@ using namespace ROOT::Experimental; -auto symlog_style = RStyle::Parse("frame { margin_left: 0.1; }" +auto symlog_style = RStyle::Parse("frame { margins_left: 0.1; }" "marker { onframe: true; clipping: true; }" ".group1 { marker_style: 8; marker_color: blue; }" ".group2 { marker_style: 8; marker_color: orange; }"); From 41e01c6cd5411d7091facfd7d599702af361342b Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 8 Jun 2021 13:44:57 +0200 Subject: [PATCH 089/309] [rcanvas] intoroduce RAttrBorder class Should be used for rect drawing, which optionally can have "rx" and "ry" attributes. Important that class inherits RAttrLine and all its properties and methods --- graf2d/gpadv7/CMakeLists.txt | 1 + graf2d/gpadv7/inc/LinkDef.h | 1 + graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx | 45 ++++++++++++++++++++++++++ graf2d/primitivesv7/inc/ROOT/RBox.hxx | 8 ++--- tutorials/v7/box.cxx | 4 +-- 5 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx diff --git a/graf2d/gpadv7/CMakeLists.txt b/graf2d/gpadv7/CMakeLists.txt index 944be3802cd9d..79ff87d1f20cb 100644 --- a/graf2d/gpadv7/CMakeLists.txt +++ b/graf2d/gpadv7/CMakeLists.txt @@ -19,6 +19,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGpadv7 ROOT/RAttrMap.hxx ROOT/RAttrBase.hxx ROOT/RAttrAxis.hxx + ROOT/RAttrBorder.hxx ROOT/RAttrLine.hxx ROOT/RAttrFill.hxx ROOT/RAttrMarker.hxx diff --git a/graf2d/gpadv7/inc/LinkDef.h b/graf2d/gpadv7/inc/LinkDef.h index 135d468ddb900..e520af5753aa5 100644 --- a/graf2d/gpadv7/inc/LinkDef.h +++ b/graf2d/gpadv7/inc/LinkDef.h @@ -79,6 +79,7 @@ #pragma link C++ class ROOT::Experimental::RAttrFill+; #pragma link C++ class ROOT::Experimental::RAttrLine+; +#pragma link C++ class ROOT::Experimental::RAttrBorder+; #pragma link C++ class ROOT::Experimental::RAttrMarker+; #pragma link C++ class ROOT::Experimental::RAttrText+; #pragma link C++ class ROOT::Experimental::RAttrAxis+; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx new file mode 100644 index 0000000000000..dc8459d9eef9b --- /dev/null +++ b/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx @@ -0,0 +1,45 @@ +/************************************************************************* + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT7_RAttrBorder +#define ROOT7_RAttrBorder + +#include +#include + +namespace ROOT { +namespace Experimental { + +/** \class RAttrBorder +\ingroup GpadROOT7 +\author Sergey Linev +\date 2021-06-08 +\brief Drawing line attributes for different objects. +\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! +*/ + +class RAttrBorder : public RAttrLine { + + RAttrValue fRx{this, "rx", 0}; /// fRy{this, "ry", 0}; /// #include -#include +#include #include #include @@ -31,7 +31,7 @@ namespace Experimental { class RBox : public RDrawable { RPadPos fP1, fP2; ///< box corners coordinates - RAttrLine fAttrBorder{this, "border"}; /// fOnFrame{this, "onframe", false}; /// fClipping{this, "clipping", false}; ///AttrFill().SetColor(RColor::kBlue); auto box4 = canvas->Draw(RPadPos(0.7_normal, 0.7_normal), RPadPos(0.9_normal,0.9_normal)); - box4->AttrBorder().SetWidth(3); + box4->AttrBorder().SetWidth(4); auto box5 = canvas->Draw(RPadPos(0.7_normal, 0.1_normal), RPadPos(0.9_normal,0.3_normal)); - box5->AttrBorder().SetWidth(3); + box5->AttrBorder().SetRx(10).SetRy(10).SetWidth(2); canvas->Show(); } From afde14db9d08c0c16a0539d79046d53ae9a9561d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 8 Jun 2021 17:22:37 +0200 Subject: [PATCH 090/309] [rcanvas] use RAttrBorder for RFrame and RPave --- graf2d/gpadv7/inc/ROOT/RFrame.hxx | 10 +++++----- graf2d/gpadv7/inc/ROOT/RPave.hxx | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RFrame.hxx b/graf2d/gpadv7/inc/ROOT/RFrame.hxx index 6452142c4e06b..23a3f1c6d71b7 100644 --- a/graf2d/gpadv7/inc/ROOT/RFrame.hxx +++ b/graf2d/gpadv7/inc/ROOT/RFrame.hxx @@ -12,7 +12,7 @@ #include "ROOT/RDrawable.hxx" #include "ROOT/RDrawableRequest.hxx" -#include "ROOT/RAttrLine.hxx" +#include "ROOT/RAttrBorder.hxx" #include "ROOT/RAttrFill.hxx" #include "ROOT/RAttrMargins.hxx" #include "ROOT/RAttrAxis.hxx" @@ -145,8 +145,8 @@ public: private: RAttrMargins fAttrMargins{this, "margins"}; /// #include -#include +#include #include #include #include @@ -31,7 +31,7 @@ namespace Experimental { class RPave : public RDrawable { RAttrText fAttrText{this, "text"}; /// fCornerX{this, "cornerx", 0.02}; /// fCornerY{this, "cornery", 0.02}; /// Date: Tue, 8 Jun 2021 17:23:59 +0200 Subject: [PATCH 091/309] [jsroot] dev 8/06/2021 with RAttrBorder support Plus many other fixes and improvemnts --- js/scripts/JSRoot.core.js | 2 +- js/scripts/JSRoot.gpad.js | 58 +++++++++++++++--- js/scripts/JSRoot.hist.js | 66 +++++++++++---------- js/scripts/JSRoot.hist3d.js | 66 ++++++++++++--------- js/scripts/JSRoot.io.js | 7 ++- js/scripts/JSRoot.latex.js | 23 ++++---- js/scripts/JSRoot.more.js | 107 +++++++++++++++++++++++----------- js/scripts/JSRoot.v7gpad.js | 49 +++++++++++----- js/scripts/JSRoot.v7hist.js | 1 + js/scripts/JSRoot.v7hist3d.js | 62 ++++++++++++-------- js/scripts/JSRoot.v7more.js | 18 +++--- 11 files changed, 295 insertions(+), 164 deletions(-) diff --git a/js/scripts/JSRoot.core.js b/js/scripts/JSRoot.core.js index 80e02b6ece9f2..2432aa6ccf766 100644 --- a/js/scripts/JSRoot.core.js +++ b/js/scripts/JSRoot.core.js @@ -104,7 +104,7 @@ /** @summary JSROOT version date * @desc Release date in format day/month/year like "14/01/2021"*/ - JSROOT.version_date = "26/05/2021"; + JSROOT.version_date = "8/06/2021"; /** @summary JSROOT version id and date * @desc Produced by concatenation of {@link JSROOT.version_id} and {@link JSROOT.version_date} diff --git a/js/scripts/JSRoot.gpad.js b/js/scripts/JSRoot.gpad.js index 57b199a879bca..bbe6b1a1204dc 100644 --- a/js/scripts/JSRoot.gpad.js +++ b/js/scripts/JSRoot.gpad.js @@ -846,20 +846,54 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { .property('shift_y', title_shift_y); return true; - }); - } - /** @summary Redraw axis, used in standalone mode for TGaxis */ - TAxisPainter.prototype.redraw = function() { - + /** @summary Convert TGaxis position into NDC to fix it when frame zoomed */ + TAxisPainter.prototype.convertTo = function(opt) { let gaxis = this.getObject(), x1 = this.axisToSvg("x", gaxis.fX1), y1 = this.axisToSvg("y", gaxis.fY1), x2 = this.axisToSvg("x", gaxis.fX2), - y2 = this.axisToSvg("y", gaxis.fY2), - w = x2 - x1, h = y1 - y2, + y2 = this.axisToSvg("y", gaxis.fY2); + + if (opt == "ndc") { + let pw = this.getPadPainter().getPadWidth(), + ph = this.getPadPainter().getPadHeight(); + + gaxis.fX1 = x1 / pw; + gaxis.fX2 = x2 / pw; + gaxis.fY1 = (ph - y1) / ph; + gaxis.fY2 = (ph - y2)/ ph; + this.use_ndc = true; + } else if (opt == "frame") { + let rect = this.getFramePainter().getFrameRect(); + gaxis.fX1 = (x1 - rect.x) / rect.width; + gaxis.fX2 = (x2 - rect.x) / rect.width; + gaxis.fY1 = (y1 - rect.y) / rect.height; + gaxis.fY2 = (y2 - rect.y) / rect.height; + this.bind_frame = true; + } + } + + /** @summary Redraw axis, used in standalone mode for TGaxis */ + TAxisPainter.prototype.redraw = function() { + + let gaxis = this.getObject(), x1, y1, x2, y2; + + if (this.bind_frame) { + let rect = this.getFramePainter().getFrameRect(); + x1 = Math.round(rect.x + gaxis.fX1 * rect.width); + x2 = Math.round(rect.x + gaxis.fX2 * rect.width); + y1 = Math.round(rect.y + gaxis.fY1 * rect.height); + y2 = Math.round(rect.y + gaxis.fY2 * rect.height); + } else { + x1 = this.axisToSvg("x", gaxis.fX1, this.use_ndc); + y1 = this.axisToSvg("y", gaxis.fY1, this.use_ndc); + x2 = this.axisToSvg("x", gaxis.fX2, this.use_ndc); + y2 = this.axisToSvg("y", gaxis.fY2, this.use_ndc); + } + let w = x2 - x1, h = y1 - y2, vertical = Math.abs(w) < Math.abs(h), sz = vertical ? h : w, reverse = false, @@ -883,12 +917,12 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return this.drawAxis(this.getG(), Math.abs(w), Math.abs(h), "translate(" + x1 + "," + y2 +")"); } - let drawGaxis = (divid, obj /*, opt*/) => { + let drawGaxis = (divid, obj, opt) => { let painter = new TAxisPainter(divid, obj, false); painter.disable_zooming = true; return jsrp.ensureTCanvas(painter, false) - .then(() => painter.redraw()).then(() => painter); + .then(() => { if (opt) painter.convertTo(opt); return painter.redraw(); }).then(() => painter); } // =============================================== @@ -2302,10 +2336,16 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return this.getPadSvg(this.this_pad_name); } + /** @summary Returns main painter on the pad + * @desc Typically main painter is TH1/TH2 object which is drawing axes + * @private */ TPadPainter.prototype.getMainPainter = function() { return this.main_painter_ref || null; } + /** @summary Assign main painter on the pad + * @desc Typically main painter is TH1/TH2 object which is drawing axes + * @private */ TPadPainter.prototype.setMainPainter = function(painter, force) { if (!this.main_painter_ref || force) this.main_painter_ref = painter; diff --git a/js/scripts/JSRoot.hist.js b/js/scripts/JSRoot.hist.js index d0d6486c496cd..567bdc5f39368 100644 --- a/js/scripts/JSRoot.hist.js +++ b/js/scripts/JSRoot.hist.js @@ -6,34 +6,26 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { "use strict"; let createDefaultPalette = () => { - - function HLStoRGB(h, l, s) { - let r, g, b; - if (s < 1e-100) { - r = g = b = l; // achromatic - } else { - function hue2rgb(p, q, t) { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2/3 - t) * 6; - return p; - } - let q = (l < 0.5) ? l * (1 + s) : l + s - l * s, - p = 2 * l - q; - r = hue2rgb(p, q, h + 1/3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); - } + let hue2rgb = (p, q, t) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2/3 - t) * 6; + return p; + }; + let HLStoRGB = (h, l, s) => { + let q = (l < 0.5) ? l * (1 + s) : l + s - l * s, + p = 2 * l - q, + r = hue2rgb(p, q, h + 1/3), + g = hue2rgb(p, q, h), + b = hue2rgb(p, q, h - 1/3); return 'rgb(' + Math.round(r*255) + ',' + Math.round(g*255) + ',' + Math.round(b*255) + ')'; - } - - let palette = [], saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50; + }; + let palette = [], minHue = 0, maxHue = 280, maxPretty = 50; for (let i = 0; i < maxPretty; ++i) { - let hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360, - rgbval = HLStoRGB(hue, lightness, saturation); - palette.push(rgbval); + let hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360; + palette.push(HLStoRGB(hue, 0.5, 1)); } return new JSROOT.ColorPalette(palette); } @@ -843,7 +835,7 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { pos_y = parseInt(this.draw_g.attr("y")), width = this.getPadPainter().getPadWidth(), pad = this.getPadPainter().getRootPad(true), - main = this.getMainPainter(), + main = palette.$main_painter || this.getMainPainter(), framep = this.getFramePainter(), zmin = 0, zmax = 100, contour = main.fContour, @@ -3093,9 +3085,11 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { * @returns {Promise} when done */ THistPainter.prototype.drawColorPalette = function(enabled, postpone_draw, can_move) { // only when create new palette, one could change frame size - - if (!this.isMainPainter()) - return Promise.resolve(null); + let mp = this.getMainPainter(); + if (mp !== this) { + if (mp && (mp.draw_content !== false)) + return Promise.resolve(null); + } let pal = this.findFunction('TPaletteAxis'), pp = this.getPadPainter(), @@ -3153,6 +3147,10 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { pal.fY2NDC = frame_painter.fY2NDC; } + // required for z scale setting + // TODO: use weak reference (via pad list of painters and any kind of string) + pal.$main_painter = this; + let arg = ""; if (postpone_draw) arg+=";postpone"; if (can_move && !this.do_redraw_palette) arg+=";can_move"; @@ -4528,7 +4526,7 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { this.scanContent(true); - if (typeof this.drawColorPalette === 'function') + if ((typeof this.drawColorPalette === 'function') && this.isMainPainter()) this.drawColorPalette(false); return this.drawAxes().then(() => { @@ -6608,8 +6606,12 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { this.draw2DBins(); + if (!pp) return true; + + pp.$main_painter = this; + // redraw palette till the end when contours are available - return pp ? pp.drawPave() : true; + return pp.drawPave(); }); }).then(() => { return this.drawHistTitle(); diff --git a/js/scripts/JSRoot.hist3d.js b/js/scripts/JSRoot.hist3d.js index a5e9c3496ce0a..6443bd1a57e41 100644 --- a/js/scripts/JSRoot.hist3d.js +++ b/js/scripts/JSRoot.hist3d.js @@ -596,7 +596,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { return pos; }; - let CreateZoomMesh = (kind, size_3d, use_y_for_z) => { + let createZoomMesh = (kind, size_3d, use_y_for_z) => { let positions, geom = new THREE.BufferGeometry(); if (kind === "z") @@ -619,8 +619,8 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { if (kind=="y") mesh.rotateZ(Math.PI/2).rotateX(Math.PI); mesh.v1 = new THREE.Vector3(positions[0], positions[1], positions[2]); - mesh.v2 = new THREE.Vector3(positions[3], positions[4], positions[5]); - mesh.v3 = new THREE.Vector3(positions[6], positions[7], positions[8]); + mesh.v2 = new THREE.Vector3(positions[6], positions[7], positions[8]); + mesh.v3 = new THREE.Vector3(positions[3], positions[4], positions[5]); mesh.globalIntersect = function(raycaster) { if (!this.v1 || !this.v2 || !this.v3) return undefined; @@ -630,9 +630,8 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { plane.applyMatrix4(this.matrixWorld); let v1 = raycaster.ray.origin.clone(), - v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10); - - let pnt = plane.intersectLine(new THREE.Line3(v1,v2), new THREE.Vector3()); + v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10), + pnt = plane.intersectLine(new THREE.Line3(v1,v2), new THREE.Vector3()); if (!pnt) return undefined; @@ -659,26 +658,39 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { if (!tgtmesh) { gg = this.geometry.clone(); - if (kind==="z") gg.vertices[1].x = gg.vertices[2].x = ticklen; - else gg.vertices[2].y = gg.vertices[3].y = -ticklen; + let pos = gg.getAttribute('position').array; + + // original vertices [0, 2, 1, 0, 3, 2] + // if (kind==="z") gg.vertices[1].x = gg.vertices[2].x = ticklen; + // else gg.vertices[2].y = gg.vertices[3].y = -ticklen; + if (kind==="z") pos[6] = pos[3] = pos[15] = ticklen; + else pos[4] = pos[16] = pos[13] = -ticklen; tgtmesh = new THREE.Mesh(gg, new THREE.MeshBasicMaterial({ color: 0xFF00, side: THREE.DoubleSide })); this.add(tgtmesh); } else { gg = tgtmesh.geometry; } - if (kind=="z") { - gg.vertices[0].z = gg.vertices[1].z = pnt1[kind]; - gg.vertices[2].z = gg.vertices[3].z = pnt2[kind]; + let pos = gg.getAttribute('position').array; + + if (kind == "z") { + // gg.vertices[0].z = gg.vertices[1].z = pnt1[kind]; + // gg.vertices[2].z = gg.vertices[3].z = pnt2[kind]; + pos[2] = pos[11] = pos[8] = pnt1[kind]; + pos[5] = pos[17] = pos[14] = pnt2[kind]; } else { - gg.vertices[0].x = gg.vertices[3].x = pnt1[kind]; - gg.vertices[1].x = gg.vertices[2].x = pnt2[kind]; + // gg.vertices[0].x = gg.vertices[3].x = pnt1[kind]; + // gg.vertices[1].x = gg.vertices[2].x = pnt2[kind]; + pos[0] = pos[9] = pos[12] = pnt1[kind]; + pos[6] = pos[3] = pos[15] = pnt2[kind]; } + gg.getAttribute('position').needsUpdate = true; + gg.computeFaceNormals(); - gg.verticesNeedUpdate = true; - gg.normalsNeedUpdate = true; + //gg.verticesNeedUpdate = true; + //gg.normalsNeedUpdate = true; return true; } @@ -708,7 +720,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { xcont.add(mesh); }); - if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + if (opts.zoom) xcont.add(createZoomMesh("x", this.size_xy3d)); top.add(xcont); xcont = new THREE.Object3D(); @@ -732,7 +744,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { //xcont.add(new THREE.Mesh(ggg2, textMaterial)); xcont.xyid = 4; - if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + if (opts.zoom) xcont.add(createZoomMesh("x", this.size_xy3d)); top.add(xcont); lbls = []; text_scale = 1; maxtextheight = 0; ticks = []; @@ -807,7 +819,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { }); ycont.xyid = 3; - if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + if (opts.zoom) ycont.add(createZoomMesh("y", this.size_xy3d)); top.add(ycont); ycont = new THREE.Object3D(); @@ -829,7 +841,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { ycont.add(mesh); }); ycont.xyid = 1; - if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + if (opts.zoom) ycont.add(createZoomMesh("y", this.size_xy3d)); top.add(ycont); } @@ -947,7 +959,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { } zcont[n].add(n==0 ? zticksline : new THREE.LineSegments(zticksline.geometry, lineMaterial)); - if (opts.zoom) zcont[n].add(CreateZoomMesh("z", this.size_z3d, opts.use_y_for_z)); + if (opts.zoom) zcont[n].add(createZoomMesh("z", this.size_z3d, opts.use_y_for_z)); zcont[n].zid = n + 2; top.add(zcont[n]); @@ -970,7 +982,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { if (this.size_z3d === 0) return; let linex_geom = jsrp.createLineSegments([grminx,0,0, grmaxx,0,0], lineMaterial, null, true); - for(let n=0;n<2;++n) { + for(let n = 0; n < 2; ++n) { let line = new THREE.LineSegments(linex_geom, lineMaterial); line.position.set(0, grminy, (n===0) ? grminz : grmaxz); line.xyboxid = 2; line.bottom = (n == 0); @@ -983,7 +995,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { } let liney_geom = jsrp.createLineSegments([0,grminy,0, 0,grmaxy,0], lineMaterial, null, true); - for(let n=0;n<2;++n) { + for(let n = 0; n < 2; ++n) { let line = new THREE.LineSegments(liney_geom, lineMaterial); line.position.set(grminx, 0, (n===0) ? grminz : grmaxz); line.xyboxid = 3; line.bottom = (n == 0); @@ -1045,7 +1057,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { if ((i1 >= i2) || (j1 >= j2)) return; - let GetBinContent = (ii,jj, level) => { + let getBinContent = (ii,jj,level) => { // return bin content in binz1, binz2, reduced flags // return true if bin should be displayed @@ -1102,7 +1114,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { for (i=i1;i0); notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); @@ -1134,7 +1146,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]); for (j=j1;j0); notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); @@ -1300,7 +1312,7 @@ JSROOT.define(['d3', 'painter', 'base3d', 'hist'], (d3, jsrp, THREE) => { for (i=i1;i { x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]); for (j=j1;j { return null; } - // for each entry in streamer info produce member function + // special handling for TStyle which has duplicated member name fLineStyle + if ((s_i.fName == "TStyle") && s_i.fElements) + s_i.fElements.arr.forEach(elem => { + if (elem.fName == "fLineStyle") elem.fName = "fLineStyles"; // like in ROOT JSON now + }); + // for each entry in streamer info produce member function if (s_i.fElements) for (let j = 0; j < s_i.fElements.arr.length; ++j) streamer.push(jsrio.createMember(s_i.fElements.arr[j], this)); diff --git a/js/scripts/JSRoot.latex.js b/js/scripts/JSRoot.latex.js index ea670f23e0a6e..5ab898df98a9e 100644 --- a/js/scripts/JSRoot.latex.js +++ b/js/scripts/JSRoot.latex.js @@ -215,7 +215,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { arg.mainnode = node; } - function extend_pos(pos, value) { + let extend_pos = (pos, value) => { let dx1, dx2, dy1, dy2; @@ -257,9 +257,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { arg.mid_shift = -mid / h || 0.001; // relative shift to get latex middle at given point arg.top_shift = -rect.y / h || 0.001; // relative shift to get latex top at given point } - } + }; - function makeem(value) { + let makeem = value => { if (Math.abs(value) < 1e-2) return null; // very small values not needed, attribute will be removed if (value == Math.round(value)) return Math.round(value) + "em"; let res = value.toFixed(2); @@ -267,9 +267,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (res.indexOf("-0.") == 0) res = "-." + res.substr(3); if (res[res.length - 1] == '0') res = res.substr(0, res.length - 1); return res + "em"; - } + }; - function get_boundary(element, approx_rect) { + let get_boundary = (element, approx_rect) => { // actually, it is workaround for getBBox() or getElementBounday, // which is not implemented for tspan element in Firefox @@ -297,7 +297,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { tspans.each(function() { if (important.indexOf(this) < 0) d3.select(this).attr('display', null); }); return box; - } + }; let features = [ { name: "#it{" }, // italic @@ -639,20 +639,19 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { // we can compare y coordinates while both nodes (root and element) on the same level if ((be.height > bs.height) && (bs.height > 0)) { - yscale = be.height / bs.height * 1.2; + yscale = be.height / bs.height * 1.3; sqrt_dy = ((be.y + be.height) - (bs.y + bs.height)) / curr.fsize / yscale; subpos.square_root.style('font-size', Math.round(100 * yscale) + '%').attr('dy', makeem(sqrt_dy)); } // we taking into account only element width - let len = be.width / subpos.fsize / yscale; - - let a = "", nn = Math.round(Math.max(len * 3, 2)); + let len = be.width / subpos.fsize / yscale, + a = "", nn = Math.round(Math.max(len * 3, 2)); while (nn--) a += '\u203E'; // unicode overline - subpos.square_root.append('svg:tspan').attr("dy", makeem(-0.25)).text(a); + subpos.square_root.append('svg:tspan').attr("dy", makeem(0)).text(a); - subpos.square_root.append('svg:tspan').attr("dy", makeem(0.25 - sqrt_dy)).attr("dx", makeem(-a.length / 3 - 0.2)).text('\u2009'); // unicode tiny space + subpos.square_root.append('svg:tspan').attr("dy", makeem(-sqrt_dy)).attr("dx", makeem(-a.length / 3 - 0.2)).text('\u2009'); // unicode tiny space break; } diff --git a/js/scripts/JSRoot.more.js b/js/scripts/JSRoot.more.js index 9b55d36cd3fae..35eba8724cc54 100644 --- a/js/scripts/JSRoot.more.js +++ b/js/scripts/JSRoot.more.js @@ -4084,6 +4084,23 @@ JSROOT.define(['d3', 'painter', 'math', 'gpad'], (d3, jsrp) => { TRatioPlotPainter.prototype = Object.create(JSROOT.ObjectPainter.prototype); + TRatioPlotPainter.prototype.setGridsRange = function(xmin, xmax) { + let ratio = this.getObject(), + pp = this.getPadPainter(); + if (xmin === xmax) { + let low_p = pp.findPainterFor(ratio.fLowerPad, "lower_pad", "TPad"), + low_fp = low_p ? low_p.getFramePainter() : null; + if (!low_fp || !low_fp.x_handle) return; + xmin = low_fp.x_handle.full_min; + xmax = low_fp.x_handle.full_max; + } + + ratio.fGridlines.forEach(line => { + line.fX1 = xmin; + line.fX2 = xmax; + }); + } + /** @summary Redraw TRatioPlot */ TRatioPlotPainter.prototype.redraw = function() { let ratio = this.getObject(), @@ -4118,7 +4135,10 @@ JSROOT.define(['d3', 'painter', 'math', 'gpad'], (d3, jsrp) => { promise_up = up_p.redrawPad().then(() => { up_fp.o_zoom = up_fp.zoom; up_fp._ratio_low_fp = low_fp; + up_fp._ratio_painter = this; + up_fp.zoom = function(xmin,xmax,ymin,ymax,zmin,zmax) { + this._ratio_painter.setGridsRange(xmin, xmax); this._ratio_low_fp.o_zoom(xmin,xmax); return this.o_zoom(xmin,xmax,ymin,ymax,zmin,zmax); } @@ -4136,45 +4156,67 @@ JSROOT.define(['d3', 'painter', 'math', 'gpad'], (d3, jsrp) => { return promise_up.then(() => { - if (low_p && low_main && low_fp && up_fp && !low_p._ratio_configured) { - low_p._ratio_configured = true; - low_main.options.Axis = 0; // draw both axes - let h = low_main.getHisto(); - h.fXaxis.fTitle = "x"; - h.fXaxis.fLabelSize = lbl_size; - h.fXaxis.fTitleSize = lbl_size; - h.fYaxis.fLabelSize = lbl_size; - h.fYaxis.fTitleSize = lbl_size; - low_p.getRootPad().fTicky = 1; - - low_p.forEachPainterInPad(objp => { - if (typeof objp.testEditable == 'function') - objp.testEditable(false); - }); - - return low_fp.zoom(up_fp.scale_xmin, up_fp.scale_xmax).then(() => { + if (!low_p || !low_main || !low_fp || !up_fp || low_p._ratio_configured) + return this; - low_fp.o_zoom = low_fp.zoom; - low_fp._ratio_up_fp = up_fp; + low_p._ratio_configured = true; + low_main.options.Axis = 0; // draw both axes + let h = low_main.getHisto(); + h.fXaxis.fTitle = "x"; + h.fXaxis.fLabelSize = lbl_size; + h.fXaxis.fTitleSize = lbl_size; + h.fYaxis.fLabelSize = lbl_size; + h.fYaxis.fTitleSize = lbl_size; + low_p.getRootPad().fTicky = 1; - low_fp.zoom = function(xmin,xmax,ymin,ymax,zmin,zmax) { - this._ratio_up_fp.o_zoom(xmin,xmax); - return this.o_zoom(xmin,xmax,ymin,ymax,zmin,zmax); - } + low_p.forEachPainterInPad(objp => { + if (typeof objp.testEditable == 'function') + objp.testEditable(false); + }); - low_fp.o_sizeChanged = low_fp.sizeChanged; - low_fp.sizeChanged = function() { - this.o_sizeChanged(); - this._ratio_up_fp.fX1NDC = this.fX1NDC; - this._ratio_up_fp.fX2NDC = this.fX2NDC; - this._ratio_up_fp.o_sizeChanged(); + let arr = [], currpad; + + if ((ratio.fGridlinePositions.length > 0) && (ratio.fGridlines.length < ratio.fGridlinePositions.length)) { + ratio.fGridlinePositions.forEach(gridy => { + let found = false; + ratio.fGridlines.forEach(line => { + if ((line.fY1 == line.fY2) && (Math.abs(line.fY1 - gridy) < 1e-6)) found = true; + }); + if (!found) { + let line = JSROOT.create("TLine"); + line.fX1 = up_fp.scale_xmin; + line.fX2 = up_fp.scale_xmax; + line.fY1 = line.fY2 = gridy; + line.fLineStyle = 2; + ratio.fGridlines.push(line); + if (currpad === undefined) currpad = this.selectCurrentPad(ratio.fLowerPad.fName); + arr.push(JSROOT.draw(this.getDom(), line)); } - - return this; }); } - return this; + return Promise.all(arr).then(() => low_fp.zoom(up_fp.scale_xmin, up_fp.scale_xmax)).then(() => { + + low_fp.o_zoom = low_fp.zoom; + low_fp._ratio_up_fp = up_fp; + low_fp._ratio_painter = this; + + low_fp.zoom = function(xmin,xmax,ymin,ymax,zmin,zmax) { + this._ratio_painter.setGridsRange(xmin, xmax); + this._ratio_up_fp.o_zoom(xmin,xmax); + return this.o_zoom(xmin,xmax,ymin,ymax,zmin,zmax); + } + + low_fp.o_sizeChanged = low_fp.sizeChanged; + low_fp.sizeChanged = function() { + this.o_sizeChanged(); + this._ratio_up_fp.fX1NDC = this.fX1NDC; + this._ratio_up_fp.fX2NDC = this.fX2NDC; + this._ratio_up_fp.o_sizeChanged(); + } + + return this; + }); }); } @@ -4182,7 +4224,6 @@ JSROOT.define(['d3', 'painter', 'math', 'gpad'], (d3, jsrp) => { let painter = new TRatioPlotPainter(divid, ratio, opt); return jsrp.ensureTCanvas(painter, false).then(() => painter.redraw()); - } // ================================================================================================== diff --git a/js/scripts/JSRoot.v7gpad.js b/js/scripts/JSRoot.v7gpad.js index 04e41b67cdf42..53e6cf4d23e9e 100644 --- a/js/scripts/JSRoot.v7gpad.js +++ b/js/scripts/JSRoot.v7gpad.js @@ -215,6 +215,11 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { line_style = this.v7EvalAttr(prefix + "style", 1); this.createAttLine({ color: line_color, width: line_width, style: line_style }); + + if (prefix == "border_") { + this.lineatt.rx = this.v7EvalAttr(prefix + "rx", 0); + this.lineatt.ry = this.v7EvalAttr(prefix + "ry", 0); + } } /** @summary Create this.markeratt object based on v7 attributes @@ -1517,10 +1522,10 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if ((this.fX1NDC === undefined) || (force && !this.modified_NDC)) { let rect = this.getPadPainter().getPadRect(); - this.fX1NDC = this.v7EvalLength("margin_left", rect.width, JSROOT.settings.FrameNDC.fX1NDC, "margin_all") / rect.width; - this.fY1NDC = this.v7EvalLength("margin_bottom", rect.height, JSROOT.settings.FrameNDC.fY1NDC, "margin_all") / rect.height; - this.fX2NDC = 1 - this.v7EvalLength("margin_right", rect.width, 1-JSROOT.settings.FrameNDC.fX2NDC, "margin_all") / rect.width; - this.fY2NDC = 1 - this.v7EvalLength("margin_top", rect.height, 1-JSROOT.settings.FrameNDC.fY2NDC, "margin_all") / rect.height; + this.fX1NDC = this.v7EvalLength("margins_left", rect.width, JSROOT.settings.FrameNDC.fX1NDC, "margins_all") / rect.width; + this.fY1NDC = this.v7EvalLength("margins_bottom", rect.height, JSROOT.settings.FrameNDC.fY1NDC, "margins_all") / rect.height; + this.fX2NDC = 1 - this.v7EvalLength("margins_right", rect.width, 1-JSROOT.settings.FrameNDC.fX2NDC, "margins_all") / rect.width; + this.fY2NDC = 1 - this.v7EvalLength("margins_top", rect.height, 1-JSROOT.settings.FrameNDC.fY2NDC, "margins_all") / rect.height; } if (!this.fillatt) @@ -1890,10 +1895,10 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { RFramePainter.prototype.sizeChanged = function() { let changes = {}; - this.v7AttrChange(changes, "margin_left", this.fX1NDC); - this.v7AttrChange(changes, "margin_bottom", this.fY1NDC); - this.v7AttrChange(changes, "margin_right", 1 - this.fX2NDC); - this.v7AttrChange(changes, "margin_top", 1 - this.fY2NDC); + this.v7AttrChange(changes, "margins_left", this.fX1NDC); + this.v7AttrChange(changes, "margins_bottom", this.fY1NDC); + this.v7AttrChange(changes, "margins_right", 1 - this.fX2NDC); + this.v7AttrChange(changes, "margins_top", 1 - this.fY2NDC); this.v7SendAttrChanges(changes, false); // do not invoke canvas update on the server this.redrawPad(); @@ -2000,7 +2005,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { // first update all attributes from objects this.updateAttributes(); - let rect = pp ? pp.getPadRect() : { width: 10, height: 10}, + let rect = pp ? pp.getPadRect() : { width: 10, height: 10 }, lm = Math.round(rect.width * this.fX1NDC), w = Math.round(rect.width * (this.fX2NDC - this.fX1NDC)), tm = Math.round(rect.height * (1 - this.fY2NDC)), @@ -2066,6 +2071,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { .attr("y", 0) .attr("width", w) .attr("height", h) + .attr("rx", this.lineatt.rx || null) + .attr("ry", this.lineatt.ry || null) .call(this.fillatt.func) .call(this.lineatt.func); @@ -4655,6 +4662,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { line_width = this.v7EvalAttr("border_width", 1), line_style = this.v7EvalAttr("border_style", 1), line_color = this.v7EvalColor("border_color", "black"), + border_rx = this.v7EvalAttr("border_rx", 0), + border_ry = this.v7EvalAttr("border_ry", 0), fill_color = this.v7EvalColor("fill_color", "white"), fill_style = this.v7EvalAttr("fill_style", 1); @@ -4679,6 +4688,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { .attr("width", pave_width) .attr("y", 0) .attr("height", pave_height) + .attr("rx", border_rx || null) + .attr("ry", border_ry || null) .style("stroke", line_color) .attr("stroke-width", line_width) .style("stroke-dasharray", jsrp.root_line_styles[line_style]) @@ -4844,7 +4855,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return this.fContour && (this.fContour.length > 1) ? this.fContour : null; }, - DeleteContour: function() { + deleteContour: function() { delete this.fContour; }, @@ -4866,7 +4877,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return color.toString(); }, - CreatePaletteColors: function(len) { + createPaletteColors: function(len) { let arr = [], indx = 0; while (arr.length < len) { @@ -4915,7 +4926,11 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return JSROOT.v7.extractRColor(next.fColor); }, - + /** @summary set full z scale range, used in zooming */ + setFullRange: function(min, max) { + this.full_min = min; + this.full_max = max; + }, createContour: function(logz, nlevels, zmin, zmax, zminpositive) { this.fContour = []; @@ -4951,7 +4966,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { } if (!this.palette || (this.palette.length != nlevels)) - this.palette = this.CreatePaletteColors(nlevels); + this.palette = this.createPaletteColors(nlevels); } }); @@ -4999,7 +5014,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (!framep) return console.log('no frame painter - no palette'); - let zmin = contour[0], + let gmin = palette.full_min, + gmax = palette.full_max, + zmin = contour[0], zmax = contour[contour.length-1], rect = framep.getFrameRect(), fx = rect.x, @@ -5050,7 +5067,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { .style("stroke", "black") .attr("fill", "none"); - framep.z_handle.configureAxis("zaxis", zmin, zmax, zmin, zmax, true, [palette_height, 0], -palette_height, { reverse: false }); + if ((gmin === undefined) || (gmax === undefined)) { gmin = zmin; gmax = zmax; } + + framep.z_handle.configureAxis("zaxis", gmin, gmax, zmin, zmax, true, [palette_height, 0], -palette_height, { reverse: false }); for (let i=0;i { } } + palette.setFullRange(main.zmin, main.zmax); palette.createContour(main.logz, nlevels, zmin, zmax, zminpos); if (this.getDimension() < 3) { diff --git a/js/scripts/JSRoot.v7hist3d.js b/js/scripts/JSRoot.v7hist3d.js index 2c325981da53e..6e00733f7b12a 100644 --- a/js/scripts/JSRoot.v7hist3d.js +++ b/js/scripts/JSRoot.v7hist3d.js @@ -565,7 +565,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { return pos; }; - let CreateZoomMesh = (kind, size_3d, use_y_for_z) => { + let createZoomMesh = (kind, size_3d, use_y_for_z) => { let positions, geom = new THREE.BufferGeometry(); if (kind === "z") @@ -587,8 +587,8 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { mesh.use_y_for_z = use_y_for_z; if (kind=="y") mesh.rotateZ(Math.PI/2).rotateX(Math.PI); mesh.v1 = new THREE.Vector3(positions[0], positions[1], positions[2]); - mesh.v2 = new THREE.Vector3(positions[3], positions[4], positions[5]); - mesh.v3 = new THREE.Vector3(positions[6], positions[7], positions[8]); + mesh.v2 = new THREE.Vector3(positions[6], positions[7], positions[8]); + mesh.v3 = new THREE.Vector3(positions[3], positions[4], positions[5]); mesh.globalIntersect = function(raycaster) { if (!this.v1 || !this.v2 || !this.v3) return undefined; @@ -598,9 +598,8 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { plane.applyMatrix4(this.matrixWorld); let v1 = raycaster.ray.origin.clone(), - v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10); - - let pnt = plane.intersectLine(new THREE.Line3(v1,v2), new THREE.Vector3()); + v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10), + pnt = plane.intersectLine(new THREE.Line3(v1,v2), new THREE.Vector3()); if (!pnt) return undefined; @@ -627,26 +626,39 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { if (!tgtmesh) { gg = this.geometry.clone(); - if (kind==="z") gg.vertices[1].x = gg.vertices[2].x = ticklen; - else gg.vertices[2].y = gg.vertices[3].y = -ticklen; + let pos = gg.getAttribute('position').array; + + // original vertices [0, 2, 1, 0, 3, 2] + // if (kind==="z") gg.vertices[1].x = gg.vertices[2].x = ticklen; + // else gg.vertices[2].y = gg.vertices[3].y = -ticklen; + if (kind==="z") pos[6] = pos[3] = pos[15] = ticklen; + else pos[4] = pos[16] = pos[13] = -ticklen; tgtmesh = new THREE.Mesh(gg, new THREE.MeshBasicMaterial({ color: 0xFF00, side: THREE.DoubleSide })); this.add(tgtmesh); } else { gg = tgtmesh.geometry; } - if (kind=="z") { - gg.vertices[0].z = gg.vertices[1].z = pnt1[kind]; - gg.vertices[2].z = gg.vertices[3].z = pnt2[kind]; + let pos = gg.getAttribute('position').array; + + if (kind == "z") { + // gg.vertices[0].z = gg.vertices[1].z = pnt1[kind]; + // gg.vertices[2].z = gg.vertices[3].z = pnt2[kind]; + pos[2] = pos[11] = pos[8] = pnt1[kind]; + pos[5] = pos[17] = pos[14] = pnt2[kind]; } else { - gg.vertices[0].x = gg.vertices[3].x = pnt1[kind]; - gg.vertices[1].x = gg.vertices[2].x = pnt2[kind]; + // gg.vertices[0].x = gg.vertices[3].x = pnt1[kind]; + // gg.vertices[1].x = gg.vertices[2].x = pnt2[kind]; + pos[0] = pos[9] = pos[12] = pnt1[kind]; + pos[6] = pos[3] = pos[15] = pnt2[kind]; } + gg.getAttribute('position').needsUpdate = true; + gg.computeFaceNormals(); - gg.verticesNeedUpdate = true; - gg.normalsNeedUpdate = true; + // gg.verticesNeedUpdate = true; + // gg.normalsNeedUpdate = true; return true; }; @@ -676,7 +688,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { xcont.add(mesh); }); - if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + if (opts.zoom) xcont.add(createZoomMesh("x", this.size_xy3d)); top.add(xcont); xcont = new THREE.Object3D(); @@ -700,7 +712,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { //xcont.add(new THREE.Mesh(ggg2, textMaterial)); xcont.xyid = 4; - if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + if (opts.zoom) xcont.add(createZoomMesh("x", this.size_xy3d)); top.add(xcont); lbls = []; text_scale = 1; maxtextheight = 0; ticks = []; @@ -775,7 +787,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { }); ycont.xyid = 3; - if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + if (opts.zoom) ycont.add(createZoomMesh("y", this.size_xy3d)); top.add(ycont); ycont = new THREE.Object3D(); @@ -797,7 +809,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { ycont.add(mesh); }); ycont.xyid = 1; - if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + if (opts.zoom) ycont.add(createZoomMesh("y", this.size_xy3d)); top.add(ycont); } @@ -916,7 +928,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { } zcont[n].add(n==0 ? zticksline : new THREE.LineSegments(zticksline.geometry, lineMaterial)); - if (opts.zoom) zcont[n].add(CreateZoomMesh("z", this.size_z3d, opts.use_y_for_z)); + if (opts.zoom) zcont[n].add(createZoomMesh("z", this.size_z3d, opts.use_y_for_z)); zcont[n].zid = n + 2; top.add(zcont[n]); @@ -1002,7 +1014,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { if ((i1 >= i2) || (j1 >= j2)) return; - let GetBinContent = (ii,jj, level) => { + let getBinContent = (ii,jj,level) => { // return bin content in binz1, binz2, reduced flags // return true if bin should be displayed @@ -1060,7 +1072,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { for (i = i1; i < i2; i += di) for (j = j1; j < j2; j += dj) { - if (!GetBinContent(i,j,nlevel)) continue; + if (!getBinContent(i,j,nlevel)) continue; nobottom = !reduced && (nlevel>0); notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); @@ -1092,7 +1104,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+di]-handle.grx[i]); for (j = j1; j < j2; j += dj) { - if (!GetBinContent(i,j,nlevel)) continue; + if (!getBinContent(i,j,nlevel)) continue; nobottom = !reduced && (nlevel>0); notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); @@ -1257,7 +1269,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { for (i = i1; i < i2; i += di) for (j = j1; j < j2; j += dj) { - if (!GetBinContent(i,j,0)) continue; + if (!getBinContent(i,j,0)) continue; // calculate required buffer size for line segments numlinevertices += (reduced ? rvertices.length : vertices.length); @@ -1282,7 +1294,7 @@ JSROOT.define(['d3', 'base3d', 'painter', 'v7hist'], (d3, THREE, jsrp) => { x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+di]-handle.grx[i]); for (j = j1; j < j2; j += dj) { - if (!GetBinContent(i,j,0)) continue; + if (!getBinContent(i,j,0)) continue; y1 = handle.gry[j] + handle.ybar1*(handle.gry[j+dj] - handle.gry[j]); y2 = handle.gry[j] + handle.ybar2*(handle.gry[j+dj] - handle.gry[j]); diff --git a/js/scripts/JSRoot.v7more.js b/js/scripts/JSRoot.v7more.js index 913b4f9ddccf9..73d8e7d442309 100644 --- a/js/scripts/JSRoot.v7more.js +++ b/js/scripts/JSRoot.v7more.js @@ -60,13 +60,13 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { clipping = onframe ? this.v7EvalAttr("clipping", false) : false, p1 = pp.getCoordinate(box.fP1, onframe), p2 = pp.getCoordinate(box.fP2, onframe), - line_width = this.v7EvalAttr("box_border_width", 1), - line_style = this.v7EvalAttr("box_border_style", 1), - line_color = this.v7EvalColor("box_border_color", "black"), - fill_color = this.v7EvalColor("box_fill_color", "white"), - fill_style = this.v7EvalAttr("box_fill_style", 1), - round_width = this.v7EvalAttr("box_round_width", 0), // not yet exists - round_height = this.v7EvalAttr("box_round_height", 0); // not yet exists + line_width = this.v7EvalAttr("border_width", 1), + line_style = this.v7EvalAttr("border_style", 1), + line_color = this.v7EvalColor("border_color", "black"), + fill_color = this.v7EvalColor("fill_color", "white"), + fill_style = this.v7EvalAttr("fill_style", 1), + border_rx = this.v7EvalAttr("border_rx", 0), + border_ry = this.v7EvalAttr("border_ry", 0); this.createG(clipping ? "main_layer" : (onframe ? "upper_layer" : false)); @@ -78,8 +78,8 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { .attr("width", p2.x-p1.x) .attr("y", p2.y) .attr("height", p1.y-p2.y) - .attr("rx", round_width) - .attr("ry", round_height) + .attr("rx", border_rx || null) + .attr("ry", border_ry || null) .style("stroke", line_color) .attr("stroke-width", line_width) .attr("fill", fill_color) From 28fc566f21645d3b3332d9b870902600ccc4cd25 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Tue, 1 Jun 2021 13:21:34 +0200 Subject: [PATCH 092/309] [ntuple] Register new performance counters in RPageSinkFile Several new counters were added to the file backend: - fSzWritePayload: that keeps track of the total volume written in commited pages. - fSzZip: total size of data before zipping - fTime{Wall,Cpu}Zip: that measure the wall clock/cpu time spent compressing. This suffices to compute the actual write throughput, where needed. --- tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx | 6 +++++ tree/ntuple/v7/src/RPageStorageFile.cxx | 23 +++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx index 50ce852529e5f..ec78655fadd0a 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx @@ -58,6 +58,12 @@ private: /// I/O performance counters that get registered in fMetrics struct RCounters { RNTupleAtomicCounter &fNPageCommitted; + RNTupleAtomicCounter &fSzWritePayload; + RNTupleAtomicCounter &fSzZip; + RNTupleAtomicCounter &fTimeWallWrite; + RNTupleAtomicCounter &fTimeWallZip; + RNTupleTickCounter &fTimeCpuWrite; + RNTupleTickCounter &fTimeCpuZip; }; std::unique_ptr fCounters; RNTupleMetrics fMetrics; diff --git a/tree/ntuple/v7/src/RPageStorageFile.cxx b/tree/ntuple/v7/src/RPageStorageFile.cxx index 905263bc6e0b7..f582732b3f073 100644 --- a/tree/ntuple/v7/src/RPageStorageFile.cxx +++ b/tree/ntuple/v7/src/RPageStorageFile.cxx @@ -51,7 +51,14 @@ ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntuple R__LOG_WARNING(NTupleLog()) << "The RNTuple file format will change. " << "Do not store real data with this version of RNTuple!"; fCounters = std::unique_ptr(new RCounters{ - *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage") + *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage"), + *fMetrics.MakeCounter("szWritePayload", "B", "volume written for committed pages"), + *fMetrics.MakeCounter("szZip", "B", "volume before zipping"), + *fMetrics.MakeCounter("timeWallWrite", "ns", "wall clock time spent writing"), + *fMetrics.MakeCounter("timeWallZip", "ns", "wall clock time spent compressing"), + *fMetrics.MakeCounter*>("timeCpuWrite", "ns", "CPU time spent writing"), + *fMetrics.MakeCounter*> ("timeCpuZip", "ns", + "CPU time spent compressing") }); fCompressor = std::make_unique(); } @@ -106,7 +113,11 @@ inline ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkFile::WriteSealedPage( const RPageStorage::RSealedPage &sealedPage, std::size_t bytesPacked) { - const auto offsetData = fWriter->WriteBlob(sealedPage.fBuffer, sealedPage.fSize, bytesPacked); + std::uint64_t offsetData; + { + RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite); + offsetData = fWriter->WriteBlob(sealedPage.fBuffer, sealedPage.fSize, bytesPacked); + } fClusterMinOffset = std::min(offsetData, fClusterMinOffset); fClusterMaxOffset = std::max(offsetData + sealedPage.fSize, fClusterMaxOffset); @@ -114,6 +125,7 @@ ROOT::Experimental::Detail::RPageSinkFile::WriteSealedPage( result.fPosition = offsetData; result.fBytesOnStorage = sealedPage.fSize; fCounters->fNPageCommitted.Inc(); + fCounters->fSzWritePayload.Add(sealedPage.fSize); return result; } @@ -122,8 +134,13 @@ ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkFile::CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) { auto element = columnHandle.fColumn->GetElement(); - auto sealedPage = SealPage(page, *element, fOptions.GetCompression()); + RPageStorage::RSealedPage sealedPage; + { + RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip); + sealedPage = SealPage(page, *element, fOptions.GetCompression()); + } + fCounters->fSzZip.Add(page.GetSize()); return WriteSealedPage(sealedPage, element->GetPackedSize(page.GetNElements())); } From 490710c40bf15e2848e99f2902cde239b5c8f6a5 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Tue, 1 Jun 2021 13:26:17 +0200 Subject: [PATCH 093/309] [ntuple,daos] Add performance counters to RPageSinkDaos Port of the available performance counters for RPageSinkFile to the DAOS backend. Note however, that common performance metrics might be probably handled by the base class; to be discussed. --- tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx | 11 +++++++ tree/ntuple/v7/src/RPageStorageDaos.cxx | 31 ++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx index 203e790cf1499..c1a55dc01e65c 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx @@ -86,6 +86,17 @@ Currently, an object is allocated for each page + 3 additional objects (anchor/h // clang-format on class RPageSinkDaos : public RPageSink { private: + /// I/O performance counters that get registered in fMetrics + struct RCounters { + RNTupleAtomicCounter &fNPageCommitted; + RNTupleAtomicCounter &fSzWritePayload; + RNTupleAtomicCounter &fSzZip; + RNTupleAtomicCounter &fTimeWallWrite; + RNTupleAtomicCounter &fTimeWallZip; + RNTupleTickCounter &fTimeCpuWrite; + RNTupleTickCounter &fTimeCpuZip; + }; + std::unique_ptr fCounters; RNTupleMetrics fMetrics; std::unique_ptr fPageAllocator; diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index 71e969b85c1a6..602f0b564f7af 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -114,6 +114,16 @@ ROOT::Experimental::Detail::RPageSinkDaos::RPageSinkDaos(std::string_view ntuple { R__LOG_WARNING(NTupleLog()) << "The DAOS backend is experimental and still under development. " << "Do not store real data with this version of RNTuple!"; + fCounters = std::unique_ptr(new RCounters{ + *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage"), + *fMetrics.MakeCounter("szWritePayload", "B", "volume written for committed pages"), + *fMetrics.MakeCounter("szZip", "B", "volume before zipping"), + *fMetrics.MakeCounter("timeWallWrite", "ns", "wall clock time spent writing"), + *fMetrics.MakeCounter("timeWallZip", "ns", "wall clock time spent compressing"), + *fMetrics.MakeCounter*>("timeCpuWrite", "ns", "CPU time spent writing"), + *fMetrics.MakeCounter*> ("timeCpuZip", "ns", + "CPU time spent compressing") + }); fCompressor = std::make_unique(); } @@ -143,8 +153,13 @@ ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkDaos::CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) { auto element = columnHandle.fColumn->GetElement(); - auto sealedPage = SealPage(page, *element, fOptions.GetCompression()); + RPageStorage::RSealedPage sealedPage; + { + RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip); + sealedPage = SealPage(page, *element, fOptions.GetCompression()); + } + fCounters->fSzZip.Add(page.GetSize()); return CommitSealedPageImpl(columnHandle.fId, sealedPage); } @@ -153,14 +168,20 @@ ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkDaos::CommitSealedPageImpl( DescriptorId_t /*columnId*/, const RPageStorage::RSealedPage &sealedPage) { - auto offsetData = std::get<0>(fDaosContainer->WriteObject(sealedPage.fBuffer, - sealedPage.fSize, - kDistributionKey, - kAttributeKey)).lo; + std::uint64_t offsetData; + { + RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite); + offsetData = std::get<0>(fDaosContainer->WriteObject(sealedPage.fBuffer, + sealedPage.fSize, + kDistributionKey, + kAttributeKey)).lo; + } RClusterDescriptor::RLocator result; result.fPosition = offsetData; result.fBytesOnStorage = sealedPage.fSize; + fCounters->fNPageCommitted.Inc(); + fCounters->fSzWritePayload.Add(sealedPage.fSize); return result; } From 27c8815a1960d9952af0fd143e8b5b998cf75aff Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Wed, 9 Jun 2021 17:45:10 +0200 Subject: [PATCH 094/309] [TClass] Clarify ctor vs GetClass() (#8250) (NFC). [skip-ci] (#8384) Co-authored-by: Philippe Canal --- core/meta/src/TClass.cxx | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 99ac81f5fe69e..7218abae943e2 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -1056,6 +1056,9 @@ void TAutoInspector::Inspect(TClass *cl, const char *tit, const char *name, ClassImp(TClass); //////////////////////////////////////////////////////////////////////////////// +/// Internal, default constructor. +/// +/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class! TClass::TClass() : TDictionary(), @@ -1090,10 +1093,10 @@ TClass::TClass() : //////////////////////////////////////////////////////////////////////////////// /// Create a TClass object. This object contains the full dictionary /// of a class. It has list to baseclasses, datamembers and methods. -/// Use this ctor to create a standalone TClass object. Most useful -/// to get a TClass interface to an interpreted class. Used by TTabCom. -/// Normally you would use TClass::GetClass("class") to get access to a -/// TClass object for a certain class. +/// Use this ctor to create a standalone TClass object. Only useful +/// to get a temporary TClass interface to an interpreted class. Used by TTabCom. +/// +/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class! TClass::TClass(const char *name, Bool_t silent) : TDictionary(name), @@ -1139,8 +1142,9 @@ TClass::TClass(const char *name, Bool_t silent) : } //////////////////////////////////////////////////////////////////////////////// -/// Create a TClass object. This object contains the full dictionary -/// of a class. It has list to baseclasses, datamembers and methods. +/// Internal constructor. +/// +/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class! TClass::TClass(const char *name, Version_t cversion, Bool_t silent) : TDictionary(name), @@ -1166,8 +1170,9 @@ TClass::TClass(const char *name, Version_t cversion, Bool_t silent) : } //////////////////////////////////////////////////////////////////////////////// -/// Create a TClass object. This object does not contain anything. We mimic -/// the case of a class fwd declared in the interpreter. +/// Internal constructor, mimicing the case of a class fwd declared in the interpreter. +/// +/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class! TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t silent) : TDictionary(name), @@ -1203,14 +1208,16 @@ TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t sil } //////////////////////////////////////////////////////////////////////////////// +/// Internal constructor. +/// /// Create a TClass object. This object contains the full dictionary /// of a class. It has list to baseclasses, datamembers and methods. /// Use this ctor to create a standalone TClass object. Most useful /// to get a TClass interface to an interpreted class. Used by TTabCom. -/// Normally you would use TClass::GetClass("class") to get access to a -/// TClass object for a certain class. /// /// This copies the ClassInfo (i.e. does *not* take ownership of it). +/// +/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class! TClass::TClass(ClassInfo_t *classInfo, Version_t cversion, const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) : @@ -1259,8 +1266,9 @@ TClass::TClass(ClassInfo_t *classInfo, Version_t cversion, //////////////////////////////////////////////////////////////////////////////// -/// Create a TClass object. This object contains the full dictionary -/// of a class. It has list to baseclasses, datamembers and methods. +/// Internal constructor. +/// +/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class! TClass::TClass(const char *name, Version_t cversion, const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) : @@ -1287,8 +1295,9 @@ TClass::TClass(const char *name, Version_t cversion, } //////////////////////////////////////////////////////////////////////////////// -/// Create a TClass object. This object contains the full dictionary -/// of a class. It has list to baseclasses, datamembers and methods. +/// Internal constructor. +/// +/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class! TClass::TClass(const char *name, Version_t cversion, const std::type_info &info, TVirtualIsAProxy *isa, From c72dcbf099bcfa16369e6fbd66f00b3ffd41c63d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Hueso=20Gonz=C3=A1lez?= Date: Wed, 9 Jun 2021 00:09:14 +0200 Subject: [PATCH 095/309] protect fIsRunning from TThread, and fix typo --- core/base/inc/TApplication.h | 2 +- core/base/src/TApplication.cxx | 8 ++++++++ core/thread/src/TThread.cxx | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/base/inc/TApplication.h b/core/base/inc/TApplication.h index 32f4b16cf6bf4..bc4c1a68a42cd 100644 --- a/core/base/inc/TApplication.h +++ b/core/base/inc/TApplication.h @@ -145,7 +145,7 @@ class TApplication : public TObject, public TQObject { TApplication *GetAppRemote() const { return fAppRemote; } - Bool_t IsRunning() const { return fIsRunning; } + Bool_t IsRunning() const; Bool_t ReturnFromRun() const { return fReturnFromRun; } void SetReturnFromRun(Bool_t ret) { fReturnFromRun = ret; } diff --git a/core/base/src/TApplication.cxx b/core/base/src/TApplication.cxx index 88ba355cf952a..f3312a098e065 100644 --- a/core/base/src/TApplication.cxx +++ b/core/base/src/TApplication.cxx @@ -245,6 +245,12 @@ TApplication::~TApplication() SafeDelete(fAppImp); } +Bool_t TApplication::IsRunning() const +{ + R__LOCKGUARD(gROOTMutex); + return fIsRunning; +} + //////////////////////////////////////////////////////////////////////////////// /// Static method. This method should be called from static library /// initializers if the library needs the low level graphics system. @@ -1619,7 +1625,9 @@ void TApplication::Run(Bool_t retrn) { SetReturnFromRun(retrn); + gROOTMutex->Lock(); fIsRunning = kTRUE; + gROOTMutex->UnLock(); gSystem->Run(); fIsRunning = kFALSE; diff --git a/core/thread/src/TThread.cxx b/core/thread/src/TThread.cxx index 42e7c1d3cd012..d3c2dc79fa1af 100644 --- a/core/thread/src/TThread.cxx +++ b/core/thread/src/TThread.cxx @@ -1204,7 +1204,7 @@ TThreadTimer::TThreadTimer(Long_t ms) : TTimer(ms, kTRUE) } //////////////////////////////////////////////////////////////////////////////// -/// Periodically execute the TThread::XAxtion() method in the main thread. +/// Periodically execute the TThread::XAction() method in the main thread. Bool_t TThreadTimer::Notify() { From 37441979f43adf6a31e028e596c5fa6f64475813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Hueso=20Gonz=C3=A1lez?= Date: Wed, 9 Jun 2021 00:19:16 +0200 Subject: [PATCH 096/309] apply when stopping also, just in case --- core/base/src/TApplication.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/base/src/TApplication.cxx b/core/base/src/TApplication.cxx index f3312a098e065..abb32607450d8 100644 --- a/core/base/src/TApplication.cxx +++ b/core/base/src/TApplication.cxx @@ -1630,7 +1630,9 @@ void TApplication::Run(Bool_t retrn) gROOTMutex->UnLock(); gSystem->Run(); + gROOTMutex->Lock(); fIsRunning = kFALSE; + gROOTMutex->UnLock(); } //////////////////////////////////////////////////////////////////////////////// From d3babea8ec6dcb6c8a891704b68acbf5068125a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Hueso=20Gonz=C3=A1lez?= Date: Wed, 9 Jun 2021 01:34:44 +0200 Subject: [PATCH 097/309] use atomic to simplify --- core/base/inc/TApplication.h | 4 ++-- core/base/src/TApplication.cxx | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/core/base/inc/TApplication.h b/core/base/inc/TApplication.h index bc4c1a68a42cd..e6d8fd1af06b3 100644 --- a/core/base/inc/TApplication.h +++ b/core/base/inc/TApplication.h @@ -58,7 +58,7 @@ class TApplication : public TObject, public TQObject { Int_t fArgc; //Number of com mand line arguments char **fArgv; //Command line arguments TApplicationImp *fAppImp; //!Window system specific application implementation - Bool_t fIsRunning; //True when in event loop (Run() has been called) + std::atomic fIsRunning; //True when in event loop (Run() has been called) Bool_t fReturnFromRun; //When true return from Run() Bool_t fNoLog; //Do not process logon and logoff macros Bool_t fNoLogo; //Do not show splash screen and welcome message @@ -145,7 +145,7 @@ class TApplication : public TObject, public TQObject { TApplication *GetAppRemote() const { return fAppRemote; } - Bool_t IsRunning() const; + Bool_t IsRunning() const { return fIsRunning; } Bool_t ReturnFromRun() const { return fReturnFromRun; } void SetReturnFromRun(Bool_t ret) { fReturnFromRun = ret; } diff --git a/core/base/src/TApplication.cxx b/core/base/src/TApplication.cxx index abb32607450d8..88ba355cf952a 100644 --- a/core/base/src/TApplication.cxx +++ b/core/base/src/TApplication.cxx @@ -245,12 +245,6 @@ TApplication::~TApplication() SafeDelete(fAppImp); } -Bool_t TApplication::IsRunning() const -{ - R__LOCKGUARD(gROOTMutex); - return fIsRunning; -} - //////////////////////////////////////////////////////////////////////////////// /// Static method. This method should be called from static library /// initializers if the library needs the low level graphics system. @@ -1625,14 +1619,10 @@ void TApplication::Run(Bool_t retrn) { SetReturnFromRun(retrn); - gROOTMutex->Lock(); fIsRunning = kTRUE; - gROOTMutex->UnLock(); gSystem->Run(); - gROOTMutex->Lock(); fIsRunning = kFALSE; - gROOTMutex->UnLock(); } //////////////////////////////////////////////////////////////////////////////// From a5111eb403962ae3f75591cac85857db10e3bc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Hueso=20Gonz=C3=A1lez?= Date: Wed, 9 Jun 2021 01:54:25 +0200 Subject: [PATCH 098/309] add atomic bool to suppression file --- etc/helgrind-root.supp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/etc/helgrind-root.supp b/etc/helgrind-root.supp index ad1b109b4d3e4..a0ac4c1dba8aa 100644 --- a/etc/helgrind-root.supp +++ b/etc/helgrind-root.supp @@ -41,6 +41,13 @@ Helgrind:Race fun:_ZN11TBufferFile12WriteVersionEPK6TClassb } +{ + Due to TApplication::fIsRunning which is a std::atomic ... may hide other problems. + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIbEcvbEv + fun:_ZNK12TApplication9IsRunningEv +} { Due to TClass::fLastReadInfo which is an std::atomic ... may hide other problems. @@ -390,4 +397,4 @@ Helgrind:Race fun:__new_exitfn fun:__cxa_atexit -} \ No newline at end of file +} From 3d850fe3d1ea9ec1cc6a5665f7c9eb47e1e02b18 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Wed, 9 Jun 2021 20:15:32 +0200 Subject: [PATCH 099/309] [skip-ci] Fix stressGUI and Makefile.win32 Discovered when running `stressGUI`: - Fix a couple of PATHs in `stressGUI.cxx` - Fix the compilation of `Aclock`, `Hello`, and `Tetris` and add support for `Win64` in `test/Makefile.win32` - Fix the following error with `tutorials/gui/Slider3Demo.C`: ``` tutorials\gui\Slider3Demo.C:198:21: error: call to member function 'SetPosition' is ambiguous ``` --- test/Makefile.win32 | 29 +++++++++++++++++++++++------ test/stressGUI.cxx | 6 +++--- tutorials/gui/Slider3Demo.C | 10 +++++----- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/test/Makefile.win32 b/test/Makefile.win32 index f490a6dcff74c..0e027feebd681 100644 --- a/test/Makefile.win32 +++ b/test/Makefile.win32 @@ -47,6 +47,18 @@ ExeSuf = .exe DllSuf = dll OutPutOpt = -out: +!IF "$(PLATFORM)" == "x86" +CPU=i386 +DLLENTRY = @12 +MACHINE=IX86 +!endif + +!IF "$(PLATFORM)" == "x64" +CPU=x86_64 +MACHINE=AMD64 +DLLENTRY = +!ENDIF + # Win32 system with Microsoft Visual C/C++ APPVER = 5.01 @@ -54,7 +66,6 @@ cc = cl link = link implib = lib lflags = $(lflags) /INCREMENTAL:NO /NOLOGO -DLLENTRY = @12 conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll @@ -334,13 +345,13 @@ all: $(PROGRAMS) $(EVENTSO): $(EVENTO) BINDEXPLIB $* $(EVENTO) > $*.def - lib -nologo -MACHINE:IX86 $(EVENTO) -def:$*.def $(OutPutOpt)$(EVENTLIB) + lib -nologo -MACHINE:$(MACHINE) $(EVENTO) -def:$*.def $(OutPutOpt)$(EVENTLIB) $(LD) $(SOFLAGS) $(LDFLAGS) $(EVENTO) $*.exp $(LIBS) $(OutPutOpt)$(EVENTSO) @echo "$(EVENTSO) done" $(EVENTMTSO): $(EVENTMTO) BINDEXPLIB $* $(EVENTMTO) > $*.def - lib -nologo -MACHINE:IX86 $(EVENTMTO) -def:$*.def $(OutPutOpt)$(EVENTMTLIB) + lib -nologo -MACHINE:$(MACHINE) $(EVENTMTO) -def:$*.def $(OutPutOpt)$(EVENTMTLIB) $(LD) $(SOFLAGS) $(LDFLAGS) $(EVENTMTO) $*.exp $(LIBS) $(OutPutOpt)$(EVENTMTSO) @echo "$(EVENTMTSO) done" @@ -511,15 +522,21 @@ $(BENCH): $(BENCHO) $(TBENCHSO) Hello: $(HELLOSO) $(HELLOSO): $(HELLOO) - $(LD) $(SOFLAGS) $(LDFLAGS) $(HELLOO) $(GLIBS) $(OutPutOpt)$@ + BINDEXPLIB $* $(HELLOO) > $*.def + lib -nologo -MACHINE:$(MACHINE) $(HELLOO) -def:$*.def $(OutPutOpt)Hello.lib + $(LD) $(SOFLAGS) $(LDFLAGS) $(HELLOO) $*.exp $(GLIBS) $(OutPutOpt)$@ Aclock: $(ACLOCKSO) $(ACLOCKSO): $(ACLOCKO) - $(LD) $(SOFLAGS) $(LDFLAGS) $(ACLOCKO) $(GLIBS) $(OutPutOpt)$@ + BINDEXPLIB $* $(ACLOCKO) > $*.def + lib -nologo -MACHINE:$(MACHINE) $(ACLOCKO) -def:$*.def $(OutPutOpt)Aclock.lib + $(LD) $(SOFLAGS) $(LDFLAGS) $(ACLOCKO) $*.exp $(GLIBS) $(OutPutOpt)$@ Tetris: $(TETRISSO) $(TETRISSO): $(TETRISO) - $(LD) $(SOFLAGS) $(LDFLAGS) $(TETRISO) $(GLIBS) $(OutPutOpt)$@ + BINDEXPLIB $* $(TETRISO) > $*.def + lib -nologo -MACHINE:$(MACHINE) $(TETRISO) -def:$*.def $(OutPutOpt)Tetris.lib + $(LD) $(SOFLAGS) $(LDFLAGS) $(TETRISO) $*.exp $(GLIBS) $(OutPutOpt)$@ $(TBENCHSO): $(TBENCHO) $(LD) $(SOFLAGS) $(LDFLAGS) $(TBENCHO) $(LIBS) $(OutPutOpt)$@ diff --git a/test/stressGUI.cxx b/test/stressGUI.cxx index e4bac4b5a5622..1a92df53413a2 100644 --- a/test/stressGUI.cxx +++ b/test/stressGUI.cxx @@ -2185,7 +2185,7 @@ void testSplitFrame() first->GetFirst()->VSplit(); first->GetSecond()->VSplit(); first->GetSecond()->GetSecond()->SetEditable(); - new TGTextEditor("stressGUI.cxx", gClient->GetRoot()); + new TGTextEditor(Form("%s/test/stressGUI.cxx", gRootSys.Data()), gClient->GetRoot()); first->GetSecond()->GetSecond()->SetEditable(kFALSE); mf->MapSubwindows(); mf->Resize(600, 400); @@ -2282,9 +2282,9 @@ void testPaletteEditor() void testHtmlBrowser() { - TGHtmlBrowser *b = new TGHtmlBrowser("http://bellenot.web.cern.ch/bellenot/Public/html_test/html_test.html"); + TGHtmlBrowser *b = new TGHtmlBrowser("https://bellenot.web.cern.ch/public/html_test/html_test.html"); ProcessFrame((TGMainFrame*)b, "HTML Browser 1"); - b->Selected("http://bellenot.web.cern.ch/bellenot/Public/html_test/gallery/"); + b->Selected("https://bellenot.web.cern.ch/public/html_test/gallery/"); ProcessFrame((TGMainFrame*)b, "HTML Browser 2"); b->CloseWindow(); } diff --git a/tutorials/gui/Slider3Demo.C b/tutorials/gui/Slider3Demo.C index 85c3d8de9dc82..3d6dfc980d80f 100644 --- a/tutorials/gui/Slider3Demo.C +++ b/tutorials/gui/Slider3Demo.C @@ -195,15 +195,15 @@ void TTripleSliderDemo::DoText(const char * /*text*/) switch (id) { case HId1: - fHslider1->SetPosition(atof(fTbh1->GetString()), - fHslider1->GetMaxPosition()); + fHslider1->SetPosition((Float_t)atof(fTbh1->GetString()), + (Float_t)fHslider1->GetMaxPosition()); break; case HId2: - fHslider1->SetPointerPosition(atof(fTbh2->GetString())); + fHslider1->SetPointerPosition((Float_t)atof(fTbh2->GetString())); break; case HId3: - fHslider1->SetPosition(fHslider1->GetMinPosition(), - atof(fTbh1->GetString())); + fHslider1->SetPosition((Float_t)fHslider1->GetMinPosition(), + (Float_t)atof(fTbh1->GetString())); break; default: break; From 1acb20294f8790b969b05736ab60fa767d8d321d Mon Sep 17 00:00:00 2001 From: Omar Zapata Date: Wed, 9 Jun 2021 17:07:33 +0200 Subject: [PATCH 100/309] JupyROOT: fixed bug closing the file descriptors caputring stderr and stdout --- bindings/jupyroot/src/IOHandler.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/jupyroot/src/IOHandler.cxx b/bindings/jupyroot/src/IOHandler.cxx index a895eabb524ab..6a2cc2766f9aa 100644 --- a/bindings/jupyroot/src/IOHandler.cxx +++ b/bindings/jupyroot/src/IOHandler.cxx @@ -105,7 +105,6 @@ static void InitCaptureImpl(int &savedStdStream, int *pipeHandle, int FILENO) fcntl(pipeHandle[0], F_SETPIPE_SZ, MAX_PIPE_SIZE); #endif dup2(pipeHandle[1], FILENO); - close(pipeHandle[1]); } void JupyROOTExecutorHandler::InitCapture() @@ -123,6 +122,12 @@ void JupyROOTExecutorHandler::EndCapture() Poll(); dup2(fSaved_stdout, STDOUT_FILENO); dup2(fSaved_stderr, STDERR_FILENO); + close(fSaved_stdout); + close(fSaved_stderr); + close(fStdout_pipe[0]); + close(fStdout_pipe[1]); + close(fStderr_pipe[0]); + close(fStderr_pipe[1]); fCapturing = false; } } From c44fe9859b7efd5728b69b85361ae588fd613cd9 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 3 Jun 2021 13:14:59 +0200 Subject: [PATCH 101/309] [DF] Add support for data-block callbacks in RDF These are callbacks that are run at the beginning of a new "data block": in the case of a TChain, a new data block starts when the TChain switches TTrees or when a new multi-thread task starts. In other cases a new data block starts with each new task. In the future RDataSources might be able to provide their own definition of a data block. For now, only actions are wired to the data-block callback logic. In the future we could also offer a special kind of Defines that only update their values at the beginning of a data block, which would provide a `DefinePerSample` feature. --- tree/dataframe/CMakeLists.txt | 1 + tree/dataframe/inc/LinkDef.h | 1 + tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 3 + .../dataframe/inc/ROOT/RDF/InterfaceUtils.hxx | 1 + tree/dataframe/inc/ROOT/RDF/RAction.hxx | 2 + tree/dataframe/inc/ROOT/RDF/RActionBase.hxx | 2 + .../inc/ROOT/RDF/RDataBlockNotifier.hxx | 58 ++++++++++++++++++ tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 1 + tree/dataframe/inc/ROOT/RDF/RJittedAction.hxx | 2 + tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx | 8 ++- tree/dataframe/src/RJittedAction.cxx | 6 ++ tree/dataframe/src/RLoopManager.cxx | 61 +++++++++++++++---- 12 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 tree/dataframe/inc/ROOT/RDF/RDataBlockNotifier.hxx diff --git a/tree/dataframe/CMakeLists.txt b/tree/dataframe/CMakeLists.txt index cf832d10c0f32..2728a76fd801f 100644 --- a/tree/dataframe/CMakeLists.txt +++ b/tree/dataframe/CMakeLists.txt @@ -52,6 +52,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTDataFrame ROOT/RDF/RActionBase.hxx ROOT/RDF/RAction.hxx ROOT/RDF/RBookedDefines.hxx + ROOT/RDF/RDataBlockNotifier.hxx ROOT/RDF/RDefineBase.hxx ROOT/RDF/RDefine.hxx ROOT/RDF/RDefineReader.hxx diff --git a/tree/dataframe/inc/LinkDef.h b/tree/dataframe/inc/LinkDef.h index d2aed5f228865..3879ac8d5d3ca 100644 --- a/tree/dataframe/inc/LinkDef.h +++ b/tree/dataframe/inc/LinkDef.h @@ -56,6 +56,7 @@ #pragma link C++ class ROOT::Detail::RDF::RMergeableValue+; #pragma link C++ class ROOT::Detail::RDF::RMergeableValue+; #pragma link C++ class ROOT::Detail::RDF::RMergeableValue+; +#pragma link C++ class TNotifyLink; #endif diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 7f09942de1b5c..9fa9563724c01 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -46,6 +46,7 @@ #include "ROOT/RDF/RMergeableValue.hxx" #include +#include #include #include #include @@ -79,6 +80,8 @@ public: { throw std::logic_error("`GetMergeableValue` is not implemented for this type of action."); } + + virtual std::function GetDataBlockCallback() { return {}; } }; } // namespace RDF diff --git a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx index 591882e77ed1c..26856c292f69b 100644 --- a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx @@ -502,6 +502,7 @@ void CallBuildAction(std::shared_ptr *prevNodeOnHeap, const char * auto actionPtr = BuildAction(cols, std::move(*helperArgOnHeap), nSlots, std::move(prevNodePtr), ActionTag{}, *defines); + loopManager.AddDataBlockCallback(actionPtr->GetDataBlockCallback()); jittedActionOnHeap->SetAction(std::move(actionPtr)); // defines points to the columns structure in the heap, created before the jitted call so that the jitter can diff --git a/tree/dataframe/inc/ROOT/RDF/RAction.hxx b/tree/dataframe/inc/ROOT/RDF/RAction.hxx index aac7c05501eac..d720ddf88dc5b 100644 --- a/tree/dataframe/inc/ROOT/RDF/RAction.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RAction.hxx @@ -164,6 +164,8 @@ private: // this one is always available but has lower precedence thanks to `...` void *PartialUpdateImpl(...) { throw std::runtime_error("This action does not support callbacks!"); } + + std::function GetDataBlockCallback() final { return fHelper.GetDataBlockCallback(); } }; } // namespace RDF diff --git a/tree/dataframe/inc/ROOT/RDF/RActionBase.hxx b/tree/dataframe/inc/ROOT/RDF/RActionBase.hxx index aeb39689272b5..2ff4ca4bc1871 100644 --- a/tree/dataframe/inc/ROOT/RDF/RActionBase.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RActionBase.hxx @@ -80,6 +80,8 @@ public: with others of the same type. */ virtual std::unique_ptr GetMergeableValue() const = 0; + + virtual std::function GetDataBlockCallback() = 0; }; } // namespace RDF } // namespace Internal diff --git a/tree/dataframe/inc/ROOT/RDF/RDataBlockNotifier.hxx b/tree/dataframe/inc/ROOT/RDF/RDataBlockNotifier.hxx new file mode 100644 index 0000000000000..a588adaed31bf --- /dev/null +++ b/tree/dataframe/inc/ROOT/RDF/RDataBlockNotifier.hxx @@ -0,0 +1,58 @@ +// Author: Enrico Guiraud, 2021 + +/************************************************************************* + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_RDF_RDATABLOCKNOTIFIER +#define ROOT_RDF_RDATABLOCKNOTIFIER + +#include +#include + +#include + +namespace ROOT { +namespace Internal { +namespace RDF { + +struct RDataBlockFlag { + bool fFlag = false; + +public: + void SetFlag() { fFlag = true; } + void UnsetFlag() { fFlag = false; } + bool CheckFlag() const { return fFlag; } + bool Notify() + { + SetFlag(); + return true; + } +}; + +class RDataBlockNotifier { + // TNotifyLink and RDataBlockFlags per processing slot + std::vector>> fNotifyLink; + std::vector fFlags; + +public: + RDataBlockNotifier(unsigned int nSlots) : fNotifyLink(nSlots), fFlags(nSlots) {} + bool CheckFlag(unsigned int slot) const { return fFlags[slot].CheckFlag(); } + void SetFlag(unsigned int slot) { fFlags[slot].SetFlag(); } + void UnsetFlag(unsigned int slot) { fFlags[slot].UnsetFlag(); } + TNotifyLink &GetChainNotifyLink(unsigned int slot) + { + if (fNotifyLink[slot] == nullptr) + fNotifyLink[slot] = std::make_unique>(&fFlags[slot]); + return *fNotifyLink[slot]; + } +}; +} // namespace RDF +} // namespace Internal +} // namespace ROOT + +#endif // ROOT_RDF_RDATABLOCKNOTIFIER diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index ba1e54f72150c..55a327418f51f 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -2586,6 +2586,7 @@ private: auto action = RDFInternal::BuildAction(validColumnNames, helperArg, nSlots, fProxiedPtr, ActionTag{}, fDefines); fLoopManager->Book(action.get()); + fLoopManager->AddDataBlockCallback(action->GetDataBlockCallback()); return MakeResultPtr(r, *fLoopManager, std::move(action)); } diff --git a/tree/dataframe/inc/ROOT/RDF/RJittedAction.hxx b/tree/dataframe/inc/ROOT/RDF/RJittedAction.hxx index 35be6091c4817..ea0aca27e8f05 100644 --- a/tree/dataframe/inc/ROOT/RDF/RJittedAction.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RJittedAction.hxx @@ -60,6 +60,8 @@ public: // Helper for RMergeableValue std::unique_ptr GetMergeableValue() const final; + + std::function GetDataBlockCallback() final; }; } // ns RDF diff --git a/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx b/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx index ab2b438538e17..39ab384578784 100644 --- a/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RLoopManager.hxx @@ -12,6 +12,7 @@ #define ROOT_RLOOPMANAGER #include "ROOT/RDF/RNodeBase.hxx" +#include "ROOT/RDF/RDataBlockNotifier.hxx" #include #include @@ -115,6 +116,8 @@ class RLoopManager : public RNodeBase { std::map fAliasColumnNameMap; ///< ColumnNameAlias-columnName pairs std::vector fCallbacks; ///< Registered callbacks std::vector fCallbacksOnce; ///< Registered callbacks to invoke just once before running the loop + std::vector fDataBlockCallbacks; ///< Registered callbacks to call at the beginning of each "data block" + RDFInternal::RDataBlockNotifier fDataBlockNotifier; unsigned int fNRuns{0}; ///< Number of event loops run /// Registry of per-slot value pointers for booked data-source columns @@ -134,8 +137,9 @@ class RLoopManager : public RNodeBase { void InitNodeSlots(TTreeReader *r, unsigned int slot); void InitNodes(); void CleanUpNodes(); - void CleanUpTask(unsigned int slot); + void CleanUpTask(TTreeReader *r, unsigned int slot); void EvalChildrenCounts(); + void SetupDataBlockCallbacks(TTreeReader *r, unsigned int slot); public: RLoopManager(TTree *tree, const ColumnNames_t &defaultBranches); @@ -192,6 +196,8 @@ public: std::shared_ptr GetGraph(); const ColumnNames_t &GetBranchNames(); + + void AddDataBlockCallback(std::function &&callback); }; } // ns RDF diff --git a/tree/dataframe/src/RJittedAction.cxx b/tree/dataframe/src/RJittedAction.cxx index 4745e8d5bad21..80b6c4f4ffdcb 100644 --- a/tree/dataframe/src/RJittedAction.cxx +++ b/tree/dataframe/src/RJittedAction.cxx @@ -93,3 +93,9 @@ std::unique_ptr RJittedAction::GetMergea R__ASSERT(fConcreteAction != nullptr); return fConcreteAction->GetMergeableValue(); } + +std::function RJittedAction::GetDataBlockCallback() +{ + R__ASSERT(fConcreteAction != nullptr); + return fConcreteAction->GetDataBlockCallback(); +} diff --git a/tree/dataframe/src/RLoopManager.cxx b/tree/dataframe/src/RLoopManager.cxx index 04cf99601e6d1..36ab2c290e6b9 100644 --- a/tree/dataframe/src/RLoopManager.cxx +++ b/tree/dataframe/src/RLoopManager.cxx @@ -302,7 +302,13 @@ namespace RDF { struct RCallCleanUpTask { RLoopManager &fLoopManager; unsigned int fArg; - ~RCallCleanUpTask() { fLoopManager.CleanUpTask(fArg); } + TTreeReader *fReader; + + RCallCleanUpTask(RLoopManager &lm, unsigned int arg = 0u, TTreeReader *reader = nullptr) + : fLoopManager(lm), fArg(arg), fReader(reader) + { + } + ~RCallCleanUpTask() { fLoopManager.CleanUpTask(fReader, fArg); } }; } // namespace RDF @@ -324,20 +330,21 @@ ColumnNames_t ROOT::Internal::RDF::GetBranchNames(TTree &t, bool allowDuplicates RLoopManager::RLoopManager(TTree *tree, const ColumnNames_t &defaultBranches) : fTree(std::shared_ptr(tree, [](TTree *) {})), fDefaultColumns(defaultBranches), fNSlots(RDFInternal::GetNSlots()), - fLoopType(ROOT::IsImplicitMTEnabled() ? ELoopType::kROOTFilesMT : ELoopType::kROOTFiles) + fLoopType(ROOT::IsImplicitMTEnabled() ? ELoopType::kROOTFilesMT : ELoopType::kROOTFiles), + fDataBlockNotifier(fNSlots) { } RLoopManager::RLoopManager(ULong64_t nEmptyEntries) : fNEmptyEntries(nEmptyEntries), fNSlots(RDFInternal::GetNSlots()), - fLoopType(ROOT::IsImplicitMTEnabled() ? ELoopType::kNoFilesMT : ELoopType::kNoFiles) + fLoopType(ROOT::IsImplicitMTEnabled() ? ELoopType::kNoFilesMT : ELoopType::kNoFiles), fDataBlockNotifier(fNSlots) { } RLoopManager::RLoopManager(std::unique_ptr ds, const ColumnNames_t &defaultBranches) : fDefaultColumns(defaultBranches), fNSlots(RDFInternal::GetNSlots()), fLoopType(ROOT::IsImplicitMTEnabled() ? ELoopType::kDataSourceMT : ELoopType::kDataSource), - fDataSource(std::move(ds)) + fDataSource(std::move(ds)), fDataBlockNotifier(fNSlots) { fDataSource->SetNSlots(fNSlots); } @@ -374,7 +381,7 @@ void RLoopManager::RunEmptySourceMT() auto genFunction = [this, &slotStack](const std::pair &range) { RSlotRAII slotRAII(slotStack); auto slot = slotRAII.fSlot; - RCallCleanUpTask cleanup{*this, slot}; + RCallCleanUpTask cleanup(*this, slot); InitNodeSlots(nullptr, slot); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing({"an empty source", range.first, range.second, slot}); try { @@ -399,7 +406,7 @@ void RLoopManager::RunEmptySource() { InitNodeSlots(nullptr, 0); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing({"an empty source", 0, fNEmptyEntries, 0u}); - RCallCleanUpTask cleanup{*this, 0u}; + RCallCleanUpTask cleanup(*this); try { for (ULong64_t currEntry = 0; currEntry < fNEmptyEntries && fNStopsReceived < fNChildren; ++currEntry) { RunAndCheckFilters(0, currEntry); @@ -423,7 +430,7 @@ void RLoopManager::RunTreeProcessorMT() tp->Process([this, &slotStack, &entryCount](TTreeReader &r) -> void { RSlotRAII slotRAII(slotStack); auto slot = slotRAII.fSlot; - RCallCleanUpTask cleanup{*this, slot}; + RCallCleanUpTask cleanup(*this, slot, &r); InitNodeSlots(&r, slot); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing(TreeDatasetLogInfo(r, slot)); const auto entryRange = r.GetEntriesRange(); // we trust TTreeProcessorMT to call SetEntriesRange @@ -448,7 +455,7 @@ void RLoopManager::RunTreeReader() TTreeReader r(fTree.get(), fTree->GetEntryList()); if (0 == fTree->GetEntriesFast()) return; - RCallCleanUpTask cleanup{*this, 0u}; + RCallCleanUpTask cleanup(*this, 0u, &r); InitNodeSlots(&r, 0); R__LOG_INFO(RDFLogChannel()) << LogRangeProcessing(TreeDatasetLogInfo(r, 0u)); @@ -478,7 +485,7 @@ void RLoopManager::RunDataSource() while (!ranges.empty() && fNStopsReceived < fNChildren) { InitNodeSlots(nullptr, 0u); fDataSource->InitSlot(0u, 0ull); - RCallCleanUpTask cleanup{*this, 0u}; + RCallCleanUpTask cleanup(*this); try { for (const auto &range : ranges) { const auto start = range.first; @@ -513,7 +520,7 @@ void RLoopManager::RunDataSourceMT() RSlotRAII slotRAII(slotStack); const auto slot = slotRAII.fSlot; InitNodeSlots(nullptr, slot); - RCallCleanUpTask cleanup{*this, slot}; + RCallCleanUpTask cleanup(*this, slot); fDataSource->InitSlot(slot, range.first); const auto start = range.first; const auto end = range.second; @@ -545,6 +552,14 @@ void RLoopManager::RunDataSourceMT() /// Named filters must be called even if the analysis logic would not require it, lest they report confusing results. void RLoopManager::RunAndCheckFilters(unsigned int slot, Long64_t entry) { + // data-block callbacks run before the rest of the graph + if (fDataBlockNotifier.CheckFlag(slot)) { + for (auto &callback : fDataBlockCallbacks) { + callback(slot); + } + fDataBlockNotifier.UnsetFlag(slot); + } + for (auto &actionPtr : fBookedActions) actionPtr->Run(slot, entry); for (auto &namedFilterPtr : fBookedNamedFilters) @@ -558,6 +573,7 @@ void RLoopManager::RunAndCheckFilters(unsigned int slot, Long64_t entry) /// calls their `InitSlot` method, to get them ready for running a task. void RLoopManager::InitNodeSlots(TTreeReader *r, unsigned int slot) { + SetupDataBlockCallbacks(r, slot); for (auto &ptr : fBookedActions) ptr->InitSlot(r, slot); for (auto &ptr : fBookedFilters) @@ -566,6 +582,20 @@ void RLoopManager::InitNodeSlots(TTreeReader *r, unsigned int slot) callback(slot); } +void RLoopManager::SetupDataBlockCallbacks(TTreeReader *r, unsigned int slot) { + if (r != nullptr) { + // we need to set a notifier so that we run the callbacks every time we switch to a new TTree + // `PrependLink` inserts this notifier into the TTree/TChain's linked list of notifiers + fDataBlockNotifier.GetChainNotifyLink(slot).PrependLink(*r->GetTree()); + } + // Whatever the data source, initially set the "new data block" flag: + // - for TChains, this ensures that we don't skip the first data block because + // the correct tree is already loaded + // - for RDataSources and empty sources, which currently don't have data blocks, this + // ensures that we run once per task + fDataBlockNotifier.SetFlag(slot); +} + /// Initialize all nodes of the functional graph before running the event loop. /// This method is called once per event-loop and performs generic initialization /// operations that do not depend on the specific processing slot (i.e. operations @@ -603,11 +633,14 @@ void RLoopManager::CleanUpNodes() fCallbacks.clear(); fCallbacksOnce.clear(); + fDataBlockCallbacks.clear(); } /// Perform clean-up operations. To be called at the end of each task execution. -void RLoopManager::CleanUpTask(unsigned int slot) +void RLoopManager::CleanUpTask(TTreeReader *r, unsigned int slot) { + if (r != nullptr) + fDataBlockNotifier.GetChainNotifyLink(slot).RemoveLink(*r->GetTree()); for (auto &ptr : fBookedActions) ptr->FinalizeSlot(slot); for (auto &ptr : fBookedFilters) @@ -821,3 +854,9 @@ void RLoopManager::AddDSValuePtrs(const std::string &col, const std::vector &&callback) +{ + if (callback) + fDataBlockCallbacks.emplace_back(std::move(callback)); +} From 7fb4e1e51774c7505c3b5c4683906fb55eec579b Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 4 Jun 2021 13:21:27 +0200 Subject: [PATCH 102/309] [DF][NFC] Remove some trailing whitespaces --- tree/dataframe/test/MaxSlotHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/dataframe/test/MaxSlotHelper.h b/tree/dataframe/test/MaxSlotHelper.h index 3ce6a9c58d191..400ea66b37c8a 100644 --- a/tree/dataframe/test/MaxSlotHelper.h +++ b/tree/dataframe/test/MaxSlotHelper.h @@ -20,5 +20,5 @@ class MaxSlotHelper : public ROOT::Detail::RDF::RActionImpl { void Exec(unsigned int slot, unsigned int /*slot2*/) { fMaxSlots[slot] = std::max(fMaxSlots[slot], slot); } void Finalize() { *fMaxSlot = *std::max_element(fMaxSlots.begin(), fMaxSlots.end()); } - std::string GetActionName() { return "MaxSlot"; } + std::string GetActionName() { return "MaxSlot"; } }; From 01cfaf011dc6e642041a208b764f1074c6a18832 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 09:33:48 +0200 Subject: [PATCH 103/309] [DF] Add test for data-block callbacks --- tree/dataframe/test/CMakeLists.txt | 1 + tree/dataframe/test/CounterHelper.h | 8 ++ .../test/dataframe_datablockcallback.cxx | 97 +++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 tree/dataframe/test/dataframe_datablockcallback.cxx diff --git a/tree/dataframe/test/CMakeLists.txt b/tree/dataframe/test/CMakeLists.txt index fd2b7322ff699..a0f7c64b2e285 100644 --- a/tree/dataframe/test/CMakeLists.txt +++ b/tree/dataframe/test/CMakeLists.txt @@ -38,6 +38,7 @@ ROOT_ADD_GTEST(dataframe_resptr dataframe_resptr.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_take dataframe_take.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_entrylist dataframe_entrylist.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_merge_results dataframe_merge_results.cxx LIBRARIES ROOTDataFrame) +ROOT_ADD_GTEST(dataframe_datablockcallback dataframe_datablockcallback.cxx CounterHelper.h LIBRARIES ROOTDataFrame) if (imt) ROOT_ADD_GTEST(dataframe_concurrency dataframe_concurrency.cxx LIBRARIES ROOTDataFrame) diff --git a/tree/dataframe/test/CounterHelper.h b/tree/dataframe/test/CounterHelper.h index 17c1bb863bc86..8ac1652e84c6b 100644 --- a/tree/dataframe/test/CounterHelper.h +++ b/tree/dataframe/test/CounterHelper.h @@ -18,7 +18,15 @@ class CounterHelper : public ROOT::Detail::RDF::RActionImpl { std::shared_ptr GetResultPtr() const { return fNCalls; } void Initialize() {} void InitTask(TTreeReader *, unsigned int) {} +#ifndef COUNTERHELPER_CALLBACKMODE void Exec(unsigned int) { ++(*fNCalls); } +#else + void Exec(unsigned int) {} + std::function GetDataBlockCallback() final + { + return [this](unsigned int) mutable { ++(*this->fNCalls); }; + } +#endif void Finalize() {} std::string GetActionName() { return "ThreadSafeCounter"; } diff --git a/tree/dataframe/test/dataframe_datablockcallback.cxx b/tree/dataframe/test/dataframe_datablockcallback.cxx new file mode 100644 index 0000000000000..d6b7320a237fa --- /dev/null +++ b/tree/dataframe/test/dataframe_datablockcallback.cxx @@ -0,0 +1,97 @@ +#define COUNTERHELPER_CALLBACKMODE +#include "CounterHelper.h" +#undef COUNTERHELPER_CALLBACKMODE + +#include +#include +#include // ROOT::EnableImplicitMT +#include +#include +#include + +#include + +#include // std::min +#include // std::hardware_concurrency + +// fixture for all tests in this file +struct RDFDataBlockCallback : ::testing::TestWithParam { + unsigned int NSLOTS; + unsigned int NENTRIES = std::max(10u, std::thread::hardware_concurrency() * 2); + + RDFDataBlockCallback() : NSLOTS(GetParam() ? std::min(4u, std::thread::hardware_concurrency()) : 1u) + { + if (GetParam()) + ROOT::EnableImplicitMT(); + } + + ~RDFDataBlockCallback() + { + if (GetParam()) + ROOT::DisableImplicitMT(); + } +}; + +// A RAII object that ensures existence of nFiles root files named prefix0.root, prefix1.root, ... +// Each file contains a TTree called "t" with one `int` branch called "x" with sequentially increasing values (0,1,2...) +struct InputFilesRAII { + unsigned int fNFiles = 0; + std::string fPrefix; + + InputFilesRAII(unsigned int nFiles, std::string prefix) : fNFiles(nFiles), fPrefix(std::move(prefix)) + { + for (auto i = 0u; i < fNFiles; ++i) { + TFile f((fPrefix + std::to_string(i) + ".root").c_str(), "recreate"); + TTree t("t", "t"); + t.Branch("x", &i); + t.Fill(); + t.Write(); + } + } + + ~InputFilesRAII() + { + for (auto i = 0u; i < fNFiles; ++i) + gSystem->Unlink((fPrefix + std::to_string(i) + ".root").c_str()); + } +}; + +TEST_P(RDFDataBlockCallback, EmptySource) { + ROOT::RDataFrame df(NENTRIES); + auto result = df.Book<>(CounterHelper(), {}); + // RDF with empty sources tries to produce 2 tasks per slot when MT is enabled + const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots() * 2u) : 1u; + EXPECT_EQ(*result, expected); +} + +TEST_P(RDFDataBlockCallback, DataSource) { + auto df = ROOT::RDF::MakeTrivialDataFrame(NENTRIES); + auto result = df.Book<>(CounterHelper(), {}); + // RTrivialDS tries to produce NSLOTS tasks + const auto expected = ROOT::IsImplicitMTEnabled() ? std::min(NENTRIES, df.GetNSlots()) : 1u; + EXPECT_EQ(*result, expected); +} + +TEST_P(RDFDataBlockCallback, TTree) { + const std::string prefix = "rdfdatablockcallback_ttree"; + InputFilesRAII file(1u, prefix); + ROOT::RDataFrame df("t", prefix + "*"); + auto result = df.Book<>(CounterHelper(), {}); + EXPECT_EQ(*result, 1u); +} + +TEST_P(RDFDataBlockCallback, TChain) { + const std::string prefix = "rdfdatablockcallback_ttree"; + InputFilesRAII file(5u, prefix); + ROOT::RDataFrame df("t", prefix + "*"); + auto result = df.Book<>(CounterHelper(), {}); + EXPECT_EQ(*result, 5u); +} + +// instantiate single-thread tests +INSTANTIATE_TEST_SUITE_P(Seq, RDFDataBlockCallback, ::testing::Values(false)); + +#ifdef R__USE_IMT + // instantiate multi-thread tests + INSTANTIATE_TEST_SUITE_P(MT, RDFDataBlockCallback, ::testing::Values(true)); +#endif From 267b8e7c57f23c5f856f53b4daeb365e550cbe24 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 4 Jun 2021 12:47:51 +0200 Subject: [PATCH 104/309] [DF] Improve Snapshot branch-address-resetting logic Instead of TTree::AddClone + TTree::CopyAddresses, use the data-block callback mechanism to reset addresses when needed. We cannot trust TTree::CopyAddresses to do the right thing because the output branch might be a different kind of branch than the input branch (e.g. TBranch vs TBranchElement), which leads to the problem described at https://github.com/root-project/root/issues/8295 . Note that TBranch::SetAddress (which we now call directly to keep the address of the output branches synced with the location of the input variables) needs the address of a _pointer that points to the object associated to the branch_ instead of just the address of that object unless the output branch is really a simple TBranch. We reuse fBranchAddresses as storage for these pointers, which until now was only used in case the column was of RVec type. This fixes #8295. As a side-effect of moving away from TTree::AddClone + TTree::CopyAddresses, these changes also fix #7727. --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 179 +++++++++++++----- 1 file changed, 129 insertions(+), 50 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 9fa9563724c01..38b9c81eab068 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -96,6 +96,41 @@ using namespace ROOT::Detail::RDF; using Hist_t = ::TH1D; +class RBranchSet { + std::vector fBranches; + std::vector fNames; + +public: + TBranch *Get(const std::string &name) const + { + auto it = std::find(fNames.begin(), fNames.end(), name); + if (it == fNames.end()) + return nullptr; + return fBranches[std::distance(fNames.begin(), it)]; + } + + void Insert(const std::string &name, TBranch *address) + { + if (address == nullptr) { + throw std::logic_error("Trying to insert a null branch address."); + } + if (std::find(fBranches.begin(), fBranches.end(), address) != fBranches.end()) { + throw std::logic_error("Trying to insert a branch address that's already present."); + } + if (std::find(fNames.begin(), fNames.end(), name) != fNames.end()) { + throw std::logic_error("Trying to insert a branch name that's already present."); + } + fNames.emplace_back(name); + fBranches.emplace_back(address); + } + + void Clear() + { + fBranches.clear(); + fNames.clear(); + } +}; + /// The container type for each thread's partial result in an action helper // We have to avoid to instantiate std::vector as that makes it impossible to return a reference to one of // the thread-local results. In addition, a common definition for the type of the container makes it easy to swap @@ -1117,9 +1152,28 @@ void *GetData(T & /*v*/) template void SetBranchesHelper(BoolArrayMap &, TTree *inputTree, TTree &outputTree, const std::string &inName, - const std::string &name, TBranch *&branch, void *&branchAddress, T *address) + const std::string &name, TBranch *&branch, void *&branchAddress, T *address, + RBranchSet &outputBranches) { - auto *inputBranch = inputTree ? inputTree->GetBranch(inName.c_str()) : nullptr; + static TClassRef TBOClRef("TBranchObject"); + // FIXME we should be using FindBranch as a fallback if GetBranch fails + TBranch *inputBranch = inputTree ? inputTree->GetBranch(inName.c_str()) : nullptr; + + auto *outputBranch = outputBranches.Get(name); + if (outputBranch) { + // the output branch was already created, we just need to (re)set its address + if (inputBranch && inputBranch->IsA() == TBOClRef) { + outputBranch->SetAddress(reinterpret_cast(inputBranch->GetAddress())); + } else if (outputBranch->IsA() != TBranch::Class()) { + branchAddress = address; + outputBranch->SetAddress(&branchAddress); + } else { + outputBranch->SetAddress(address); + branchAddress = address; + } + return; + } + if (inputBranch) { // Respect the original bufsize and splitlevel arguments // In particular, by keeping splitlevel equal to 0 if this was the case for `inputBranch`, we avoid @@ -1128,16 +1182,17 @@ void SetBranchesHelper(BoolArrayMap &, TTree *inputTree, TTree &outputTree, cons const auto bufSize = inputBranch->GetBasketSize(); const auto splitLevel = inputBranch->GetSplitLevel(); - static TClassRef tbo_cl("TBranchObject"); - if (inputBranch->IsA() == tbo_cl) { + if (inputBranch->IsA() == TBOClRef) { // Need to pass a pointer to pointer - outputTree.Branch(name.c_str(), (T **)inputBranch->GetAddress(), bufSize, splitLevel); + outputBranch = + outputTree.Branch(name.c_str(), reinterpret_cast(inputBranch->GetAddress()), bufSize, splitLevel); } else { - outputTree.Branch(name.c_str(), address, bufSize, splitLevel); + outputBranch = outputTree.Branch(name.c_str(), address, bufSize, splitLevel); } } else { - outputTree.Branch(name.c_str(), address); + outputBranch = outputTree.Branch(name.c_str(), address); } + outputBranches.Insert(name, outputBranch); // This is not an array branch, so we don't need to register the address of the input branch. branch = nullptr; branchAddress = nullptr; @@ -1154,7 +1209,8 @@ void SetBranchesHelper(BoolArrayMap &, TTree *inputTree, TTree &outputTree, cons /// `branchAddress`) so we can intercept changes in the address of the input branch and tell the output branch. template void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &outputTree, const std::string &inName, - const std::string &outName, TBranch *&branch, void *&branchAddress, RVec *ab) + const std::string &outName, TBranch *&branch, void *&branchAddress, RVec *ab, + RBranchSet &outputBranches) { TBranch *inputBranch = nullptr; if (inputTree) { @@ -1164,6 +1220,7 @@ void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &output inputBranch = inputTree->FindBranch(inName.c_str()); } } + auto *outputBranch = outputBranches.Get(outName); const bool isTClonesArray = inputBranch != nullptr && std::string(inputBranch->GetClassName()) == "TClonesArray"; const auto mustWriteRVec = !inputBranch || isTClonesArray || ROOT::ESTLType::kSTLvector == TClassEdit::IsSTLCont(inputBranch->GetClassName()); @@ -1180,7 +1237,13 @@ void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &output "be written out as a std::vector instead of a TClonesArray. Specify that the type of the branch is " "TClonesArray as a Snapshot template parameter to write out a TClonesArray instead.", inName.c_str()); } - outputTree.Branch(outName.c_str(), ab); + if (outputBranch) { + branchAddress = GetData(*ab); + outputBranch->SetAddress(&branchAddress); + } else { + auto *b = outputTree.Branch(outName.c_str(), ab); + outputBranches.Insert(outName, b); + } return; } @@ -1197,13 +1260,22 @@ void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &output /// so we need to explicitly manage storage of the data that the tree needs to Fill branches with. auto dataPtr = UpdateBoolArrayIfBool(boolArrays, *ab, outName); - auto *const outputBranch = outputTree.Branch(outName.c_str(), dataPtr, leaflist.c_str()); - outputBranch->SetTitle(inputBranch->GetTitle()); - - // Record the branch ptr and the address associated to it if this is not a bool array - if (!std::is_same::value) { - branch = outputBranch; - branchAddress = GetData(*ab); + if (outputBranch) { + if (outputBranch->IsA() != TBranch::Class()) { + branchAddress = dataPtr; + outputBranch->SetAddress(&branchAddress); + } else { + outputBranch->SetAddress(dataPtr); + } + } else { + outputBranch = outputTree.Branch(outName.c_str(), dataPtr, leaflist.c_str()); + outputBranch->SetTitle(inputBranch->GetTitle()); + outputBranches.Insert(outName, outputBranch); + // Record the branch ptr and the address associated to it if this is not a bool array + if (!std::is_same::value) { + branch = outputBranch; + branchAddress = GetData(*ab); + } } } @@ -1238,13 +1310,15 @@ class SnapshotHelper : public RActionImpl> { const RSnapshotOptions fOptions; std::unique_ptr fOutputFile; std::unique_ptr fOutputTree; // must be a ptr because TTrees are not copy/move constructible - bool fIsFirstEvent{true}; + bool fBranchAddressesNeedReset{true}; const ColumnNames_t fInputBranchNames; // This contains the resolved aliases const ColumnNames_t fOutputBranchNames; TTree *fInputTree = nullptr; // Current input tree. Set at initialization time (`InitTask`) BoolArrayMap fBoolArrays; // Storage for C arrays of bools to be written out - std::vector fBranches; // Addresses of branches in output, non-null only for the ones holding C arrays - std::vector fBranchAddresses; // Addresses associated to output branches, non-null only for the ones holding C arrays + // TODO we might be able to unify fBranches, fBranchAddresses and fOutputBranches + std::vector fBranches; // Addresses of branches in output, non-null only for the ones holding C arrays + std::vector fBranchAddresses; // Addresses of objects associated to output branches + RBranchSet fOutputBranches; public: using ColumnTypes_t = TypeList; @@ -1264,20 +1338,17 @@ public: { if (r) fInputTree = r->GetTree(); + fBranchAddressesNeedReset = true; } void Exec(unsigned int /* slot */, ColTypes &... values) { using ind_t = std::index_sequence_for; - if (! fIsFirstEvent) { + if (!fBranchAddressesNeedReset) { UpdateCArraysPtrs(values..., ind_t{}); } else { SetBranches(values..., ind_t{}); - // AddClone guarantees that if the input file changes the branches of the output tree are updated with the new - // addresses of the branch values - if (fInputTree != nullptr) - fInputTree->AddClone(fOutputTree.get()); - fIsFirstEvent = false; + fBranchAddressesNeedReset = false; } UpdateBoolArrays(values..., ind_t{}); fOutputTree->Fill(); @@ -1303,10 +1374,11 @@ public: void SetBranches(ColTypes &... values, std::index_sequence /*dummy*/) { // create branches in output tree (and fill fBoolArrays for RVec columns) - int expander[] = {(SetBranchesHelper(fBoolArrays, fInputTree, *fOutputTree, fInputBranchNames[S], - fOutputBranchNames[S], fBranches[S], fBranchAddresses[S], &values), - 0)..., - 0}; + int expander[] = { + (SetBranchesHelper(fBoolArrays, fInputTree, *fOutputTree, fInputBranchNames[S], fOutputBranchNames[S], + fBranches[S], fBranchAddresses[S], &values, fOutputBranches), + 0)..., + 0}; (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9 } @@ -1355,6 +1427,12 @@ public: } std::string GetActionName() { return "Snapshot"; } + + std::function GetDataBlockCallback() final + { + auto callback = [this](unsigned int) mutable { fBranchAddressesNeedReset = true; }; + return {callback}; + } }; /// Helper object for a multi-thread Snapshot action @@ -1364,7 +1442,7 @@ class SnapshotHelperMT : public RActionImpl> { std::unique_ptr fMerger; // must use a ptr because TBufferMerger is not movable std::vector> fOutputFiles; std::vector> fOutputTrees; - std::vector fIsFirstEvent; // vector does not allow concurrent writing of different elements + std::vector fBranchAddressesNeedReset; // vector does not allow concurrent writing of different elements const std::string fFileName; // name of the output file name const std::string fDirName; // name of TFile subdirectory in which output must be written (possibly empty) const std::string fTreeName; // name of output tree @@ -1377,17 +1455,18 @@ class SnapshotHelperMT : public RActionImpl> { std::vector> fBranches; // Addresses associated to output branches per slot, non-null only for the ones holding C arrays std::vector> fBranchAddresses; + std::vector fOutputBranches; public: using ColumnTypes_t = TypeList; SnapshotHelperMT(const unsigned int nSlots, std::string_view filename, std::string_view dirname, std::string_view treename, const ColumnNames_t &vbnames, const ColumnNames_t &bnames, const RSnapshotOptions &options) - : fNSlots(nSlots), fOutputFiles(fNSlots), fOutputTrees(fNSlots), fIsFirstEvent(fNSlots, 1), fFileName(filename), - fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames), + : fNSlots(nSlots), fOutputFiles(fNSlots), fOutputTrees(fNSlots), fBranchAddressesNeedReset(fNSlots, 1), + fFileName(filename), fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames), fOutputBranchNames(ReplaceDotWithUnderscore(bnames)), fInputTrees(fNSlots), fBoolArrays(fNSlots), fBranches(fNSlots, std::vector(vbnames.size(), nullptr)), - fBranchAddresses(fNSlots, std::vector(vbnames.size(), nullptr)) + fBranchAddresses(fNSlots, std::vector(vbnames.size(), nullptr)), fOutputBranches(fNSlots) { ValidateSnapshotOutput(fOptions, fTreeName, fFileName); } @@ -1418,15 +1497,8 @@ public: if (r) { // not an empty-source RDF fInputTrees[slot] = r->GetTree(); - // AddClone guarantees that if the input file changes the branches of the output tree are updated with the new - // addresses of the branch values. We need this in case of friend trees with different cluster granularity - // than the main tree. - // FIXME: AddClone might result in many many (safe) warnings printed by TTree::CopyAddresses, see ROOT-9487. - const auto friendsListPtr = fInputTrees[slot]->GetListOfFriends(); - if (friendsListPtr && friendsListPtr->GetEntries() > 0) - fInputTrees[slot]->AddClone(fOutputTrees[slot].get()); } - fIsFirstEvent[slot] = 1; // reset first event flag for this slot + fBranchAddressesNeedReset[slot] = 1; // reset first event flag for this slot } void FinalizeTask(unsigned int slot) @@ -1435,16 +1507,17 @@ public: fOutputFiles[slot]->Write(); // clear now to avoid concurrent destruction of output trees and input tree (which has them listed as fClones) fOutputTrees[slot].reset(nullptr); + fOutputBranches[slot].Clear(); } void Exec(unsigned int slot, ColTypes &... values) { using ind_t = std::index_sequence_for; - if (!fIsFirstEvent[slot]) { + if (fBranchAddressesNeedReset[slot] == 0) { UpdateCArraysPtrs(slot, values..., ind_t{}); } else { SetBranches(slot, values..., ind_t{}); - fIsFirstEvent[slot] = 0; + fBranchAddressesNeedReset[slot] = 0; } UpdateBoolArrays(slot, values..., ind_t{}); fOutputTrees[slot]->Fill(); @@ -1475,13 +1548,13 @@ public: void SetBranches(unsigned int slot, ColTypes &... values, std::index_sequence /*dummy*/) { // hack to call TTree::Branch on all variadic template arguments - int expander[] = { - (SetBranchesHelper(fBoolArrays[slot], fInputTrees[slot], *fOutputTrees[slot], fInputBranchNames[S], - fOutputBranchNames[S], fBranches[slot][S], fBranchAddresses[slot][S], &values), - 0)..., - 0}; - (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9 - (void)slot; // avoid unused variable warnings in gcc6.2 + int expander[] = {(SetBranchesHelper(fBoolArrays[slot], fInputTrees[slot], *fOutputTrees[slot], + fInputBranchNames[S], fOutputBranchNames[S], fBranches[slot][S], + fBranchAddresses[slot][S], &values, fOutputBranches[slot]), + 0)..., + 0}; + (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9 + (void)slot; // avoid unused variable warnings in gcc6.2 } template @@ -1529,6 +1602,12 @@ public: } std::string GetActionName() { return "Snapshot"; } + + std::function GetDataBlockCallback() final + { + auto callback = [this](unsigned int slot) mutable { fBranchAddressesNeedReset[slot] = 1; }; + return {callback}; + } }; template Date: Wed, 9 Jun 2021 17:42:00 +0200 Subject: [PATCH 105/309] [DF][NFC] Simplify SnapshotHelper[MT]::GetDataBlockCallback Co-authored-by: Axel Naumann --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 38b9c81eab068..bde8b214c6050 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -1430,8 +1430,7 @@ public: std::function GetDataBlockCallback() final { - auto callback = [this](unsigned int) mutable { fBranchAddressesNeedReset = true; }; - return {callback}; + return [this](unsigned int) mutable { fBranchAddressesNeedReset = true; }; } }; @@ -1605,8 +1604,7 @@ public: std::function GetDataBlockCallback() final { - auto callback = [this](unsigned int slot) mutable { fBranchAddressesNeedReset[slot] = 1; }; - return {callback}; + return [this](unsigned int slot) mutable { fBranchAddressesNeedReset[slot] = 1; }; } }; From 46590d92e381f5e0b62df34c878426a06bf62c53 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 9 Jun 2021 17:44:25 +0200 Subject: [PATCH 106/309] [DF][NFC] Update some comments --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index bde8b214c6050..4214341b4c034 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -1193,7 +1193,7 @@ void SetBranchesHelper(BoolArrayMap &, TTree *inputTree, TTree &outputTree, cons outputBranch = outputTree.Branch(name.c_str(), address); } outputBranches.Insert(name, outputBranch); - // This is not an array branch, so we don't need to register the address of the input branch. + // This is not an array branch, so we don't register the address of the output branch here branch = nullptr; branchAddress = nullptr; } @@ -1229,12 +1229,11 @@ void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &output // Treat: // 2. RVec coming from a custom column or a source // 3. RVec coming from a column on disk of type vector (the RVec is adopting the data of that vector) - // 4. TClonesArray. - // In all cases, we write out a std::vector when the column is RVec + // 4. TClonesArray written out as RVec if (isTClonesArray) { Warning("Snapshot", "Branch \"%s\" contains TClonesArrays but the type specified to Snapshot was RVec. The branch will " - "be written out as a std::vector instead of a TClonesArray. Specify that the type of the branch is " + "be written out as a RVec instead of a TClonesArray. Specify that the type of the branch is " "TClonesArray as a Snapshot template parameter to write out a TClonesArray instead.", inName.c_str()); } if (outputBranch) { From 3f948948aff6e3ad8990c675374ea56782745736 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 9 Jun 2021 17:45:05 +0200 Subject: [PATCH 107/309] [DF] Use different filenames in different test cases Co-authored-by: Axel Naumann --- tree/dataframe/test/dataframe_datablockcallback.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/dataframe/test/dataframe_datablockcallback.cxx b/tree/dataframe/test/dataframe_datablockcallback.cxx index d6b7320a237fa..a000f9e1e79ea 100644 --- a/tree/dataframe/test/dataframe_datablockcallback.cxx +++ b/tree/dataframe/test/dataframe_datablockcallback.cxx @@ -81,7 +81,7 @@ TEST_P(RDFDataBlockCallback, TTree) { } TEST_P(RDFDataBlockCallback, TChain) { - const std::string prefix = "rdfdatablockcallback_ttree"; + const std::string prefix = "rdfdatablockcallback_tchain"; InputFilesRAII file(5u, prefix); ROOT::RDataFrame df("t", prefix + "*"); auto result = df.Book<>(CounterHelper(), {}); From 1469c34e939f9a7fcac9ba862a898aa60a623785 Mon Sep 17 00:00:00 2001 From: Enric Tejedor Saavedra Date: Thu, 10 Jun 2021 09:52:13 +0200 Subject: [PATCH 108/309] [PyROOT] Remove setting of -mavx in EXTRA_CLING_ARGS To prevent adding the flag when ROOT is not built with AVX support. --- .../cling/python/cppyy_backend/loader.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py index 2c2ba91aed84d..986f993ea1d7c 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/loader.py @@ -85,21 +85,7 @@ def set_cling_compile_options(add_defaults = False): CURRENT_ARGS = os.environ['EXTRA_CLING_ARGS'] if add_defaults: - has_avx = False - try: - with open('/proc/cpuinfo', 'r') as ci: - for line in ci: - if 'avx' in line: - has_avx = True - break - except Exception: - try: - cli_arg = subprocess.check_output(['sysctl', 'machdep.cpu.features']) - has_avx = 'avx' in cli_arg.decode("utf-8").strip().lower() - except Exception: - pass CURRENT_ARGS += ' -O2' - if has_avx: CURRENT_ARGS += ' -mavx' os.putenv('EXTRA_CLING_ARGS', CURRENT_ARGS) os.environ['EXTRA_CLING_ARGS'] = CURRENT_ARGS From 90fc26355c63a23ce90870d9014a164e343e3249 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 2 Jun 2021 17:25:08 -0500 Subject: [PATCH 109/309] Correct value of TLeaf*::GetDeserializeType and usage thereof. Rename DeserializeType::kDestructive into DeserializeType::kExternal as it describe better the situation (the TBufferFile is not large enough to hold the deserialized data). Correct the value of GetDeserializeType for TLeafB, TLeafG, TLeafO, TLeafS in particular several where incorrectly marked as kExternal when part of an array (fLeafCount != nullptr); This fixes #6520. --- tree/tree/inc/TLeaf.h | 5 +++-- tree/tree/inc/TLeafB.h | 2 +- tree/tree/inc/TLeafD.h | 2 +- tree/tree/inc/TLeafD32.h | 1 + tree/tree/inc/TLeafElement.h | 2 +- tree/tree/inc/TLeafF16.h | 1 + tree/tree/inc/TLeafG.h | 3 ++- tree/tree/inc/TLeafI.h | 2 +- tree/tree/inc/TLeafL.h | 3 ++- tree/tree/inc/TLeafO.h | 6 ++++++ tree/tree/inc/TLeafS.h | 3 ++- tree/tree/src/TBranch.cxx | 8 +++++--- tree/tree/src/TLeafElement.cxx | 8 ++++---- 13 files changed, 30 insertions(+), 16 deletions(-) diff --git a/tree/tree/inc/TLeaf.h b/tree/tree/inc/TLeaf.h index 4608fc470f279..25aa6fad87fef 100644 --- a/tree/tree/inc/TLeaf.h +++ b/tree/tree/inc/TLeaf.h @@ -98,7 +98,8 @@ class TLeaf : public TNamed { enum class DeserializeType { kInvalid = 0, // Invalid deserialization information. - kDestructive, // Deserialization of this Leaf requires a separate output buffer. + kExternal, // Deserialization of this Leaf requires a separate output buffer, i.e. the on-disk and in-memory representation are likely to be different sizes. + kDestructive = kExternal, // For backward compatibility kInPlace, // Deserialization can be done directly in the input buffer. kZeroCopy, // In-memory and on-disk representation of this object are identical. }; @@ -113,7 +114,7 @@ class TLeaf : public TNamed { virtual void FillBasket(TBuffer &b); virtual Int_t *GenerateOffsetArray(Int_t base, Int_t events) { return GenerateOffsetArrayBase(base, events); } TBranch *GetBranch() const { return fBranch; } - virtual DeserializeType GetDeserializeType() const { return DeserializeType::kDestructive; } + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kExternal; } virtual TString GetFullName() const; /// If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has variable size, /// return a pointer to the TLeaf that stores such size. Return a nullptr otherwise. diff --git a/tree/tree/inc/TLeafB.h b/tree/tree/inc/TLeafB.h index a26832a4323f8..2c45e52137bed 100644 --- a/tree/tree/inc/TLeafB.h +++ b/tree/tree/inc/TLeafB.h @@ -38,7 +38,7 @@ class TLeafB : public TLeaf { virtual void Export(TClonesArray* list, Int_t n); virtual void FillBasket(TBuffer& b); - virtual DeserializeType GetDeserializeType() const { return fLeafCount ? DeserializeType::kDestructive : DeserializeType::kZeroCopy; } + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kZeroCopy; } virtual Int_t GetMaximum() const { return fMaximum; } virtual Int_t GetMinimum() const { return fMinimum; } const char *GetTypeName() const; diff --git a/tree/tree/inc/TLeafD.h b/tree/tree/inc/TLeafD.h index d4187f9bb978c..e899201f12384 100644 --- a/tree/tree/inc/TLeafD.h +++ b/tree/tree/inc/TLeafD.h @@ -50,7 +50,7 @@ class TLeafD : public TLeaf { virtual void SetAddress(void *add=0); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() == DeserializeType::kInPlace; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } ClassDef(TLeafD,1); //A TLeaf for a 64 bit floating point data type. }; diff --git a/tree/tree/inc/TLeafD32.h b/tree/tree/inc/TLeafD32.h index ff2378141dd35..810d19feb595f 100644 --- a/tree/tree/inc/TLeafD32.h +++ b/tree/tree/inc/TLeafD32.h @@ -39,6 +39,7 @@ class TLeafD32 : public TLeaf { TLeafD32(TBranch *parent, const char *name, const char *type); virtual ~TLeafD32(); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kExternal; } virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); const char *GetTypeName() const { return "Double32_t"; } diff --git a/tree/tree/inc/TLeafElement.h b/tree/tree/inc/TLeafElement.h index a976d71749c94..1319f81242693 100644 --- a/tree/tree/inc/TLeafElement.h +++ b/tree/tree/inc/TLeafElement.h @@ -63,7 +63,7 @@ class TLeafElement : public TLeaf { template T GetTypedValueSubArray(Int_t i=0, Int_t j=0) const {return ((TBranchElement*)fBranch)->GetTypedValue(i, j, kTRUE);} virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() != DeserializeType::kDestructive; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void *GetValuePointer() const { return ((TBranchElement*)fBranch)->GetValuePointer(); } virtual Bool_t IncludeRange(TLeaf *); diff --git a/tree/tree/inc/TLeafF16.h b/tree/tree/inc/TLeafF16.h index 5a25256b6209b..1aade8cee3698 100644 --- a/tree/tree/inc/TLeafF16.h +++ b/tree/tree/inc/TLeafF16.h @@ -38,6 +38,7 @@ class TLeafF16 : public TLeaf { TLeafF16(TBranch *parent, const char *name, const char *type); virtual ~TLeafF16(); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kExternal; } virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); const char *GetTypeName() const { return "Float16_t"; } diff --git a/tree/tree/inc/TLeafG.h b/tree/tree/inc/TLeafG.h index 2531ee728012b..175fb2764928d 100644 --- a/tree/tree/inc/TLeafG.h +++ b/tree/tree/inc/TLeafG.h @@ -39,6 +39,7 @@ class TLeafG : public TLeaf { virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kInPlace; } const char *GetTypeName() const; virtual Int_t GetMaximum() const { return (Int_t)fMaximum; } virtual Int_t GetMinimum() const { return (Int_t)fMinimum; } @@ -52,7 +53,7 @@ class TLeafG : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() == DeserializeType::kInPlace; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Long_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafI.h b/tree/tree/inc/TLeafI.h index b82361822aab7..03decaa024559 100644 --- a/tree/tree/inc/TLeafI.h +++ b/tree/tree/inc/TLeafI.h @@ -51,7 +51,7 @@ class TLeafI : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() == DeserializeType::kInPlace; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Int_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafL.h b/tree/tree/inc/TLeafL.h index f4fc662313ac3..b120668746855 100644 --- a/tree/tree/inc/TLeafL.h +++ b/tree/tree/inc/TLeafL.h @@ -39,6 +39,7 @@ class TLeafL : public TLeaf { virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kInPlace; } const char *GetTypeName() const; virtual Int_t GetMaximum() const { return (Int_t)fMaximum; } virtual Int_t GetMinimum() const { return (Int_t)fMinimum; } @@ -52,7 +53,7 @@ class TLeafL : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() == DeserializeType::kInPlace; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Long64_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafO.h b/tree/tree/inc/TLeafO.h index c5ee1078832c0..6d53a77780665 100644 --- a/tree/tree/inc/TLeafO.h +++ b/tree/tree/inc/TLeafO.h @@ -38,6 +38,7 @@ class TLeafO : public TLeaf { virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kZeroCopy; } virtual Int_t GetMaximum() const {return fMaximum;} virtual Int_t GetMinimum() const {return fMinimum;} const char *GetTypeName() const; @@ -53,6 +54,11 @@ class TLeafO : public TLeaf { virtual void SetMaximum(Bool_t max) { fMaximum = max; } virtual void SetMinimum(Bool_t min) { fMinimum = min; } + // Deserialize N events from an input buffer. Since chars are stored unchanged, there + // is nothing to do here but return true if we don't have variable-length arrays. + virtual bool ReadBasketFast(TBuffer&, Long64_t) { return true; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return true; } + ClassDef(TLeafO,1); //A TLeaf for an 8 bit Integer data type. }; diff --git a/tree/tree/inc/TLeafS.h b/tree/tree/inc/TLeafS.h index 08c6417230c2d..e05c1479c1d92 100644 --- a/tree/tree/inc/TLeafS.h +++ b/tree/tree/inc/TLeafS.h @@ -38,6 +38,7 @@ class TLeafS : public TLeaf { virtual void Export(TClonesArray *list, Int_t n); virtual void FillBasket(TBuffer &b); + virtual DeserializeType GetDeserializeType() const { return DeserializeType::kInPlace; } virtual Int_t GetMaximum() const { return fMaximum; } virtual Int_t GetMinimum() const { return fMinimum; } const char *GetTypeName() const; @@ -49,7 +50,7 @@ class TLeafS : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() == DeserializeType::kInPlace; } + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Short_t max) { fMaximum = max; } diff --git a/tree/tree/src/TBranch.cxx b/tree/tree/src/TBranch.cxx index 118f3a3d0be0f..353da5c7d82cf 100644 --- a/tree/tree/src/TBranch.cxx +++ b/tree/tree/src/TBranch.cxx @@ -1428,7 +1428,7 @@ Int_t TBranch::GetBasketAndFirst(TBasket *&basket, Long64_t &first, /// still fail, depending on the contents of the individual TBaskets loaded. Bool_t TBranch::SupportsBulkRead() const { return (fNleaves == 1) && - (static_cast(fLeaves.UncheckedAt(0))->GetDeserializeType() != TLeaf::DeserializeType::kDestructive); + (static_cast(fLeaves.UncheckedAt(0))->GetDeserializeType() != TLeaf::DeserializeType::kExternal); } //////////////////////////////////////////////////////////////////////////////// @@ -1456,7 +1456,9 @@ Int_t TBranch::GetBulkEntries(Long64_t entry, TBuffer &user_buf) // TODO: eventually support multiple leaves. if (R__unlikely(fNleaves != 1)) return -1; TLeaf *leaf = static_cast(fLeaves.UncheckedAt(0)); - if (R__unlikely(leaf->GetDeserializeType() == TLeaf::DeserializeType::kDestructive)) {return -1;} + if (R__unlikely(leaf->GetDeserializeType() == TLeaf::DeserializeType::kExternal)) { + return -1; + } // Remember which entry we are reading. fReadEntry = entry; @@ -1534,7 +1536,7 @@ Int_t TBranch::GetEntriesSerialized(Long64_t entry, TBuffer &user_buf, TBuffer * if (R__unlikely(fNleaves != 1)) { return -1; } TLeaf *leaf = static_cast(fLeaves.UncheckedAt(0)); if (R__unlikely(leaf->GetDeserializeType() == TLeaf::DeserializeType::kDestructive)) { - Error("GetEntriesSerialized", "Encountered a branch with destructive deserialization; failing.\n"); + Error("GetEntriesSerialized", "Encountered a branch with destructive deserialization; failing."); return -1; } diff --git a/tree/tree/src/TLeafElement.cxx b/tree/tree/src/TLeafElement.cxx index e076d9214c871..d21ebb94a760f 100644 --- a/tree/tree/src/TLeafElement.cxx +++ b/tree/tree/src/TLeafElement.cxx @@ -116,13 +116,13 @@ TLeafElement::GetDeserializeType() const TClass *clptr = nullptr; EDataType type = EDataType::kOther_t; if (fBranch->GetExpectedType(clptr, type)) { // Returns non-zero in case of failure - fDeserializeTypeCache.store(DeserializeType::kDestructive, std::memory_order_relaxed); - return DeserializeType::kDestructive; // I don't know what it is, but we aren't going to use bulk IO. + fDeserializeTypeCache.store(DeserializeType::kExternal, std::memory_order_relaxed); + return DeserializeType::kExternal; // I don't know what it is, but we aren't going to use bulk IO. } fDataTypeCache.store(type, std::memory_order_release); if (clptr) { // Something that requires a dictionary to read; skip. - fDeserializeTypeCache.store(DeserializeType::kDestructive, std::memory_order_relaxed); - return DeserializeType::kDestructive; + fDeserializeTypeCache.store(DeserializeType::kExternal, std::memory_order_relaxed); + return DeserializeType::kExternal; } if ((fType == EDataType::kChar_t) || fType == EDataType::kUChar_t || type == EDataType::kBool_t) { From d01a3549ac2615ea286a21201eb9de3036cd5515 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 2 Jun 2021 17:40:12 -0500 Subject: [PATCH 110/309] ReadBasketFast no longer required GetDeserializeType to be called explicitly before hand --- tree/tree/src/TLeafElement.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tree/tree/src/TLeafElement.cxx b/tree/tree/src/TLeafElement.cxx index d21ebb94a760f..e5f45fcac7156 100644 --- a/tree/tree/src/TLeafElement.cxx +++ b/tree/tree/src/TLeafElement.cxx @@ -135,14 +135,16 @@ TLeafElement::GetDeserializeType() const return DeserializeType::kInPlace; } - fDeserializeTypeCache.store(DeserializeType::kDestructive, std::memory_order_relaxed); - return DeserializeType::kDestructive; + fDeserializeTypeCache.store(DeserializeType::kExternal, std::memory_order_relaxed); + return DeserializeType::kExternal; } //////////////////////////////////////////////////////////////////////////////// /// Deserialize N events from an input buffer. Bool_t TLeafElement::ReadBasketFast(TBuffer &input_buf, Long64_t N) { + if (R__likely(fDeserializeTypeCache.load(std::memory_order_relaxed) == DeserializeType::kInvalid)) + GetDeserializeType(); // Set fDataTypeCache if need be. EDataType type = fDataTypeCache.load(std::memory_order_consume); return input_buf.ByteSwapBuffer(fLen*N, type); } From 4b611065e268255026f16ec849fcce181fb10f81 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 2 Jun 2021 17:40:34 -0500 Subject: [PATCH 111/309] Extend BulkApiMultiple test to more data type --- tree/tree/test/BulkApiMultiple.cxx | 198 ++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 1 deletion(-) diff --git a/tree/tree/test/BulkApiMultiple.cxx b/tree/tree/test/BulkApiMultiple.cxx index 75c30d8793a8b..b728d4463815c 100644 --- a/tree/tree/test/BulkApiMultiple.cxx +++ b/tree/tree/test/BulkApiMultiple.cxx @@ -25,20 +25,44 @@ class BulkApiMultipleTest : public ::testing::Test { // Otherwise, we keep with the current ROOT defaults. auto tree = new TTree("T", "A ROOT tree of floats."); + float f = 2; double g = 3; + bool b = true; + short s = 4; + int i = 5; + Long64_t ll = (1<<20) + 1; + char c = 7; + TBranch *branch2 = tree->Branch("myFloat", &f, 320000, 1); TBranch *branch3 = tree->Branch("myDouble", &g, 320000, 1); + TBranch *branch4 = tree->Branch("myBool", &b, 320000, 1); + TBranch *branch5 = tree->Branch("myShort", &s, 320000, 1); + TBranch *branch6 = tree->Branch("myInt", &i, 320000, 1); + TBranch *branch7 = tree->Branch("myLongLong", &ll, 320000, 1); + TBranch *branch8 = tree->Branch("myChar", &c, 320000, 1); + branch2->SetAutoDelete(kFALSE); branch3->SetAutoDelete(kFALSE); + branch4->SetAutoDelete(kFALSE); + branch5->SetAutoDelete(kFALSE); + branch6->SetAutoDelete(kFALSE); + branch7->SetAutoDelete(kFALSE); + branch8->SetAutoDelete(kFALSE); + for (Long64_t ev = 0; ev < fEventCount; ev++) { tree->Fill(); f ++; g ++; + b = !b; + s ++; + i ++; + ll ++; + c ++; } hfile = tree->GetCurrentFile(); hfile->Write(); - tree->Print(); + //tree->Print(); printf("Successful write of all events.\n"); hfile->Close(); @@ -46,6 +70,178 @@ class BulkApiMultipleTest : public ::testing::Test { } }; +template +void increment(T &value) +{ + value++; +} + +void increment(bool &value) +{ + value = !value; +} + +template +void SimpleBulkReadFunc(const char *filename, const char *treename, const char *branchname, T initialvalue) +{ + auto hfile = TFile::Open(filename); + printf("Starting read of file %s.\n", filename); + TStopwatch sw; + + printf("Using outlined bulk read APIs.\n"); + TBufferFile branchbuf(TBuffer::kWrite, 32 * 1024); + auto tree = hfile->Get(treename); + ASSERT_TRUE(tree); + + TBranch *branch = tree->GetBranch(branchname); + ASSERT_TRUE(branch); + //branch->GetListOfBaskets()->ls(); + + T value = initialvalue; + Long64_t evt_idx = 0; + Long64_t events = tree->GetEntries(); + while (events) { + auto count = branch->GetBulkRead().GetBulkEntries(evt_idx, branchbuf); + ASSERT_GE(count, 0); + events = events > count ? (events - count) : 0; + + auto entry = reinterpret_cast(branchbuf.GetCurrent()); + for (Int_t idx = 0; idx < count; idx++) { + if (R__unlikely((evt_idx < 16000000) && (entry[idx] != value))) { + std::cerr << "In tree " << treename << " Incorrect value for " << branchname + << " branch: " << entry[idx] << " instead of " << value << " at entry #" << evt_idx + idx << '\n'; + tree->Scan(branchname, "", "", 10, evt_idx + idx); + ASSERT_TRUE(false); + } + increment( value ); + } + evt_idx += count; + } + sw.Stop(); + printf("GetBulkEntries: Successful read of all events in %s.\n", treename); + printf("GetBulkEntries: Total elapsed time (seconds) for bulk APIs: %.2f\n", sw.RealTime()); + delete hfile; +} + +TEST_F(BulkApiMultipleTest, simpleReadF) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myFloat", 2); +} + +TEST_F(BulkApiMultipleTest, simpleReadD) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myDouble", 3); +} + +TEST_F(BulkApiMultipleTest, simpleReadB) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myBool", true); +} + +TEST_F(BulkApiMultipleTest, simpleReadS) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myShort", 4); +} + +TEST_F(BulkApiMultipleTest, simpleReadI) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myInt", 5); +} + +TEST_F(BulkApiMultipleTest, simpleReadLL) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myLongLong", (1<<20) + 1); +} + +TEST_F(BulkApiMultipleTest, simpleReadC) +{ + SimpleBulkReadFunc(fFileName.c_str(), "T", "myChar", 7); +} + +template +void SimpleSerializedReadFunc(const char *filename, const char *treename, const char *branchname, T initialvalue) +{ + auto hfile = TFile::Open(filename); + printf("Starting read of file %s.\n", filename); + TStopwatch sw; + + printf("Using outlined bulk read APIs.\n"); + TBufferFile branchbuf(TBuffer::kWrite, 32 * 1024); + auto tree = hfile->Get(treename); + ASSERT_TRUE(tree); + + TBranch *branch = tree->GetBranch(branchname); + ASSERT_TRUE(branch); + //branch->GetListOfBaskets()->ls(); + + T value = initialvalue; + Long64_t evt_idx = 0; + Long64_t events = tree->GetEntries(); + while (events) { + auto count = branch->GetBulkRead().GetEntriesSerialized(evt_idx, branchbuf); + ASSERT_GE(count, 0); + events = events > count ? (events - count) : 0; + + auto entry = reinterpret_cast(branchbuf.GetCurrent()); + for (Int_t idx = 0; idx < count; idx++) { + auto tmp = *reinterpret_cast(&entry[idx]); + auto tmp_ptr = reinterpret_cast(&tmp); + // std::cerr << "BEFORE In tree " << treename << " Incorrect value for " << branchname + // << " branch: " << entry[idx] << " instead of " << value << " at entry #" << evt_idx + idx << '\n'; + frombuf(tmp_ptr, entry + idx); + if (R__unlikely((evt_idx < 16000000) && (entry[idx] != value))) { + std::cerr << "In tree " << treename << " Incorrect value for " << branchname + << " branch: " << entry[idx] << " instead of " << value << " with diff: " << (entry[idx] - value) + << " at entry #" << evt_idx + idx << '\n'; + tree->Scan(branchname, "", "", 10, evt_idx + idx); + ASSERT_TRUE(false); + } + increment( value ); + } + evt_idx += count; + } + sw.Stop(); + printf("GetBulkEntries: Successful read of all events in %s.\n", treename); + printf("GetBulkEntries: Total elapsed time (seconds) for bulk APIs: %.2f\n", sw.RealTime()); + delete hfile; +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadF) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myFloat", 2); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadD) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myDouble", 3); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadB) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myBool", true); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadS) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myShort", 4); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadI) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myInt", 5); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadLL) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myLongLong", (1<<20) + 1); +} + +TEST_F(BulkApiMultipleTest, simpleSerializedReadC) +{ + SimpleSerializedReadFunc(fFileName.c_str(), "T", "myChar", 7); +} + + TEST_F(BulkApiMultipleTest, stdRead) { auto hfile = TFile::Open(fFileName.c_str()); From 8055a2094506e93e8e27f062323ac700eba49dc0 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 2 Jun 2021 17:49:27 -0500 Subject: [PATCH 112/309] Always accept to return the serialized buffer. The user can always find a way to deserialize it. It might be as simple as byte swapping or might requires to call a full StreamerInfoAction sequence. --- tree/tree/inc/TLeaf.h | 2 +- tree/tree/inc/TLeafB.h | 3 +-- tree/tree/inc/TLeafD.h | 1 - tree/tree/inc/TLeafElement.h | 3 +-- tree/tree/inc/TLeafF.h | 1 - tree/tree/inc/TLeafG.h | 1 - tree/tree/inc/TLeafI.h | 1 - tree/tree/inc/TLeafL.h | 1 - tree/tree/inc/TLeafO.h | 1 - tree/tree/inc/TLeafS.h | 1 - tree/tree/src/TBranch.cxx | 4 ---- 11 files changed, 3 insertions(+), 16 deletions(-) diff --git a/tree/tree/inc/TLeaf.h b/tree/tree/inc/TLeaf.h index 25aa6fad87fef..08b2a2a240b03 100644 --- a/tree/tree/inc/TLeaf.h +++ b/tree/tree/inc/TLeaf.h @@ -152,7 +152,7 @@ class TLeaf : public TNamed { virtual void ReadBasket(TBuffer &) {} virtual void ReadBasketExport(TBuffer &, TClonesArray *, Int_t) {} virtual bool ReadBasketFast(TBuffer&, Long64_t) { return false; } // Read contents of leaf into a user-provided buffer. - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return false; } // Read contents of leaf into a user-provided buffer + virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return true; } virtual void ReadValue(std::istream & /*s*/, Char_t /*delim*/ = ' ') { Error("ReadValue", "Not implemented!"); } diff --git a/tree/tree/inc/TLeafB.h b/tree/tree/inc/TLeafB.h index 2c45e52137bed..145e6667ac851 100644 --- a/tree/tree/inc/TLeafB.h +++ b/tree/tree/inc/TLeafB.h @@ -56,8 +56,7 @@ class TLeafB : public TLeaf { // Deserialize N events from an input buffer. Since chars are stored unchanged, there // is nothing to do here but return true if we don't have variable-length arrays. - virtual bool ReadBasketFast(TBuffer&, Long64_t) { return !fLeafCount; } - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return !fLeafCount; } + virtual bool ReadBasketFast(TBuffer&, Long64_t) { return true; } ClassDef(TLeafB,1); //A TLeaf for an 8 bit Integer data type. }; diff --git a/tree/tree/inc/TLeafD.h b/tree/tree/inc/TLeafD.h index e899201f12384..44a06ba4dfff7 100644 --- a/tree/tree/inc/TLeafD.h +++ b/tree/tree/inc/TLeafD.h @@ -50,7 +50,6 @@ class TLeafD : public TLeaf { virtual void SetAddress(void *add=0); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } ClassDef(TLeafD,1); //A TLeaf for a 64 bit floating point data type. }; diff --git a/tree/tree/inc/TLeafElement.h b/tree/tree/inc/TLeafElement.h index 1319f81242693..06a3e5c2a4b95 100644 --- a/tree/tree/inc/TLeafElement.h +++ b/tree/tree/inc/TLeafElement.h @@ -63,8 +63,7 @@ class TLeafElement : public TLeaf { template T GetTypedValueSubArray(Int_t i=0, Int_t j=0) const {return ((TBranchElement*)fBranch)->GetTypedValue(i, j, kTRUE);} virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } - + virtual void *GetValuePointer() const { return ((TBranchElement*)fBranch)->GetValuePointer(); } virtual Bool_t IncludeRange(TLeaf *); virtual Bool_t IsOnTerminalBranch() const; diff --git a/tree/tree/inc/TLeafF.h b/tree/tree/inc/TLeafF.h index 6d259e85b6fad..013b564691ac6 100644 --- a/tree/tree/inc/TLeafF.h +++ b/tree/tree/inc/TLeafF.h @@ -50,7 +50,6 @@ class TLeafF : public TLeaf { virtual void SetAddress(void *add=0); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return true; } ClassDef(TLeafF,1); //A TLeaf for a 32 bit floating point data type. }; diff --git a/tree/tree/inc/TLeafG.h b/tree/tree/inc/TLeafG.h index 175fb2764928d..78c6beec7abd9 100644 --- a/tree/tree/inc/TLeafG.h +++ b/tree/tree/inc/TLeafG.h @@ -53,7 +53,6 @@ class TLeafG : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Long_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafI.h b/tree/tree/inc/TLeafI.h index 03decaa024559..c8fdc47804ac0 100644 --- a/tree/tree/inc/TLeafI.h +++ b/tree/tree/inc/TLeafI.h @@ -51,7 +51,6 @@ class TLeafI : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Int_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafL.h b/tree/tree/inc/TLeafL.h index b120668746855..bd7e6125b4823 100644 --- a/tree/tree/inc/TLeafL.h +++ b/tree/tree/inc/TLeafL.h @@ -53,7 +53,6 @@ class TLeafL : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Long64_t max) {fMaximum = max;} diff --git a/tree/tree/inc/TLeafO.h b/tree/tree/inc/TLeafO.h index 6d53a77780665..a5fe062523ae5 100644 --- a/tree/tree/inc/TLeafO.h +++ b/tree/tree/inc/TLeafO.h @@ -57,7 +57,6 @@ class TLeafO : public TLeaf { // Deserialize N events from an input buffer. Since chars are stored unchanged, there // is nothing to do here but return true if we don't have variable-length arrays. virtual bool ReadBasketFast(TBuffer&, Long64_t) { return true; } - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return true; } ClassDef(TLeafO,1); //A TLeaf for an 8 bit Integer data type. }; diff --git a/tree/tree/inc/TLeafS.h b/tree/tree/inc/TLeafS.h index e05c1479c1d92..e27a82aa1c493 100644 --- a/tree/tree/inc/TLeafS.h +++ b/tree/tree/inc/TLeafS.h @@ -50,7 +50,6 @@ class TLeafS : public TLeaf { virtual void ReadBasket(TBuffer &b); virtual void ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n); virtual bool ReadBasketFast(TBuffer&, Long64_t); - virtual bool ReadBasketSerialized(TBuffer&, Long64_t) { return GetDeserializeType() > DeserializeType::kExternal; } virtual void ReadValue(std::istream& s, Char_t delim = ' '); virtual void SetAddress(void *add=0); virtual void SetMaximum(Short_t max) { fMaximum = max; } diff --git a/tree/tree/src/TBranch.cxx b/tree/tree/src/TBranch.cxx index 353da5c7d82cf..98a4d5bc32236 100644 --- a/tree/tree/src/TBranch.cxx +++ b/tree/tree/src/TBranch.cxx @@ -1594,10 +1594,6 @@ Int_t TBranch::GetEntriesSerialized(Long64_t entry, TBuffer &user_buf, TBuffer * Int_t N = ((fNextBasketEntry < 0) ? fEntryNumber : fNextBasketEntry) - first; //Info("GetEntriesSerialized", "Requesting %d events; fNextBasketEntry=%lld; first=%lld.\n", N, fNextBasketEntry, first); - if (R__unlikely(!leaf->ReadBasketSerialized(user_buf, N))) { - Error("GetEntriesSerialized", "Leaf failed to read.\n"); - return -1; - } user_buf.SetBufferOffset(bufbegin); if (count_buf) { From f99e10dce1dbdbecc2469f0526af68ddd3a2f2d1 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 8 Jun 2021 13:58:32 -0500 Subject: [PATCH 113/309] Modernize BulkApiMultiple test. And resolve issue with floating point saturation in the input --- tree/tree/test/BulkApiMultiple.cxx | 156 ++++++++++++++++------------- 1 file changed, 88 insertions(+), 68 deletions(-) diff --git a/tree/tree/test/BulkApiMultiple.cxx b/tree/tree/test/BulkApiMultiple.cxx index b728d4463815c..95a7e8e7fd744 100644 --- a/tree/tree/test/BulkApiMultiple.cxx +++ b/tree/tree/test/BulkApiMultiple.cxx @@ -12,10 +12,14 @@ #include "gtest/gtest.h" +static const Long64_t gRollOver = std::pow(10, (std::numeric_limits::digits10-1)); + class BulkApiMultipleTest : public ::testing::Test { public: - static constexpr Int_t fEventCount = 1e7; + static constexpr Long64_t fEventCount = 1e7; const std::string fFileName = "BulkApiMultipleTest.root"; + static constexpr float fFloatInitial = 2.0; + static constexpr double fDoubleInitial = 3.0; protected: virtual void SetUp() @@ -26,8 +30,8 @@ class BulkApiMultipleTest : public ::testing::Test { // Otherwise, we keep with the current ROOT defaults. auto tree = new TTree("T", "A ROOT tree of floats."); - float f = 2; - double g = 3; + float f = fFloatInitial; + double g = fDoubleInitial; bool b = true; short s = 4; int i = 5; @@ -52,6 +56,10 @@ class BulkApiMultipleTest : public ::testing::Test { for (Long64_t ev = 0; ev < fEventCount; ev++) { tree->Fill(); + if (ev && (ev % gRollOver) == 0) { + f = 1.0; + g = 2.0; + } f ++; g ++; b = !b; @@ -70,17 +78,49 @@ class BulkApiMultipleTest : public ::testing::Test { } }; + +template +bool rollover(Long64_t /* ev */, T & /* value */) +{ + return false; +} + +bool rollover(Long64_t ev, float &value) +{ + if (ev && (ev % gRollOver) == 0) { + value = BulkApiMultipleTest::fFloatInitial; + return true; + } + return false; +} + +bool rollover(Long64_t ev, double &value) +{ + if (ev && (ev % gRollOver) == 0) { + value = BulkApiMultipleTest::fDoubleInitial; + return true; + } + return false; +} + template -void increment(T &value) +void increment(Long64_t ev, T &value) { - value++; + if (!rollover(ev, value)) + ++value; } -void increment(bool &value) +void increment(Long64_t /* ev */, bool &value) { value = !value; } +template +bool compare(T value, T expected) +{ + return (ULong64_t)value == (ULong64_t)expected; +} + template void SimpleBulkReadFunc(const char *filename, const char *treename, const char *branchname, T initialvalue) { @@ -92,6 +132,7 @@ void SimpleBulkReadFunc(const char *filename, const char *treename, const char * TBufferFile branchbuf(TBuffer::kWrite, 32 * 1024); auto tree = hfile->Get(treename); ASSERT_TRUE(tree); + EXPECT_EQ(tree->GetEntries(), BulkApiMultipleTest::fEventCount); TBranch *branch = tree->GetBranch(branchname); ASSERT_TRUE(branch); @@ -99,25 +140,21 @@ void SimpleBulkReadFunc(const char *filename, const char *treename, const char * T value = initialvalue; Long64_t evt_idx = 0; - Long64_t events = tree->GetEntries(); - while (events) { - auto count = branch->GetBulkRead().GetBulkEntries(evt_idx, branchbuf); - ASSERT_GE(count, 0); - events = events > count ? (events - count) : 0; - + while (auto count = branch->GetBulkRead().GetBulkEntries(evt_idx, branchbuf)) { + if (count < 0) + break; auto entry = reinterpret_cast(branchbuf.GetCurrent()); for (Int_t idx = 0; idx < count; idx++) { - if (R__unlikely((evt_idx < 16000000) && (entry[idx] != value))) { - std::cerr << "In tree " << treename << " Incorrect value for " << branchname - << " branch: " << entry[idx] << " instead of " << value << " at entry #" << evt_idx + idx << '\n'; - tree->Scan(branchname, "", "", 10, evt_idx + idx); - ASSERT_TRUE(false); - } - increment( value ); + EXPECT_TRUE(compare(entry[idx], value)) + << "In tree " << treename << " Incorrect value for " << branchname + << " branch: " << entry[idx] << ", expected " << value << " at entry #" << evt_idx + idx + << (tree->Scan(branchname, "", "", 10, evt_idx + idx - 3), '\n'); + increment( evt_idx + idx, value ); } evt_idx += count; } sw.Stop(); + EXPECT_EQ(evt_idx, BulkApiMultipleTest::fEventCount); printf("GetBulkEntries: Successful read of all events in %s.\n", treename); printf("GetBulkEntries: Total elapsed time (seconds) for bulk APIs: %.2f\n", sw.RealTime()); delete hfile; @@ -169,6 +206,7 @@ void SimpleSerializedReadFunc(const char *filename, const char *treename, const TBufferFile branchbuf(TBuffer::kWrite, 32 * 1024); auto tree = hfile->Get(treename); ASSERT_TRUE(tree); + EXPECT_EQ(tree->GetEntries(), BulkApiMultipleTest::fEventCount); TBranch *branch = tree->GetBranch(branchname); ASSERT_TRUE(branch); @@ -176,11 +214,9 @@ void SimpleSerializedReadFunc(const char *filename, const char *treename, const T value = initialvalue; Long64_t evt_idx = 0; - Long64_t events = tree->GetEntries(); - while (events) { - auto count = branch->GetBulkRead().GetEntriesSerialized(evt_idx, branchbuf); - ASSERT_GE(count, 0); - events = events > count ? (events - count) : 0; + while (auto count = branch->GetBulkRead().GetEntriesSerialized(evt_idx, branchbuf)) { + if (count < 0) + break; auto entry = reinterpret_cast(branchbuf.GetCurrent()); for (Int_t idx = 0; idx < count; idx++) { @@ -189,18 +225,16 @@ void SimpleSerializedReadFunc(const char *filename, const char *treename, const // std::cerr << "BEFORE In tree " << treename << " Incorrect value for " << branchname // << " branch: " << entry[idx] << " instead of " << value << " at entry #" << evt_idx + idx << '\n'; frombuf(tmp_ptr, entry + idx); - if (R__unlikely((evt_idx < 16000000) && (entry[idx] != value))) { - std::cerr << "In tree " << treename << " Incorrect value for " << branchname - << " branch: " << entry[idx] << " instead of " << value << " with diff: " << (entry[idx] - value) - << " at entry #" << evt_idx + idx << '\n'; - tree->Scan(branchname, "", "", 10, evt_idx + idx); - ASSERT_TRUE(false); - } - increment( value ); + ASSERT_TRUE(compare(entry[idx], value)) + << "In tree " << treename << " Incorrect value for " << branchname + << " branch: " << entry[idx] << ", expected " << value << " at entry #" << evt_idx + idx + << (tree->Scan(branchname, "", "", 10, evt_idx + idx - 3), '\n'); + increment( evt_idx + idx, value ); } evt_idx += count; } sw.Stop(); + EXPECT_EQ(BulkApiMultipleTest::fEventCount, evt_idx); printf("GetBulkEntries: Successful read of all events in %s.\n", treename); printf("GetBulkEntries: Total elapsed time (seconds) for bulk APIs: %.2f\n", sw.RealTime()); delete hfile; @@ -254,22 +288,18 @@ TEST_F(BulkApiMultipleTest, stdRead) TTreeReaderValue myF(myReader, "myFloat"); TTreeReaderValue myG(myReader, "myDouble"); Long64_t idx = 0; - float idx_f = 1; - double idx_g = 2; + float idx_f = fFloatInitial; + double idx_g = fDoubleInitial; Int_t events = fEventCount; sw.Start(); while (myReader.Next()) { if (R__unlikely(idx == events)) {break;} - idx_f++; - idx_g++; - if (R__unlikely((idx < 16000000) && (*myF != idx_f))) { - printf("Incorrect value on myFloat branch: %f, expected %f (event %lld)\n", *myF, idx_f, idx); - ASSERT_TRUE(false); - } - if (R__unlikely((idx < 15000000) && (*myG != idx_g))) { - printf("Incorrect value on myDouble branch: %f, expected %f (event %lld)\n", *myG, idx_g, idx); - ASSERT_TRUE(false); - } + ASSERT_TRUE(compare(*myF, idx_f)) + << "Incorrect value on myFloat branch: " << *myF << ", expected " << idx_f << " (event " << idx << ")\n"; + ASSERT_TRUE(compare(*myG, idx_g)) + << "Incorrect value on myDouble branch: " << *myG << ", expected " << idx_g << " (event " << idx << ")\n"; + increment(idx, idx_f); + increment(idx, idx_g); idx++; } sw.Stop(); @@ -288,35 +318,25 @@ TEST_F(BulkApiMultipleTest, fastRead) ROOT::Experimental::TTreeReaderValueFast myF(myReader, "myFloat"); ROOT::Experimental::TTreeReaderValueFast myG(myReader, "myDouble"); myReader.SetEntry(0); - if (ROOT::Internal::TTreeReaderValueBase::kSetupMatch != myF.GetSetupStatus()) { - printf("TTreeReaderValueFast failed to initialize. Status code: %d\n", myF.GetSetupStatus()); - ASSERT_TRUE(false); - } - if (ROOT::Internal::TTreeReaderValueBase::kSetupMatch != myG.GetSetupStatus()) { - printf("TTreeReaderValueFast failed to initialize. Status code: %d\n", myG.GetSetupStatus()); - ASSERT_TRUE(false); - } - if (myReader.GetEntryStatus() != TTreeReader::kEntryValid) { - printf("TTreeReaderFast failed to initialize. Entry status: %d\n", myReader.GetEntryStatus()); - ASSERT_TRUE(false); - } + ASSERT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupMatch, myF.GetSetupStatus()) << + "TTreeReaderValueFast failed to initialize. Status code: " << myF.GetSetupStatus() << "\n"; + ASSERT_EQ(ROOT::Internal::TTreeReaderValueBase::kSetupMatch, myG.GetSetupStatus()) << + "TTreeReaderValueFast failed to initialize. Status code: " << myG.GetSetupStatus() << "\n"; + ASSERT_EQ(myReader.GetEntryStatus(), TTreeReader::kEntryValid) << + "TTreeReaderFast failed to initialize. Entry status: " << myReader.GetEntryStatus() << "\n"; Int_t events = fEventCount; Long64_t idx = 0; - float idx_f = 1; - double idx_g = 2; + float idx_f = fFloatInitial; + double idx_g = fDoubleInitial; for (auto reader_idx : myReader) { ASSERT_LT(reader_idx, events); ASSERT_EQ(reader_idx, idx); - idx_f++; - idx_g++; - if (R__unlikely((idx < 16000000) && (*myF != idx_f))) { - printf("Incorrect value on myFloat branch: %f, expected %f (event %lld)\n", *myF, idx_f, idx); - ASSERT_TRUE(false); - } - if (R__unlikely((idx < 15000000) && (*myG != idx_g))) { - printf("Incorrect value on myDouble branch: %f, expected %f (event %lld)\n", *myG, idx_g, idx); - ASSERT_TRUE(false); - } + ASSERT_TRUE(compare(*myF, idx_f)) + << "Incorrect value on myFloat branch: " << *myF << ", expected " << idx_f << " (event " << idx << ")\n"; + ASSERT_TRUE(compare(*myG, idx_g)) + << "Incorrect value on myDouble branch: " << *myG << ", expected " << idx_g << " (event " << idx << ")\n"; + increment(idx, idx_f); + increment(idx, idx_g); idx++; } sw.Stop(); From 5248b5804cd3ebb0b07a227ea84828590c123bdd Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 8 Jun 2021 10:19:58 -0500 Subject: [PATCH 114/309] Mark the 'unset' state of fDeserializeTypeCache.load as the unlikely case --- tree/tree/src/TLeafElement.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tree/tree/src/TLeafElement.cxx b/tree/tree/src/TLeafElement.cxx index e5f45fcac7156..1122da495cce5 100644 --- a/tree/tree/src/TLeafElement.cxx +++ b/tree/tree/src/TLeafElement.cxx @@ -110,7 +110,7 @@ TLeafElement::~TLeafElement() TLeaf::DeserializeType TLeafElement::GetDeserializeType() const { - if (R__likely(fDeserializeTypeCache.load(std::memory_order_relaxed) != DeserializeType::kInvalid)) + if (R__unlikely(fDeserializeTypeCache.load(std::memory_order_relaxed) != DeserializeType::kInvalid)) return fDeserializeTypeCache; TClass *clptr = nullptr; @@ -143,7 +143,7 @@ TLeafElement::GetDeserializeType() const /// Deserialize N events from an input buffer. Bool_t TLeafElement::ReadBasketFast(TBuffer &input_buf, Long64_t N) { - if (R__likely(fDeserializeTypeCache.load(std::memory_order_relaxed) == DeserializeType::kInvalid)) + if (R__unlikely(fDeserializeTypeCache.load(std::memory_order_relaxed) == DeserializeType::kInvalid)) GetDeserializeType(); // Set fDataTypeCache if need be. EDataType type = fDataTypeCache.load(std::memory_order_consume); return input_buf.ByteSwapBuffer(fLen*N, type); From d9e15857c189edcfa75af5c6244ff68fac74f06f Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 10:00:32 +0200 Subject: [PATCH 115/309] [DF] Add RDisplay to LinkDef To help cling autoloading. --- tree/dataframe/inc/LinkDef.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/dataframe/inc/LinkDef.h b/tree/dataframe/inc/LinkDef.h index 3879ac8d5d3ca..8103468082da6 100644 --- a/tree/dataframe/inc/LinkDef.h +++ b/tree/dataframe/inc/LinkDef.h @@ -20,6 +20,7 @@ #pragma link C++ namespace ROOT::Internal::RDF::GraphDrawing; #pragma link C++ namespace ROOT::Detail::RDF; #pragma link C++ namespace ROOT::RDF; +#pragma link C++ class ROOT::RDF::RDisplay-; #pragma link C++ class ROOT::Internal::RDF::RActionBase-; #pragma link C++ class ROOT::Internal::RDF::RJittedAction-; #pragma link C++ class ROOT::Detail::RDF::RFilterBase-; From 8f2ee58af3811dba9a0575a92e493291410e3c31 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 15:27:48 +0200 Subject: [PATCH 116/309] [json] cast UTF8 string to const char * Required in C++20 where new char8_t type is introduced. --- io/io/test/TBufferJSONTests.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io/io/test/TBufferJSONTests.cxx b/io/io/test/TBufferJSONTests.cxx index c874c89cd5e16..6a4cc59c86e3c 100644 --- a/io/io/test/TBufferJSONTests.cxx +++ b/io/io/test/TBufferJSONTests.cxx @@ -7,7 +7,7 @@ // check utf8 coding with two bytes - most frequent usecase TEST(TBufferJSON, utf8_2) { - std::string str0 = u8"test \u0444"; // this should be cyrillic letter f + std::string str0 = reinterpret_cast(u8"test \u0444"); // this should be cyrillic letter f auto len0 = str0.length(); @@ -28,7 +28,7 @@ TEST(TBufferJSON, utf8_2) // check utf8 coding with three bytes TEST(TBufferJSON, utf8_3) { - std::string str0 = u8"test \u7546"; // no idea that + std::string str0 = reinterpret_cast(u8"test \u7546"); // no idea that auto len0 = str0.length(); From 6e7462bf70c0a27083d88228ddce51234916e0ca Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 10:19:50 +0200 Subject: [PATCH 117/309] [DF][NFC] Clarify comment --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 4214341b4c034..e6889969dfeca 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -1271,6 +1271,7 @@ void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &output outputBranch->SetTitle(inputBranch->GetTitle()); outputBranches.Insert(outName, outputBranch); // Record the branch ptr and the address associated to it if this is not a bool array + // The case of RVec is taken care of by the `UpdateBoolArrayIfBool` call above if (!std::is_same::value) { branch = outputBranch; branchAddress = GetData(*ab); From c203562fc4328db27aec940f44a7af714e23d4b0 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Mon, 7 Jun 2021 14:23:35 +0200 Subject: [PATCH 118/309] [llvm] Suppress -Wmisleading-indentation note: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit interpreter/llvm/src/lib/Target/X86/X86GenDAGISel.inc:266881: note: ‘-Wmisleading-indentation’ is disabled from this point onwards, since column-tracking was disabled due to the size of the code/headers We cannot disable the note, we can only disable the warning itself. --- interpreter/llvm/src/lib/Target/X86/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interpreter/llvm/src/lib/Target/X86/CMakeLists.txt b/interpreter/llvm/src/lib/Target/X86/CMakeLists.txt index ed34a59df4ad8..06e9e7a249d08 100644 --- a/interpreter/llvm/src/lib/Target/X86/CMakeLists.txt +++ b/interpreter/llvm/src/lib/Target/X86/CMakeLists.txt @@ -70,6 +70,14 @@ set(sources X86WinEHState.cpp ) +if (LLVM_COMPILER_IS_GCC_COMPATIBLE) + # note: ‘-Wmisleading-indentation’ is disabled from this point onwards, since + # column-tracking was disabled due to the size of the code/headers. + set_source_files_properties(X86ISelDAGToDAG.cpp PROPERTIES + COMPILE_FLAGS -Wno-misleading-indentation + ) +endif() + add_llvm_target(X86CodeGen ${sources}) add_subdirectory(AsmParser) From 8cd38ed96347e72ee1bda1a17a4d00f74b5a5d17 Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Thu, 10 Jun 2021 21:08:05 +0200 Subject: [PATCH 119/309] Fix compilation on RHEL/CentOS 7 with gcc 4.8.5 gcc 4.8.5 says the template overload is ambiguous: .../tree/dataframe/inc/ROOT/RDF/RInterface.hxx: In instantiation of 'ROOT::RDF::RResultPtr ROOT::RDF::RInterface::Book(Helper&&, const ColumnNames_t&) [with FirstColumn = ROOT::Detail::RDF::RInferredType; OtherColumns = {}; Helper = CounterHelper; Proxied = ROOT::Detail::RDF::RLoopManager; DataSource = void; typename Helper::Result_t = std::__atomic_base; ROOT::RDF::RInterface::ColumnNames_t = std::vector >]': .../tree/dataframe/test/dataframe_interface.cxx:765:4: required from here .../tree/dataframe/inc/ROOT/RDF/RInterface.hxx:2430:54: error: call of overloaded 'CallCreateActionWithoutColsIfPossible(std::shared_ptr >&, std::shared_ptr&, ROOT::TypeTraits::TypeList)' is ambiguous return CallCreateActionWithoutColsIfPossible(resPtr, hPtr, TTraits::TypeList{}); ^ .../tree/dataframe/inc/ROOT/RDF/RInterface.hxx:2430:54: note: candidates are: .../tree/dataframe/inc/ROOT/RDF/RInterface.hxx:2738:9: note: decltype ((hPtr->.Exec(0u), ROOT::RDF::RResultPtr{})) ROOT::RDF::RInterface::CallCreateActionWithoutColsIfPossible(const std::shared_ptr&, const std::shared_ptr<_Tp1>&, ROOT::TypeTraits::TypeList) [with Helper = CounterHelper; ActionResultType = std::__atomic_base; Proxied = ROOT::Detail::RDF::RLoopManager; DataSource = void; decltype ((hPtr->.Exec(0u), ROOT::RDF::RResultPtr{})) = ROOT::RDF::RResultPtr >] auto CallCreateActionWithoutColsIfPossible(const std::shared_ptr &resPtr, ^ .../tree/dataframe/inc/ROOT/RDF/RInterface.hxx:2748:4: note: ROOT::RDF::RResultPtr ROOT::RDF::RInterface::CallCreateActionWithoutColsIfPossible(const std::shared_ptr&, Others ...) [with Helper = CounterHelper; ActionResultType = std::__atomic_base; Others = {std::shared_ptr, ROOT::TypeTraits::TypeList}; Proxied = ROOT::Detail::RDF::RLoopManager; DataSource = void] CallCreateActionWithoutColsIfPossible(const std::shared_ptr &, Others...) ^ --- tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index 55a327418f51f..d1b31121d31a6 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -2746,7 +2746,9 @@ private: template RResultPtr - CallCreateActionWithoutColsIfPossible(const std::shared_ptr &, Others...) + CallCreateActionWithoutColsIfPossible(const std::shared_ptr &, + const std::shared_ptr& /*hPtr*/, + Others...) { throw std::logic_error(std::string("An action was booked with no input columns, but the action requires " "columns! The action helper type was ") + From 878cdba97f1ef48b7c70df61a4dffc4b640a7673 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 11:52:45 +0200 Subject: [PATCH 120/309] [rcanvas] make draw option for TObject attribute value One potentially can configure option via CSS. Extract TObjectDisplayItem into separate include --- graf2d/gpadv7/CMakeLists.txt | 1 + graf2d/gpadv7/inc/ROOT/RDisplayItem.hxx | 33 ----------- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 57 +++++++++++++++++++ graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 25 ++++++-- graf2d/gpadv7/src/RDisplayItem.cxx | 12 ---- graf2d/gpadv7/src/TObjectDrawable.cxx | 26 +++++---- tutorials/v7/draw_v6.cxx | 2 +- 7 files changed, 95 insertions(+), 61 deletions(-) create mode 100644 graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx diff --git a/graf2d/gpadv7/CMakeLists.txt b/graf2d/gpadv7/CMakeLists.txt index 79ff87d1f20cb..12144dd827cdc 100644 --- a/graf2d/gpadv7/CMakeLists.txt +++ b/graf2d/gpadv7/CMakeLists.txt @@ -40,6 +40,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGpadv7 ROOT/RPadPos.hxx ROOT/RPave.hxx ROOT/RVirtualCanvasPainter.hxx + ROOT/TObjectDisplayItem.hxx ROOT/TObjectDrawable.hxx SOURCES src/RCanvas.cxx diff --git a/graf2d/gpadv7/inc/ROOT/RDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/RDisplayItem.hxx index e141e7ab76c87..2933172b71d4b 100644 --- a/graf2d/gpadv7/inc/ROOT/RDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/RDisplayItem.hxx @@ -11,8 +11,6 @@ #include -class TObject; - namespace ROOT { namespace Experimental { @@ -106,37 +104,6 @@ public: RIndirectDisplayItem(const RDrawable &dr); }; - -/** \class TObjectDisplayItem -\ingroup GpadROOT7 -\brief Display item for TObject with drawing options -\author Sergey Linev -\date 2017-05-31 -\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! -*/ - -class TObjectDisplayItem : public RDisplayItem { -protected: - - int fKind{0}; ///< object kind - const TObject *fObject{nullptr}; ///< ROOT6 object - std::string fOption; ///< drawing options - bool fOwner{false}; /// + +#include +#include "TObject.h" + +namespace ROOT { +namespace Experimental { + + +/** \class TObjectDisplayItem +\ingroup GpadROOT7 +\brief Display item for TObject with drawing options +\author Sergey Linev +\date 2017-05-31 +\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! +*/ + +class TObjectDisplayItem : public RDisplayItem { +protected: + + int fKind{0}; ///< object kind + const TObject *fObject{nullptr}; ///< ROOT6 object + std::string fOption; ///< drawing options + bool fOwner{false}; /// +#include class TObject; class TColor; @@ -35,9 +36,9 @@ private: kObject = 1, ///< plain object }; - int fKind{kNone}; ///< object kind - Internal::RIOShared fObj; ///< The object to be painted - std::string fOpts; ///< drawing options + int fKind{kNone}; ///< object kind + Internal::RIOShared fObj; ///< The object to be painted + RAttrValue fOpt{this, "opt"}; /// &obj, const std::string &opt = "") : RDrawable("tobject"), fKind(kObject), fObj(obj), fOpts(opt) {} + TObjectDrawable(const std::shared_ptr &obj) : TObjectDrawable() + { + fKind = kObject; + fObj = obj; + } + + TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : TObjectDrawable() + { + fKind = kObject; + fObj = obj; + fOpt = opt; + } TObjectDrawable(EKind kind, bool persistent = false); virtual ~TObjectDrawable() = default; + + std::shared_ptr GetObject() const { return fObj.get_shared(); } + + void SetOpt(const std::string &opt) { fOpt = opt; } + std::string GetOpt() const { return fOpt; } }; } // namespace Experimental diff --git a/graf2d/gpadv7/src/RDisplayItem.cxx b/graf2d/gpadv7/src/RDisplayItem.cxx index 855c8d5a24c52..b6b12f95bcef1 100644 --- a/graf2d/gpadv7/src/RDisplayItem.cxx +++ b/graf2d/gpadv7/src/RDisplayItem.cxx @@ -11,7 +11,6 @@ #include "ROOT/RDrawable.hxx" #include "TString.h" -#include "TObject.h" using namespace ROOT::Experimental; @@ -50,7 +49,6 @@ RDrawableDisplayItem::~RDrawableDisplayItem() fDrawable->OnDisplayItemDestroyed(this); } - /////////////////////////////////////////////////////////// /// Constructor @@ -60,13 +58,3 @@ RIndirectDisplayItem::RIndirectDisplayItem(const RDrawable &dr) fCssClass = &dr.fCssClass; fId = &dr.fId; } - - -/////////////////////////////////////////////////////////// -/// destructor -TObjectDisplayItem::~TObjectDisplayItem() -{ - if (fOwner) delete fObject; -} - - diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 3a0e7ab4db28b..475ae4cfbc2b4 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -25,12 +25,12 @@ using namespace ROOT::Experimental; -TObjectDrawable::TObjectDrawable(EKind kind, bool persistent) : RDrawable("tobject"), fKind(kind) +TObjectDrawable::TObjectDrawable(EKind kind, bool persistent) : TObjectDrawable() { - if (!persistent) return; + fKind = kind; - fOpts = "persistent"; - fObj = CreateSpecials(kind); + if (persistent) + fObj = CreateSpecials(kind); } //////////////////////////////////////////////////////////////////// @@ -89,30 +89,34 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) return nullptr; } - //////////////////////////////////////////////////////////////////// /// Create display item which will be delivered to the client std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ctxt) { if (GetVersion() > ctxt.GetLastVersion()) { - if ((fKind == kObject) || (fOpts == "persistent")) - return std::make_unique(fKind, fObj.get(), fOpts); + if ((fKind == kObject) || fObj) + return std::make_unique(fKind, fObj.get(), GetOpt()); auto specials = CreateSpecials(fKind); - return std::make_unique(fKind, specials.release(), fOpts, true); + return std::make_unique(fKind, specials.release(), GetOpt(), true); } return nullptr; } +//////////////////////////////////////////////////////////////////// +/// fill context menu items for the ROOT class + void TObjectDrawable::PopulateMenu(RMenuItems &items) { - // fill context menu items for the ROOT class if (fKind == kObject) items.PopulateObjectMenu(fObj.get(), fObj.get()->IsA()); } +//////////////////////////////////////////////////////////////////// +/// Execute object method + void TObjectDrawable::Execute(const std::string &exec) { if (fKind != kObject) return; @@ -132,7 +136,7 @@ void TObjectDrawable::Execute(const std::string &exec) } std::stringstream cmd; - cmd << "((" << obj->ClassName() << "* ) " << std::hex << std::showbase << (size_t)obj << ")->" << ex << ";"; + cmd << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj << ")->" << ex << ";"; std::cout << "TObjectDrawable::Execute Obj " << obj->GetName() << "Cmd " << cmd.str() << std::endl; gROOT->ProcessLine(cmd.str().c_str()); } diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index 5c6dda178995d..f9617c16a1d3e 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -35,7 +35,7 @@ void draw_v6() using namespace ROOT::Experimental; static constexpr int npoints = 10; - double x[npoints] = { 0., 1., 2., 3., 4., 5., 6., 7., 8., 9. }; + double x[npoints] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. }; double y[npoints] = { .1, .2, .3, .4, .3, .2, .1, .2, .3, .4 }; auto gr = std::make_shared(npoints, x, y); From 62602e14de104057d8ceaaaec34f16cddd0f2d1c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 13:53:16 +0200 Subject: [PATCH 121/309] [rdrawable] extract ROOT colors from TAttLine, TAttFill, ... Check if object has some attributes as base class and extract color value of that attributes. If color index higher then 9, send actual color value with TObjectDisplayItem. Allows to draw histograms or graphs without need to transfer full list of colors. --- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 9 +++++ graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 3 ++ graf2d/gpadv7/src/TObjectDrawable.cxx | 38 ++++++++++++++++++- tutorials/v7/draw_v6.cxx | 5 +-- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx index a4e40af37f196..ab709e9ca1f26 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx @@ -12,6 +12,7 @@ #include #include +#include #include "TObject.h" namespace ROOT { @@ -33,6 +34,8 @@ protected: const TObject *fObject{nullptr}; ///< ROOT6 object std::string fOption; ///< drawing options bool fOwner{false}; /// fColIndex; ///< stored color index + std::vector fColValue; ///< stored color value public: @@ -49,6 +52,12 @@ public: if (fOwner) delete fObject; } + void AddTColor(int color_indx, const std::string &color_value) + { + fColIndex.emplace_back(color_indx); + fColValue.emplace_back(color_value); + } + }; } // namespace Experimental diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index febbf98a9c1a1..08c79a727028a 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -19,6 +19,7 @@ namespace ROOT { namespace Experimental { class RPadBase; +class TObjectDisplayItem; /** \class TObjectDrawable \ingroup GpadROOT7 @@ -54,6 +55,8 @@ protected: void Execute(const std::string &) final; + void ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member); + public: // special kinds, see TWebSnapshot enums enum EKind { diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 475ae4cfbc2b4..1f9a65583e33c 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -89,14 +89,48 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) return nullptr; } +//////////////////////////////////////////////////////////////////// +/// Check if object has specified color value and store it in display item +/// Ensure that color matches on client side too + +void TObjectDrawable::ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member) +{ + TClass *cl = fObj->IsA(); + if (!cl->GetBaseClass(class_name)) return; + + auto offset = cl->GetDataMemberOffset(class_member); + if (offset <= 0) return; + + Color_t *icol = (Color_t *)((char *) fObj.get() + offset); + if (*icol < 10) return; + + TColor *col = gROOT->GetColor(*icol); + if (col) item->AddTColor(*icol, col->AsHexString()); +} + + //////////////////////////////////////////////////////////////////// /// Create display item which will be delivered to the client std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ctxt) { if (GetVersion() > ctxt.GetLastVersion()) { - if ((fKind == kObject) || fObj) - return std::make_unique(fKind, fObj.get(), GetOpt()); + if ((fKind == kObject) || fObj) { + auto item = std::make_unique(fKind, fObj.get(), GetOpt()); + if ((fKind == kObject) && fObj) { + ExtractTColor(item, "TAttLine", "fLineColor"); + ExtractTColor(item, "TAttFill", "fFillColor"); + ExtractTColor(item, "TAttMarker", "fMarkerColor"); + ExtractTColor(item, "TAttText", "fTextColor"); + ExtractTColor(item, "TAttPad", "fFrameFillColor"); + ExtractTColor(item, "TAttPad", "fFrameLineColor"); + ExtractTColor(item, "TAttAxis", "fAxisColor"); + ExtractTColor(item, "TAttAxis", "fLabelColor"); + ExtractTColor(item, "TAttAxis", "fTitleColor"); + } + + return item; + } auto specials = CreateSpecials(fKind); return std::make_unique(fKind, specials.release(), GetOpt(), true); diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index f9617c16a1d3e..f4b7520fb5086 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -62,12 +62,11 @@ void draw_v6() auto canvas = RCanvas::Create("RCanvas showing a v6 objects"); - // place copy of gStyle object, will be applied on JSROOT side + // add gStyle object, will be applied on JSROOT side // set on the canvas before any other object is drawn canvas->Draw(TObjectDrawable::kStyle); - // copy all existing ROOT colors, required when colors was modified - // or when colors should be possible from client side + // add ROOT colors, required when they are changed from default values canvas->Draw(TObjectDrawable::kColors); // copy custom palette to canvas, will be used for col drawings From a804570dee72e776ac0cd3749d8c480c0acb8299 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 14:18:49 +0200 Subject: [PATCH 122/309] [rdrawable] let use different csstype for TObjectDarable Depending from object class type like "th1" or "tgraph" can be used Deliver csstype with attributes to the client --- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 18 +++++++++++++++--- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 17 ++++++++++++----- graf2d/gpadv7/src/TObjectDrawable.cxx | 18 +++++++++++------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx index ab709e9ca1f26..d0a995807e0c7 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx @@ -10,6 +10,7 @@ #define ROOT7_TObjectDisplayItem #include +#include #include #include @@ -27,11 +28,12 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class TObjectDisplayItem : public RDisplayItem { +class TObjectDisplayItem : public RIndirectDisplayItem { protected: int fKind{0}; ///< object kind const TObject *fObject{nullptr}; ///< ROOT6 object + std::string fCssType; ///< CSS type std::string fOption; ///< drawing options bool fOwner{false}; /// fColIndex; ///< stored color index @@ -39,12 +41,22 @@ protected: public: - TObjectDisplayItem(int kind, const TObject *obj, const std::string &opt, bool owner = false) + /// normal constructor, also copies drawable id and csstype + TObjectDisplayItem(const RDrawable &dr, int kind, const TObject *obj, const std::string &opt) : RIndirectDisplayItem(dr) { + fCssType = dr.GetCssType(); fKind = kind; fObject = obj; fOption = opt; - fOwner = owner; + } + + /// constructor for special objects like palette, takes ownership!! + TObjectDisplayItem(int kind, const TObject *obj, const std::string &opt) : RIndirectDisplayItem() + { + fKind = kind; + fObject = obj; + fOption = opt; + fOwner = true; } virtual ~TObjectDisplayItem() diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index 08c79a727028a..a2571be5bae63 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -14,6 +14,7 @@ class TObject; class TColor; +class TClass; namespace ROOT { namespace Experimental { @@ -57,6 +58,8 @@ protected: void ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member); + static std::string DetectCssType(const std::shared_ptr &obj); + public: // special kinds, see TWebSnapshot enums enum EKind { @@ -65,22 +68,26 @@ public: kPalette = 6 ///< list of colors from palette }; - TObjectDrawable() : RDrawable("tobject") {} - - TObjectDrawable(const std::shared_ptr &obj) : TObjectDrawable() + TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj)) { fKind = kObject; fObj = obj; } - TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : TObjectDrawable() + TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : RDrawable(DetectCssType(obj)) { fKind = kObject; fObj = obj; fOpt = opt; } - TObjectDrawable(EKind kind, bool persistent = false); + TObjectDrawable(EKind kind, bool persistent = false) : RDrawable("tobject") + { + fKind = kind; + + if (persistent) + fObj = CreateSpecials(kind); + } virtual ~TObjectDrawable() = default; diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 1f9a65583e33c..404d7062acb7a 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -22,15 +22,19 @@ #include #include #include +#include using namespace ROOT::Experimental; -TObjectDrawable::TObjectDrawable(EKind kind, bool persistent) : TObjectDrawable() +std::string TObjectDrawable::DetectCssType(const std::shared_ptr &obj) { - fKind = kind; - - if (persistent) - fObj = CreateSpecials(kind); + const char *clname = obj ? obj->ClassName() : "TObject"; + if (strncmp(clname, "TH1", 3) == 0) return "th1"; + if (strncmp(clname, "TH2", 3) == 0) return "th2"; + if (strncmp(clname, "TH3", 3) == 0) return "th3"; + if (strncmp(clname, "TGraph", 6) == 0) return "tgraph"; + if (strncmp(clname, "TLine", 5) == 0) return "tline"; + return "tobject"; } //////////////////////////////////////////////////////////////////// @@ -116,7 +120,7 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct { if (GetVersion() > ctxt.GetLastVersion()) { if ((fKind == kObject) || fObj) { - auto item = std::make_unique(fKind, fObj.get(), GetOpt()); + auto item = std::make_unique(*this, fKind, fObj.get(), GetOpt()); if ((fKind == kObject) && fObj) { ExtractTColor(item, "TAttLine", "fLineColor"); ExtractTColor(item, "TAttFill", "fFillColor"); @@ -133,7 +137,7 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct } auto specials = CreateSpecials(fKind); - return std::make_unique(fKind, specials.release(), GetOpt(), true); + return std::make_unique(fKind, specials.release(), GetOpt()); } return nullptr; From df1608a3ee458313485013562a841fb5bd0eab98 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 15:19:25 +0200 Subject: [PATCH 123/309] Let evaluate line attributes from css for TObjectDrawable Let customize TObject drawings in RCanvas --- tutorials/v7/draw_v6.cxx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index f4b7520fb5086..32c0dab33f72f 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -30,10 +30,12 @@ #include +using namespace ROOT::Experimental; + +auto v6_style = RStyle::Parse("tgraph { line_width: 3; line_color: red; }"); + void draw_v6() { - using namespace ROOT::Experimental; - static constexpr int npoints = 10; double x[npoints] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. }; double y[npoints] = { .1, .2, .3, .4, .3, .2, .1, .2, .3, .4 }; @@ -85,7 +87,11 @@ void draw_v6() // show same object again, but with other draw options subpads[1][1]->Draw(th2, "lego2"); - canvas->Show(); // new window in default browser should popup and async update will be triggered + // add style, evaluated only on client side + canvas->UseStyle(v6_style); + + // new window in web browser should popup and async update will be triggered + canvas->Show(); // synchronous, wait until drawing is really finished canvas->Update(false, [](bool res) { std::cout << "First sync update done = " << (res ? "true" : "false") << std::endl; }); From ec78ae8c2dc10d7f00ddc183615206fb4ed87b1d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 15:37:04 +0200 Subject: [PATCH 124/309] [rdrawable] no need to extract draw option from TObject attributes Now many attributes for TObjectDrawable will be evaluated on the client side and therefore option can be handled there as well --- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 7 ++----- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 2 +- graf2d/gpadv7/src/TObjectDrawable.cxx | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx index d0a995807e0c7..ef9cbd4cb2da2 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx @@ -34,7 +34,6 @@ protected: int fKind{0}; ///< object kind const TObject *fObject{nullptr}; ///< ROOT6 object std::string fCssType; ///< CSS type - std::string fOption; ///< drawing options bool fOwner{false}; /// fColIndex; ///< stored color index std::vector fColValue; ///< stored color value @@ -42,20 +41,18 @@ protected: public: /// normal constructor, also copies drawable id and csstype - TObjectDisplayItem(const RDrawable &dr, int kind, const TObject *obj, const std::string &opt) : RIndirectDisplayItem(dr) + TObjectDisplayItem(const RDrawable &dr, int kind, const TObject *obj) : RIndirectDisplayItem(dr) { fCssType = dr.GetCssType(); fKind = kind; fObject = obj; - fOption = opt; } /// constructor for special objects like palette, takes ownership!! - TObjectDisplayItem(int kind, const TObject *obj, const std::string &opt) : RIndirectDisplayItem() + TObjectDisplayItem(int kind, const TObject *obj) : RIndirectDisplayItem() { fKind = kind; fObject = obj; - fOption = opt; fOwner = true; } diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index a2571be5bae63..c760001e35c91 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -78,7 +78,7 @@ public: { fKind = kObject; fObj = obj; - fOpt = opt; + SetOpt(opt); } TObjectDrawable(EKind kind, bool persistent = false) : RDrawable("tobject") diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 404d7062acb7a..e986b30701d6e 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -120,7 +120,7 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct { if (GetVersion() > ctxt.GetLastVersion()) { if ((fKind == kObject) || fObj) { - auto item = std::make_unique(*this, fKind, fObj.get(), GetOpt()); + auto item = std::make_unique(*this, fKind, fObj.get()); if ((fKind == kObject) && fObj) { ExtractTColor(item, "TAttLine", "fLineColor"); ExtractTColor(item, "TAttFill", "fFillColor"); @@ -137,7 +137,7 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct } auto specials = CreateSpecials(fKind); - return std::make_unique(fKind, specials.release(), GetOpt()); + return std::make_unique(fKind, specials.release()); } return nullptr; From 599d59f168caf08523f8dc04da731f2afc071d33 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 17:57:38 +0200 Subject: [PATCH 125/309] [rdrawable] add basic attributes to TObjectDrawable If similar ROOT6 attributes defined in the object, they will be applied on the client side. Like RAttrLine will be converted into TAttLine. Any custom color can be used without limitations. --- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 22 +++++++++++++++++++++- graf2d/gpadv7/src/TObjectDrawable.cxx | 3 ++- tutorials/v7/draw_v6.cxx | 5 +++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index c760001e35c91..f3bb967be7b07 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -11,6 +11,10 @@ #include #include +#include +#include +#include +#include class TObject; class TColor; @@ -24,7 +28,7 @@ class TObjectDisplayItem; /** \class TObjectDrawable \ingroup GpadROOT7 -\brief Provides v7 drawing facilities for TObject types (TGraph etc). +\brief Provides v7 drawing facilities for TObject types (TGraph, TH1, TH2, etc). \author Sergey Linev \date 2017-05-31 \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! @@ -41,6 +45,10 @@ private: int fKind{kNone}; ///< object kind Internal::RIOShared fObj; ///< The object to be painted RAttrValue fOpt{this, "opt"}; /// &obj) if (strncmp(clname, "TH2", 3) == 0) return "th2"; if (strncmp(clname, "TH3", 3) == 0) return "th3"; if (strncmp(clname, "TGraph", 6) == 0) return "tgraph"; - if (strncmp(clname, "TLine", 5) == 0) return "tline"; + if (strcmp(clname, "TLine") == 0) return "tline"; + if (strcmp(clname, "TBox") == 0) return "tbox"; return "tobject"; } diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index 32c0dab33f72f..905f0a147119b 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -80,14 +80,15 @@ void draw_v6() subpads[0][0]->Draw(gr, "AL"); - subpads[0][1]->Draw(th1, ""); + // one can change basic attributes via v7 classes, value will be replaced on client side + subpads[0][1]->Draw(th1)->AttrLine().SetColor(RColor::kBlue).SetWidth(3).SetStyle(2); subpads[1][0]->Draw(th2, "colz"); // show same object again, but with other draw options subpads[1][1]->Draw(th2, "lego2"); - // add style, evaluated only on client side + // add style, here used to configure TGraph attrbutes, evaluated only on client side canvas->UseStyle(v6_style); // new window in web browser should popup and async update will be triggered From 6f4fb3cba08522c08718959c976d1400f93b5ee0 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 10 Jun 2021 18:24:14 +0200 Subject: [PATCH 126/309] [jsroot] dev 10/06/2021 with TObjectDrawble attributes Support v7 attributes calculation and convertion into v6 attributes. Support extracted colors. --- js/scripts/JSRoot.core.js | 2 +- js/scripts/JSRoot.gpad.js | 9 +++-- js/scripts/JSRoot.interactive.js | 23 +++++++++---- js/scripts/JSRoot.painter.js | 10 +++--- js/scripts/JSRoot.v7gpad.js | 58 +++++++++++++++++++++++++++++++- js/scripts/JSRoot.v7hist.js | 1 - 6 files changed, 86 insertions(+), 17 deletions(-) diff --git a/js/scripts/JSRoot.core.js b/js/scripts/JSRoot.core.js index 2432aa6ccf766..952cb60158f7d 100644 --- a/js/scripts/JSRoot.core.js +++ b/js/scripts/JSRoot.core.js @@ -104,7 +104,7 @@ /** @summary JSROOT version date * @desc Release date in format day/month/year like "14/01/2021"*/ - JSROOT.version_date = "8/06/2021"; + JSROOT.version_date = "10/06/2021"; /** @summary JSROOT version id and date * @desc Produced by concatenation of {@link JSROOT.version_id} and {@link JSROOT.version_date} diff --git a/js/scripts/JSRoot.gpad.js b/js/scripts/JSRoot.gpad.js index bbe6b1a1204dc..dec08e905eba0 100644 --- a/js/scripts/JSRoot.gpad.js +++ b/js/scripts/JSRoot.gpad.js @@ -3264,7 +3264,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { // set palette if (snap.fSnapshot.fBuf && (!this.options || !this.options.IgnorePalette)) { let palette = []; - for (let n=0;n { if (d.check("CP",true)) this.options.CreatePalette = d.partAsInt(0,0); + if (d.check("NOZOOMX")) this.options.NoZoomX = true; + if (d.check("NOZOOMY")) this.options.NoZoomY = true; + if (d.check('WHITE')) pad.fFillColor = 0; if (d.check('LOG2X')) { pad.fLogx = 2; pad.fUxmin = 0; pad.fUxmax = 1; pad.fX1 = 0; pad.fX2 = 1; } if (d.check('LOGX')) { pad.fLogx = 1; pad.fUxmin = 0; pad.fUxmax = 1; pad.fX1 = 0; pad.fX2 = 1; } @@ -4016,7 +4019,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { painter.selectCurrentPad(prev_name); return painter; }); - } + }; // ========================================================================================== @@ -4030,7 +4033,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { kResizeOpaque: JSROOT.BIT(21), kIsGrayscale: JSROOT.BIT(22), kShowToolTips: JSROOT.BIT(23) - } + }; /** * @summary Painter for TCanvas object diff --git a/js/scripts/JSRoot.interactive.js b/js/scripts/JSRoot.interactive.js index 91c3e813f8cc6..d85bcf2d69c79 100644 --- a/js/scripts/JSRoot.interactive.js +++ b/js/scripts/JSRoot.interactive.js @@ -725,6 +725,13 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { let svg_x = svg.selectAll(".xaxis_container"), svg_y = svg.selectAll(".yaxis_container"); + this.can_zoom_x = this.can_zoom_y = JSROOT.settings.Zooming; + + if (pp && pp.options) { + if (pp.options.NoZoomX) this.can_zoom_x = false; + if (pp.options.NoZoomY) this.can_zoom_y = false; + } + if (!svg.property('interactive_set')) { this.addKeysHandler(); @@ -990,7 +997,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (this.zoom_labels) { this.zoom_labels.processLabelsMove('stop', m); } else { - let changed = [true, true]; + let changed = [this.can_zoom_x, this.can_zoom_y]; m[0] = Math.max(0, Math.min(this.getFrameWidth(), m[0])); m[1] = Math.max(0, Math.min(this.getFrameHeight(), m[1])); @@ -1070,11 +1077,13 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (valid_x && valid_y && this._dblclick_handler) if (this.processFrameClick({ x: m[0], y: m[1] }, true)) return; - let kind = "xyz"; + let kind = (this.can_zoom_x ? "x" : "") + (this.can_zoom_y ? "y" : "") + "z"; if (!valid_x) { + if (!this.can_zoom_y) return; kind = this.swap_xy ? "x" : "y"; if ((m[0] > fw) && this[kind+"2_handle"]) kind += "2"; // let unzoom second axis } else if (!valid_y) { + if (!this.can_zoom_x) return; kind = this.swap_xy ? "y" : "x"; if ((m[1] < 0) && this[kind+"2_handle"]) kind += "2"; // let unzoom second axis } @@ -1310,18 +1319,19 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { /** @summary Handles mouse wheel event */ mouseWheel: function(evnt) { evnt.stopPropagation(); - evnt.preventDefault(); this.clearInteractiveElements(); - let itemx = { name: "x", reverse: this.reverse_x, ignore: false }, + let itemx = { name: "x", reverse: this.reverse_x }, itemy = { name: "y", reverse: this.reverse_y, ignore: !this.isAllowedDefaultYZooming() }, cur = d3.pointer(evnt, this.getFrameSvg().node()), w = this.getFrameWidth(), h = this.getFrameHeight(); - this.analyzeMouseWheelEvent(evnt, this.swap_xy ? itemy : itemx, cur[0] / w, (cur[1] >=0) && (cur[1] <= h), cur[1] < 0); + if (this.can_zoom_x) + this.analyzeMouseWheelEvent(evnt, this.swap_xy ? itemy : itemx, cur[0] / w, (cur[1] >=0) && (cur[1] <= h), cur[1] < 0); - this.analyzeMouseWheelEvent(evnt, this.swap_xy ? itemx : itemy, 1 - cur[1] / h, (cur[0] >= 0) && (cur[0] <= w), cur[0] > w); + if (this.can_zoom_y) + this.analyzeMouseWheelEvent(evnt, this.swap_xy ? itemx : itemy, 1 - cur[1] / h, (cur[0] >= 0) && (cur[0] <= w), cur[0] > w); this.zoom(itemx.min, itemx.max, itemy.min, itemy.max); @@ -1336,7 +1346,6 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.zoomSingle("y2", itemy.second.min, itemy.second.max); if (itemy.second.changed) this.zoomChangedInteractive('y2', true); } - }, /** @summary Show frame context menu */ diff --git a/js/scripts/JSRoot.painter.js b/js/scripts/JSRoot.painter.js index 175773b5dc5d6..933e5c44df245 100644 --- a/js/scripts/JSRoot.painter.js +++ b/js/scripts/JSRoot.painter.js @@ -318,12 +318,14 @@ JSROOT.define(['d3'], (d3) => { /** @summary Add new color * @param {string} rgb - color name or just string with rgb value + * @param {array} [lst] - optional colors list, to which add colors * @returns {number} index of new color */ - jsrp.addColor = function(rgb) { - let indx = jsrp.root_colors.indexOf(rgb); + jsrp.addColor = function(rgb, lst) { + if (!lst) lst = jsrp.root_colors; + let indx = lst.indexOf(rgb); if (indx >= 0) return indx; - jsrp.root_colors.push(rgb); - return jsrp.root_colors.length-1; + lst.push(rgb); + return lst.length-1; } // ===================================================================== diff --git a/js/scripts/JSRoot.v7gpad.js b/js/scripts/JSRoot.v7gpad.js index 53e6cf4d23e9e..9ab7db69fbeab 100644 --- a/js/scripts/JSRoot.v7gpad.js +++ b/js/scripts/JSRoot.v7gpad.js @@ -3249,6 +3249,57 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { } } + /** @summary Extract properties from TObjectDisplayItem */ + RPadPainter.prototype.extractTObjectProp = function(snap) { + if (snap.fColIndex && snap.fColValue) { + let colors = this.root_colors || jsrp.root_colors; + for (let k = 0; k < snap.fColIndex.length; ++k) + colors[snap.fColIndex[k]] = snap.fColValue[k]; + } + + // painter used only for evaluation of attributes + let pattr = new JSROOT.ObjectPainter(), obj = snap.fObject; + pattr.assignObject(snap); + pattr.csstype = snap.fCssType; + pattr.rstyle = snap.fStyle; + + snap.fOption = pattr.v7EvalAttr("opt", ""); + + let extract_color = (member_name, attr_name) => { + let col = pattr.v7EvalColor(attr_name, ""); + if (col) obj[member_name] = jsrp.addColor(col, this.root_colors); + } + + // handle TAttLine + if ((obj.fLineColor !== undefined) && (obj.fLineWidth !== undefined) && (obj.fLineStyle !== undefined)) { + extract_color("fLineColor", "line_color"); + obj.fLineWidth = pattr.v7EvalAttr("line_width", obj.fLineWidth); + obj.fLineStyle = pattr.v7EvalAttr("line_style", obj.fLineStyle); + } + + // handle TAttFill + if ((obj.fFillColor !== undefined) && (obj.fFillStyle !== undefined)) { + extract_color("fFillColor", "fill_color"); + obj.fFillStyle = pattr.v7EvalAttr("fill_style", obj.fFillStyle); + } + + // handle TAttMarker + if ((obj.fMarkerColor !== undefined) && (obj.fMarkerStyle !== undefined) && (obj.fMarkerSize !== undefined)) { + extract_color("fMarkerColor", "marker_color"); + obj.fMarkerStyle = pattr.v7EvalAttr("marker_style", obj.fMarkerStyle); + obj.fMarkerSize = pattr.v7EvalAttr("marker_size", obj.fMarkerSize); + } + + // handle TAttText + if ((obj.fTextColor !== undefined) && (obj.fTextAlign !== undefined) && (obj.fTextAngle !== undefined) && (obj.fTextSize !== undefined)) { + extract_color("fTextColor", "text_color"); + obj.fTextAlign = pattr.v7EvalAttr("text_align", obj.fTextAlign); + obj.fTextAngle = pattr.v7EvalAttr("text_angle", obj.fTextAngle); + obj.fTextSize = pattr.v7EvalAttr("text_size", obj.fTextSize); + // TODO: v7 font handling differs much from v6, ignore for the moment + } + } + /** @summary Function called when drawing next snapshot from the list * @returns {Promise} with pad painter when ready * @private */ @@ -3300,6 +3351,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { return this.drawNextSnap(lst, indx); }); + if (snap._typename === "ROOT::Experimental::TObjectDisplayItem") + this.extractTObjectProp(snap); + let promise; if (objpainter.updateObject(snap.fDrawable || snap.fObject || snap, snap.fOption || "")) @@ -3340,7 +3394,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (snap._typename === "ROOT::Experimental::TObjectDisplayItem") { // identifier used in RObjectDrawable - let webSnapIds = { kNone: 0, kObject: 1, kColors: 4, kStyle: 5, kPalette: 6 }; + const webSnapIds = { kNone: 0, kObject: 1, kColors: 4, kStyle: 5, kPalette: 6 }; if (snap.fKind == webSnapIds.kStyle) { JSROOT.extend(JSROOT.gStyle, snap.fObject); @@ -3372,6 +3426,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (!this.getFramePainter()) return JSROOT.draw(this.getDom(), { _typename: "TFrame", $dummy: true }, "") .then(() => this.drawNextSnap(lst, indx-1)); // call same object again + + this.extractTObjectProp(snap); } // TODO - fDrawable is v7, fObject from v6, maybe use same data member? diff --git a/js/scripts/JSRoot.v7hist.js b/js/scripts/JSRoot.v7hist.js index b468769c96afb..225aeb3b602ea 100644 --- a/js/scripts/JSRoot.v7hist.js +++ b/js/scripts/JSRoot.v7hist.js @@ -3796,7 +3796,6 @@ JSROOT.define(['d3', 'painter', 'v7gpad'], (d3, jsrp) => { // ============================================================= - function RHistStatsPainter(divid, palette, opt) { JSROOT.v7.RPavePainter.call(this, divid, palette, opt, "stats"); } From 2f2db89edc3977c6f9809f98d86fa07dd18dbe06 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 15:22:34 +0200 Subject: [PATCH 127/309] [DF] Use ROOT_GENERATE_DICTIONARY properly in dataframe/test As per the discussion at https://github.com/root-project/root/issues/8308 . --- tree/dataframe/test/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tree/dataframe/test/CMakeLists.txt b/tree/dataframe/test/CMakeLists.txt index a0f7c64b2e285..e30fd1906f03c 100644 --- a/tree/dataframe/test/CMakeLists.txt +++ b/tree/dataframe/test/CMakeLists.txt @@ -17,14 +17,14 @@ ROOT_ADD_GTEST(dataframe_nodes dataframe_nodes.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_regression dataframe_regression.cxx LIBRARIES Physics ROOTDataFrame) ROOT_ADD_GTEST(dataframe_utils dataframe_utils.cxx LIBRARIES ROOTDataFrame) ROOT_ADD_GTEST(dataframe_report dataframe_report.cxx LIBRARIES ROOTDataFrame) -ROOT_GENERATE_DICTIONARY(TwoFloatsDict TwoFloats.h LINKDEF TwoFloatsLinkDef.h OPTIONS -inlineInputHeader) -ROOT_ADD_GTEST(dataframe_splitcoll_arrayview dataframe_splitcoll_arrayview.cxx TwoFloatsDict.cxx LIBRARIES ROOTDataFrame) -ROOT_ADD_GTEST(dataframe_redefine dataframe_redefine.cxx LIBRARIES ROOTDataFrame) +ROOT_ADD_GTEST(dataframe_splitcoll_arrayview dataframe_splitcoll_arrayview.cxx LIBRARIES ROOTDataFrame) target_include_directories(dataframe_splitcoll_arrayview PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +ROOT_GENERATE_DICTIONARY(TwoFloatsDict TwoFloats.h MODULE dataframe_splitcoll_arrayview LINKDEF TwoFloatsLinkDef.h OPTIONS -inlineInputHeader) +ROOT_ADD_GTEST(dataframe_redefine dataframe_redefine.cxx LIBRARIES ROOTDataFrame) if(NOT MSVC OR win_broken_tests) - ROOT_GENERATE_DICTIONARY(MaxSlotHelperDict MaxSlotHelper.h LINKDEF MaxSlotHelperLinkDef.h OPTIONS -inlineInputHeader) - ROOT_ADD_GTEST(dataframe_simple dataframe_simple.cxx MaxSlotHelperDict.cxx LIBRARIES ROOTDataFrame) + ROOT_ADD_GTEST(dataframe_simple dataframe_simple.cxx LIBRARIES ROOTDataFrame) target_include_directories(dataframe_simple PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + ROOT_GENERATE_DICTIONARY(MaxSlotHelperDict MaxSlotHelper.h MODULE dataframe_simple LINKDEF MaxSlotHelperLinkDef.h OPTIONS -inlineInputHeader DEPENDENCIES ROOTDataFrame) if(NOT (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES arm64) OR M1_BROKEN_TESTS) ROOT_ADD_GTEST(dataframe_snapshot dataframe_snapshot.cxx LIBRARIES ROOTDataFrame) endif() From 9e193c1ef91ddc2d9b8afd6fc162f86e1c43dc09 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 11:27:32 +0200 Subject: [PATCH 128/309] [DF] Add test for duplicate columns passed to Snapshot --- tree/dataframe/test/dataframe_interface.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tree/dataframe/test/dataframe_interface.cxx b/tree/dataframe/test/dataframe_interface.cxx index 9638c00025826..14881255e233c 100644 --- a/tree/dataframe/test/dataframe_interface.cxx +++ b/tree/dataframe/test/dataframe_interface.cxx @@ -765,3 +765,11 @@ TEST(RDataFrameInterface, BookWithoutColumns) EXPECT_EQ(ROOT::RDataFrame(3).Book<>(CounterHelper()).GetValue(), 3); EXPECT_THROW(ROOT::RDataFrame(3).Book(MaxSlotHelper(1u)), std::logic_error); } + +TEST(RDataFrameInterface, SnapshotWithDuplicateColumns) +{ + EXPECT_THROW( + (ROOT::RDataFrame(1).Snapshot("t", "neverwritten.root", {"rdfentry_", "rdfentry_"})), + std::logic_error); + EXPECT_THROW((ROOT::RDataFrame(1).Snapshot("t", "neverwritten.root", {"rdfentry_", "rdfentry_"})), std::logic_error); +} From f6c7ef228d931ac562a917b8a6f415f306fe128d Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 10 Jun 2021 11:26:51 +0200 Subject: [PATCH 129/309] [DF] Throw if the same column is passed multiple times to Snapshot --- tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx | 2 ++ tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 2 ++ tree/dataframe/src/RDFInterfaceUtils.cxx | 15 ++++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx index 26856c292f69b..9a24dca4cba01 100644 --- a/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx +++ b/tree/dataframe/inc/ROOT/RDF/InterfaceUtils.hxx @@ -653,6 +653,8 @@ template struct IsDeque_t> : std::true_type {}; // clang-format on +void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols); + } // namespace RDF } // namespace Internal diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index d1b31121d31a6..f3596266d8b9d 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -595,6 +595,7 @@ public: { const auto columnListWithoutSizeColumns = RDFInternal::FilterArraySizeColNames(columnList, "Snapshot"); const auto validCols = GetValidatedColumnNames(columnListWithoutSizeColumns.size(), columnListWithoutSizeColumns); + RDFInternal::CheckForDuplicateSnapshotColumns(validCols); const auto fullTreeName = treename; const auto parsedTreePath = RDFInternal::ParseTreePath(fullTreeName); @@ -2693,6 +2694,7 @@ private: RDFInternal::CheckTypesAndPars(sizeof...(ColumnTypes), columnListWithoutSizeColumns.size()); const auto validCols = GetValidatedColumnNames(columnListWithoutSizeColumns.size(), columnListWithoutSizeColumns); + RDFInternal::CheckForDuplicateSnapshotColumns(validCols); CheckAndFillDSColumns(validCols, TTraits::TypeList()); const auto parsedTreePath = RDFInternal::ParseTreePath(fullTreeName); diff --git a/tree/dataframe/src/RDFInterfaceUtils.cxx b/tree/dataframe/src/RDFInterfaceUtils.cxx index b3b372cf6e058..9bfb2ceef5775 100644 --- a/tree/dataframe/src/RDFInterfaceUtils.cxx +++ b/tree/dataframe/src/RDFInterfaceUtils.cxx @@ -37,7 +37,7 @@ #endif #include -#include +#include #include #include #include @@ -847,6 +847,19 @@ std::vector FindUndefinedDSColumns(const ColumnNames_t &requestedCols, con return mustBeDefined; } +void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols) +{ + std::unordered_set uniqueCols; + for (auto &col : cols) { + if (!uniqueCols.insert(col).second) { + const auto msg = "Error: column \"" + col + + "\" was passed to Snapshot twice. This is not supported: only one of the columns would be " + "readable with RDataFrame."; + throw std::logic_error(msg); + } + } +} + } // namespace RDF } // namespace Internal } // namespace ROOT From abe4a2efc4d292c37d0a04811e4203e8e396daa6 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Fri, 11 Jun 2021 11:36:05 +0200 Subject: [PATCH 130/309] Change the documentation of TQObject Following the changes for Win64, adapt the example in the documentation to use the proper `Longptr_t` type. Thanks @Sergey Linev --- core/base/inc/TQObject.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/base/inc/TQObject.h b/core/base/inc/TQObject.h index 14ba3ebb1e3e7..1aaf004798df2 100644 --- a/core/base/inc/TQObject.h +++ b/core/base/inc/TQObject.h @@ -146,7 +146,7 @@ class TQObject { /// ~~~ /// /// If we call Emit with an array of the parameters, they should be converted - /// to long type. + /// to Longptr_t type. /// Example: /// ~~~ {.cpp} /// TQObject *processor; // data processor @@ -155,9 +155,9 @@ class TQObject { /// processor->Connect("Evaluated(Float_t,Float_t)", /// "TH1F",hist,"Fill12(Axis_t,Axis_t)"); /// - /// Long_t args[2]; - /// args[0] = (Long_t)processor->GetValue(1); - /// args[1] = (Long_t)processor->GetValue(2); + /// Longptr_t args[2]; + /// args[0] = (Longptr_t)processor->GetValue(1); + /// args[1] = (Longptr_t)processor->GetValue(2); /// /// processor->Emit("Evaluated(Float_t,Float_t)",args); /// ~~~ From 5d8ea94da37ed7e0acd4fc5c085fbfdbba5d2cb9 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 12:13:53 +0200 Subject: [PATCH 131/309] [RF] Remove useless interface in RooAbsFunc. --- roofit/roofitcore/inc/RooAbsFunc.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/roofit/roofitcore/inc/RooAbsFunc.h b/roofit/roofitcore/inc/RooAbsFunc.h index 9acfa24d12be1..aaad061f003db 100644 --- a/roofit/roofitcore/inc/RooAbsFunc.h +++ b/roofit/roofitcore/inc/RooAbsFunc.h @@ -40,9 +40,6 @@ class RooAbsFunc { } virtual Double_t operator()(const Double_t xvector[]) const = 0; - virtual RooSpan getValues(std::vector> /*coordinates*/) const { - throw std::logic_error("Not implemented."); - } virtual Double_t getMinLimit(UInt_t dimension) const = 0; virtual Double_t getMaxLimit(UInt_t dimension) const = 0; @@ -68,12 +65,12 @@ class RooAbsFunc { return "(unnamed)" ; } - virtual std::list* binBoundaries(Int_t) const { return 0 ; } + virtual std::list* binBoundaries(Int_t) const { return nullptr; } + /// Interface for returning an optional hint for initial sampling points when constructing a curve + /// projected on observable. virtual std::list* plotSamplingHint(RooAbsRealLValue& /*obs*/, Double_t /*xlo*/, Double_t /*xhi*/) const { - // Interface for returning an optional hint for initial sampling points when constructing a curve - // projected on observable. - return 0 ; + return nullptr; } protected: From 1bd5845d5903f035536514b623a9b1892620ebf2 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 11:06:55 +0200 Subject: [PATCH 132/309] [RF] Remove stray friend declaration. --- roofit/roofitcore/inc/RooAbsArg.h | 1 - 1 file changed, 1 deletion(-) diff --git a/roofit/roofitcore/inc/RooAbsArg.h b/roofit/roofitcore/inc/RooAbsArg.h index 58220f4b42bb5..6d081a897e2cb 100644 --- a/roofit/roofitcore/inc/RooAbsArg.h +++ b/roofit/roofitcore/inc/RooAbsArg.h @@ -615,7 +615,6 @@ class RooAbsArg : public TNamed, public RooPrintable { friend class RooObjectFactory ; friend class RooHistPdf ; friend class RooHistFunc ; - friend class RooHistFunc2 ; void registerProxy(RooArgProxy& proxy) ; void registerProxy(RooSetProxy& proxy) ; void registerProxy(RooListProxy& proxy) ; From 79bb8e6589f380318d674e1558f959f9d67ec0e7 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 22 Nov 2020 18:24:46 +0100 Subject: [PATCH 133/309] [RF] Add RooAbsArg::setCachedValue. When objects RooFit objects need to be used in batch computations, their values must sometimes be overwritten, using copyCache(). In batch computations, however, copyCache() doesn't work, since there is no object to copy from. This is solved using `setCachedValue`, which writes into the `_value` member of an object, making it look like this was the result of a computation. This is also helpful when having to set values without casting to an *LValue type or when computations have already been performed. --- roofit/roofitcore/inc/RooAbsArg.h | 6 ++++++ roofit/roofitcore/inc/RooAbsCategory.h | 1 + roofit/roofitcore/inc/RooAbsReal.h | 18 +++++++++++++++++- roofit/roofitcore/src/RooAbsCategory.cxx | 18 ++++++++++++++++++ roofit/roofitcore/src/RooAbsReal.cxx | 1 - 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/roofit/roofitcore/inc/RooAbsArg.h b/roofit/roofitcore/inc/RooAbsArg.h index 6d081a897e2cb..91f35fec5532c 100644 --- a/roofit/roofitcore/inc/RooAbsArg.h +++ b/roofit/roofitcore/inc/RooAbsArg.h @@ -502,6 +502,12 @@ class RooAbsArg : public TNamed, public RooPrintable { RooExpensiveObjectCache& expensiveObjectCache() const ; virtual void setExpensiveObjectCache(RooExpensiveObjectCache &cache) { _eocache = &cache; } + /// Overwrite the current value stored in this object, making it look like this object computed that value. + /// \param[in] value Value to store. + /// \param[in] notifyClients Notify users of this object that they need to + /// recompute their values. + virtual void setCachedValue(double /*value*/, bool /*notifyClients*/ = true) {}; + /// @} //////////////////////////////////////////////////////////////////////////// diff --git a/roofit/roofitcore/inc/RooAbsCategory.h b/roofit/roofitcore/inc/RooAbsCategory.h index 006bab66b20df..f381ba2a62ed1 100644 --- a/roofit/roofitcore/inc/RooAbsCategory.h +++ b/roofit/roofitcore/inc/RooAbsCategory.h @@ -202,6 +202,7 @@ class RooAbsCategory : public RooAbsArg { friend class RooVectorDataStore ; virtual void syncCache(const RooArgSet* set=0) ; virtual void copyCache(const RooAbsArg* source, Bool_t valueOnly=kFALSE, Bool_t setValueDirty=kTRUE) ; + void setCachedValue(double value, bool notifyClients = true) final; virtual void attachToTree(TTree& t, Int_t bufSize=32000) ; virtual void attachToVStore(RooVectorDataStore& vstore) ; virtual void setTreeBranchStatus(TTree& t, Bool_t active) ; diff --git a/roofit/roofitcore/inc/RooAbsReal.h b/roofit/roofitcore/inc/RooAbsReal.h index 53eb63fea1119..234743758235b 100644 --- a/roofit/roofitcore/inc/RooAbsReal.h +++ b/roofit/roofitcore/inc/RooAbsReal.h @@ -309,7 +309,7 @@ class RooAbsReal : public RooAbsArg { virtual void printValue(std::ostream& os) const ; virtual void printMultiline(std::ostream& os, Int_t contents, Bool_t verbose=kFALSE, TString indent="") const ; - static void setCacheCheck(Bool_t flag) ; + inline void setCachedValue(double value, bool notifyClients = true) final; // Evaluation error logging class EvalError { @@ -592,4 +592,20 @@ class BatchInterfaceAccessor { }; +//////////////////////////////////////////////////////////////////////////////// +/// Overwrite the value stored in this object's cache. +/// This can be used to fake a computation that resulted in `value`. +/// \param[in] value Value to write. +/// \param[in] setValDirty If true, notify users of this object that its value changed. +/// This is the default. +void RooAbsReal::setCachedValue(double value, bool notifyClients) { + _value = value; + + if (notifyClients) { + setValueDirty(); + _valueDirty = false; + } +} + + #endif diff --git a/roofit/roofitcore/src/RooAbsCategory.cxx b/roofit/roofitcore/src/RooAbsCategory.cxx index d29bb84691696..afb1ffdb60559 100644 --- a/roofit/roofitcore/src/RooAbsCategory.cxx +++ b/roofit/roofitcore/src/RooAbsCategory.cxx @@ -562,6 +562,24 @@ void RooAbsCategory::copyCache(const RooAbsArg *source, Bool_t /*valueOnly*/, Bo } } + +//////////////////////////////////////////////////////////////////////////////// +/// Overwrite the value stored in this object's cache. +/// This can be used to fake a computation that resulted in `value`. +/// \param[in] value Value to write. The argument is reinterpreted as a category state. +/// If such a state does not exist, this will create undefined behaviour. +/// \param[in] notifyClients If true, notify users of this object that its value changed. +/// This is the default. +void RooAbsCategory::setCachedValue(double value, bool notifyClients) { + _currentIndex = static_cast(value); + + if (notifyClients) { + setValueDirty(); + _valueDirty = false; + } +} + + //////////////////////////////////////////////////////////////////////////////// /// Return name and index of the `n`th defined state. When states are defined using /// defineType() or operator[], the order of insertion is tracked, to mimic the behaviour diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index 04325e4ec51f9..769e5420677c8 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -3221,7 +3221,6 @@ void RooAbsReal::copyCache(const RooAbsArg* source, Bool_t /*valueOnly*/, Bool_t } - //////////////////////////////////////////////////////////////////////////////// void RooAbsReal::attachToVStore(RooVectorDataStore& vstore) From bf4b0a4c5cdaedbbae14887a28d3bd478eef279d Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 29 May 2020 11:58:14 +0200 Subject: [PATCH 134/309] [RF] Add addTerm() function to RooProduct. Using addTerm(), one can attach new terms to a product. This will be used to simplify HistFactory models, which use products of products of products ... --- roofit/roofitcore/inc/RooProduct.h | 3 +++ roofit/roofitcore/src/RooProduct.cxx | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/roofit/roofitcore/inc/RooProduct.h b/roofit/roofitcore/inc/RooProduct.h index 7cdbcc5495d2a..fa95e07923a51 100644 --- a/roofit/roofitcore/inc/RooProduct.h +++ b/roofit/roofitcore/inc/RooProduct.h @@ -33,6 +33,9 @@ class RooProduct : public RooAbsReal { RooProduct(const char *name, const char *title, const RooArgList& _prodSet) ; RooProduct(const RooProduct& other, const char* name = 0); + + void addTerm(RooAbsArg* term); + virtual TObject* clone(const char* newname) const { return new RooProduct(*this, newname); } virtual Bool_t forceAnalyticalInt(const RooAbsArg& dep) const ; virtual Int_t getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, diff --git a/roofit/roofitcore/src/RooProduct.cxx b/roofit/roofitcore/src/RooProduct.cxx index 9190b98a00f26..ea85fe95c7aea 100644 --- a/roofit/roofitcore/src/RooProduct.cxx +++ b/roofit/roofitcore/src/RooProduct.cxx @@ -81,15 +81,7 @@ RooProduct::RooProduct(const char* name, const char* title, const RooArgList& pr _cacheMgr(this,10) { for (auto comp : prodSet) { - if (dynamic_cast(comp)) { - _compRSet.add(*comp) ; - } else if (dynamic_cast(comp)) { - _compCSet.add(*comp) ; - } else { - coutE(InputArguments) << "RooProduct::ctor(" << GetName() << ") ERROR: component " << comp->GetName() - << " is not of type RooAbsReal or RooAbsCategory" << endl ; - RooErrorHandler::softAbort() ; - } + addTerm(comp); } TRACE_CREATE } @@ -109,6 +101,19 @@ RooProduct::RooProduct(const RooProduct& other, const char* name) : } +//////////////////////////////////////////////////////////////////////////////// +/// Add a term to this product. +void RooProduct::addTerm(RooAbsArg* term) { + if (dynamic_cast(term)) { + _compRSet.add(*term) ; + } else if (dynamic_cast(term)) { + _compCSet.add(*term) ; + } else { + coutE(InputArguments) << "RooProduct::addTerm(" << GetName() << ") ERROR: component " << term->GetName() + << " is not of type RooAbsReal or RooAbsCategory" << endl ; + throw std::invalid_argument("RooProduct can only handle terms deriving from RooAbsReal or RooAbsCategory."); + } +} //////////////////////////////////////////////////////////////////////////////// /// Force internal handling of integration of given observable if any From 127cc601dce3fec40880f3f47fff8af13217c344 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 4 Jun 2020 14:57:38 +0200 Subject: [PATCH 135/309] [HF] Add self-contained test for creating models. - Add test fixture that creates a HistFactory model. It tests four modes: - uniform binning, norm systmatics - custom binning, norm systematics - uniform binning, shape systematics - custom binning, shape systematics - Add a test that evaluates and fits those models. - With/without const term optimisation (this affects how many batch evaluation functions are called, and tests that pre-computed results in the data store are accessed correctly). - With/without batch mode in fit. - Add dependency to RooBatchCompute. - In the batch eval test, activate the FastEvaluations topic message stream to check if classes need a getValues() implementation. --- roofit/histfactory/test/CMakeLists.txt | 2 +- roofit/histfactory/test/testHistFactory.cxx | 489 ++++++++++++++++++++ 2 files changed, 490 insertions(+), 1 deletion(-) diff --git a/roofit/histfactory/test/CMakeLists.txt b/roofit/histfactory/test/CMakeLists.txt index a664c52b27536..f797b08d33a66 100644 --- a/roofit/histfactory/test/CMakeLists.txt +++ b/roofit/histfactory/test/CMakeLists.txt @@ -7,5 +7,5 @@ # @author Stephan Hageboeck CERN, 2019 ROOT_ADD_GTEST(testHistFactory testHistFactory.cxx - LIBRARIES RooFitCore RooFit RooStats HistFactory + LIBRARIES RooFitCore RooFit RooStats HistFactory RooBatchCompute COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/ref_6.16_example_UsingC_channel1_meas_model.root ${CMAKE_CURRENT_SOURCE_DIR}/ref_6.16_example_UsingC_combined_meas_model.root) diff --git a/roofit/histfactory/test/testHistFactory.cxx b/roofit/histfactory/test/testHistFactory.cxx index 5b9b343743bd3..ffd8cc21611a4 100644 --- a/roofit/histfactory/test/testHistFactory.cxx +++ b/roofit/histfactory/test/testHistFactory.cxx @@ -1,15 +1,28 @@ // Tests for the HistFactory // Authors: Stephan Hageboeck, CERN 01/2019 +#include "RooStats/HistFactory/Measurement.h" +#include "RooStats/HistFactory/MakeModelAndMeasurementsFast.h" #include "RooStats/HistFactory/Sample.h" #include "RooStats/ModelConfig.h" + #include "RooWorkspace.h" #include "RooArgSet.h" +#include "RooSimultaneous.h" +#include "RooRealSumPdf.h" +#include "RooRealVar.h" +#include "RooHelpers.h" +#include "RooFitResult.h" +#include "RooPlot.h" +#include "RunContext.h" #include "TROOT.h" #include "TFile.h" +#include "TCanvas.h" #include "gtest/gtest.h" +#include + using namespace RooStats; using namespace RooStats::HistFactory; @@ -81,3 +94,479 @@ TEST(HistFactory, Read_ROOT6_16_Combined_Model) { EXPECT_NEAR(pdf->getVal(), 0.17488817, 1.E-8); EXPECT_NEAR(pdf->getVal(*obs), 0.95652174, 1.E-8); } + + + +enum MakeModelMode {kEquidistantBins=0, kCustomBins=1, kEquidistantBins_histoSyst=2, kCustomBins_histoSyst=3}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Fixture class to set up a toy hist factory model. +/// In the SetUp() phase +/// - A file with histograms is created. Depending on the value of MakeModelMode, +/// equidistant or custom bins are used, and shape systematics are added. +/// - A Measurement with the histograms in the file is created. +/// - The corresponding workspace is created. +class HFFixture : public testing::TestWithParam { +public: + std::string _inputFile{"TestMakeModel.root"}; + static constexpr bool _verbose = false; + double _customBins[3] = {0., 1.8, 2.}; + const double _targetMu = 2.; + const double _targetNominal[2] = {110., 120.}; + const double _targetSysUp[2] = {112., 140.}; + const double _targetSysDo[2] = {108., 100.}; + std::unique_ptr ws; + std::set _systNames; // Systematics defined during set up + + void SetUp() { + { + TFile example(_inputFile.c_str(), "RECREATE"); + TH1F *data, *signal, *bkg1, *bkg2, *statUnc, *systUncUp, *systUncDo; + if (GetParam() == kEquidistantBins || GetParam() == kEquidistantBins_histoSyst) { + data = new TH1F("data","data", 2,1,2); + signal = new TH1F("signal","signal histogram (pb)", 2,1,2); + bkg1 = new TH1F("background1","background 1 histogram (pb)", 2,1,2); + bkg2 = new TH1F("background2","background 2 histogram (pb)", 2,1,2); + statUnc = new TH1F("background1_statUncert", "statUncert", 2,1,2); + systUncUp = new TH1F("shapeUnc_sigUp", "signal shape uncert.", 2,1,2); + systUncDo = new TH1F("shapeUnc_sigDo", "signal shape uncert.", 2,1,2); + } else if (GetParam() == kCustomBins || GetParam() == kCustomBins_histoSyst) { + data = new TH1F("data","data", 2, _customBins); + signal = new TH1F("signal","signal histogram (pb)", 2, _customBins); + bkg1 = new TH1F("background1","background 1 histogram (pb)", 2, _customBins); + bkg2 = new TH1F("background2","background 2 histogram (pb)", 2, _customBins); + statUnc = new TH1F("background1_statUncert", "statUncert", 2, _customBins); + systUncUp = new TH1F("shapeUnc_sigUp", "signal shape uncert.", 2, _customBins); + systUncDo = new TH1F("shapeUnc_sigDo", "signal shape uncert.", 2, _customBins); + } else { + // Harden the test and make clang-tidy happy: + FAIL() << "This should not be reachable."; + } + + bkg1->SetBinContent(1, 100); + bkg2->SetBinContent(2, 100); + + for (unsigned int bin=0; bin < 2; ++bin) { + signal-> SetBinContent(bin+1, _targetNominal[bin] - 100.); + systUncUp->SetBinContent(bin+1, _targetSysUp[bin] - 100.); + systUncDo->SetBinContent(bin+1, _targetSysDo[bin] - 100.); + + if (GetParam() < kEquidistantBins_histoSyst) { + data->SetBinContent(bin+1, _targetMu * signal->GetBinContent(bin+1) + 100.); + } else { + // Set data such that alpha = -1., fit should pull parameter. + data->SetBinContent(bin+1, _targetMu * systUncDo->GetBinContent(bin+1) + 100.); + } + + // A small statistical uncertainty + statUnc->SetBinContent(bin+1, .05); // 5% uncertainty + } + + + for (auto hist : {data, signal, bkg1, bkg2, statUnc, systUncUp, systUncDo}) { + example.WriteTObject(hist); + } + } + + + // Create the measurement + Measurement meas("meas", "meas"); + + meas.SetOutputFilePrefix( "example_variableBins" ); + meas.SetPOI( "SigXsecOverSM" ); + meas.AddConstantParam("alpha_syst1"); + meas.AddConstantParam("Lumi"); + if (GetParam() >= kEquidistantBins_histoSyst) { + // We are testing the shape systematics. Switch off the normalisation + // systematics for the background here: + meas.AddConstantParam("alpha_syst2"); + meas.AddConstantParam("alpha_syst4"); + meas.AddConstantParam("gamma_stat_channel1_bin_0"); + meas.AddConstantParam("gamma_stat_channel1_bin_1"); + } + + meas.SetExportOnly(true); + + meas.SetLumi( 1.0 ); + meas.SetLumiRelErr( 0.10 ); + + + // Create a channel + Channel chan( "channel1" ); + chan.SetData( "data", _inputFile); + chan.SetStatErrorConfig( 0.05, "Poisson" ); + _systNames.insert("gamma_stat_channel1_bin_0"); + _systNames.insert("gamma_stat_channel1_bin_1"); + + + + // Now, create some samples + + // Create the signal sample + Sample signal( "signal", "signal", _inputFile); + signal.AddOverallSys( "syst1", 0.95, 1.05 ); + _systNames.insert("alpha_syst1"); + + signal.AddNormFactor( "SigXsecOverSM", 1, 0, 3 ); + if (GetParam() >= kEquidistantBins_histoSyst) { + signal.AddHistoSys("SignalShape", + "shapeUnc_sigDo", _inputFile, "", + "shapeUnc_sigUp", _inputFile, ""); + _systNames.insert("alpha_SignalShape"); + } + chan.AddSample( signal ); + + // Background 1 + Sample background1( "background1", "background1", _inputFile); + background1.ActivateStatError( "background1_statUncert", _inputFile); + background1.AddOverallSys( "syst2", 0.95, 1.05 ); + background1.AddOverallSys( "syst3", 0.99, 1.01 ); + _systNames.insert("alpha_syst2"); + _systNames.insert("alpha_syst3"); + chan.AddSample( background1 ); + + // Background 2 + Sample background2( "background2", "background2", _inputFile); + background2.ActivateStatError(); + background2.AddOverallSys( "syst3", 0.99, 1.01 ); + background2.AddOverallSys( "syst4", 0.95, 1.05 ); + _systNames.insert("alpha_syst3"); + _systNames.insert("alpha_syst4"); + chan.AddSample( background2 ); + + + // Done with this channel + // Add it to the measurement: + meas.AddChannel( chan ); + + if (!_verbose) { + RooMsgService::instance().getStream(1).minLevel = RooFit::PROGRESS; + RooMsgService::instance().getStream(2).minLevel = RooFit::WARNING; + } + RooHelpers::HijackMessageStream hijackW(RooFit::WARNING, RooFit::HistFactory); + + // Collect the histograms from their files, + meas.CollectHistograms(); + + // Now, create the measurement + ws.reset( MakeModelAndMeasurementFast(meas) ); + + EXPECT_TRUE(hijackW.str().empty()) << "Warnings logged for HistFactory:\n" << hijackW.str(); + } + + void TearDown() { + + } +}; + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Test that the model consists of what is expected +TEST_P(HFFixture, ModelProperties) { + auto simPdf = dynamic_cast(ws->pdf("simPdf")); + ASSERT_NE(simPdf, nullptr); + + auto channelPdf = dynamic_cast(ws->pdf("channel1_model")); + ASSERT_NE(channelPdf, nullptr); + + auto obs = dynamic_cast(ws->var("obs_x_channel1")); + + // Nice to inspect the model if needed: + channelPdf->graphVizTree("/tmp/graphVizTree.dot"); + + // Check bin widths + ASSERT_NE(obs, nullptr); + if (GetParam() == kEquidistantBins || GetParam() == kEquidistantBins_histoSyst) { + EXPECT_DOUBLE_EQ(obs->getBinWidth(0), 0.5); + EXPECT_DOUBLE_EQ(obs->getBinWidth(1), 0.5); + EXPECT_EQ(obs->numBins(), 2); + } else if (GetParam() == kCustomBins || GetParam() == kCustomBins_histoSyst) { + EXPECT_DOUBLE_EQ(obs->getBinWidth(0), _customBins[1] - _customBins[0]); + EXPECT_DOUBLE_EQ(obs->getBinWidth(1), _customBins[2] - _customBins[1]); + EXPECT_EQ(obs->numBins(), 2); + } else { + throw std::logic_error("Test set up wrongly."); + } + + RooStats::ModelConfig* mc = dynamic_cast(ws->obj("ModelConfig")); + ASSERT_NE(mc, nullptr); + + + // Check that parameters are in the model + for (const auto& systName : _systNames) { + auto& var = *ws->var(systName.c_str()); + + EXPECT_TRUE(channelPdf->dependsOnValue(var)) << "Expect channel pdf to depend on " << systName; + if (!var.isConstant()) { + EXPECT_NE(mc->GetNuisanceParameters()->find(systName.c_str()), nullptr) << systName << " should be in list of nuisance parameters."; + } + } + + // Check that sub models depend on their systematic uncertainties. + for (auto& subModelName : std::initializer_list{"signal_channel1_shapes", "background1_channel1_shapes", "background2_channel1_shapes"}) { + auto subModel = ws->function(subModelName.c_str()); + ASSERT_NE(subModel, nullptr) << "Unable to retrieve sub model with name " << subModelName; + if (subModelName.find("signal") != std::string::npos) { + EXPECT_FALSE(subModel->dependsOn(*ws->var("gamma_stat_channel1_bin_0"))); + EXPECT_FALSE(subModel->dependsOn(*ws->var("gamma_stat_channel1_bin_1"))); + } else { + EXPECT_TRUE(subModel->dependsOn(*ws->var("gamma_stat_channel1_bin_0"))); + EXPECT_TRUE(subModel->dependsOn(*ws->var("gamma_stat_channel1_bin_1"))); + } + } + + EXPECT_TRUE (ws->function("signal_channel1_scaleFactors")->dependsOn(*ws->var("SigXsecOverSM"))); + EXPECT_TRUE (ws->function("signal_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst1"))); + EXPECT_FALSE(ws->function("signal_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst2"))); + EXPECT_FALSE(ws->function("signal_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst3"))); + EXPECT_FALSE(ws->function("signal_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst4"))); + + EXPECT_FALSE(ws->function("background1_channel1_scaleFactors")->dependsOn(*ws->var("SigXsecOverSM"))); + EXPECT_FALSE(ws->function("background1_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst1"))); + EXPECT_TRUE (ws->function("background1_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst2"))); + EXPECT_TRUE (ws->function("background1_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst3"))); + EXPECT_FALSE(ws->function("background1_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst4"))); + + EXPECT_FALSE(ws->function("background2_channel1_scaleFactors")->dependsOn(*ws->var("SigXsecOverSM"))); + EXPECT_FALSE(ws->function("background2_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst1"))); + EXPECT_FALSE(ws->function("background2_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst2"))); + EXPECT_TRUE (ws->function("background2_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst3"))); + EXPECT_TRUE (ws->function("background2_channel1_scaleFactors")->dependsOn(*ws->var("alpha_syst4"))); + + EXPECT_EQ(*mc->GetParametersOfInterest()->begin(), ws->var("SigXsecOverSM")); +} + + +/// Test that the values returned are as expected. +TEST_P(HFFixture, Evaluation) { + auto simPdf = dynamic_cast(ws->pdf("simPdf")); + ASSERT_NE(simPdf, nullptr); + + auto channelPdf = dynamic_cast(ws->pdf("channel1_model")); + ASSERT_NE(channelPdf, nullptr); + + auto obs = dynamic_cast(ws->var("obs_x_channel1")); + + RooStats::ModelConfig* mc = dynamic_cast(ws->obj("ModelConfig")); + ASSERT_NE(mc, nullptr); + + // Test evaluating the model: + double normResults[2] = {0., 0.}; + for (unsigned int i=0; i < 2; ++i) { + obs->setBin(i); + EXPECT_NEAR(channelPdf->getVal(), + _targetNominal[i]/obs->getBinWidth(i), 1.E-9); + EXPECT_NEAR(channelPdf->getVal(mc->GetObservables()), + _targetNominal[i]/obs->getBinWidth(i)/(_targetNominal[0]+_targetNominal[1]), 1.E-9); + normResults[i] = channelPdf->getVal(mc->GetObservables()); + } + EXPECT_NEAR(normResults[0] * obs->getBinWidth(0) + normResults[1] * obs->getBinWidth(1), 1, 1.E-9) << "Integral over PDF range should be 1."; + + + // Test that shape uncertainties have an effect: + if (GetParam() >= kEquidistantBins_histoSyst) { + auto var = ws->var("alpha_SignalShape"); + ASSERT_NE(var, nullptr); + + // Test syst up: + var->setVal(1.); + for (unsigned int i=0; i < 2; ++i) { + obs->setBin(i); + EXPECT_NEAR(channelPdf->getVal(), + _targetSysUp[i]/obs->getBinWidth(i), 1.E-6); + EXPECT_NEAR(channelPdf->getVal(mc->GetObservables()), + _targetSysUp[i]/obs->getBinWidth(i)/(_targetSysUp[0]+_targetSysUp[1]), 1.E-6); + } + + // Test syst down: + var->setVal(-1.); + for (unsigned int i=0; i < 2; ++i) { + obs->setBin(i); + EXPECT_NEAR(channelPdf->getVal(), + _targetSysDo[i]/obs->getBinWidth(i), 1.E-6); + EXPECT_NEAR(channelPdf->getVal(mc->GetObservables()), + _targetSysDo[i]/obs->getBinWidth(i)/(_targetSysDo[0]+_targetSysDo[1]), 1.E-6); + } + } +} + + +/// Test that the values returned are as expected. +TEST_P(HFFixture, BatchEvaluation) { + RooHelpers::HijackMessageStream evalMessages(RooFit::INFO, RooFit::FastEvaluations); + + auto simPdf = dynamic_cast(ws->pdf("simPdf")); + ASSERT_NE(simPdf, nullptr); + + auto channelPdf = dynamic_cast(ws->pdf("channel1_model")); + ASSERT_NE(channelPdf, nullptr); + + auto obs = dynamic_cast(ws->var("obs_x_channel1")); + + RooStats::ModelConfig* mc = dynamic_cast(ws->obj("ModelConfig")); + ASSERT_NE(mc, nullptr); + + // Test evaluating the model: + RooBatchCompute::RunContext evalDataOrig; + auto batch = evalDataOrig.makeBatch(obs, 2); + obs->setBin(0); + batch[0] = obs->getVal(); + obs->setBin(1); + batch[1] = obs->getVal(); + + RooBatchCompute::RunContext evalData1; + evalData1.spans = evalDataOrig.spans; + auto results = channelPdf->getValues(evalData1, nullptr); + RooBatchCompute::RunContext evalData2; + evalData2.spans = evalDataOrig.spans; + auto normResults = channelPdf->getValues(evalData2, mc->GetObservables()); + + for (unsigned int i=0; i < 2; ++i) { + obs->setBin(i); + EXPECT_NEAR(results[i], + _targetNominal[i]/obs->getBinWidth(i), 1.E-9); + EXPECT_NEAR(normResults[i], + _targetNominal[i]/obs->getBinWidth(i)/(_targetNominal[0]+_targetNominal[1]), 1.E-9); + } + EXPECT_NEAR(normResults[0] * obs->getBinWidth(0) + normResults[1] * obs->getBinWidth(1), 1, 1.E-9) << "Integral over PDF range should be 1."; + + + // Test that shape uncertainties have an effect: + if (GetParam() >= kEquidistantBins_histoSyst) { + auto var = ws->var("alpha_SignalShape"); + ASSERT_NE(var, nullptr); + + // Test syst up: + var->setVal(1.); + RooBatchCompute::RunContext evalData3; + evalData3.spans = evalDataOrig.spans; + auto resultsSyst = channelPdf->getValues(evalData3, nullptr); + RooBatchCompute::RunContext evalData4; + evalData4.spans = evalDataOrig.spans; + auto normResultsSyst = channelPdf->getValues(evalData4, mc->GetObservables()); + for (unsigned int i=0; i < 2; ++i) { + EXPECT_NEAR(resultsSyst[i], + _targetSysUp[i]/obs->getBinWidth(i), 1.E-6); + EXPECT_NEAR(normResultsSyst[i], + _targetSysUp[i]/obs->getBinWidth(i)/(_targetSysUp[0]+_targetSysUp[1]), 1.E-6); + } + + // Test syst down: + var->setVal(-1.); + RooBatchCompute::RunContext evalData5; + evalData5.spans = evalDataOrig.spans; + resultsSyst = channelPdf->getValues(evalData5, nullptr); + RooBatchCompute::RunContext evalData6; + evalData6.spans = evalDataOrig.spans; + normResultsSyst = channelPdf->getValues(evalData6, mc->GetObservables()); + for (unsigned int i=0; i < 2; ++i) { + obs->setBin(i); + EXPECT_NEAR(resultsSyst[i], + _targetSysDo[i]/obs->getBinWidth(i), 1.E-6); + EXPECT_NEAR(normResultsSyst[i], + _targetSysDo[i]/obs->getBinWidth(i)/(_targetSysDo[0]+_targetSysDo[1]), 1.E-6); + } + } + + EXPECT_TRUE(evalMessages.str().empty()) << "RooFit issued " << evalMessages.str().substr(0, 1000) << " [...]"; +} + + +/// Fit the model to data, and check parameters. +TEST_P(HFFixture, Fit) { + constexpr bool createPlot = false; + + auto simPdf = dynamic_cast(ws->pdf("simPdf")); + ASSERT_NE(simPdf, nullptr); + + auto channelPdf = dynamic_cast(ws->pdf("channel1_model")); + ASSERT_NE(channelPdf, nullptr); + + // Test fitting the model to data + RooAbsData* data = dynamic_cast(ws->data("obsData")); + ASSERT_NE(data, nullptr); + + RooStats::ModelConfig* mc = dynamic_cast(ws->obj("ModelConfig")); + ASSERT_NE(mc, nullptr); + + for (bool batchFit : {true, false}) { + for (bool constTermOptimisation : {true, false}) { // This tests both correct pre-caching of constant terms and (if false) that all evaluateSpan() are correct. + SCOPED_TRACE(batchFit ? "Batch fit" : "Normal fit"); + SCOPED_TRACE(constTermOptimisation ? "const term optimisation" : "No const term optimisation"); + + std::unique_ptr pars( simPdf->getParameters(*data) ); + // Kick parameters: + for (auto par : *pars) { + auto real = dynamic_cast(par); + if (real && !real->isConstant()) + real->setVal(real->getVal() * 0.95); + } + + auto fitResult = simPdf->fitTo(*data, + RooFit::BatchMode(batchFit), + RooFit::Optimize(constTermOptimisation), + RooFit::GlobalObservables(*mc->GetGlobalObservables()), + RooFit::Save(), + RooFit::PrintLevel(-1)); + ASSERT_NE(fitResult, nullptr); + if (verbose) + fitResult->Print(); + EXPECT_EQ(fitResult->status(), 0); + + + auto checkParam = [fitResult](const std::string& param, double target, double absPrecision) { + auto par = dynamic_cast(fitResult->floatParsFinal().find(param.c_str())); + if (!par) { + // Parameter was constant in this fit + par = dynamic_cast(fitResult->constPars().find(param.c_str())); + ASSERT_NE(par, nullptr); + EXPECT_DOUBLE_EQ(par->getVal(), target) << "Constant parameter " << param << " is off target."; + } else { + EXPECT_NEAR(par->getVal(), target, par->getError()) << "Parameter " << param << " close to target " << target << " within uncertainty"; + EXPECT_NEAR(par->getVal(), target, absPrecision) << "Parameter " << param << " close to target " << target; + } + }; + + if (GetParam() < kEquidistantBins_histoSyst) { + // Model is set up such that background scale factors should be close to 1, and signal == 2 + checkParam("SigXsecOverSM", 2., 1.E-2); + checkParam("alpha_syst2", 0., 1.E-2); + checkParam("alpha_syst3", 0., 1.E-2); + checkParam("alpha_syst4", 0., 1.E-2); + checkParam("gamma_stat_channel1_bin_0", 1., 1.E-2); + checkParam("gamma_stat_channel1_bin_1", 1., 1.E-2); + } else if (GetParam() <= kCustomBins_histoSyst) { + // Model is set up with a -1 sigma pull on the signal shape parameter. + checkParam("SigXsecOverSM", 2., 1.E-1); // Higher tolerance: Expect a pull due to shape syst. + checkParam("alpha_syst2", 0., 1.E-2); + checkParam("alpha_syst3", 0., 3.E-2); // Micro pull due to shape syst. + checkParam("alpha_syst4", 0., 1.E-2); + checkParam("gamma_stat_channel1_bin_0", 1., 1.E-2); + checkParam("gamma_stat_channel1_bin_1", 1., 1.E-2); + checkParam("alpha_SignalShape", -0.9, 5.E-2); // Pull slightly lower than 1 because of constraint term + } + } + } + + + if (createPlot) { + auto obs = dynamic_cast(ws->var("obs_x_channel1")); + auto frame = obs->frame(); + data->plotOn(frame); + channelPdf->plotOn(frame); + channelPdf->plotOn(frame, RooFit::Components("signal_channel1_shapes"), RooFit::LineColor(kRed)); + TCanvas canv; + frame->Draw(); + canv.Draw(); + canv.SaveAs(("/tmp/HFTest" + std::to_string(GetParam()) + ".png").c_str()); + } +} + + +INSTANTIATE_TEST_SUITE_P(MakeModelWithNormSysts, + HFFixture, + testing::Values(kEquidistantBins, kCustomBins)); + +INSTANTIATE_TEST_SUITE_P(MakeModelWithHistoSysts, + HFFixture, + testing::Values(kEquidistantBins_histoSyst, kCustomBins_histoSyst)); + From 9a8bc8a342d5446801ae2b1c0527d8de7f8cc0c1 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 18:35:01 +0200 Subject: [PATCH 136/309] [HF] Add test of gamma parameters to testHistFactory. --- roofit/histfactory/test/testHistFactory.cxx | 75 ++++++++++++++++----- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/roofit/histfactory/test/testHistFactory.cxx b/roofit/histfactory/test/testHistFactory.cxx index ffd8cc21611a4..542046156df15 100644 --- a/roofit/histfactory/test/testHistFactory.cxx +++ b/roofit/histfactory/test/testHistFactory.cxx @@ -96,8 +96,13 @@ TEST(HistFactory, Read_ROOT6_16_Combined_Model) { } - -enum MakeModelMode {kEquidistantBins=0, kCustomBins=1, kEquidistantBins_histoSyst=2, kCustomBins_histoSyst=3}; +/// What kind of model is set up. Use this to instantiate +/// a test suite. +/// \note Make sure that equidistant bins have even numbers, +/// so those tests can be found using `% 2 == kEquidistantBins`. +enum MakeModelMode {kEquidistantBins=0, kCustomBins=1, + kEquidistantBins_histoSyst = 2, kCustomBins_histoSyst = 3, + kEquidistantBins_statSyst = 4, kCustomBins_statSyst = 5}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Fixture class to set up a toy hist factory model. /// In the SetUp() phase @@ -121,7 +126,8 @@ class HFFixture : public testing::TestWithParam { { TFile example(_inputFile.c_str(), "RECREATE"); TH1F *data, *signal, *bkg1, *bkg2, *statUnc, *systUncUp, *systUncDo; - if (GetParam() == kEquidistantBins || GetParam() == kEquidistantBins_histoSyst) { + data = signal = bkg1 = bkg2 = statUnc = systUncUp = systUncDo = nullptr; + if (GetParam() % 2 == kEquidistantBins) { data = new TH1F("data","data", 2,1,2); signal = new TH1F("signal","signal histogram (pb)", 2,1,2); bkg1 = new TH1F("background1","background 1 histogram (pb)", 2,1,2); @@ -129,7 +135,7 @@ class HFFixture : public testing::TestWithParam { statUnc = new TH1F("background1_statUncert", "statUncert", 2,1,2); systUncUp = new TH1F("shapeUnc_sigUp", "signal shape uncert.", 2,1,2); systUncDo = new TH1F("shapeUnc_sigDo", "signal shape uncert.", 2,1,2); - } else if (GetParam() == kCustomBins || GetParam() == kCustomBins_histoSyst) { + } else if (GetParam() % 2 == kCustomBins) { data = new TH1F("data","data", 2, _customBins); signal = new TH1F("signal","signal histogram (pb)", 2, _customBins); bkg1 = new TH1F("background1","background 1 histogram (pb)", 2, _customBins); @@ -150,11 +156,18 @@ class HFFixture : public testing::TestWithParam { systUncUp->SetBinContent(bin+1, _targetSysUp[bin] - 100.); systUncDo->SetBinContent(bin+1, _targetSysDo[bin] - 100.); - if (GetParam() < kEquidistantBins_histoSyst) { + if (GetParam() <= kCustomBins) { data->SetBinContent(bin+1, _targetMu * signal->GetBinContent(bin+1) + 100.); - } else { + } else if (GetParam() <= kCustomBins_histoSyst) { // Set data such that alpha = -1., fit should pull parameter. data->SetBinContent(bin+1, _targetMu * systUncDo->GetBinContent(bin+1) + 100.); + } else if (GetParam() <= kCustomBins_statSyst) { + // Tighten the stat. errors of the model, and kick bin 0, so the gammas have to adapt + signal->SetBinError(bin+1, 0.1 * sqrt(signal->GetBinContent(bin+1))); + bkg1 ->SetBinError(bin+1, 0.1 * sqrt(bkg1 ->GetBinContent(bin+1))); + bkg2 ->SetBinError(bin+1, 0.1 * sqrt(bkg2 ->GetBinContent(bin+1))); + + data->SetBinContent(bin+1, _targetMu * signal->GetBinContent(bin+1) + 100. + (bin == 0 ? 50. : 0.)); } // A small statistical uncertainty @@ -175,13 +188,20 @@ class HFFixture : public testing::TestWithParam { meas.SetPOI( "SigXsecOverSM" ); meas.AddConstantParam("alpha_syst1"); meas.AddConstantParam("Lumi"); - if (GetParam() >= kEquidistantBins_histoSyst) { + if (GetParam() == kEquidistantBins_histoSyst || GetParam() == kCustomBins_histoSyst) { // We are testing the shape systematics. Switch off the normalisation // systematics for the background here: meas.AddConstantParam("alpha_syst2"); meas.AddConstantParam("alpha_syst4"); meas.AddConstantParam("gamma_stat_channel1_bin_0"); meas.AddConstantParam("gamma_stat_channel1_bin_1"); + } else if (GetParam() == kEquidistantBins_statSyst || GetParam() == kCustomBins_statSyst) { + // Fix all systematics but the gamma parameters + // Cannot set the POI constant here, happens in the fit test. + meas.AddConstantParam("alpha_syst2"); + meas.AddConstantParam("alpha_syst3"); + meas.AddConstantParam("alpha_syst4"); + meas.AddConstantParam("alpha_SignalShape"); } meas.SetExportOnly(true); @@ -193,7 +213,7 @@ class HFFixture : public testing::TestWithParam { // Create a channel Channel chan( "channel1" ); chan.SetData( "data", _inputFile); - chan.SetStatErrorConfig( 0.05, "Poisson" ); + chan.SetStatErrorConfig( 0.005, "Poisson" ); _systNames.insert("gamma_stat_channel1_bin_0"); _systNames.insert("gamma_stat_channel1_bin_1"); @@ -271,20 +291,19 @@ TEST_P(HFFixture, ModelProperties) { auto obs = dynamic_cast(ws->var("obs_x_channel1")); // Nice to inspect the model if needed: - channelPdf->graphVizTree("/tmp/graphVizTree.dot"); + if (false) + channelPdf->graphVizTree("/tmp/graphVizTree.dot"); // Check bin widths ASSERT_NE(obs, nullptr); - if (GetParam() == kEquidistantBins || GetParam() == kEquidistantBins_histoSyst) { + if (GetParam() % 2 == kEquidistantBins) { EXPECT_DOUBLE_EQ(obs->getBinWidth(0), 0.5); EXPECT_DOUBLE_EQ(obs->getBinWidth(1), 0.5); EXPECT_EQ(obs->numBins(), 2); - } else if (GetParam() == kCustomBins || GetParam() == kCustomBins_histoSyst) { + } else if (GetParam() % 2 == kCustomBins) { EXPECT_DOUBLE_EQ(obs->getBinWidth(0), _customBins[1] - _customBins[0]); EXPECT_DOUBLE_EQ(obs->getBinWidth(1), _customBins[2] - _customBins[1]); EXPECT_EQ(obs->numBins(), 2); - } else { - throw std::logic_error("Test set up wrongly."); } RooStats::ModelConfig* mc = dynamic_cast(ws->obj("ModelConfig")); @@ -474,6 +493,7 @@ TEST_P(HFFixture, BatchEvaluation) { /// Fit the model to data, and check parameters. TEST_P(HFFixture, Fit) { constexpr bool createPlot = false; + constexpr bool verbose = false; auto simPdf = dynamic_cast(ws->pdf("simPdf")); ASSERT_NE(simPdf, nullptr); @@ -493,6 +513,10 @@ TEST_P(HFFixture, Fit) { SCOPED_TRACE(batchFit ? "Batch fit" : "Normal fit"); SCOPED_TRACE(constTermOptimisation ? "const term optimisation" : "No const term optimisation"); + // Stop if one of the previous runs had a failure to keep the terminal clean. + if (HasFailure()) + break; + std::unique_ptr pars( simPdf->getParameters(*data) ); // Kick parameters: for (auto par : *pars) { @@ -500,13 +524,19 @@ TEST_P(HFFixture, Fit) { if (real && !real->isConstant()) real->setVal(real->getVal() * 0.95); } + if (GetParam() >= kEquidistantBins_statSyst) { + auto poi = dynamic_cast(pars->find("SigXsecOverSM")); + ASSERT_NE(poi, nullptr); + poi->setVal(2.); + poi->setConstant(); + } auto fitResult = simPdf->fitTo(*data, RooFit::BatchMode(batchFit), RooFit::Optimize(constTermOptimisation), RooFit::GlobalObservables(*mc->GetGlobalObservables()), RooFit::Save(), - RooFit::PrintLevel(-1)); + RooFit::PrintLevel(verbose ? 1 : -1)); ASSERT_NE(fitResult, nullptr); if (verbose) fitResult->Print(); @@ -526,7 +556,7 @@ TEST_P(HFFixture, Fit) { } }; - if (GetParam() < kEquidistantBins_histoSyst) { + if (GetParam() <= kCustomBins) { // Model is set up such that background scale factors should be close to 1, and signal == 2 checkParam("SigXsecOverSM", 2., 1.E-2); checkParam("alpha_syst2", 0., 1.E-2); @@ -543,6 +573,15 @@ TEST_P(HFFixture, Fit) { checkParam("gamma_stat_channel1_bin_0", 1., 1.E-2); checkParam("gamma_stat_channel1_bin_1", 1., 1.E-2); checkParam("alpha_SignalShape", -0.9, 5.E-2); // Pull slightly lower than 1 because of constraint term + } else if (GetParam() <= kCustomBins_statSyst) { + // Model is set up with a -1 sigma pull on the signal shape parameter. + checkParam("SigXsecOverSM", 2., 1.E-1); // Higher tolerance: Expect a pull due to shape syst. + checkParam("alpha_syst2", 0., 1.E-2); + checkParam("alpha_syst3", 0., 1.E-2); + checkParam("alpha_syst4", 0., 1.E-2); + checkParam("gamma_stat_channel1_bin_0", 1.09, 1.E-2); // This should be pulled + checkParam("gamma_stat_channel1_bin_1", 1., 1.E-2); + checkParam("alpha_SignalShape", 0., 1.E-2); } } } @@ -558,6 +597,8 @@ TEST_P(HFFixture, Fit) { frame->Draw(); canv.Draw(); canv.SaveAs(("/tmp/HFTest" + std::to_string(GetParam()) + ".png").c_str()); + + channelPdf->graphVizTree(("/tmp/HFTest" + std::to_string(GetParam()) + ".dot").c_str()); } } @@ -570,3 +611,7 @@ INSTANTIATE_TEST_SUITE_P(MakeModelWithHistoSysts, HFFixture, testing::Values(kEquidistantBins_histoSyst, kCustomBins_histoSyst)); +INSTANTIATE_TEST_SUITE_P(MakeModelWithHistoAndStatSysts, + HFFixture, + testing::Values(kEquidistantBins_statSyst, kCustomBins_statSyst)); + From 24cbf04736a8993affcbc66c42d859ba8b5faa54 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 5 Jun 2020 11:25:18 +0200 Subject: [PATCH 137/309] [RF] Optimise analytical integration of ParamHistFunc. To make the integral of a ParamHistFunc more efficient, RooDataHist can now hand out all its bin volumes as a RooSpan. --- roofit/histfactory/src/ParamHistFunc.cxx | 31 ++++++------------------ roofit/roofitcore/inc/RooDataHist.h | 4 +++ roofit/roofitcore/src/RooDataHist.cxx | 3 +-- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/roofit/histfactory/src/ParamHistFunc.cxx b/roofit/histfactory/src/ParamHistFunc.cxx index fe6689e3422b7..bb53ab9f0ca8d 100644 --- a/roofit/histfactory/src/ParamHistFunc.cxx +++ b/roofit/histfactory/src/ParamHistFunc.cxx @@ -660,34 +660,17 @@ Double_t ParamHistFunc::analyticalIntegralWN(Int_t /*code*/, const RooArgSet* /* // Simply loop over bins, // get the height, and // multiply by the bind width - - RooFIter paramIter = _paramSet.fwdIterator(); - RooRealVar* param = NULL; - Int_t nominalItr = 0; - while((param = (RooRealVar*) paramIter.next())) { + auto binVolumes = _dataSet.binVolumes(0, _dataSet.numEntries()); + + for (unsigned int i=0; i < _paramSet.size(); ++i) { + const auto& param = static_cast(_paramSet[i]); + assert(static_cast(i) == _dataSet.getIndex(param)); // We assume that each parameter i belongs to bin i // Get the gamma's value - Double_t paramVal = (*param).getVal(); - - // Get the bin volume - _dataSet.get( nominalItr ); - Double_t binVolumeDS = _dataSet.binVolume(); //_binning->binWidth( nominalItr ); + const double paramVal = param.getVal(); // Finally, get the subtotal - value += paramVal*binVolumeDS; - - ++nominalItr; - - /* - std::cout << "Integrating : " - << " bin: " << nomValue - << " binVolume: " << binVolumeDS - << " paramValue: " << paramVal - << " nomValue: " << nomValue - << " subTotal: " << value - << std::endl; - */ - + value += paramVal * binVolumes[i]; } return value; diff --git a/roofit/roofitcore/inc/RooDataHist.h b/roofit/roofitcore/inc/RooDataHist.h index b21fc124f3190..ab8ad00eb7103 100644 --- a/roofit/roofitcore/inc/RooDataHist.h +++ b/roofit/roofitcore/inc/RooDataHist.h @@ -84,6 +84,10 @@ class RooDataHist : public RooAbsData, public RooDirItem { RooSpan getWeightBatch(std::size_t first, std::size_t len) const override; void getBatches(RooBatchCompute::RunContext& evalData, std::size_t begin, std::size_t len) const override; + /// Retrieve all bin volumes. Bins are indexed according to getIndex(). + RooSpan binVolumes(std::size_t first, std::size_t len) const { + return {_binv + first, len}; + } Double_t sum(bool correctForBinSize, bool inverseCorr=false) const ; Double_t sum(const RooArgSet& sumSet, const RooArgSet& sliceSet, bool correctForBinSize, bool inverseCorr=false) ; diff --git a/roofit/roofitcore/src/RooDataHist.cxx b/roofit/roofitcore/src/RooDataHist.cxx index fb3a3f72a0b91..6e29eacfbcd19 100644 --- a/roofit/roofitcore/src/RooDataHist.cxx +++ b/roofit/roofitcore/src/RooDataHist.cxx @@ -2140,8 +2140,7 @@ void RooDataHist::Streamer(TBuffer &R__b) { //////////////////////////////////////////////////////////////////////////////// /// Return event weights of all events in range [first, first+len). -/// If no contiguous structure of weights is stored, an empty batch is be returned. -/// In this case, the single-value weight() needs to be used to retrieve it. +/// If cacheValidEntries() has been called, out-of-range events will have a weight of 0. RooSpan RooDataHist::getWeightBatch(std::size_t first, std::size_t len) const { return _maskedWeights.empty() ? RooSpan{_wgt + first, len} : From 28a2c328ace1356e72a73bdb991d73b32e97c40c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 9 Jun 2020 12:10:07 +0200 Subject: [PATCH 138/309] [RF] React to custom binning when plotting data. When an observable has custom binnings, and data should be plotted, the default was to use equidistant binning. Now, RooAbsData uses the custom binning, unless the user overrides the binning. --- roofit/roofitcore/src/RooAbsData.cxx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/roofit/roofitcore/src/RooAbsData.cxx b/roofit/roofitcore/src/RooAbsData.cxx index 12481e3eb305d..7d191c392683a 100644 --- a/roofit/roofitcore/src/RooAbsData.cxx +++ b/roofit/roofitcore/src/RooAbsData.cxx @@ -1626,7 +1626,7 @@ RooPlot* RooAbsData::plotOn(RooPlot* frame, const RooLinkedList& argList) const // New experimental plotOn() with varargs... // Define configuration for this method - RooCmdConfig pc(Form("RooTreeData::plotOn(%s)",GetName())) ; + RooCmdConfig pc(Form("RooAbsData::plotOn(%s)",GetName())) ; pc.defineString("drawOption","DrawOption",0,"P") ; pc.defineString("cutRange","CutRange",0,"",kTRUE) ; pc.defineString("cutString","CutSpec",0,"") ; @@ -1769,11 +1769,14 @@ RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const TString histName(GetName()); histName.Append("_plot"); TH1F *hist ; - if (o.bins) { + if (o.bins) { hist= static_cast(var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), RooFit::Binning(*o.bins))) ; + } else if (!frame->getPlotVar()->getBinning().isUniform()) { + hist = static_cast(var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), + RooFit::Binning(frame->getPlotVar()->getBinning()))); } else { hist= var->createHistogram(histName.Data(), "Events", - frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), frame->GetNbinsX()); + frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), frame->GetNbinsX()); } // Keep track of sum-of-weights error From 0676d958a86c20b52a6e9da19233999e5890e8b4 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 11 Jun 2020 18:44:42 +0200 Subject: [PATCH 139/309] [RF] Add getBin(), totVolume(), evaluateSpan() to RooHistFunc. - Add functions to retrieve bin numbers and volumes to RooHistFunc. This is used to speed up HistFactory and to fix ROOT-4958 (HistFactory cannot deal with non-uniform binning). - Implement evaluateSpan(). --- roofit/roofitcore/inc/RooHistFunc.h | 10 ++- roofit/roofitcore/src/RooHistFunc.cxx | 113 +++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/roofit/roofitcore/inc/RooHistFunc.h b/roofit/roofitcore/inc/RooHistFunc.h index 3278936430869..46ff30de47b29 100644 --- a/roofit/roofitcore/inc/RooHistFunc.h +++ b/roofit/roofitcore/inc/RooHistFunc.h @@ -46,6 +46,10 @@ class RooHistFunc : public RooAbsReal { return *_dataHist ; } + /// Get total bin volume spanned by this hist function. + /// In 1-d, this is e.g. the range spanned on the x-axis. + Double_t totVolume() const; + /// Set histogram interpolation order. void setInterpolationOrder(Int_t order) { @@ -81,15 +85,17 @@ class RooHistFunc : public RooAbsReal { RooArgSet const& getHistObsList() const { return _histObsList; } + Int_t getBin() const; + std::vector getBins(RooBatchCompute::RunContext& evalData) const; + protected: Bool_t importWorkspaceHook(RooWorkspace& ws) ; Bool_t areIdentical(const RooDataHist& dh1, const RooDataHist& dh2) ; Double_t evaluate() const; - Double_t totalVolume() const ; + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* /*normSet*/) const; friend class RooAbsCachedReal ; - Double_t totVolume() const ; virtual void ioStreamerPass2() ; diff --git a/roofit/roofitcore/src/RooHistFunc.cxx b/roofit/roofitcore/src/RooHistFunc.cxx index ba77be4935f9f..c051475e37fa1 100644 --- a/roofit/roofitcore/src/RooHistFunc.cxx +++ b/roofit/roofitcore/src/RooHistFunc.cxx @@ -24,10 +24,6 @@ multidimensional histogram. The histogram can have an arbitrary number of real o discrete dimensions and may have negative values. **/ -#include "RooFit.h" -#include "Riostream.h" -#include "TBuffer.h" - #include "RooHistFunc.h" #include "RooDataHist.h" #include "RooMsgService.h" @@ -36,8 +32,12 @@ discrete dimensions and may have negative values. #include "RooWorkspace.h" #include "RooHistPdf.h" #include "RooHelpers.h" +#include "RunContext.h" #include "TError.h" +#include "TBuffer.h" + +#include using namespace std; @@ -201,6 +201,49 @@ Double_t RooHistFunc::evaluate() const return ret ; } + +//////////////////////////////////////////////////////////////////////////////// +/// Compute value of the HistFunc for every entry in `evalData`. +/// \param[in/out] evalData Struct with input data. The computation results will be stored here. +/// \param[in] normSet Set of observables to normalise over (ignored). +RooSpan RooHistFunc::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* /*normSet*/) const { + std::vector> inputValues; + std::size_t batchSize = 0; + for (const auto& obs : _depList) { + auto realObs = dynamic_cast(obs); + if (realObs) { + auto inputs = realObs->getValues(evalData, nullptr); + batchSize = std::max(batchSize, inputs.size()); + inputValues.push_back(std::move(inputs)); + } else { + inputValues.emplace_back(); + } + } + + auto results = evalData.makeBatch(this, batchSize); + + for (std::size_t i = 0; i < batchSize; ++i) { + bool skip = false; + + for (auto j = 0u; j < _histObsList.size(); ++j) { + const auto histObs = _histObsList[j]; + + if (i < inputValues[j].size()) { + histObs->setCachedValue(inputValues[j][i], false); + if (!histObs->inRange(nullptr)) { + skip = true; + break; + } + } + } + + results[i] = skip ? 0. : _dataHist->weightFast(_histObsList, _intOrder, false, _cdfBoundaries); + } + + return results; +} + + //////////////////////////////////////////////////////////////////////////////// /// Only handle case of maximum in all variables @@ -537,3 +580,65 @@ void RooHistFunc::ioStreamerPass2() } } + +//////////////////////////////////////////////////////////////////////////////// +/// Compute bin number corresponding to current coordinates. +/// \return If a bin is not in the current range of the observables, return -1. +Int_t RooHistFunc::getBin() const { + if (!_depList.empty()) { + for (auto i = 0u; i < _histObsList.size(); ++i) { + const auto harg = _histObsList[i]; + const auto parg = _depList[i]; + + if (harg != parg) { + parg->syncCache() ; + harg->copyCache(parg,kTRUE) ; + if (!harg->inRange(nullptr)) { + return -1; + } + } + } + } + + return _dataHist->getIndex(_histObsList, true); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Compute bin numbers corresponding to all coordinates in `evalData`. +/// \return Vector of bin numbers. If a bin is not in the current range of the observables, return -1. +std::vector RooHistFunc::getBins(RooBatchCompute::RunContext& evalData) const { + std::vector> depData; + for (const auto dep : _depList) { + auto real = dynamic_cast(dep); + if (real) { + depData.push_back(real->getValues(evalData, nullptr)); + } else { + depData.emplace_back(nullptr, 0); + } + } + + const auto batchSize = std::max_element(depData.begin(), depData.end(), + [](const RooSpan& a, const RooSpan& b){ return a.size() < b.size(); })->size(); + std::vector results; + + for (std::size_t evt = 0; evt < batchSize; ++evt) { + if (!_depList.empty()) { + for (auto i = 0u; i < _histObsList.size(); ++i) { + const auto harg = _histObsList[i]; + + if (evt < depData[i].size()) + harg->setCachedValue(depData[i][evt], false); + + if (!harg->inRange(nullptr)) { + results.push_back(-1); + continue; + } + } + } + + results.push_back(_dataHist->getIndex(_histObsList, true)); + } + + return results; +} From cf24112ee4073f5119f07400c9789362fd674913 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 30 Oct 2020 10:45:30 +0100 Subject: [PATCH 140/309] [RF] Implement evaluateSpan for RooProduct. --- roofit/roofitcore/inc/RooProduct.h | 2 ++ roofit/roofitcore/src/RooProduct.cxx | 49 +++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/roofit/roofitcore/inc/RooProduct.h b/roofit/roofitcore/inc/RooProduct.h index fa95e07923a51..c012ca33ba9fc 100644 --- a/roofit/roofitcore/inc/RooProduct.h +++ b/roofit/roofitcore/inc/RooProduct.h @@ -77,6 +77,8 @@ class RooProduct : public RooAbsReal { Double_t calculate(const RooArgList& partIntList) const; Double_t evaluate() const; + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const; + const char* makeFPName(const char *pfx,const RooArgSet& terms) const ; ProdMap* groupProductTerms(const RooArgSet&) const; Int_t getPartIntList(const RooArgSet* iset, const char *rangeName=0) const; diff --git a/roofit/roofitcore/src/RooProduct.cxx b/roofit/roofitcore/src/RooProduct.cxx index ea85fe95c7aea..cc35594f222f7 100644 --- a/roofit/roofitcore/src/RooProduct.cxx +++ b/roofit/roofitcore/src/RooProduct.cxx @@ -23,18 +23,18 @@ A RooProduct represents the product of a given set of RooAbsReal objects. **/ - -#include -#include - #include "RooProduct.h" + #include "RooNameReg.h" #include "RooAbsReal.h" #include "RooAbsCategory.h" -#include "RooErrorHandler.h" #include "RooMsgService.h" +#include "RunContext.h" #include "RooTrace.h" +#include +#include + using namespace std ; ClassImp(RooProduct); @@ -384,6 +384,45 @@ Double_t RooProduct::evaluate() const } +//////////////////////////////////////////////////////////////////////////////// +/// Evaluate product of input functions for all points found in `evalData`. +RooSpan RooProduct::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const { + RooSpan prod; + + assert(_compRSet.nset() == normSet); + + for (const auto item : _compRSet) { + auto rcomp = static_cast(item); + auto componentValues = rcomp->getValues(evalData, normSet); + + if (prod.empty()) { + prod = evalData.makeBatch(this, componentValues.size()); + for (auto& val : prod) val = 1.; + } else if (prod.size() == 1 && componentValues.size() > 1) { + const double val = prod[0]; + prod = evalData.makeBatch(this, componentValues.size()); + std::fill(prod.begin(), prod.end(), val); + } + assert(prod.size() == componentValues.size() || componentValues.size() == 1); + + for (unsigned int i = 0; i < prod.size(); ++i) { + prod[i] *= componentValues.size() == 1 ? componentValues[0] : componentValues[i]; + } + } + + for (const auto item : _compCSet) { + auto ccomp = static_cast(item); + const int catIndex = ccomp->getCurrentIndex(); + + for (unsigned int i = 0; i < prod.size(); ++i) { + prod[i] *= catIndex; + } + } + + return prod; +} + + //////////////////////////////////////////////////////////////////////////////// /// Forward the plot sampling hint from the p.d.f. that defines the observable obs From f469fd7714ed17826d592a1657c2b05c4cd627b2 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 30 Oct 2020 20:40:46 +0100 Subject: [PATCH 141/309] [HF] Make nominal model accessible in PiecewiseInterpolation. --- .../inc/RooStats/HistFactory/PiecewiseInterpolation.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h index 758d68094d130..e3ca6b4636980 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h @@ -37,6 +37,11 @@ class PiecewiseInterpolation : public RooAbsReal { PiecewiseInterpolation(const PiecewiseInterpolation& other, const char* name = 0); virtual TObject* clone(const char* newname) const { return new PiecewiseInterpolation(*this, newname); } + /// Return pointer to the nominal hist function. + const RooAbsReal* nominalHist() const { + return &_nominal.arg(); + } + // virtual Double_t defaultErrorLevel() const ; // void printMetaArgs(std::ostream& os) const ; From 0ed9693e6b5925aba023bbb0914904debd50344f Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 11 Jun 2020 18:46:08 +0200 Subject: [PATCH 142/309] [RF] Add RooBinWidthFunction. Added a function that returns the bin width (volume) or the inverse bin width. This can be used to convert densities to event counts and vice versa, e.g. in HistFactoryModels. --- roofit/roofitcore/CMakeLists.txt | 2 + roofit/roofitcore/inc/LinkDef.h | 5 +- roofit/roofitcore/inc/RooBinWidthFunction.h | 81 +++++++++++++++++++ roofit/roofitcore/src/RooBinWidthFunction.cxx | 67 +++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 roofit/roofitcore/inc/RooBinWidthFunction.h create mode 100644 roofit/roofitcore/src/RooBinWidthFunction.cxx diff --git a/roofit/roofitcore/CMakeLists.txt b/roofit/roofitcore/CMakeLists.txt index 864e12bcf2853..707c8b3216373 100644 --- a/roofit/roofitcore/CMakeLists.txt +++ b/roofit/roofitcore/CMakeLists.txt @@ -225,6 +225,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooWrapperPdf.h RooNaNPacker.h RooBinSamplingPdf.h + RooBinWidthFunction.h RooFitLegacy/RooCatTypeLegacy.h RooFitLegacy/RooCategorySharedProperties.h RooFitLegacy/RooHashTable.h @@ -438,6 +439,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore src/RooHelpers.cxx src/RooWrapperPdf.cxx src/RooBinSamplingPdf.cxx + src/RooBinWidthFunction.cxx src/RooFitLegacy/RooCatTypeLegacy.cxx src/RooFitLegacy/RooCategorySharedProperties.cxx src/RooFitLegacy/RooHashTable.cxx diff --git a/roofit/roofitcore/inc/LinkDef.h b/roofit/roofitcore/inc/LinkDef.h index c11859e1b0ba4..c35aff3911873 100644 --- a/roofit/roofitcore/inc/LinkDef.h +++ b/roofit/roofitcore/inc/LinkDef.h @@ -196,6 +196,8 @@ #pragma read sourceClass="RooCategoryProxy" targetClass="RooTemplateProxy"; #pragma link C++ class RooTemplateProxy+; #pragma read sourceClass="RooCategoryProxy" targetClass="RooTemplateProxy"; +#pragma link C++ class RooTemplateProxy+; +#pragma link C++ class RooTemplateProxy+; #pragma link C++ class RooRealVar- ; #pragma link C++ class RooRealVarSharedProperties+ ; #pragma read sourceClass="RooRealVarSharedProperties" targetClass="RooRealVarSharedProperties" version="[1]" \ @@ -356,4 +358,5 @@ #pragma link C++ options=nomap class std::map+ ; #pragma link off class RooErrorHandler+ ; #endif -#pragma link C++ class RooBinSamplingPdf+; +#pragma link C++ class RooBinSamplingPdf+; +#pragma link C++ class RooBinWidthFunction+; diff --git a/roofit/roofitcore/inc/RooBinWidthFunction.h b/roofit/roofitcore/inc/RooBinWidthFunction.h new file mode 100644 index 0000000000000..c9ad9fafe8fd7 --- /dev/null +++ b/roofit/roofitcore/inc/RooBinWidthFunction.h @@ -0,0 +1,81 @@ +// Author Stephan Hageboeck, CERN, 6/2020 +/***************************************************************************** + * Project: RooFit * + * Package: RooFitCore * + * File: $Id$ + * Authors: * + * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu * + * DK, David Kirkby, UC Irvine, dkirkby@uci.edu * + * * + * Copyright (c) 2000-2020, Regents of the University of California * + * and Stanford University. All rights reserved. * + * * + * Redistribution and use in source and binary forms, * + * with or without modification, are permitted according to the terms * + * listed in LICENSE (http://roofit.sourceforge.net/license.txt) * + *****************************************************************************/ + +#ifndef ROOFIT_ROOFITCORE_INC_BINWIDTHFUNCTION_H_ +#define ROOFIT_ROOFITCORE_INC_BINWIDTHFUNCTION_H_ + +#include "RooAbsReal.h" +#include "RooTemplateProxy.h" +#include "RooHistFunc.h" + +namespace BatchHelpers { struct RunContext; } + +class RooBinWidthFunction : public RooAbsReal { +public: + /// Create an empty instance. + RooBinWidthFunction() : + _histFunc("HistFuncForBinWidth", "Handle to a RooHistFunc, whose bin volumes should be returned.", this, + /*valueServer=*/true, /*shapeServer=*/true) { } + + /// Create an instance. + /// \param name Name to identify the object. + /// \param title Title for e.g. plotting. + /// \param histFunc RooHistFunc object whose bin widths should be returned. + /// \param divideByBinWidth If true, return inverse bin width. + RooBinWidthFunction(const char* name, const char* title, const RooHistFunc& histFunc, bool divideByBinWidth) : + RooAbsReal(name, title), + _histFunc("HistFuncForBinWidth", "Handle to a RooHistFunc, whose bin volumes should be returned.", this, histFunc, /*valueServer=*/true, /*shapeServer=*/true), + _divideByBinWidth(divideByBinWidth) { } + + /// Copy an existing object. + RooBinWidthFunction(const RooBinWidthFunction& other, const char* newname = nullptr) : + RooAbsReal(other, newname), + _histFunc("HistFuncForBinWidth", this, other._histFunc), + _divideByBinWidth(other._divideByBinWidth) { } + + virtual ~RooBinWidthFunction() { } + + /// Copy the object and return as TObject*. + virtual TObject* clone(const char* newname = nullptr) const override { + return new RooBinWidthFunction(*this, newname); + } + + // Plotting and binning hints + /// Test if internal RooHistFunc is binned. + bool isBinnedDistribution(const RooArgSet& obs) const override { + return _histFunc->isBinnedDistribution(obs); + } + /// Return bin boundaries of internal RooHistFunc. + std::list* binBoundaries(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const override { + return _histFunc->binBoundaries(obs, xlo, xhi); + } + /// Return plotSamplingHint of internal RooHistFunc. + std::list* plotSamplingHint(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const override { + return _histFunc->plotSamplingHint(obs, xlo, xhi); + } + + double evaluate() const override; + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const override; + +private: + RooTemplateProxy _histFunc; + bool _divideByBinWidth{false}; + + ClassDefOverride(RooBinWidthFunction, 1); +}; + +#endif diff --git a/roofit/roofitcore/src/RooBinWidthFunction.cxx b/roofit/roofitcore/src/RooBinWidthFunction.cxx new file mode 100644 index 0000000000000..ffbafccf639fb --- /dev/null +++ b/roofit/roofitcore/src/RooBinWidthFunction.cxx @@ -0,0 +1,67 @@ +// Author Stephan Hageboeck, CERN, 10/2020 +/***************************************************************************** + * Project: RooFit * + * Package: RooFitCore * + * File: $Id$ + * Authors: * + * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu * + * DK, David Kirkby, UC Irvine, dkirkby@uci.edu * + * * + * Copyright (c) 2000-2020, Regents of the University of California * + * and Stanford University. All rights reserved. * + * * + * Redistribution and use in source and binary forms, * + * with or without modification, are permitted according to the terms * + * listed in LICENSE (http://roofit.sourceforge.net/license.txt) * + *****************************************************************************/ + + +/** + * \class RooBinWidthFunction + * + * RooBinWidthFunction is a class that returns the bin width (or volume) given a RooHistFunc. + * It can be used to normalise by bin width or to compute event densities. Using the extra + * argument of the constructor, it can also return the inverse of the bin width (or volume). + */ + +#include "RooBinWidthFunction.h" + +#include "RooDataHist.h" +#include "RunContext.h" + + +/// Compute current bin of observable, and return its volume or inverse volume, depending +/// on configuration chosen in the constructor. +/// If the bin is not valid, return a volume of 1. +double RooBinWidthFunction::evaluate() const { + const RooDataHist& dataHist = _histFunc->dataHist(); + const auto idx = _histFunc->getBin(); + auto volumes = dataHist.binVolumes(0, dataHist.numEntries()); + const double volume = idx >= 0 ? volumes[idx] : 1.; + + return _divideByBinWidth ? 1./volume : volume; +} + + +/// Compute bin index for all values of the observable(s) in `evalData`, and return their volumes or inverse volumes, depending +/// on the configuration chosen in the constructor. +/// If a bin is not valid, return a volume of 1. +RooSpan RooBinWidthFunction::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* /*normSet*/) const { + const RooDataHist& dataHist = _histFunc->dataHist(); + std::vector bins = _histFunc->getBins(evalData); + auto volumes = dataHist.binVolumes(0, dataHist.numEntries()); + + auto results = evalData.makeBatch(this, bins.size()); + + if (_divideByBinWidth) { + for (std::size_t i=0; i < bins.size(); ++i) { + results[i] = bins[i] >= 0 ? 1./volumes[bins[i]] : 1.; + } + } else { + for (std::size_t i=0; i < bins.size(); ++i) { + results[i] = bins[i] >= 0 ? volumes[bins[i]] : 1.; + } + } + + return results; +} From 5b788a4c592aa236a1c303c877b642d92d1d362c Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 1 Nov 2020 15:19:34 +0100 Subject: [PATCH 143/309] [HF] Clean up / speed up bin calculation in ParamHistFunc. Also clean up includes and data members. Incrementing the class version wasn't necessary, since that was done already in 18ac2c9cb8. --- .../inc/RooStats/HistFactory/ParamHistFunc.h | 33 +--- roofit/histfactory/src/ParamHistFunc.cxx | 172 +++++++----------- 2 files changed, 79 insertions(+), 126 deletions(-) diff --git a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h index 1c11d8a1b501f..c6ba50c714676 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h @@ -12,20 +12,14 @@ #ifndef ROO_PARAMHISTFUNC #define ROO_PARAMHISTFUNC -#include -#include - #include "RooAbsReal.h" -#include "RooRealProxy.h" #include "RooListProxy.h" #include "RooObjCacheManager.h" #include "RooDataHist.h" // Forward Declarations class RooRealVar; -class RooArgList ; class RooWorkspace; -class RooBinning; class ParamHistFunc : public RooAbsReal { public: @@ -36,7 +30,7 @@ class ParamHistFunc : public RooAbsReal { virtual ~ParamHistFunc() ; ParamHistFunc(const ParamHistFunc& other, const char* name = 0); - virtual TObject* clone(const char* newname) const { return new ParamHistFunc(*this, newname); } + virtual TObject* clone(const char* newname) const override { return new ParamHistFunc(*this, newname); } const RooArgList& paramList() const { return _paramSet ; } @@ -55,18 +49,18 @@ class ParamHistFunc : public RooAbsReal { double binVolume() const { return _dataSet.binVolume(); } - virtual Bool_t forceAnalyticalInt(const RooAbsArg&) const { return kTRUE ; } + virtual Bool_t forceAnalyticalInt(const RooAbsArg&) const override { return kTRUE ; } - Int_t getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, const RooArgSet* normSet,const char* rangeName=0) const ; - Double_t analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName=0) const ; + Int_t getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, const RooArgSet* normSet,const char* rangeName=0) const override; + Double_t analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName=0) const override; static RooArgList createParamSet(RooWorkspace& w, const std::string&, const RooArgList& Vars); static RooArgList createParamSet(RooWorkspace& w, const std::string&, const RooArgList& Vars, Double_t, Double_t); static RooArgList createParamSet(const std::string&, Int_t, Double_t, Double_t); - virtual std::list* binBoundaries(RooAbsRealLValue& /*obs*/, Double_t /*xlo*/, Double_t /*xhi*/) const ; - virtual std::list* plotSamplingHint(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const ; - virtual Bool_t isBinnedDistribution(const RooArgSet& /*obs*/) const {return kTRUE;} + virtual std::list* binBoundaries(RooAbsRealLValue& /*obs*/, Double_t /*xlo*/, Double_t /*xhi*/) const override; + virtual std::list* plotSamplingHint(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const override; + virtual Bool_t isBinnedDistribution(const RooArgSet& /*obs*/) const override { return true; } protected: @@ -88,11 +82,8 @@ class ParamHistFunc : public RooAbsReal { } ; mutable RooObjCacheManager _normIntMgr ; // The integration cache manager - // Turn into a RooListProxy - //RooRealProxy _dataVar; // The RooRealVar RooListProxy _dataVars; // The RooRealVars RooListProxy _paramSet ; // interpolation parameters - //RooAbsBinning* _binning; // Holds the binning of the dataVar (at construction time) Int_t _numBins; struct NumBins { @@ -108,21 +99,17 @@ class ParamHistFunc : public RooAbsReal { }; mutable NumBins _numBinsPerDim; //! mutable RooDataHist _dataSet; - //Bool_t _normalized; - - // std::vector< Double_t > _nominalVals; // The nominal vals when gamma = 1.0 ( = 1.0 by default) - RooArgList _ownedList ; // List of owned components - Int_t getCurrentBin() const ; + Int_t getCurrentBin() const; Int_t addVarSet( const RooArgList& vars ); Int_t addParamSet( const RooArgList& params ); static Int_t GetNumBins( const RooArgSet& vars ); - Double_t evaluate() const; + double evaluate() const override; private: static NumBins getNumBinsPerDim(RooArgSet const& vars); - ClassDef(ParamHistFunc,6) // Sum of RooAbsReal objects + ClassDefOverride(ParamHistFunc, 6) }; #endif diff --git a/roofit/histfactory/src/ParamHistFunc.cxx b/roofit/histfactory/src/ParamHistFunc.cxx index bb53ab9f0ca8d..0994e3fc0a3df 100644 --- a/roofit/histfactory/src/ParamHistFunc.cxx +++ b/roofit/histfactory/src/ParamHistFunc.cxx @@ -35,35 +35,22 @@ */ -#include -#include -#include -#include - -#include "TH1.h" - -#include "RooFit.h" #include "RooStats/HistFactory/ParamHistFunc.h" -#include "RooAbsReal.h" -#include "RooAbsPdf.h" #include "RooConstVar.h" #include "RooBinning.h" #include "RooErrorHandler.h" - -#include "RooGaussian.h" -#include "RooHistFunc.h" #include "RooArgSet.h" -#include "RooNLLVar.h" -#include "RooChi2Var.h" #include "RooMsgService.h" - -// Forward declared: #include "RooRealVar.h" #include "RooArgList.h" #include "RooWorkspace.h" -//using namespace std; +#include "TH1.h" + +#include +#include +#include ClassImp(ParamHistFunc); @@ -168,14 +155,13 @@ Int_t ParamHistFunc::GetNumBins( const RooArgSet& vars ) { oocoutE(static_cast(nullptr), InputArguments) << errorMsg << std::endl; throw std::runtime_error(errorMsg); } - RooRealVar* var = (RooRealVar*) comp; + auto var = static_cast(comp); Int_t varNumBins = var->numBins(); numBins *= varNumBins; } return numBins; - } @@ -204,26 +190,11 @@ ParamHistFunc::~ParamHistFunc() //////////////////////////////////////////////////////////////////////////////// -/// Get the index of the gamma parameter associated -/// with the current bin. -/// This number is the "RooDataSet" style index -/// and it must be because it uses the RooDataSet method directly -/// This is intended to be fed into the getParameter(Int_t) method: -/// -/// RooRealVar currentParam = getParameter( getCurrentBin() ); -Int_t ParamHistFunc::getCurrentBin() const { - Int_t dataSetIndex = _dataSet.getIndex( _dataVars, true ); // calcTreeIndex(); - return dataSetIndex; - -} - - -//////////////////////////////////////////////////////////////////////////////// -/// Get the parameter associate with the -/// input RooDataHist style index +/// Get the parameter associated with the index. +/// The index follows RooDataHist indexing conventions. /// It uses the binMap to convert the RooDataSet style index /// into the TH1 style index (which is how they are stored -/// internally in the '_paramSet' vector +/// internally in the '_paramSet' vector). RooRealVar& ParamHistFunc::getParameter( Int_t index ) const { auto const& n = _numBinsPerDim; @@ -284,9 +255,7 @@ void ParamHistFunc::setShape( TH1* shape ) { TH1BinNumber++; } - //RooRealVar& var = dynamic_cast(getParameter(i)); - RooRealVar& var = dynamic_cast(_paramSet[i]); - var.setVal( shape->GetBinContent(TH1BinNumber) ); + static_cast(_paramSet[i]).setVal( shape->GetBinContent(TH1BinNumber) ); } } @@ -325,7 +294,7 @@ RooArgList ParamHistFunc::createParamSet(RooWorkspace& w, const std::string& Pre } else if( numVars == 1 ) { - + // For each bin, create a RooRealVar for( Int_t i = 0; i < numBins; ++i) { @@ -347,42 +316,42 @@ RooArgList ParamHistFunc::createParamSet(RooWorkspace& w, const std::string& Pre } else if( numVars == 2 ) { - + // Create a vector of indices // all starting at 0 std::vector< Int_t > Indices(numVars, 0); RooRealVar* varx = (RooRealVar*) vars.at(0); RooRealVar* vary = (RooRealVar*) vars.at(1); - + // For each bin, create a RooRealVar for( Int_t j = 0; j < vary->numBins(); ++j) { for( Int_t i = 0; i < varx->numBins(); ++i) { - // Ordering is important: - // To match TH1, list goes over x bins - // first, then y - - std::stringstream VarNameStream; - VarNameStream << Prefix << "_bin_" << i << "_" << j; - std::string VarName = VarNameStream.str(); - - RooRealVar gamma( VarName.c_str(), VarName.c_str(), 1.0 ); - // "Hard-Code" a minimum of 0.0 - gamma.setMin( 0.0 ); - gamma.setConstant( false ); - - w.import( gamma, RooFit::RecycleConflictNodes() ); - RooRealVar* gamma_wspace = (RooRealVar*) w.var( VarName.c_str() ); - - paramSet.add( *gamma_wspace ); - + // Ordering is important: + // To match TH1, list goes over x bins + // first, then y + + std::stringstream VarNameStream; + VarNameStream << Prefix << "_bin_" << i << "_" << j; + std::string VarName = VarNameStream.str(); + + RooRealVar gamma( VarName.c_str(), VarName.c_str(), 1.0 ); + // "Hard-Code" a minimum of 0.0 + gamma.setMin( 0.0 ); + gamma.setConstant( false ); + + w.import( gamma, RooFit::RecycleConflictNodes() ); + RooRealVar* gamma_wspace = (RooRealVar*) w.var( VarName.c_str() ); + + paramSet.add( *gamma_wspace ); + } } } else if( numVars == 3 ) { - + // Create a vector of indices // all starting at 0 std::vector< Int_t > Indices(numVars, 0); @@ -390,31 +359,31 @@ RooArgList ParamHistFunc::createParamSet(RooWorkspace& w, const std::string& Pre RooRealVar* varx = (RooRealVar*) vars.at(0); RooRealVar* vary = (RooRealVar*) vars.at(1); RooRealVar* varz = (RooRealVar*) vars.at(2); - + // For each bin, create a RooRealVar for( Int_t k = 0; k < varz->numBins(); ++k) { for( Int_t j = 0; j < vary->numBins(); ++j) { - for( Int_t i = 0; i < varx->numBins(); ++i) { - - // Ordering is important: - // To match TH1, list goes over x bins - // first, then y, then z - - std::stringstream VarNameStream; - VarNameStream << Prefix << "_bin_" << i << "_" << j << "_" << k; - std::string VarName = VarNameStream.str(); - - RooRealVar gamma( VarName.c_str(), VarName.c_str(), 1.0 ); - // "Hard-Code" a minimum of 0.0 - gamma.setMin( 0.0 ); - gamma.setConstant( false ); - - w.import( gamma, RooFit::RecycleConflictNodes() ); - RooRealVar* gamma_wspace = (RooRealVar*) w.var( VarName.c_str() ); - - paramSet.add( *gamma_wspace ); - - } + for( Int_t i = 0; i < varx->numBins(); ++i) { + + // Ordering is important: + // To match TH1, list goes over x bins + // first, then y, then z + + std::stringstream VarNameStream; + VarNameStream << Prefix << "_bin_" << i << "_" << j << "_" << k; + std::string VarName = VarNameStream.str(); + + RooRealVar gamma( VarName.c_str(), VarName.c_str(), 1.0 ); + // "Hard-Code" a minimum of 0.0 + gamma.setMin( 0.0 ); + gamma.setConstant( false ); + + w.import( gamma, RooFit::RecycleConflictNodes() ); + RooRealVar* gamma_wspace = (RooRealVar*) w.var( VarName.c_str() ); + + paramSet.add( *gamma_wspace ); + + } } } } @@ -472,9 +441,6 @@ RooArgList ParamHistFunc::createParamSet(RooWorkspace& w, const std::string& Pre RooArgList ParamHistFunc::createParamSet(const std::string& Prefix, Int_t numBins, Double_t gamma_min, Double_t gamma_max) { - - // _paramSet.add( createParamSet() ); - // Get the number of bins // in the nominal histogram @@ -534,6 +500,15 @@ ParamHistFunc::NumBins ParamHistFunc::getNumBinsPerDim(RooArgSet const& vars) { } +//////////////////////////////////////////////////////////////////////////////// +/// Get the index of the gamma parameter associated with the current bin. +/// e.g. `RooRealVar& currentParam = getParameter( getCurrentBin() );` +Int_t ParamHistFunc::getCurrentBin() const { + // We promise that our coordinates and the data hist coordinates have same layout. + return _dataSet.getIndex(_dataVars, /*fast=*/true); +} + + //////////////////////////////////////////////////////////////////////////////// /// return 0 for success /// return 1 for failure @@ -582,36 +557,27 @@ Int_t ParamHistFunc::addParamSet( const RooArgList& params ) { // If so, add them to the // list of params - RooFIter paramIter = params.fwdIterator() ; - RooAbsArg* comp ; - while((comp = (RooAbsArg*) paramIter.next())) { - if (!dynamic_cast(comp)) { + for (const auto comp : params) { + if (!dynamic_cast(comp)) { auto errorMsg = std::string("ParamHistFunc::(") + GetName() + ") ERROR: component " - + comp->GetName() + " in paramater list is not of type RooRealVar"; + + comp->GetName() + " in parameter list is not of type RooRealVar."; coutE(InputArguments) << errorMsg << std::endl; throw std::runtime_error(errorMsg); } _paramSet.add( *comp ); - } return 0; - } //////////////////////////////////////////////////////////////////////////////// - +/// Find the bin corresponding to the current value of the observable, and evaluate +/// the associated parameter. Double_t ParamHistFunc::evaluate() const { - // Find the bin cooresponding to the current - // value of the RooRealVar: - - RooRealVar* param = (RooRealVar*) &(getParameter()); - Double_t value = param->getVal(); - return value; - + return getParameter().getVal(); } From dc65afe00ec72d18ebc5d31e7b2d6b50c6a20423 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 1 Nov 2020 11:10:17 +0100 Subject: [PATCH 144/309] [HF] Rework histFactory logic to simplify models. - [NFC] Rename sampleProduct. - Instead of using a structure like product(product(product(.., ..), ..), ..), HistFactory computations are reordered like product(.., .., .., ..). This reduces the number of nodes in the computation graph. - In the summation of the PDFs, sample scale factors and bins are now separated, such that batch evaluations can be used on the bins, and the scale factors only have to multiplied with the bins only once. The RooRealSumPdf now implements: sumPdf = Sum_i( product(all scale factors for i) * sample_i ) - Instead of creating the computation graph using factory expressions, objects are instantiated explicitly. This increases type safety, and limits errors due to wrongly interpreted strings. - Instead of using one hard-coded bin width for all bins, the RooBinWidthFunction is used to compute event densities. This allows for non-uniform binning in HistFactory models. - Use nominal histogram to correct bin counts to event densities. This should allow for custom binning with HistFactory. --- .../HistFactory/HistoToWorkspaceFactoryFast.h | 25 +- .../src/HistoToWorkspaceFactoryFast.cxx | 583 ++++++------------ 2 files changed, 217 insertions(+), 391 deletions(-) diff --git a/roofit/histfactory/inc/RooStats/HistFactory/HistoToWorkspaceFactoryFast.h b/roofit/histfactory/inc/RooStats/HistFactory/HistoToWorkspaceFactoryFast.h index b1e3fd95a96d3..1653d04ca9056 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/HistoToWorkspaceFactoryFast.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/HistoToWorkspaceFactoryFast.h @@ -30,7 +30,8 @@ #include "RooStats/HistFactory/Systematics.h" class ParamHistFunc; - +class RooProduct; +class RooHistFunc; namespace RooStats{ namespace HistFactory{ @@ -69,7 +70,7 @@ namespace RooStats{ std::vector& likelihoodTermNames, std::vector& totSystTermNames); - std::string AddNormFactor(RooWorkspace* proto, std::string& channel, + std::unique_ptr CreateNormFactor(RooWorkspace* proto, std::string& channel, std::string& sigmaEpsilon, Sample& sample, bool doRatio); void AddMultiVarGaussConstraint(RooWorkspace* proto, std::string prefix, @@ -86,16 +87,14 @@ namespace RooStats{ std::map logNormSyst, std::map noSyst); - void LinInterpWithConstraint(RooWorkspace* proto, const TH1* nominal, std::vector, - std::string prefix, std::string productPrefix, - std::string systTerm, - std::vector& likelihoodTermNames); + RooAbsArg* MakeLinInterpWithConstraint(RooHistFunc* nominalHistFunc, RooWorkspace* proto, const std::vector&, + const std::string& prefix, std::vector& likelihoodTermNames, const RooArgList& observables) const; RooWorkspace* MakeSingleChannelWorkspace(Measurement& measurement, Channel& channel); - void MakeTotalExpected(RooWorkspace* proto, std::string totName, - std::vector& syst_x_expectedPrefixNames, - std::vector& normByNames); + void MakeTotalExpected(RooWorkspace* proto, const std::string& totName, + const std::vector& sampleScaleFactors, + std::vector>& sampleHistFuncs) const; RooDataSet* MergeDataSets(RooWorkspace* combined, std::vector>& wspace_vec, @@ -104,8 +103,8 @@ namespace RooStats{ RooArgList obsList, RooCategory* channelCat); - void ProcessExpectedHisto(const TH1* hist, RooWorkspace* proto, std::string prefix, - std::string productPrefix, std::string systTerm ); + RooHistFunc* MakeExpectedHistFunc(const TH1* hist, RooWorkspace* proto, std::string prefix, + const RooArgList& observables) const; void SetObsToExpected(RooWorkspace* proto, std::string obsPrefix, std::string expPrefix, int lowBin, int highBin); @@ -137,7 +136,9 @@ namespace RooStats{ std::vector fObsNameVec; std::string fObsName; std::vector fPreprocessFunctions; - + + RooArgList createObservables(const TH1 *hist, RooWorkspace *proto) const; + ClassDef(RooStats::HistFactory::HistoToWorkspaceFactoryFast,3) }; diff --git a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx index 8d57317977605..92147c92abb1d 100644 --- a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx +++ b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx @@ -50,6 +50,8 @@ #include "RooCustomizer.h" #include "RooPlot.h" #include "RooHelpers.h" +#include "RooBinning.h" +#include "RooBinWidthFunction.h" #include "RooStats/RooStatsUtils.h" #include "RooStats/ModelConfig.h" #include "RooStats/HistFactory/PiecewiseInterpolation.h" @@ -318,22 +320,44 @@ namespace HistFactory{ } - void HistoToWorkspaceFactoryFast::ProcessExpectedHisto(const TH1* hist,RooWorkspace* proto, - string prefix, string productPrefix, - string systTerm ) { +/// Create observables of type RooRealVar. Creates 1 to 3 observables, depending on the type of the histogram. +RooArgList HistoToWorkspaceFactoryFast::createObservables(const TH1 *hist, RooWorkspace *proto) const { + RooArgList observables; + + for (unsigned int idx=0; idx < fObsNameVec.size(); ++idx) { + if (!proto->var(fObsNameVec[idx].c_str())) { + const TAxis *axis = (idx == 0) ? hist->GetXaxis() : (idx == 1 ? hist->GetYaxis() : hist->GetZaxis()); + Int_t nbins = axis->GetNbins(); + Double_t xmin = axis->GetXmin(); + Double_t xmax = axis->GetXmax(); + // create observable + auto obs = static_cast(proto->factory( + Form("%s[%f,%f]", fObsNameVec[idx].c_str(), xmin, xmax))); + obs->setBins(nbins); + if (axis->IsVariableBinSize()) { + RooBinning binning(nbins, axis->GetXbins()->GetArray()); + obs->setBinning(binning); + } + } + + observables.add(*proto->var(fObsNameVec[idx].c_str())); + } + + return observables; +} + + /// Create the nominal hist function from `hist`, and register it in the workspace. + RooHistFunc* HistoToWorkspaceFactoryFast::MakeExpectedHistFunc(const TH1* hist,RooWorkspace* proto, string prefix, + const RooArgList& observables) const { if(hist) { cxcoutI(HistFactory) << "processing hist " << hist->GetName() << endl; } else { cxcoutF(HistFactory) << "hist is empty" << endl; R__ASSERT(hist != 0); - return; + return nullptr; } - /// require dimension >=1 or <=3 - if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); } - R__ASSERT( fObsNameVec.size()>=1 && fObsNameVec.size()<=3 ); - - /// determine histogram dimensionality + // determine histogram dimensionality unsigned int histndim(1); std::string classname = hist->ClassName(); if (classname.find("TH1")==0) { histndim=1; } @@ -341,36 +365,15 @@ namespace HistFactory{ else if (classname.find("TH3")==0) { histndim=3; } R__ASSERT( histndim==fObsNameVec.size() ); - /// create roorealvar observables - RooArgList observables; - std::vector::iterator itr = fObsNameVec.begin(); - for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) { - if ( !proto->var(itr->c_str()) ) { - const TAxis* axis(0); - if (idx==0) { axis = hist->GetXaxis(); } - if (idx==1) { axis = hist->GetYaxis(); } - if (idx==2) { axis = hist->GetZaxis(); } - Int_t nbins = axis->GetNbins(); - Double_t xmin = axis->GetXmin(); - Double_t xmax = axis->GetXmax(); - // create observable - proto->factory(Form("%s[%f,%f]",itr->c_str(),xmin,xmax)); - proto->var(itr->c_str())->setBins(nbins); - } - observables.add( *proto->var(itr->c_str()) ); - } - - RooDataHist* histDHist = new RooDataHist((prefix+"nominalDHist").c_str(),"",observables,hist); - RooHistFunc* histFunc = new RooHistFunc((prefix+"_nominal").c_str(),"",observables,*histDHist,0) ; - - proto->import(*histFunc); + prefix += "_Hist_alphanominal"; - /// now create the product of the overall efficiency times the sigma(params) for this estimate - proto->factory(("prod:"+productPrefix+"("+prefix+"_nominal,"+systTerm+")").c_str() ); + RooDataHist histDHist((prefix + "DHist").c_str(),"",observables,hist); + RooHistFunc histFunc(prefix.c_str(),"",observables,histDHist,0); - delete histDHist; - delete histFunc; + proto->import(histFunc, RecycleConflictNodes()); + auto histFuncInWS = static_cast(proto->arg(prefix.c_str())); + return histFuncInWS; } void HistoToWorkspaceFactoryFast::AddMultiVarGaussConstraint(RooWorkspace* proto, string prefix,int lowBin, int highBin, vector& constraintTermNames){ @@ -399,60 +402,21 @@ namespace HistFactory{ RooMultiVarGaussian constraint((prefix+"Constraint").c_str(),"", floating, mean, Cov); - proto->import(constraint); + proto->import(constraint, RecycleConflictNodes()); constraintTermNames.push_back(constraint.GetName()); } - void HistoToWorkspaceFactoryFast::LinInterpWithConstraint(RooWorkspace* proto, const TH1* nominal, - std::vector histoSysList, - string prefix, string productPrefix, - string systTerm, - vector& constraintTermNames){ + /// Create a linear interpolation object that holds nominal and systematics, import it into the workspace, + /// and return a pointer to it. + RooAbsArg* HistoToWorkspaceFactoryFast::MakeLinInterpWithConstraint(RooHistFunc* nominalFunc, + RooWorkspace* proto, const std::vector& histoSysList, + const string& prefix, std::vector& constraintTermNames, + const RooArgList& observables) const { // these are the nominal predictions: eg. the mean of some space of variations // later fill these in a loop over histogram bins - // require dimension >=1 or <=3 - if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); } - R__ASSERT( fObsNameVec.size()>=1 && fObsNameVec.size()<=3 ); - - // determine histogram dimensionality - unsigned int histndim(1); - std::string classname = nominal->ClassName(); - if (classname.find("TH1")==0) { histndim=1; } - else if (classname.find("TH2")==0) { histndim=2; } - else if (classname.find("TH3")==0) { histndim=3; } - R__ASSERT( histndim==fObsNameVec.size() ); - - // create roorealvar observables - RooArgList observables; - std::vector::iterator itr = fObsNameVec.begin(); - for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) { - if ( !proto->var(itr->c_str()) ) { - const TAxis* axis(nullptr); - if (idx==0) { axis = nominal->GetXaxis(); } - else if (idx==1) { axis = nominal->GetYaxis(); } - else if (idx==2) { axis = nominal->GetZaxis(); } - else { - std::cout << "Error: Too many observables. " - << "HistFactory only accepts up to 3 observables (3d) " - << std::endl; - throw hf_exc(); - } - Int_t nbins = axis->GetNbins(); - Double_t xmin = axis->GetXmin(); - Double_t xmax = axis->GetXmax(); - // create observable - proto->factory(Form("%s[%f,%f]",itr->c_str(),xmin,xmax)); - proto->var(itr->c_str())->setBins(nbins); - } - observables.add( *proto->var(itr->c_str()) ); - } - - RooDataHist* nominalDHist = new RooDataHist((prefix+"nominalDHist").c_str(),"",observables,nominal); - RooHistFunc* nominalFunc = new RooHistFunc((prefix+"nominal").c_str(),"",observables,*nominalDHist,0) ; - // make list of abstract parameters that interpolate in space of variations RooArgList params( ("alpha_Hist") ); // range is set using defined macro (see top of the page) @@ -463,7 +427,7 @@ namespace HistFactory{ std::stringstream str; str<<"_"<var(("alpha_" + histoSysName).c_str()); @@ -490,7 +454,7 @@ namespace HistFactory{ std::stringstream str; str<<"_"<import(interp); // individual params have already been imported in first loop of this function + proto->import(interp, RecycleConflictNodes()); // individual params have already been imported in first loop of this function - // now create the product of the overall efficiency times the sigma(params) for this estimate - proto->factory(("prod:"+productPrefix+"("+prefix+","+systTerm+")").c_str() ); + auto interpInWS = proto->arg(prefix.c_str()); + assert(interpInWS); + return interpInWS; } // GHL: Consider passing the NormFactor list instead of the entire sample - string HistoToWorkspaceFactoryFast::AddNormFactor(RooWorkspace* proto, string& channel, string& sigmaEpsilon, Sample& sample, bool doRatio){ - string overallNorm_times_sigmaEpsilon ; - string prodNames; + std::unique_ptr HistoToWorkspaceFactoryFast::CreateNormFactor(RooWorkspace* proto, string& channel, string& sigmaEpsilon, Sample& sample, bool doRatio){ + + std::vector prodNames; vector normList = sample.GetNormFactorList(); vector normFactorNames, rangeNames; + + string overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_scaleFactors"; + auto sigEps = proto->arg(sigmaEpsilon.c_str()); + assert(sigEps); + std::unique_ptr normFactor( new RooProduct(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(), RooArgList(*sigEps) ) ); + if(normList.size() > 0){ for(vector::iterator itr = normList.begin(); itr != normList.end(); ++itr){ @@ -530,7 +501,6 @@ namespace HistFactory{ NormFactor& norm = *itr; string varname; - if(!prodNames.empty()) prodNames += ","; if(doRatio) { varname = norm.GetName() + "_" + channel; } @@ -557,13 +527,18 @@ namespace HistFactory{ " Instead, add \n\t " << varname << " \n" << " to your top-level XML's entry" << endl; } - prodNames+=varname; + prodNames.push_back(varname); rangeNames.push_back(range.str()); normFactorNames.push_back(varname); } - overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_overallNorm_x_sigma_epsilon"; - proto->factory(("prod::" + overallNorm_times_sigmaEpsilon + "(" + prodNames + "," + sigmaEpsilon + ")").c_str()); + + for (const auto& name : prodNames) { + auto arg = proto->arg(name.c_str()); + assert(arg); + normFactor->addTerm(arg); + } + } unsigned int rangeIndex=0; @@ -571,16 +546,13 @@ namespace HistFactory{ if( count (normFactorNames.begin(), normFactorNames.end(), *nit) > 1 ){ cxcoutI(HistFactory) <<" is duplicated for , but only one factor will be included. \n Instead, define something like" - << "\n\t \nin your top-level XML's entry and use & syst_x_expectedPrefixNames, - vector& normByNames){ + void HistoToWorkspaceFactoryFast::MakeTotalExpected(RooWorkspace* proto, const string& totName, + const vector& sampleScaleFactors, std::vector>& sampleHistFuncs) const { + assert(sampleScaleFactors.size() == sampleHistFuncs.size()); // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j - string command; - string coeffList=""; - string shapeList=""; - string prepend=""; - if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); } + if (fObsNameVec.empty() && !fObsName.empty()) + throw std::logic_error("HistFactory didn't process the observables correctly. Please file a bug report."); - double binWidth(1.0); - std::string obsNameVecStr; - std::vector::iterator itr = fObsNameVec.begin(); - for (; itr!=fObsNameVec.end(); ++itr) { - std::string obsName = *itr; - binWidth *= proto->var(obsName.c_str())->numBins()/(proto->var(obsName.c_str())->getMax() - proto->var(obsName.c_str())->getMin()) ; // MB: Note: requires fixed bin sizes - if (obsNameVecStr.size()>0) { obsNameVecStr += "_"; } - obsNameVecStr += obsName; + auto firstHistFunc = dynamic_cast(sampleHistFuncs.front().front()); + if (!firstHistFunc) { + auto piecewiseInt = dynamic_cast(sampleHistFuncs.front().front()); + firstHistFunc = dynamic_cast(piecewiseInt->nominalHist()); } + assert(firstHistFunc); - //vector::iterator it=syst_x_expectedPrefixNames.begin(); - for(unsigned int j=0; jfactory(command.c_str()); - proto->var(Form("binWidth_%s_%d",obsNameVecStr.c_str(),j))->setConstant(); - coeffList+=prepend+"binWidth_"+obsNameVecStr+str.str(); - - command="prod::L_x_"+syst_x_expectedPrefixNames.at(j)+"("+normByNames.at(j)+","+syst_x_expectedPrefixNames.at(j)+")"; - /*RooAbsReal* tempFunc =(RooAbsReal*) */ - proto->factory(command.c_str()); - shapeList+=prepend+"L_x_"+syst_x_expectedPrefixNames.at(j); - prepend=","; - - // add to num int to product - // tempFunc->specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ; - // tempFunc->forceNumInt(); + // Prepare a function to divide all bin contents by bin width to get a density: + const std::string binWidthFunctionName = totName + "_binWidth"; + RooBinWidthFunction binWidth(binWidthFunctionName.c_str(), "Divide by bin width to obtain probability density", *firstHistFunc, true); + proto->import(binWidth); + auto binWidthWS = proto->function(binWidthFunctionName.c_str()); + assert(binWidthWS); - } + // Loop through samples and create products of their functions: + RooArgSet coefList; + RooArgSet shapeList; + for (unsigned int i=0; i < sampleHistFuncs.size(); ++i) { + assert(!sampleHistFuncs[i].empty()); + coefList.add(*sampleScaleFactors[i]); - proto->defineSet("coefList",coeffList.c_str()); - proto->defineSet("shapeList",shapeList.c_str()); - // proto->factory(command.c_str()); - RooRealSumPdf tot(totName.c_str(),totName.c_str(),*proto->set("shapeList"),*proto->set("coefList"),kTRUE); + std::vector& thisSampleHistFuncs = sampleHistFuncs[i]; + thisSampleHistFuncs.push_back(binWidthWS); + + if (thisSampleHistFuncs.size() == 1) { + // Just one function. Book it. + shapeList.add(*thisSampleHistFuncs.front()); + } else { + // Have multiple functions. We need to multiply them. + std::string name = thisSampleHistFuncs.front()->GetName(); + auto pos = name.find("Hist_alpha"); + if (pos != std::string::npos) { + name = name.substr(0, pos) + "shapes"; + } else if ( (pos = name.find("nominal")) != std::string::npos) { + name = name.substr(0, pos) + "shapes"; + } + + RooArgSet terms; + for (auto func : thisSampleHistFuncs) { + terms.add(*func); + } + + RooProduct shapeProduct(name.c_str(), name.c_str(), terms); + proto->import(shapeProduct, RecycleConflictNodes()); + shapeList.add(*proto->function(name.c_str())); + } + } + + // Sum all samples + RooRealSumPdf tot(totName.c_str(), totName.c_str(), shapeList, coefList, true); tot.specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ; tot.specialIntegratorConfig(kTRUE)->method2D().setLabel("RooBinIntegrator") ; tot.specialIntegratorConfig(kTRUE)->methodND().setLabel("RooBinIntegrator") ; @@ -792,27 +774,8 @@ namespace HistFactory{ // for mixed generation in RooSimultaneous tot.setAttribute("GenerateBinned"); // for use with RooSimultaneous::generate in mixed mode - // tot.setAttribute("GenerateUnbinned"); // we don't want that - /* - // Use binned numeric integration - int nbins = 0; - if( fObsNameVec.size() == 1 ) { - nbins = proto->var(fObsNameVec.at(0).c_str())->numBins(); - - cout <<"num bis for RooRealSumPdf = "<numBins(); - tot.specialIntegratorConfig(kTRUE)->getConfigSection("RooBinIntegrator").setRealValue("numBins",nbins); - tot.forceNumInt(); - - } else { - cout << "Bin Integrator only supports 1-d. Will be slow." << std::endl; - } - */ - - - proto->import(tot); - + proto->import(tot, RecycleConflictNodes()); } void HistoToWorkspaceFactoryFast::AddPoissonTerms(RooWorkspace* proto, string prefix, string obsPrefix, string expPrefix, int lowBin, int highBin, @@ -1253,7 +1216,9 @@ namespace HistFactory{ fObsNameVec.push_back( fObsName ); } - R__ASSERT( fObsNameVec.size()>=1 && fObsNameVec.size()<=3 ); + if (fObsNameVec.size() == 0 || fObsNameVec.size() >= 3) { + throw hf_exc("HistFactory is limited to 1- to 3-dimensional histograms."); + } cxcoutP(HistFactory) << "\n-----------------------------------------\n" << "\tStarting to process '" @@ -1276,14 +1241,14 @@ namespace HistFactory{ } RooArgSet likelihoodTerms("likelihoodTerms"), constraintTerms("constraintTerms"); - vector likelihoodTermNames, constraintTermNames, totSystTermNames, syst_x_expectedPrefixNames, normalizationNames; + vector likelihoodTermNames, constraintTermNames, totSystTermNames; + // All histogram functions to be multiplied in each sample + std::vector> allSampleHistFuncs; + std::vector sampleScaleFactors; vector< pair > statNamePairs; vector< pair > statHistPairs; // - std::string statFuncName; // the name of the ParamHistFunc - std::string statNodeName; // the name of the McStat Node - // Constraint::Type statConstraintType=Constraint::Gaussian; - // Double_t statRelErrorThreshold=0.0; + const std::string statFuncName = "mc_stat_" + channel_name; string prefix, range; @@ -1292,8 +1257,8 @@ namespace HistFactory{ // this is ratio of lumi to nominal lumi. We will include relative uncertainty in model std::stringstream lumiStr; // lumi range - lumiStr<<"["<factory(("Lumi"+lumiStr.str()).c_str()); + lumiStr << "Lumi[" << fNomLumi << ",0," << 10.*fNomLumi << "]"; + proto->factory(lumiStr.str().c_str()); cxcoutI(HistFactory) << "lumi str = " << lumiStr.str() << endl; std::stringstream lumiErrorStr; @@ -1310,11 +1275,7 @@ namespace HistFactory{ // loop through estimates, add expectation, floating bin predictions, // and terms that constrain floating to expectation via uncertainties // GHL: Loop over samples instead, which doesn't contain the data - vector::iterator it = channel.GetSamples().begin(); - for(; it!=channel.GetSamples().end(); ++it) { - - //ES// string overallSystName = it->name+"_"+it->channel+"_epsilon"; - Sample& sample = (*it); + for (Sample& sample : channel.GetSamples()) { string overallSystName = sample.GetName() + "_" + channel_name + "_epsilon"; string systSourcePrefix = "alpha_"; @@ -1324,13 +1285,17 @@ namespace HistFactory{ AddConstraintTerms(proto,measurement, systSourcePrefix, overallSystName, sample.GetOverallSysList(), constraintTermNames , totSystTermNames); + allSampleHistFuncs.emplace_back(); + std::vector& sampleHistFuncs = allSampleHistFuncs.back(); + // GHL: Consider passing the NormFactor list instead of the entire sample - overallSystName = AddNormFactor(proto, channel_name, overallSystName, sample, doRatio); + auto normFactors = CreateNormFactor(proto, channel_name, overallSystName, sample, doRatio); + assert(normFactors); // Create the string for the object // that is added to the RooRealSumPdf // for this channel - string syst_x_expectedPrefix = ""; +// string syst_x_expectedPrefix = ""; // get histogram //ES// TH1* nominal = it->nominal; @@ -1346,28 +1311,24 @@ namespace HistFactory{ // - If we have no HistoSys's, do part A // - else, if the histo syst's don't match, return (we ignore this case) // - finally, we take the syst's and apply the linear interpolation w/ constraint + string expPrefix = sample.GetName() + "_" + channel_name; + // create roorealvar observables + RooArgList observables = createObservables(sample.GetHisto(), proto); + RooHistFunc* nominalHistFunc = MakeExpectedHistFunc(sample.GetHisto(), proto, expPrefix, observables); + assert(nominalHistFunc); if(sample.GetHistoSysList().size() == 0) { - // If no HistoSys cxcoutI(HistFactory) << sample.GetName() + "_" + channel_name + " has no variation histograms " << endl; - string expPrefix = sample.GetName() + "_" + channel_name; //+"_expN"; - syst_x_expectedPrefix = sample.GetName() + "_" + channel_name + "_overallSyst_x_Exp"; - ProcessExpectedHisto(sample.GetHisto(), proto, expPrefix, syst_x_expectedPrefix, - overallSystName); - } - else { + sampleHistFuncs.push_back(nominalHistFunc); + } else { // If there ARE HistoSys(s) // name of source for variation string constraintPrefix = sample.GetName() + "_" + channel_name + "_Hist_alpha"; - syst_x_expectedPrefix = sample.GetName() + "_" + channel_name + "_overallSyst_x_HistSyst"; - // constraintTermNames are passed by reference and appended to, - // overallSystName is a std::string for this sample - LinInterpWithConstraint(proto, nominal, sample.GetHistoSysList(), - constraintPrefix, syst_x_expectedPrefix, overallSystName, - constraintTermNames); + sampleHistFuncs.push_back( MakeLinInterpWithConstraint(nominalHistFunc, proto, + sample.GetHistoSysList(), constraintPrefix, constraintTermNames, observables) ); } //////////////////////////////////// @@ -1390,34 +1351,7 @@ namespace HistFactory{ << "for channel " << channel_name << std::endl; - /* - Constraint::Type type = channel.GetStatErrorConfig().GetConstraintType(); - statConstraintType = Constraint::Gaussian; - if( type == Constraint::Gaussian) { - std::cout << "Using Gaussian StatErrors" << std::endl; - statConstraintType = Constraint::Gaussian; - } - if( type == Constraint::Poisson ) { - std::cout << "Using Poisson StatErrors" << std::endl; - statConstraintType = Constraint::Poisson; - } - */ - - //statRelErrorThreshold = channel.GetStatErrorConfig().GetRelErrorThreshold(); - - // First, get the uncertainty histogram - // and push it back to our vectors - - //if( sample.GetStatError().GetErrorHist() ) { - //statErrorHist = (TH1*) sample.GetStatError().GetErrorHist()->Clone(); - //} - //if( statErrorHist == NULL ) { - - // We need to get the *ABSOLUTE* uncertainty for use in Stat Uncertainties - // This can be done in one of two ways: - // - Use the built-in Errors in the TH1 itself (they are aboslute) - // - Take the supplied *RELATIVE* error and multiply by the nominal - string UncertName = syst_x_expectedPrefix + "_StatAbsolUncert"; + string UncertName = sample.GetName() + "_" + channel_name + "_StatAbsolUncert"; TH1* statErrorHist = NULL; if( sample.GetStatError().GetErrorHist() == NULL ) { @@ -1461,19 +1395,18 @@ namespace HistFactory{ // and then create the poisson term: Pois(tau | n_exp)Pois(data | n_exp) - // Next, try to get the ParamHistFunc (it may have been + // Next, try to get the common ParamHistFunc (it may have been // created by another sample in this channel) // or create it if it doesn't yet exist: - statFuncName = "mc_stat_" + channel_name; - ParamHistFunc* paramHist = (ParamHistFunc*) proto->function( statFuncName.c_str() ); - if( paramHist == NULL ) { + ParamHistFunc* paramHist = dynamic_cast( proto->function(statFuncName.c_str()) ); + if( paramHist == nullptr ) { // Get a RooArgSet of the observables: // Names in the list fObsNameVec: - RooArgList observables; + RooArgList theObservables; std::vector::iterator itr = fObsNameVec.begin(); for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) { - observables.add( *proto->var(itr->c_str()) ); + theObservables.add( *proto->var(itr->c_str()) ); } // Create the list of terms to @@ -1483,34 +1416,19 @@ namespace HistFactory{ Double_t gammaMax = 10.0; RooArgList statFactorParams = ParamHistFunc::createParamSet(*proto, ParamSetPrefix.c_str(), - observables, + theObservables, gammaMin, gammaMax); ParamHistFunc statUncertFunc(statFuncName.c_str(), statFuncName.c_str(), - observables, statFactorParams ); + theObservables, statFactorParams ); proto->import( statUncertFunc, RecycleConflictNodes() ); paramHist = (ParamHistFunc*) proto->function( statFuncName.c_str() ); + } - } // END: If Statement: Create ParamHistFunc - - // Create the node as a product - // of this function and the - // expected value from MC - statNodeName = sample.GetName() + "_" + channel_name + "_overallSyst_x_StatUncert"; - - RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() ); - RooProduct nodeWithMcStat(statNodeName.c_str(), statNodeName.c_str(), - RooArgSet(*paramHist, *expFunc) ); - - proto->import( nodeWithMcStat, RecycleConflictNodes() ); - - // Push back the final name of the node - // to be used in the RooRealSumPdf - // (node to be created later) - syst_x_expectedPrefix = nodeWithMcStat.GetName(); - + // apply stat function to sample + sampleHistFuncs.push_back(paramHist); } } // END: if DoMcStat @@ -1532,7 +1450,6 @@ namespace HistFactory{ << std::endl; std::vector paramHistFuncList; - std::vector shapeFactorNameList; for(unsigned int i=0; i < sample.GetShapeFactorList().size(); ++i) { @@ -1540,12 +1457,12 @@ namespace HistFactory{ std::string funcName = channel_name + "_" + shapeFactor.GetName() + "_shapeFactor"; ParamHistFunc* paramHist = (ParamHistFunc*) proto->function( funcName.c_str() ); - if( paramHist == NULL ) { + if( paramHist == nullptr ) { - RooArgList observables; + RooArgList theObservables; std::vector::iterator itr = fObsNameVec.begin(); for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) { - observables.add( *proto->var(itr->c_str()) ); + theObservables.add( *proto->var(itr->c_str()) ); } // Create the Parameters @@ -1555,11 +1472,11 @@ namespace HistFactory{ // We should change this to range from 0 to /inf RooArgList shapeFactorParams = ParamHistFunc::createParamSet(*proto, funcParams.c_str(), - observables, 0, 1000); + theObservables, 0, 1000); // Create the Function ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(), - observables, shapeFactorParams ); + theObservables, shapeFactorParams ); // Set an initial shape, if requested if( shapeFactor.GetInitialShape() != NULL ) { @@ -1584,38 +1501,20 @@ namespace HistFactory{ } // End: Create ShapeFactor ParamHistFunc paramHistFuncList.push_back(paramHist); - shapeFactorNameList.push_back(funcName); - } // End loop over ShapeFactor Systematics // Now that we have the right ShapeFactor, // we multiply the expected function - //std::string shapeFactorNodeName = syst_x_expectedPrefix + "_x_" + funcName; - // Dynamically build the name as a long product - std::string shapeFactorNodeName = syst_x_expectedPrefix; - for( unsigned int i=0; i < shapeFactorNameList.size(); ++i) { - shapeFactorNodeName += "_x_" + shapeFactorNameList.at(i); - } + // Append to product of functions + for (auto paramHistFunc : paramHistFuncList) { + proto->import(*paramHistFunc, RecycleConflictNodes()); + auto paramHFinWS = proto->arg(paramHistFunc->GetName()); + assert(paramHFinWS); + delete paramHistFunc; - RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() ); - RooArgSet nodesForProduct(*expFunc); - for( unsigned int i=0; i < paramHistFuncList.size(); ++i) { - nodesForProduct.add( *paramHistFuncList.at(i) ); + sampleHistFuncs.push_back(paramHFinWS); } - //RooProduct nodeWithShapeFactor(shapeFactorNodeName.c_str(), - // shapeFactorNodeName.c_str(), - //RooArgSet(*paramHist, *expFunc) ); - RooProduct nodeWithShapeFactor(shapeFactorNodeName.c_str(), - shapeFactorNodeName.c_str(), - nodesForProduct ); - - proto->import( nodeWithShapeFactor, RecycleConflictNodes() ); - - // Push back the final name of the node - // to be used in the RooRealSumPdf - // (node to be created later) - syst_x_expectedPrefix = nodeWithShapeFactor.GetName(); } } // End: if ShapeFactorName!="" @@ -1660,21 +1559,21 @@ namespace HistFactory{ //std::string funcParams = "gamma_" + it->shapeFactorName; //paramHist = CreateParamHistFunc( proto, fObsNameVec, funcParams, funcName ); - RooArgList observables; + RooArgList theObservables; std::vector::iterator itr = fObsNameVec.begin(); for(; itr!=fObsNameVec.end(); ++itr ) { - observables.add( *proto->var(itr->c_str()) ); + theObservables.add( *proto->var(itr->c_str()) ); } // Create the Parameters std::string funcParams = "gamma_" + shapeSys.GetName(); RooArgList shapeFactorParams = ParamHistFunc::createParamSet(*proto, funcParams.c_str(), - observables, 0, 10); + theObservables, 0, 10); // Create the Function ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(), - observables, shapeFactorParams ); + theObservables, shapeFactorParams ); proto->import( shapeFactorFunc, RecycleConflictNodes() ); paramHist = (ParamHistFunc*) proto->function( funcName.c_str() ); @@ -1709,49 +1608,44 @@ namespace HistFactory{ // we create the total RooProduct // we multiply the expected functio - std::string NodeName = syst_x_expectedPrefix; - RooArgList ShapeSysForNode; - RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() ); - ShapeSysForNode.add( *expFunc ); + for( unsigned int i = 0; i < ShapeSysNames.size(); ++i ) { - std::string ShapeSysName = ShapeSysNames.at(i); - ShapeSysForNode.add( *proto->function(ShapeSysName.c_str()) ); - NodeName = NodeName + "_x_" + ShapeSysName; + auto func = proto->function(ShapeSysNames.at(i).c_str()); + assert(func); + sampleHistFuncs.push_back(func); } - // Create the name for this NEW Node - RooProduct nodeWithShapeFactor(NodeName.c_str(), NodeName.c_str(), ShapeSysForNode ); - proto->import( nodeWithShapeFactor, RecycleConflictNodes() ); - - // Push back the final name of the node - // to be used in the RooRealSumPdf - // (node to be created later) - syst_x_expectedPrefix = nodeWithShapeFactor.GetName(); - } // End: NumObsVar == 1 } // End: GetShapeSysList.size() != 0 - // Append the name of the "node" - // that is to be summed with the - // RooRealSumPdf - syst_x_expectedPrefixNames.push_back(syst_x_expectedPrefix); // GHL: This was pretty confusing before, // hopefully using the measurement directly // will improve it - if( sample.GetNormalizeByTheory() ) { - normalizationNames.push_back( "Lumi" ); - } - else { - TString lumiParamString; - lumiParamString += measurement.GetLumi(); - lumiParamString.ReplaceAll(' ', TString()); - normalizationNames.push_back(lumiParamString.Data()); + auto lumi = proto->arg("Lumi"); + if( !sample.GetNormalizeByTheory() ) { + if (!lumi) { + TString lumiParamString; + lumiParamString += measurement.GetLumi(); + lumiParamString.ReplaceAll(' ', TString()); + lumi = proto->factory(("Lumi[" + lumiParamString + "]").Data()); + } else { + static_cast(lumi)->setVal(measurement.GetLumi()); + } } + assert(lumi); + normFactors->addTerm(lumi); + // Append the name of the "node" + // that is to be summed with the + // RooRealSumPdf + proto->import(*normFactors, RecycleConflictNodes()); + auto normFactorsInWS = dynamic_cast(proto->arg(normFactors->GetName())); + assert(normFactorsInWS); + + sampleScaleFactors.push_back(normFactorsInWS); } // END: Loop over EstimateSummaries - // proto->Print(); // If a non-zero number of samples call for // Stat Uncertainties, create the statFactor functions @@ -1759,10 +1653,10 @@ namespace HistFactory{ // Create the histogram of (binwise) // stat uncertainties: - unique_ptr fracStatError( MakeScaledUncertaintyHist( statNodeName + "_RelErr", statHistPairs) ); + unique_ptr fracStatError( MakeScaledUncertaintyHist( channel_name + "_StatUncert" + "_RelErr", statHistPairs) ); if( fracStatError == NULL ) { cxcoutE(HistFactory) << "Error: Failed to make ScaledUncertaintyHist for: " - << statNodeName << std::endl; + << channel_name + "_StatUncert" + "_RelErr" << std::endl; throw hf_exc(); } @@ -1806,10 +1700,8 @@ namespace HistFactory{ /////////////////////////////////// // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j - //MakeTotalExpected(proto,channel_name+"_model",channel_name,"Lumi",fLowBin,fHighBin, - // syst_x_expectedPrefixNames, normalizationNames); - MakeTotalExpected(proto, channel_name+"_model", //channel_name,"Lumi",fLowBin,fHighBin, - syst_x_expectedPrefixNames, normalizationNames); + MakeTotalExpected(proto, channel_name+"_model", + sampleScaleFactors, allSampleHistFuncs); likelihoodTermNames.push_back(channel_name+"_model"); ////////////////////////////////////// @@ -1863,7 +1755,6 @@ namespace HistFactory{ } proto->defineSet("constraintTerms",constraintTerms); proto->defineSet("likelihoodTerms",likelihoodTerms); - // proto->Print(); // list of observables RooArgList observables; @@ -1937,39 +1828,6 @@ namespace HistFactory{ ConfigureHistFactoryDataset( obsDataUnbinned.get(), mnominal, proto, fObsNameVec ); - /* - //ES// TH1* mnominal = summary.at(0).nominal; - TH1* mnominal = data.GetHisto(); - TAxis* ax = mnominal->GetXaxis(); - TAxis* ay = mnominal->GetYaxis(); - TAxis* az = mnominal->GetZaxis(); - - for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension - Double_t xval = ax->GetBinCenter(i); - proto->var( fObsNameVec[0].c_str() )->setVal( xval ); - if (fObsNameVec.size()==1) { - Double_t fval = mnominal->GetBinContent(i); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } else { // 2 or more dimensions - for (int j=1; j<=ay->GetNbins(); ++j) { - Double_t yval = ay->GetBinCenter(j); - proto->var( fObsNameVec[1].c_str() )->setVal( yval ); - if (fObsNameVec.size()==2) { - Double_t fval = mnominal->GetBinContent(i,j); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } else { // 3 dimensions - for (int k=1; k<=az->GetNbins(); ++k) { - Double_t zval = az->GetBinCenter(k); - proto->var( fObsNameVec[2].c_str() )->setVal( zval ); - Double_t fval = mnominal->GetBinContent(i,j,k); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } - } - } - } - } - */ - proto->import(*obsDataUnbinned); } // End: Has non-null 'data' entry @@ -1992,39 +1850,6 @@ namespace HistFactory{ ConfigureHistFactoryDataset( obsDataUnbinned.get(), mnominal, proto, fObsNameVec ); - /* - //ES// TH1* mnominal = summary.at(0).nominal; - TH1* mnominal = data.GetHisto(); - TAxis* ax = mnominal->GetXaxis(); - TAxis* ay = mnominal->GetYaxis(); - TAxis* az = mnominal->GetZaxis(); - - for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension - Double_t xval = ax->GetBinCenter(i); - proto->var( fObsNameVec[0].c_str() )->setVal( xval ); - if (fObsNameVec.size()==1) { - Double_t fval = mnominal->GetBinContent(i); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } else { // 2 or more dimensions - for (int j=1; j<=ay->GetNbins(); ++j) { - Double_t yval = ay->GetBinCenter(j); - proto->var( fObsNameVec[1].c_str() )->setVal( yval ); - if (fObsNameVec.size()==2) { - Double_t fval = mnominal->GetBinContent(i,j); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } else { // 3 dimensions - for (int k=1; k<=az->GetNbins(); ++k) { - Double_t zval = az->GetBinCenter(k); - proto->var( fObsNameVec[2].c_str() )->setVal( zval ); - Double_t fval = mnominal->GetBinContent(i,j,k); - obsDataUnbinned->add( *proto->set("obsAndWeight"), fval ); - } - } - } - } - } - */ - proto->import(*obsDataUnbinned); } // End: Has non-null 'data' entry From fca7b9d1f6200166193674ca8a00fb632dc746cd Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 2 Nov 2020 20:15:04 +0100 Subject: [PATCH 145/309] [HF] Silence a warning when combining channels with same constraints. --- roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx index 92147c92abb1d..e9264bf067493 100644 --- a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx +++ b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx @@ -1979,7 +1979,7 @@ RooArgList HistoToWorkspaceFactoryFast::createObservables(const TH1 *hist, RooWo if(!model) cout <<"failed to find model for channel"<set("globalObservables"), /*silent=*/true); // silent because observables might exist in other channel. // constrainedParams->add( * ch->set("constrainedParams") ); pdfMap[channel_name]=model; From a32a325c3ac534e057b93e884826d9ac2a0c6a20 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 15 Nov 2020 18:52:03 +0100 Subject: [PATCH 146/309] [HF] Implement PiecewiseInterpolation::evaluateSpan. - This required adding a dependency to RooBatchCompute. --- roofit/histfactory/CMakeLists.txt | 2 + .../HistFactory/PiecewiseInterpolation.h | 1 + .../src/PiecewiseInterpolation.cxx | 134 ++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/roofit/histfactory/CMakeLists.txt b/roofit/histfactory/CMakeLists.txt index bf40c031380df..b30c7d12f1ab1 100644 --- a/roofit/histfactory/CMakeLists.txt +++ b/roofit/histfactory/CMakeLists.txt @@ -64,6 +64,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(HistFactory src/Systematics.cxx DICTIONARY_OPTIONS "-writeEmptyRootPCM" + LIBRARIES + RooBatchCompute DEPENDENCIES RooFit RooFitCore diff --git a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h index e3ca6b4636980..d3f1595d43da0 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h @@ -96,6 +96,7 @@ class PiecewiseInterpolation : public RooAbsReal { std::vector _interpCode; Double_t evaluate() const; + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const; ClassDef(PiecewiseInterpolation,3) // Sum of RooAbsReal objects }; diff --git a/roofit/histfactory/src/PiecewiseInterpolation.cxx b/roofit/histfactory/src/PiecewiseInterpolation.cxx index 514ca3cba1769..3018dbd7a03c1 100644 --- a/roofit/histfactory/src/PiecewiseInterpolation.cxx +++ b/roofit/histfactory/src/PiecewiseInterpolation.cxx @@ -33,9 +33,11 @@ #include "RooMsgService.h" #include "RooNumIntConfig.h" #include "RooTrace.h" +#include "RunContext.h" #include #include +#include using namespace std; @@ -309,6 +311,138 @@ Double_t PiecewiseInterpolation::evaluate() const } + +//////////////////////////////////////////////////////////////////////////////// +/// Interpolate between input distributions for all values of the observable in `evalData`. +/// \param[in/out] evalData Struct holding spans pointing to input data. The results of this function will be stored here. +/// \param[in] normSet Arguments to normalise over. +RooSpan PiecewiseInterpolation::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const { + auto nominal = _nominal->getValues(evalData, normSet); + auto sum = evalData.makeBatch(this, nominal.size()); + std::copy(nominal.begin(), nominal.end(), sum.begin()); + + for (unsigned int i=0; i < _paramSet.size(); ++i) { + const double param = static_cast(_paramSet.at(i))->getVal(); + auto low = static_cast(_lowSet.at(i) )->getValues(evalData, normSet); + auto high = static_cast(_highSet.at(i))->getValues(evalData, normSet); + const int icode = _interpCode[i]; + + switch(icode) { + case 0: { + // piece-wise linear + for (unsigned int j=0; j < nominal.size(); ++j) { + if(param >0) + sum[j] += param * (high[j] - nominal[j]); + else + sum[j] += param * (nominal[j] - low[j] ); + } + break; + } + case 1: { + // pice-wise log + for (unsigned int j=0; j < nominal.size(); ++j) { + if(param >=0) + sum[j] *= pow(high[j]/ nominal[j], +param); + else + sum[j] *= pow(low[j] / nominal[j], -param); + } + break; + } + case 2: + // parabolic with linear + for (unsigned int j=0; j < nominal.size(); ++j) { + const double a = 0.5*(high[j]+low[j])-nominal[j]; + const double b = 0.5*(high[j]-low[j]); + const double c = 0; + if (param > 1.) { + sum[j] += (2*a+b)*(param -1)+high[j]-nominal[j]; + } else if (param < -1.) { + sum[j] += -1*(2*a-b)*(param +1)+low[j]-nominal[j]; + } else { + sum[j] += a*pow(param ,2) + b*param +c; + } + } + break; + case 3: { + //parabolic version of log-normal + for (unsigned int j=0; j < nominal.size(); ++j) { + const double a = 0.5*(high[j]+low[j])-nominal[j]; + const double b = 0.5*(high[j]-low[j]); + const double c = 0; + if (param > 1.) { + sum[j] += (2*a+b)*(param -1)+high[j]-nominal[j]; + } else if (param < -1.) { + sum[j] += -1*(2*a-b)*(param +1)+low[j]-nominal[j]; + } else { + sum[j] += a*pow(param ,2) + b*param +c; + } + } + break; + } + case 4: + for (unsigned int j=0; j < nominal.size(); ++j) { + const double x = param; + if (x > 1.) { + sum[j] += x * (high[j] - nominal[j]); + } else if (x < -1.) { + sum[j] += x * (nominal[j] - low[j]); + } else { + const double eps_plus = high[j] - nominal[j]; + const double eps_minus = nominal[j] - low[j]; + const double S = 0.5 * (eps_plus + eps_minus); + const double A = 0.0625 * (eps_plus - eps_minus); + + double val = nominal[j] + x * (S + x * A * ( 15. + x * x * (-10. + x * x * 3. ) ) ); + + if (val < 0.) val = 0.; + sum[j] += val - nominal[j]; + } + } + break; + case 5: + for (unsigned int j=0; j < nominal.size(); ++j) { + if (param > 1. || param < -1.) { + if(param>0) + sum[j] += param * (high[j] - nominal[j]); + else + sum[j] += param * (nominal[j] - low[j] ); + } else if (nominal[j] != 0) { + const double eps_plus = high[j] - nominal[j]; + const double eps_minus = nominal[j] - low[j]; + const double S = (eps_plus + eps_minus)/2; + const double A = (eps_plus - eps_minus)/2; + + //fcns+der are eq at bd + const double a = S; + const double b = 3*A/(2*1.); + //double c = 0; + const double d = -A/(2*1.*1.*1.); + + double val = nominal[j] + a * param + b * pow(param, 2) + d * pow(param, 4); + if (val < 0.) val = 0.; + + sum[j] += val - nominal[j]; + } + } + break; + default: + coutE(InputArguments) << "PiecewiseInterpolation::evaluateSpan(): " << _paramSet[i].GetName() + << " with unknown interpolation code" << icode << std::endl; + throw std::invalid_argument("PiecewiseInterpolation::evaluateSpan() got invalid interpolation code " + std::to_string(icode)); + break; + } + } + + if (_positiveDefinite) { + for (double& val : sum) { + if (val < 0.) + val = 0.; + } + } + + return sum; +} + //////////////////////////////////////////////////////////////////////////////// Bool_t PiecewiseInterpolation::setBinIntegrator(RooArgSet& allVars) From 1ecd30ec86cf54f4441120d3bfbbfe3f99a82839 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 22 Nov 2020 18:47:06 +0100 Subject: [PATCH 147/309] [RF] Implement RooRealSumPdf::evaluateSpan(). --- roofit/roofitcore/inc/RooRealSumPdf.h | 2 +- roofit/roofitcore/src/RooRealSumPdf.cxx | 52 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/roofit/roofitcore/inc/RooRealSumPdf.h b/roofit/roofitcore/inc/RooRealSumPdf.h index 89b2991e1dfbf..6e1ce92ca742b 100644 --- a/roofit/roofitcore/inc/RooRealSumPdf.h +++ b/roofit/roofitcore/inc/RooRealSumPdf.h @@ -20,7 +20,6 @@ #include "RooListProxy.h" #include "RooAICRegistry.h" #include "RooObjCacheManager.h" -#include class RooRealSumPdf : public RooAbsPdf { public: @@ -68,6 +67,7 @@ class RooRealSumPdf : public RooAbsPdf { virtual void setCacheAndTrackHints(RooArgSet&) ; protected: + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const; class CacheElem : public RooAbsCacheElement { public: diff --git a/roofit/roofitcore/src/RooRealSumPdf.cxx b/roofit/roofitcore/src/RooRealSumPdf.cxx index fde4464ea4e15..f13bae48032e0 100644 --- a/roofit/roofitcore/src/RooRealSumPdf.cxx +++ b/roofit/roofitcore/src/RooRealSumPdf.cxx @@ -51,6 +51,7 @@ to the fractions of the various functions. **This requires setting the last argu #include "RooRealVar.h" #include "RooMsgService.h" #include "RooNaNPacker.h" +#include "RunContext.h" #include @@ -265,6 +266,57 @@ Double_t RooRealSumPdf::evaluate() const } +//////////////////////////////////////////////////////////////////////////////// +/// Calculate the value for all values of the observable in `evalData`. +RooSpan RooRealSumPdf::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* /*normSet*/) const { + // Do running sum of coef/func pairs, calculate lastCoef. + RooSpan values; + double sumCoeff = 0.; + for (unsigned int i = 0; i < _funcList.size(); ++i) { + const auto func = static_cast(&_funcList[i]); + const auto coef = static_cast(i < _coefList.size() ? &_coefList[i] : nullptr); + const double coefVal = coef != nullptr ? coef->getVal() : (1. - sumCoeff); + + if (func->isSelectedComp()) { + auto funcValues = func->getValues(evalData, nullptr); // No normSet here, because we are summing functions! + if (values.empty() || (values.size() == 1 && funcValues.size() > 1)) { + const double init = values.empty() ? 0. : values[0]; + values = evalData.makeBatch(this, funcValues.size()); + for (unsigned int j = 0; j < values.size(); ++j) { + values[j] = init + funcValues[j] * coefVal; + } + } else { + assert(values.size() == funcValues.size()); + for (unsigned int j = 0; j < values.size(); ++j) { + values[j] += funcValues[j] * coefVal; + } + } + } + + // Warn about degeneration of last coefficient + if (coef == nullptr && (coefVal < 0 || coefVal > 1.)) { + if (!_haveWarned) { + coutW(Eval) << "RooRealSumPdf::evaluateSpan(" << GetName() + << ") WARNING: sum of FUNC coefficients not in range [0-1], value=" + << sumCoeff << ". This means that the PDF is not properly normalised. If the PDF was meant to be extended, provide as many coefficients as functions." << endl ; + _haveWarned = true; + } + // Signal that we are in an undefined region by handing back one NaN. + values[0] = RooNaNPacker::packFloatIntoNaN(100.f * (coefVal < 0. ? -coefVal : coefVal - 1.)); + } + + sumCoeff += coefVal; + } + + // Introduce floor if so requested + if (_doFloor || _doFloorGlobal) { + for (unsigned int j = 0; j < values.size(); ++j) { + values[j] += std::max(0., values[j]); + } + } + + return values; +} //////////////////////////////////////////////////////////////////////////////// From 81729634c9573359cc17fbb6270cd2b412aa518f Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 22 Nov 2020 18:56:32 +0100 Subject: [PATCH 148/309] [RF] Allow for broadcasting in RooProdPdf::evaluateSpan(). If a node does not depend on observables, it might return a span of size 1. If this gets multiplied with a node that depends on observables, the size-1 value must be broadcast. --- roofit/roofitcore/src/RooProdPdf.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 48705d5498097..577b07a0092a7 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -534,8 +534,13 @@ RooSpan RooProdPdf::evaluateSpan(RooBatchCompute::RunContext& evalData, if (outputs.empty()) { outputs = evalData.makeBatch(this, partialInt.size()); - for (double& val : outputs) val = 1.; + std::fill(outputs.begin(), outputs.end(), 1.); + } else if (outputs.size() == 1 && partialInt.size() > 1) { + const double val = outputs[0]; + outputs = evalData.makeBatch(this, partialInt.size()); + std::fill(outputs.begin(), outputs.end(), val); } + assert(outputs.size() == partialInt.size()); for (std::size_t j=0; j < outputs.size(); ++j) { outputs[j] *= partialInt[j]; From 41dcb21f8504083c23be15ff20f8b97c8a38693d Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Sun, 22 Nov 2020 19:03:50 +0100 Subject: [PATCH 149/309] [RF] Allow for broadcasting in RooAddPdf::evaluateSpan. --- roofit/roofitcore/src/RooAddPdf.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/roofit/roofitcore/src/RooAddPdf.cxx b/roofit/roofitcore/src/RooAddPdf.cxx index 8c2426bb91003..3ae9ec268ca0b 100644 --- a/roofit/roofitcore/src/RooAddPdf.cxx +++ b/roofit/roofitcore/src/RooAddPdf.cxx @@ -863,17 +863,15 @@ RooSpan RooAddPdf::evaluateSpan(RooBatchCompute::RunContext& evalData, c const RooArgSet* nset = normAndCache.first; CacheElem* cache = normAndCache.second; - RooSpan output; for (unsigned int pdfNo = 0; pdfNo < _pdfList.size(); ++pdfNo) { const auto& pdf = static_cast(_pdfList[pdfNo]); auto pdfOutputs = pdf.getValues(evalData, nset); - if (output.empty()) { + if (output.empty() || (output.size() == 1 && pdfOutputs.size() > 1)) { + const double init = output.empty() ? 0. : output[0]; output = evalData.makeBatch(this, pdfOutputs.size()); - for (double& val : output) { //CHECK_VECTORISE - val = 0.; - } + std::fill(output.begin(), output.end(), init); } assert(output.size() == pdfOutputs.size()); From ae7ad730e0e14e898980694e71f4c96d187eccdd Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 11:56:25 +0200 Subject: [PATCH 150/309] [RF] Implement batch evaluations for RooBinIntegrator. --- roofit/roofitcore/inc/RooBinIntegrator.h | 7 ++ roofit/roofitcore/src/RooBinIntegrator.cxx | 94 +++++++++++++++------- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/roofit/roofitcore/inc/RooBinIntegrator.h b/roofit/roofitcore/inc/RooBinIntegrator.h index 2f4faebdcb5de..73a1582191c31 100644 --- a/roofit/roofitcore/inc/RooBinIntegrator.h +++ b/roofit/roofitcore/inc/RooBinIntegrator.h @@ -21,6 +21,10 @@ #include #include +namespace RooBatchCompute { +struct RunContext; +} + class RooBinIntegrator : public RooAbsIntegrator { public: @@ -59,6 +63,9 @@ class RooBinIntegrator : public RooAbsIntegrator { Bool_t _useIntegrandLimits; // If true limits of function binding are ued + std::unique_ptr _evalData; //! Run context for evaluating a function. + std::unique_ptr _evalDataOrig; //! Run context to save bin centres in between invocations. + double* xvec(double xx) { _x[0] = xx ; return _x ; } double* xvec(double xx, double yy) { _x[0] = xx ; _x[1] = yy ; return _x ; } double* xvec(double xx, double yy, double zz) { _x[0] = xx ; _x[1] = yy ; _x[2] = zz ; return _x ; } diff --git a/roofit/roofitcore/src/RooBinIntegrator.cxx b/roofit/roofitcore/src/RooBinIntegrator.cxx index b4c4aeebff3b2..69ae56ad9bdb8 100644 --- a/roofit/roofitcore/src/RooBinIntegrator.cxx +++ b/roofit/roofitcore/src/RooBinIntegrator.cxx @@ -23,12 +23,8 @@ RooBinIntegrator computes the integral over a binned distribution by summing the contents of all bins. **/ - -#include "RooFit.h" -#include "Riostream.h" - -#include "TClass.h" #include "RooBinIntegrator.h" + #include "RooArgSet.h" #include "RooRealVar.h" #include "RooNumber.h" @@ -36,6 +32,11 @@ contents of all bins. #include "RooNumIntConfig.h" #include "RooNumIntFactory.h" #include "RooMsgService.h" +#include "RunContext.h" +#include "RooRealBinding.h" + +#include "TClass.h" +#include "Math/Util.h" #include @@ -85,22 +86,35 @@ RooBinIntegrator::RooBinIntegrator(const RooAbsFunc& function) : _xmin.resize(_function->getDimension()) ; _xmax.resize(_function->getDimension()) ; + auto realBinding = dynamic_cast(integrand()); + if (realBinding) { + _evalData.reset(new RooBatchCompute::RunContext()); + _evalDataOrig.reset(new RooBatchCompute::RunContext()); + } + for (UInt_t i=0 ; i<_function->getDimension() ; i++) { _xmin[i]= integrand()->getMinLimit(i); _xmax[i]= integrand()->getMaxLimit(i); // Retrieve bin configuration from integrand - list* tmp = integrand()->binBoundaries(i) ; + std::unique_ptr> tmp{ integrand()->binBoundaries(i) }; if (!tmp) { oocoutW((TObject*)0,Integration) << "RooBinIntegrator::RooBinIntegrator WARNING: integrand provide no binning definition observable #" - << i << " substituting default binning of " << _numBins << " bins" << endl ; - tmp = new list ; + << i << " substituting default binning of " << _numBins << " bins" << endl ; + tmp.reset( new list ); for (Int_t j=0 ; j<=_numBins ; j++) { - tmp->push_back(_xmin[i]+j*(_xmax[i]-_xmin[i])/_numBins) ; + tmp->push_back(_xmin[i]+j*(_xmax[i]-_xmin[i])/_numBins) ; } } _binb.emplace_back(tmp->begin(), tmp->end()); - delete tmp; + + if (realBinding) { + const std::vector& binb = _binb.back(); + RooSpan binCentres = _evalDataOrig->makeBatch(realBinding->observable(i), binb.size() - 1); + for (unsigned int ibin = 0; ibin < binb.size() - 1; ++ibin) { + binCentres[ibin] = (binb[ibin + 1] + binb[ibin]) / 2.; + } + } } checkLimits(); @@ -121,22 +135,35 @@ RooBinIntegrator::RooBinIntegrator(const RooAbsFunc& function, const RooNumIntCo // Allocate coordinate buffer size after number of function dimensions _x = new Double_t[_function->getDimension()] ; + auto realBinding = dynamic_cast(integrand()); + if (realBinding) { + _evalData.reset(new RooBatchCompute::RunContext()); + _evalDataOrig.reset(new RooBatchCompute::RunContext()); + } + for (UInt_t i=0 ; i<_function->getDimension() ; i++) { _xmin.push_back(integrand()->getMinLimit(i)); _xmax.push_back(integrand()->getMaxLimit(i)); // Retrieve bin configuration from integrand - list* tmp = integrand()->binBoundaries(i) ; + std::unique_ptr> tmp{ integrand()->binBoundaries(i) }; if (!tmp) { oocoutW((TObject*)0,Integration) << "RooBinIntegrator::RooBinIntegrator WARNING: integrand provide no binning definition observable #" << i << " substituting default binning of " << _numBins << " bins" << endl ; - tmp = new list ; + tmp.reset( new list ); for (Int_t j=0 ; j<=_numBins ; j++) { tmp->push_back(_xmin[i]+j*(_xmax[i]-_xmin[i])/_numBins) ; } } _binb.emplace_back(tmp->begin(), tmp->end()); - delete tmp; + + if (realBinding) { + const std::vector& binb = _binb.back(); + RooSpan binCentres = _evalDataOrig->makeBatch(realBinding->observable(i), binb.size() - 1); + for (unsigned int ibin = 0; ibin < binb.size() - 1; ++ibin) { + binCentres[ibin] = (binb[ibin + 1] + binb[ibin]) / 2.; + } + } } checkLimits(); @@ -211,27 +238,40 @@ Bool_t RooBinIntegrator::checkLimits() const //////////////////////////////////////////////////////////////////////////////// -/// Calculate numeric integral at given set of function binding parameters - +/// Calculate numeric integral at given set of function binding parameters. Double_t RooBinIntegrator::integral(const Double_t *) { assert(isValid()); - double sum = 0. ; + ROOT::Math::KahanSum sum; if (_function->getDimension() == 1) { const std::vector& binb = _binb[0]; - for (unsigned int ibin=0; ibin < binb.size() - 1; ++ibin) { - const double xhi = binb[ibin + 1]; - const double xlo = binb[ibin]; - const double xcenter = (xhi+xlo)/2.; - const double binInt = integrand(xvec(xcenter))*(xhi-xlo) ; - sum += binInt ; - } - } + if (_evalData) { + // Real bindings support batch evaluations. Can fast track now. + auto realBinding = static_cast(integrand()); - if (_function->getDimension()==2) { + // Reset computation results to only contain known bin centres, and keep all memory intact: + _evalData->spans = _evalDataOrig->spans; + auto results = realBinding->getValues(*_evalData); + assert(results.size() == binb.size() - 1); + + for (unsigned int ibin = 0; ibin < binb.size() - 1; ++ibin) { + const double width = binb[ibin + 1] - binb[ibin]; + sum += results[ibin] * width; + } + } else { + // Need to use single-value interface + for (unsigned int ibin=0; ibin < binb.size() - 1; ++ibin) { + const double xhi = binb[ibin + 1]; + const double xlo = binb[ibin]; + const double xcenter = (xhi+xlo)/2.; + const double binInt = integrand(xvec(xcenter))*(xhi-xlo) ; + sum += binInt ; + } + } + } else if (_function->getDimension() == 2) { const std::vector& binbx = _binb[0]; const std::vector& binby = _binb[1]; @@ -249,9 +289,7 @@ Double_t RooBinIntegrator::integral(const Double_t *) sum += binInt ; } } - } - - if (_function->getDimension()==3) { + } else if (_function->getDimension() == 3) { const std::vector& binbx = _binb[0]; const std::vector& binby = _binb[1]; const std::vector& binbz = _binb[2]; From ea2a65ff6067e829d3ec13465ab78e4113297977 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 12:19:36 +0200 Subject: [PATCH 151/309] [RF] Support batch evaluations with RunContext in RooRealBinding. --- roofit/roofitcore/inc/RooRealBinding.h | 3 +++ roofit/roofitcore/src/RooBinIntegrator.cxx | 2 +- roofit/roofitcore/src/RooRealBinding.cxx | 17 +++++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/roofit/roofitcore/inc/RooRealBinding.h b/roofit/roofitcore/inc/RooRealBinding.h index 91e65a8bb0220..2572112c1ddeb 100644 --- a/roofit/roofitcore/inc/RooRealBinding.h +++ b/roofit/roofitcore/inc/RooRealBinding.h @@ -34,6 +34,7 @@ class RooRealBinding : public RooAbsFunc { virtual Double_t operator()(const Double_t xvector[]) const; virtual RooSpan getValues(std::vector> coordinates) const; + RooSpan getValuesOfBoundFunction(RooBatchCompute::RunContext& evalData) const; virtual Double_t getMinLimit(UInt_t dimension) const; virtual Double_t getMaxLimit(UInt_t dimension) const; @@ -43,6 +44,8 @@ class RooRealBinding : public RooAbsFunc { virtual const char* getName() const ; virtual std::list* binBoundaries(Int_t) const ; + /// Return a pointer to the observable that defines the `i`-th dimension of the function. + RooAbsRealLValue* observable(unsigned int i) const { return i < _vars.size() ? _vars[i] : nullptr; } virtual std::list* plotSamplingHint(RooAbsRealLValue& /*obs*/, Double_t /*xlo*/, Double_t /*xhi*/) const ; protected: diff --git a/roofit/roofitcore/src/RooBinIntegrator.cxx b/roofit/roofitcore/src/RooBinIntegrator.cxx index 69ae56ad9bdb8..ac5271eb82912 100644 --- a/roofit/roofitcore/src/RooBinIntegrator.cxx +++ b/roofit/roofitcore/src/RooBinIntegrator.cxx @@ -254,7 +254,7 @@ Double_t RooBinIntegrator::integral(const Double_t *) // Reset computation results to only contain known bin centres, and keep all memory intact: _evalData->spans = _evalDataOrig->spans; - auto results = realBinding->getValues(*_evalData); + auto results = realBinding->getValuesOfBoundFunction(*_evalData); assert(results.size() == binb.size() - 1); for (unsigned int ibin = 0; ibin < binb.size() - 1; ++ibin) { diff --git a/roofit/roofitcore/src/RooRealBinding.cxx b/roofit/roofitcore/src/RooRealBinding.cxx index 0316f4a8d3400..f198a6e54881a 100644 --- a/roofit/roofitcore/src/RooRealBinding.cxx +++ b/roofit/roofitcore/src/RooRealBinding.cxx @@ -197,6 +197,8 @@ Double_t RooRealBinding::operator()(const Double_t xvector[]) const //////////////////////////////////////////////////////////////////////////////// /// Evaluate the bound object at all locations indicated by the data in `coordinates`. +/// If `_clipInvalid` is set, the function is set to zero at all points in the arguments +/// that are not within the range of the observables. /// \param coordinates Vector of spans that contain the points where the function should be evaluated. /// The ordinal position in the vector corresponds to the ordinal position in the set of /// {observables, parameters} that were passed to the constructor. @@ -233,8 +235,7 @@ RooSpan RooRealBinding::getValues(std::vectorgetValues(*_evalData, _nset); - assert(coordinates.front().size() == results.size()); + auto results = getValuesOfBoundFunction(*_evalData); if (_clipInvalid) { RooSpan resultsWritable(_evalData->getWritableBatch(_func)); @@ -257,6 +258,18 @@ RooSpan RooRealBinding::getValues(std::vector RooRealBinding::getValuesOfBoundFunction(RooBatchCompute::RunContext& evalData) const { + return _func->getValues(evalData, _nset); +} + + //////////////////////////////////////////////////////////////////////////////// /// Return lower limit on i-th variable From c84193f3fb524cdbdf35a890890fcb5732cb0190 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 7 May 2021 12:20:24 +0200 Subject: [PATCH 152/309] [HF] Implement batch evaluations in ParamHistFunc. --- .../inc/RooStats/HistFactory/ParamHistFunc.h | 1 + roofit/histfactory/src/ParamHistFunc.cxx | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h index c6ba50c714676..14fb9104d9d2a 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h @@ -105,6 +105,7 @@ class ParamHistFunc : public RooAbsReal { Int_t addParamSet( const RooArgList& params ); static Int_t GetNumBins( const RooArgSet& vars ); double evaluate() const override; + RooSpan evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const override; private: static NumBins getNumBinsPerDim(RooArgSet const& vars); diff --git a/roofit/histfactory/src/ParamHistFunc.cxx b/roofit/histfactory/src/ParamHistFunc.cxx index 0994e3fc0a3df..dcd79bb7da09a 100644 --- a/roofit/histfactory/src/ParamHistFunc.cxx +++ b/roofit/histfactory/src/ParamHistFunc.cxx @@ -45,6 +45,7 @@ #include "RooRealVar.h" #include "RooArgList.h" #include "RooWorkspace.h" +#include "RunContext.h" #include "TH1.h" @@ -581,6 +582,48 @@ Double_t ParamHistFunc::evaluate() const } +//////////////////////////////////////////////////////////////////////////////// +/// Find all bins corresponding to the values of the observables in `evalData`, and evaluate +/// the associated parameters. +/// \param[in/out] evalData Input/output data for evaluating the ParamHistFunc. +/// \param[in] normSet Normalisation set passed on to objects that are serving values to us. +RooSpan ParamHistFunc::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const { + std::vector oldValues; + std::vector> data; + std::size_t batchSize = 0; + + // Retrieve data for all variables + for (auto arg : _dataVars) { + const auto* var = static_cast(arg); + oldValues.push_back(var->getVal()); + data.push_back(var->getValues(evalData, normSet)); + batchSize = std::max(batchSize, data.back().size()); + } + + // Run computation for each entry in the dataset + RooSpan output = evalData.makeBatch(this, batchSize); + + for (std::size_t i = 0; i < batchSize; ++i) { + for (unsigned int j = 0; j < _dataVars.size(); ++j) { + assert(i < data[j].size()); + auto& var = static_cast(_dataVars[j]); + var.setCachedValue(data[j][i], /*notifyClients=*/false); + } + + const auto index = _dataSet.getIndex(_dataVars, /*fast=*/true); + const RooRealVar& param = getParameter(index); + output[i] = param.getVal(); + } + + // Restore old values + for (unsigned int j = 0; j < _dataVars.size(); ++j) { + auto& var = static_cast(_dataVars[j]); + var.setCachedValue(oldValues[j], /*notifyClients=*/false); + } + + return output; +} + //////////////////////////////////////////////////////////////////////////////// /// Advertise that all integrals can be handled internally. From 1dcda9cafbe7b5fbb6c7afe51e439b2b090449e8 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 10:44:03 +0200 Subject: [PATCH 153/309] [RF] RooAbsData: Remove TH1F, fix memory leaks, improve string parsing. - For an unknown reason, RooAbsData was explicitly using TH1F, although none of its features/interfaces are used anywhere. - By replacing it with unique_ptr, we are now actually including what we use, and fix memory leaks that happened when the functions return early because of an error. - Remove usage of strtok with buffer size limited to 1024 characters. --- roofit/roofitcore/src/RooAbsData.cxx | 142 ++++++++++++--------------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/roofit/roofitcore/src/RooAbsData.cxx b/roofit/roofitcore/src/RooAbsData.cxx index 7d191c392683a..2c1a372f4c4fb 100644 --- a/roofit/roofitcore/src/RooAbsData.cxx +++ b/roofit/roofitcore/src/RooAbsData.cxx @@ -26,15 +26,11 @@ points for its contents and provides an iterator over its elements **/ #include "RooAbsData.h" -#include "RooFit.h" - -#include #include "TBuffer.h" #include "TClass.h" #include "TMath.h" #include "TTree.h" -#include "strlcpy.h" #include "RooFormulaVar.h" #include "RooCmdConfig.h" @@ -56,6 +52,7 @@ points for its contents and provides an iterator over its elements #include "RooPlot.h" #include "RooCurve.h" #include "RooHist.h" +#include "RooHelpers.h" #include "TMatrixDSym.h" #include "TPaveText.h" @@ -64,6 +61,9 @@ points for its contents and provides an iterator over its elements #include "TH3.h" #include "Math/Util.h" +#include +#include + using namespace std; @@ -564,57 +564,53 @@ RooPlot* RooAbsData::plotOn(RooPlot* frame, const RooCmdArg& arg1, const RooCmdA TH1 *RooAbsData::createHistogram(const char* varNameList, Int_t xbins, Int_t ybins, Int_t zbins) const { // Parse list of variable names - char buf[1024] ; - strlcpy(buf,varNameList,1024) ; - char* varName = strtok(buf,",:") ; + const auto varNames = RooHelpers::tokenise(varNameList, ",:"); + RooLinkedList argList; + RooRealVar* vars[3] = {nullptr, nullptr, nullptr}; + + for (unsigned int i = 0; i < varNames.size(); ++i) { + if (i >= 3) { + coutW(InputArguments) << "RooAbsData::createHistogram(" << GetName() << "): Can only create 3-dimensional histograms. Variable " + << i << " " << varNames[i] << " unused." << std::endl; + continue; + } - RooRealVar* xvar = (RooRealVar*) get()->find(varName) ; - if (!xvar) { - coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ; - return 0 ; - } - varName = strtok(0,",") ; - RooRealVar* yvar = varName ? (RooRealVar*) get()->find(varName) : 0 ; - if (varName && !yvar) { - coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ; - return 0 ; - } - varName = strtok(0,",") ; - RooRealVar* zvar = varName ? (RooRealVar*) get()->find(varName) : 0 ; - if (varName && !zvar) { - coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varName << endl ; - return 0 ; + vars[i] = static_cast( get()->find(varNames[i].data()) ); + if (!vars[i]) { + coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << ") ERROR: dataset does not contain an observable named " << varNames[i] << std::endl; + return nullptr; + } } - // Construct list of named arguments to pass to the implementation version of createHistogram() + if (!vars[0]) { + coutE(InputArguments) << "RooAbsData::createHistogram(" << GetName() << "): No variable to be histogrammed in list '" << varNameList << "'" << std::endl; + return nullptr; + } - RooLinkedList argList ; - if (xbins<=0 || !xvar->hasMax() || !xvar->hasMin() ) { - argList.Add(RooFit::AutoBinning(xbins==0?xvar->numBins():abs(xbins)).Clone()) ; + if (xbins<=0 || !vars[0]->hasMax() || !vars[0]->hasMin() ) { + argList.Add(RooFit::AutoBinning(xbins==0?vars[0]->numBins():abs(xbins)).Clone()) ; } else { argList.Add(RooFit::Binning(xbins).Clone()) ; } - if (yvar) { - if (ybins<=0 || !yvar->hasMax() || !yvar->hasMin() ) { - argList.Add(RooFit::YVar(*yvar,RooFit::AutoBinning(ybins==0?yvar->numBins():abs(ybins))).Clone()) ; + if (vars[1]) { + if (ybins<=0 || !vars[1]->hasMax() || !vars[1]->hasMin() ) { + argList.Add(RooFit::YVar(*vars[1],RooFit::AutoBinning(ybins==0?vars[1]->numBins():abs(ybins))).Clone()) ; } else { - argList.Add(RooFit::YVar(*yvar,RooFit::Binning(ybins)).Clone()) ; + argList.Add(RooFit::YVar(*vars[1],RooFit::Binning(ybins)).Clone()) ; } } - - if (zvar) { - if (zbins<=0 || !zvar->hasMax() || !zvar->hasMin() ) { - argList.Add(RooFit::ZVar(*zvar,RooFit::AutoBinning(zbins==0?zvar->numBins():abs(zbins))).Clone()) ; + if (vars[2]) { + if (zbins<=0 || !vars[2]->hasMax() || !vars[2]->hasMin() ) { + argList.Add(RooFit::ZVar(*vars[2],RooFit::AutoBinning(zbins==0?vars[2]->numBins():abs(zbins))).Clone()) ; } else { - argList.Add(RooFit::ZVar(*zvar,RooFit::Binning(zbins)).Clone()) ; + argList.Add(RooFit::ZVar(*vars[2],RooFit::Binning(zbins)).Clone()) ; } } - // Call implementation function - TH1* result = createHistogram(GetName(),*xvar,argList) ; + TH1* result = createHistogram(GetName(), *vars[0], argList); // Delete temporary list of RooCmdArgs argList.Delete() ; @@ -1768,21 +1764,21 @@ RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const // create and fill a temporary histogram of this variable TString histName(GetName()); histName.Append("_plot"); - TH1F *hist ; + std::unique_ptr hist; if (o.bins) { - hist= static_cast(var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), RooFit::Binning(*o.bins))) ; + hist.reset( var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), RooFit::Binning(*o.bins)) ); } else if (!frame->getPlotVar()->getBinning().isUniform()) { - hist = static_cast(var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), - RooFit::Binning(frame->getPlotVar()->getBinning()))); + hist.reset( var->createHistogram(histName.Data(), RooFit::AxisLabel("Events"), + RooFit::Binning(frame->getPlotVar()->getBinning())) ); } else { - hist= var->createHistogram(histName.Data(), "Events", - frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), frame->GetNbinsX()); + hist.reset( var->createHistogram(histName.Data(), "Events", + frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), frame->GetNbinsX()) ); } // Keep track of sum-of-weights error hist->Sumw2() ; - if(0 == fillHistogram(hist,RooArgList(*var),o.cuts,o.cutRange)) { + if(0 == fillHistogram(hist.get(), RooArgList(*var),o.cuts,o.cutRange)) { coutE(Plotting) << ClassName() << "::" << GetName() << ":plotOn: fillHistogram() failed" << endl; return 0; @@ -1802,7 +1798,6 @@ RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const if(0 == graph) { coutE(Plotting) << ClassName() << "::" << GetName() << ":plotOn: unable to create a RooHist object" << endl; - delete hist; return 0; } @@ -1818,7 +1813,7 @@ RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const // Store the number of entries before the cut, if any was made if ((o.cuts && strlen(o.cuts)) || o.cutRange) { - coutI(Plotting) << "RooTreeData::plotOn: plotting " << hist->GetSum() << " events out of " << nEnt << " total events" << endl ; + coutI(Plotting) << "RooTreeData::plotOn: plotting " << hist->GetSumOfWeights() << " events out of " << nEnt << " total events" << endl ; graph->setRawEntries(nEnt) ; } @@ -1858,11 +1853,6 @@ RooPlot *RooAbsData::plotOn(RooPlot *frame, PlotOpt o) const // add the RooHist to the specified plot frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm); - - - // cleanup - delete hist; - return frame; } @@ -1896,22 +1886,22 @@ RooPlot* RooAbsData::plotAsymOn(RooPlot* frame, const RooAbsCategoryLValue& asym // create and fill temporary histograms of this variable for each state TString hist1Name(GetName()),hist2Name(GetName()); hist1Name.Append("_plot1"); - TH1F *hist1, *hist2 ; + std::unique_ptr hist1, hist2; hist2Name.Append("_plot2"); if (o.bins) { - hist1= var->createHistogram(hist1Name.Data(), "Events", *o.bins) ; - hist2= var->createHistogram(hist2Name.Data(), "Events", *o.bins) ; + hist1.reset( var->createHistogram(hist1Name.Data(), "Events", *o.bins) ); + hist2.reset( var->createHistogram(hist2Name.Data(), "Events", *o.bins) ); } else { - hist1= var->createHistogram(hist1Name.Data(), "Events", + hist1.reset( var->createHistogram(hist1Name.Data(), "Events", frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), - frame->GetNbinsX()); - hist2= var->createHistogram(hist2Name.Data(), "Events", + frame->GetNbinsX()) ); + hist2.reset( var->createHistogram(hist2Name.Data(), "Events", frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), - frame->GetNbinsX()); + frame->GetNbinsX()) ); } - assert(0 != hist1 && 0 != hist2); + assert(hist1 && hist2); TString cuts1,cuts2 ; if (o.cuts && strlen(o.cuts)) { @@ -1922,8 +1912,8 @@ RooPlot* RooAbsData::plotAsymOn(RooPlot* frame, const RooAbsCategoryLValue& asym cuts2 = Form("(%s<0)",asymCat.GetName()); } - if(0 == fillHistogram(hist1,RooArgList(*var),cuts1.Data(),o.cutRange) || - 0 == fillHistogram(hist2,RooArgList(*var),cuts2.Data(),o.cutRange)) { + if(! fillHistogram(hist1.get(), RooArgList(*var),cuts1.Data(),o.cutRange) || + ! fillHistogram(hist2.get(), RooArgList(*var),cuts2.Data(),o.cutRange)) { coutE(Plotting) << ClassName() << "::" << GetName() << ":plotAsymOn: createHistogram() failed" << endl; return 0; @@ -1953,10 +1943,6 @@ RooPlot* RooAbsData::plotAsymOn(RooPlot* frame, const RooAbsCategoryLValue& asym // add the RooHist to the specified plot frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm); - // cleanup - delete hist1; - delete hist2; - return frame; } @@ -1990,22 +1976,22 @@ RooPlot* RooAbsData::plotEffOn(RooPlot* frame, const RooAbsCategoryLValue& effCa // create and fill temporary histograms of this variable for each state TString hist1Name(GetName()),hist2Name(GetName()); hist1Name.Append("_plot1"); - TH1F *hist1, *hist2 ; + std::unique_ptr hist1, hist2; hist2Name.Append("_plot2"); if (o.bins) { - hist1= var->createHistogram(hist1Name.Data(), "Events", *o.bins) ; - hist2= var->createHistogram(hist2Name.Data(), "Events", *o.bins) ; + hist1.reset( var->createHistogram(hist1Name.Data(), "Events", *o.bins) ); + hist2.reset( var->createHistogram(hist2Name.Data(), "Events", *o.bins) ); } else { - hist1= var->createHistogram(hist1Name.Data(), "Events", + hist1.reset( var->createHistogram(hist1Name.Data(), "Events", frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), - frame->GetNbinsX()); - hist2= var->createHistogram(hist2Name.Data(), "Events", + frame->GetNbinsX()) ); + hist2.reset( var->createHistogram(hist2Name.Data(), "Events", frame->GetXaxis()->GetXmin(), frame->GetXaxis()->GetXmax(), - frame->GetNbinsX()); + frame->GetNbinsX()) ); } - assert(0 != hist1 && 0 != hist2); + assert(hist1 && hist2); TString cuts1,cuts2 ; if (o.cuts && strlen(o.cuts)) { @@ -2016,8 +2002,8 @@ RooPlot* RooAbsData::plotEffOn(RooPlot* frame, const RooAbsCategoryLValue& effCa cuts2 = Form("(%s==0)",effCat.GetName()); } - if(0 == fillHistogram(hist1,RooArgList(*var),cuts1.Data(),o.cutRange) || - 0 == fillHistogram(hist2,RooArgList(*var),cuts2.Data(),o.cutRange)) { + if(! fillHistogram(hist1.get(), RooArgList(*var),cuts1.Data(),o.cutRange) || + ! fillHistogram(hist2.get(), RooArgList(*var),cuts2.Data(),o.cutRange)) { coutE(Plotting) << ClassName() << "::" << GetName() << ":plotEffOn: createHistogram() failed" << endl; return 0; @@ -2047,10 +2033,6 @@ RooPlot* RooAbsData::plotEffOn(RooPlot* frame, const RooAbsCategoryLValue& effCa // add the RooHist to the specified plot frame->addPlotable(graph,o.drawOptions,o.histInvisible,o.refreshFrameNorm); - // cleanup - delete hist1; - delete hist2; - return frame; } From caf9c770dbdda1477c5e959df62435c411241b82 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 10:46:21 +0200 Subject: [PATCH 154/309] [RF] Check preconditions of RooDataHist::calcTreeIndex in debug builds. Callers can set the fast argument to retrieve coordinates by index instead of name. Now, the the assumption that the coordinates have the same index is checked in debug builds. --- roofit/roofitcore/src/RooDataHist.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roofit/roofitcore/src/RooDataHist.cxx b/roofit/roofitcore/src/RooDataHist.cxx index 6e29eacfbcd19..84cf2c0f6897a 100644 --- a/roofit/roofitcore/src/RooDataHist.cxx +++ b/roofit/roofitcore/src/RooDataHist.cxx @@ -977,7 +977,7 @@ Int_t RooDataHist::getIndex(const RooAbsCollection& coord, Bool_t fast) const { std::size_t RooDataHist::calcTreeIndex(const RooAbsCollection& coords, bool fast) const { // With fast, caller promises that layout of "coords" is identical to our internal "vars" - assert(!fast || _vars.size() == coords.size()); + assert(!fast || coords.hasSameLayout(_vars)); if (&_vars == &coords) fast = true; From 5ad86c541d5cbf7958e1c5ce1d66af9c5c4217c8 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 10:59:02 +0200 Subject: [PATCH 155/309] [RF][NFC] Unify access to integrand in RooBinIntegrators constructor. The constructors were mixing _function and integrand(), which resolve to the same object in the end. --- roofit/roofitcore/src/RooBinIntegrator.cxx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/roofit/roofitcore/src/RooBinIntegrator.cxx b/roofit/roofitcore/src/RooBinIntegrator.cxx index ac5271eb82912..865aff35dae16 100644 --- a/roofit/roofitcore/src/RooBinIntegrator.cxx +++ b/roofit/roofitcore/src/RooBinIntegrator.cxx @@ -77,7 +77,7 @@ RooBinIntegrator::RooBinIntegrator(const RooAbsFunc& function) : RooAbsIntegrator(function) { _useIntegrandLimits= kTRUE; - assert(0 != integrand() && integrand()->isValid()); + assert(_function && _function->isValid()); // Allocate coordinate buffer size after number of function dimensions _x = new Double_t[_function->getDimension()] ; @@ -86,18 +86,18 @@ RooBinIntegrator::RooBinIntegrator(const RooAbsFunc& function) : _xmin.resize(_function->getDimension()) ; _xmax.resize(_function->getDimension()) ; - auto realBinding = dynamic_cast(integrand()); + auto realBinding = dynamic_cast(_function); if (realBinding) { _evalData.reset(new RooBatchCompute::RunContext()); _evalDataOrig.reset(new RooBatchCompute::RunContext()); } for (UInt_t i=0 ; i<_function->getDimension() ; i++) { - _xmin[i]= integrand()->getMinLimit(i); - _xmax[i]= integrand()->getMaxLimit(i); + _xmin[i]= _function->getMinLimit(i); + _xmax[i]= _function->getMaxLimit(i); // Retrieve bin configuration from integrand - std::unique_ptr> tmp{ integrand()->binBoundaries(i) }; + std::unique_ptr> tmp{ _function->binBoundaries(i) }; if (!tmp) { oocoutW((TObject*)0,Integration) << "RooBinIntegrator::RooBinIntegrator WARNING: integrand provide no binning definition observable #" << i << " substituting default binning of " << _numBins << " bins" << endl ; @@ -130,23 +130,23 @@ RooBinIntegrator::RooBinIntegrator(const RooAbsFunc& function, const RooNumIntCo const RooArgSet& configSet = config.getConfigSection(IsA()->GetName()) ; _useIntegrandLimits= kTRUE; _numBins = (Int_t) configSet.getRealValue("numBins") ; - assert(0 != integrand() && integrand()->isValid()); + assert(_function && _function->isValid()); // Allocate coordinate buffer size after number of function dimensions _x = new Double_t[_function->getDimension()] ; - auto realBinding = dynamic_cast(integrand()); + auto realBinding = dynamic_cast(_function); if (realBinding) { _evalData.reset(new RooBatchCompute::RunContext()); _evalDataOrig.reset(new RooBatchCompute::RunContext()); } for (UInt_t i=0 ; i<_function->getDimension() ; i++) { - _xmin.push_back(integrand()->getMinLimit(i)); - _xmax.push_back(integrand()->getMaxLimit(i)); + _xmin.push_back(_function->getMinLimit(i)); + _xmax.push_back(_function->getMaxLimit(i)); // Retrieve bin configuration from integrand - std::unique_ptr> tmp{ integrand()->binBoundaries(i) }; + std::unique_ptr> tmp{ _function->binBoundaries(i) }; if (!tmp) { oocoutW((TObject*)0,Integration) << "RooBinIntegrator::RooBinIntegrator WARNING: integrand provide no binning definition observable #" << i << " substituting default binning of " << _numBins << " bins" << endl ; From af76bcea4c345b1d4474d307e1626ff93609807f Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 11:09:10 +0200 Subject: [PATCH 156/309] [HF] Use ROOT's make_unique in HistFactory. --- roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx index e9264bf067493..ec179702afa8b 100644 --- a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx +++ b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx @@ -64,6 +64,7 @@ #include "TStopwatch.h" #include "TVectorD.h" #include "TMatrixDSym.h" +#include "ROOT/RMakeUnique.hxx" // specific to this package #include "RooStats/HistFactory/LinInterpVar.h" @@ -492,7 +493,7 @@ RooArgList HistoToWorkspaceFactoryFast::createObservables(const TH1 *hist, RooWo string overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_scaleFactors"; auto sigEps = proto->arg(sigmaEpsilon.c_str()); assert(sigEps); - std::unique_ptr normFactor( new RooProduct(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(), RooArgList(*sigEps) ) ); + auto normFactor = std::make_unique(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(), RooArgList(*sigEps)); if(normList.size() > 0){ From 5dc31c8e6cf71c2b40fbc7cfdaa3ad149e39518a Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 11:51:11 +0200 Subject: [PATCH 157/309] [RF] Extend RooArg{Set|List}'s iterator constructor to accept pointers. So far, the constructor took only direct objects, but with a small change it can also support e.g. vector. --- roofit/roofitcore/inc/RooArgList.h | 9 +++++---- roofit/roofitcore/inc/RooArgSet.h | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/roofit/roofitcore/inc/RooArgList.h b/roofit/roofitcore/inc/RooArgList.h index d1c8748a62911..e35eb36f944c2 100644 --- a/roofit/roofitcore/inc/RooArgList.h +++ b/roofit/roofitcore/inc/RooArgList.h @@ -42,17 +42,17 @@ class RooArgList : public RooAbsCollection { } /// Construct from iterators. - /// \tparam Iterator_t An iterator pointing to RooFit objects or references thereof. + /// \tparam Iterator_t An iterator pointing to RooFit objects or pointers/references thereof. /// \param beginIt Iterator to first element to add. - /// \param end Iterator to end of range to be added. + /// \param endIt Iterator to end of range to be added. /// \param name Optional name of the collection. template::value_type, + typename value_type = typename std::remove_pointer::value_type>, typename = std::enable_if::value> > RooArgList(Iterator_t beginIt, Iterator_t endIt, const char* name="") : RooArgList(name) { for (auto it = beginIt; it != endIt; ++it) { - add(*it); + processArg(*it); } } @@ -92,6 +92,7 @@ class RooArgList : public RooAbsCollection { private: void processArg(const RooAbsArg& arg) { add(arg); } + void processArg(const RooAbsArg* arg) { add(*arg); } void processArg(const char* name) { _name = name; } ClassDef(RooArgList,1) // Ordered list of RooAbsArg objects diff --git a/roofit/roofitcore/inc/RooArgSet.h b/roofit/roofitcore/inc/RooArgSet.h index 9aaa29979d2a3..a684c171ead13 100644 --- a/roofit/roofitcore/inc/RooArgSet.h +++ b/roofit/roofitcore/inc/RooArgSet.h @@ -58,18 +58,18 @@ class RooArgSet : public RooAbsCollection { (void)dummy; } - /// Construct from iterators. - /// \tparam Iterator_t An iterator pointing to RooFit objects or references thereof. + /// Construct a (non-owning) RooArgSet from iterators. + /// \tparam Iterator_t An iterator pointing to RooFit objects or to pointers/references of those. /// \param beginIt Iterator to first element to add. - /// \param end Iterator to end of range to be added. + /// \param endIt Iterator to end of range to be added. /// \param name Optional name of the collection. template::value_type, + typename value_type = typename std::remove_pointer::value_type>::type, typename = std::enable_if::value> > RooArgSet(Iterator_t beginIt, Iterator_t endIt, const char* name="") : RooArgSet(name) { for (auto it = beginIt; it != endIt; ++it) { - add(*it); + processArg(*it); } } @@ -129,6 +129,7 @@ class RooArgSet : public RooAbsCollection { private: void processArg(const RooAbsArg& var) { add(var); } + void processArg(const RooAbsArg* var) { add(*var); } void processArg(const RooArgSet& set) { add(set); if (_name.Length() == 0) _name = set.GetName(); } void processArg(const RooArgList& list); void processArg(const char* name) { _name = name; } From 03b6b1620de8b7213fb5b87d6f74e1760a91f3ba Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 7 Jun 2021 11:16:17 +0200 Subject: [PATCH 158/309] [HF] Simplify histFactory code using new RooArgSet constructor. --- roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx index ec179702afa8b..9f4e14730e119 100644 --- a/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx +++ b/roofit/histfactory/src/HistoToWorkspaceFactoryFast.cxx @@ -755,12 +755,7 @@ RooArgList HistoToWorkspaceFactoryFast::createObservables(const TH1 *hist, RooWo name = name.substr(0, pos) + "shapes"; } - RooArgSet terms; - for (auto func : thisSampleHistFuncs) { - terms.add(*func); - } - - RooProduct shapeProduct(name.c_str(), name.c_str(), terms); + RooProduct shapeProduct(name.c_str(), name.c_str(), RooArgSet(thisSampleHistFuncs.begin(), thisSampleHistFuncs.end())); proto->import(shapeProduct, RecycleConflictNodes()); shapeList.add(*proto->function(name.c_str())); } From 398a179ed525f438db226f2b12d253176b6aecbc Mon Sep 17 00:00:00 2001 From: Sitong An Date: Fri, 11 Jun 2021 11:59:21 +0200 Subject: [PATCH 159/309] [TMVA SOFIE] Fast Inference Code Generation Initial Commit (#7544) * initial commit for tmva-sofie fast inference code generation system. * Fix cmake issues for tmva-sofie. Specifically, fix cmake issues related to protobuf * Clean up cmake files * fix DeepCode memory leak commplaint, change unidirectional_broadcast to return a T* * fix DeepCode ofstream warning * fix Deepcode std ector empty warning * fix cmake comments for sofie pr * fix Cmake file include_dir * add build option * add Rmodel.hxx sstream include * Add readme * Update and test sofie cmake as per Oksana's request * remove empty line * remove NO_CXXMODULE line --- CMakeLists.txt | 2 +- cmake/modules/RootBuildOptions.cmake | 1 + cmake/modules/SearchInstalledSoftware.cmake | 24 + tmva/CMakeLists.txt | 6 +- tmva/rmva/CMakeLists.txt | 2 +- tmva/sofie/CMakeLists.txt | 44 ++ tmva/sofie/README.md | 47 ++ tmva/sofie/inc/LinkDef.h | 15 + tmva/sofie/inc/TMVA/OperatorList.hxx | 3 + tmva/sofie/inc/TMVA/RModel.hxx | 122 ++++ tmva/sofie/inc/TMVA/RModelParser_ONNX.hxx | 56 ++ tmva/sofie/inc/TMVA/ROperator.hxx | 45 ++ tmva/sofie/inc/TMVA/ROperator_Gemm.hxx | 199 ++++++ tmva/sofie/inc/TMVA/ROperator_Relu.hxx | 70 ++ tmva/sofie/inc/TMVA/ROperator_Transpose.hxx | 120 ++++ tmva/sofie/inc/TMVA/SOFIE_common.hxx | 91 +++ tmva/sofie/onnx_proto3 | 717 ++++++++++++++++++++ tmva/sofie/src/Prototype.cxx | 62 ++ tmva/sofie/src/RModel.cxx | 355 ++++++++++ tmva/sofie/src/RModelParser_ONNX.cxx | 299 ++++++++ tmva/sofie/src/SOFIE_common.cxx | 107 +++ 21 files changed, 2384 insertions(+), 3 deletions(-) create mode 100644 tmva/sofie/CMakeLists.txt create mode 100644 tmva/sofie/README.md create mode 100644 tmva/sofie/inc/LinkDef.h create mode 100644 tmva/sofie/inc/TMVA/OperatorList.hxx create mode 100644 tmva/sofie/inc/TMVA/RModel.hxx create mode 100644 tmva/sofie/inc/TMVA/RModelParser_ONNX.hxx create mode 100644 tmva/sofie/inc/TMVA/ROperator.hxx create mode 100644 tmva/sofie/inc/TMVA/ROperator_Gemm.hxx create mode 100644 tmva/sofie/inc/TMVA/ROperator_Relu.hxx create mode 100644 tmva/sofie/inc/TMVA/ROperator_Transpose.hxx create mode 100644 tmva/sofie/inc/TMVA/SOFIE_common.hxx create mode 100644 tmva/sofie/onnx_proto3 create mode 100644 tmva/sofie/src/Prototype.cxx create mode 100644 tmva/sofie/src/RModel.cxx create mode 100644 tmva/sofie/src/RModelParser_ONNX.cxx create mode 100644 tmva/sofie/src/SOFIE_common.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 0615ee50b61f0..ac6efba6ab539 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. +# Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. # All rights reserved. # # For the licensing terms see $ROOTSYS/LICENSE. diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index 1cc9f48926367..26d21b1ee7fdb 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -172,6 +172,7 @@ ROOT_BUILD_OPTION(tcmalloc OFF "Use tcmalloc memory allocator") ROOT_BUILD_OPTION(tmva ON "Build TMVA multi variate analysis library") ROOT_BUILD_OPTION(tmva-cpu ON "Build TMVA with CPU support for deep learning (requires BLAS)") ROOT_BUILD_OPTION(tmva-gpu OFF "Build TMVA with GPU support for deep learning (requries CUDA)") +ROOT_BUILD_OPTION(tmva-sofie OFF "Build TMVA with support for sofie - fast inference code generation (requires protobuf 3)") ROOT_BUILD_OPTION(tmva-pymva ON "Enable support for Python in TMVA (requires numpy)") ROOT_BUILD_OPTION(tmva-rmva OFF "Enable support for R in TMVA") ROOT_BUILD_OPTION(spectrum ON "Enable support for TSpectrum") diff --git a/cmake/modules/SearchInstalledSoftware.cmake b/cmake/modules/SearchInstalledSoftware.cmake index c64ab05414e21..881b3d5e2ac50 100644 --- a/cmake/modules/SearchInstalledSoftware.cmake +++ b/cmake/modules/SearchInstalledSoftware.cmake @@ -1600,6 +1600,30 @@ if (vecgeom) endif() endif() +#---Check for protobuf------------------------------------------------------------------- + +if(tmva-sofie) + message(STATUS "Looking for Protobuf") + find_package(Protobuf) + if(NOT Protobuf_FOUND) + if(fail-on-missing) + message(FATAL_ERROR "Protobuf libraries not found and they are required (tmva-sofie option enabled)") + else() + message(STATUS "Protobuf not found. Switching off tmva-sofie option") + set(tmva-sofie OFF CACHE BOOL "Disabled because Protobuf not found" FORCE) + endif() + else() + if(Protobuf_VERSION LESS 3.0) + if(fail-on-missing) + message(FATAL_ERROR "Protobuf libraries found but is less than the version required (3.0) (tmva-sofie option enabled)") + else() + message(STATUS "Protobuf found but its version is not high enough (>3.0). Switching off tmva-sofie option") + set(tmva-sofie OFF CACHE BOOL "Disabled because found Protobuf version is not enough" FORCE) + endif() + endif() + endif() +endif() + #---Check for CUDA----------------------------------------------------------------------- # if tmva-gpu is off and cuda is on cuda is searched but not used in tmva # if cuda is off but tmva-gpu is on cuda is searched and activated if found ! diff --git a/tmva/CMakeLists.txt b/tmva/CMakeLists.txt index b7dfb09fbf33d..6868f6cfa808e 100644 --- a/tmva/CMakeLists.txt +++ b/tmva/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. +# Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. # All rights reserved. # # For the licensing terms see $ROOTSYS/LICENSE. @@ -16,3 +16,7 @@ endif() if(r OR tmva-rmva) add_subdirectory(rmva) endif() + +if (tmva-sofie) + add_subdirectory(sofie) +endif() diff --git a/tmva/rmva/CMakeLists.txt b/tmva/rmva/CMakeLists.txt index bd2d698d950b5..4690d1417f02b 100644 --- a/tmva/rmva/CMakeLists.txt +++ b/tmva/rmva/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. +# Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. # All rights reserved. # # For the licensing terms see $ROOTSYS/LICENSE. diff --git a/tmva/sofie/CMakeLists.txt b/tmva/sofie/CMakeLists.txt new file mode 100644 index 0000000000000..aa4834baf1d1d --- /dev/null +++ b/tmva/sofie/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. +# All rights reserved. +# +# For the licensing terms see $ROOTSYS/LICENSE. +# For the list of contributors see $ROOTSYS/README/CREDITS. + +############################################################################ +# CMakeLists.txt file for building TMVA SOFIE package +############################################################################ +#Author: Sitong An, Lorenzo Moneta 10/03/2021 + +#sofie is built only if protobuf is found + +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS "onnx_proto3") +set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE) + +ROOT_STANDARD_LIBRARY_PACKAGE(ROOTTMVASofie + HEADERS + TMVA/OperatorList.hxx + TMVA/RModel.hxx + TMVA/RModelParser_ONNX.hxx + TMVA/ROperator.hxx + TMVA/ROperator_Gemm.hxx + TMVA/ROperator_Relu.hxx + TMVA/ROperator_Transpose.hxx + TMVA/SOFIE_common.hxx + ${PROTO_HDRS} + SOURCES + src/RModel.cxx + src/RModelParser_ONNX.cxx + src/SOFIE_common.cxx + ${PROTO_SRCS} + LIBRARIES + ${Protobuf_LIBRARIES} + DEPENDENCIES + TMVA +) + +target_include_directories(ROOTTMVASofie PUBLIC + $) +target_include_directories(ROOTTMVASofie PUBLIC + ${Protobuf_INCLUDE_DIRS}) +set_target_properties(ROOTTMVASofie PROPERTIES + POSITION_INDEPENDENT_CODE TRUE) diff --git a/tmva/sofie/README.md b/tmva/sofie/README.md new file mode 100644 index 0000000000000..d309b62ce737e --- /dev/null +++ b/tmva/sofie/README.md @@ -0,0 +1,47 @@ + +## About + +ROOT/TMVA SOFIE (“System for Optimized Fast Inference code Emit”) generates C++ functions easily invokable for the fast inference of trained neural network models. It takes ONNX model files as inputs and produces C++ header files that can be included and utilized in a “plug-and-go” style. + +This is a new development in TMVA and is currently in early experimental stage. Bug reports and suggestions for improvements are [warmly welcomed](mailto:s.an@cern.ch). + + +## Prerequisite + +- Protobuf 3.0 or higher (for input of ONNX model files) +- BLAS or Eigen (for execution of the generated code for inference) + +## Installation + +Build ROOT with the cmake option tmva-sofie enabled. + + $ cmake ../root -Dtmva-sofie=ON + $ make -j8 + + +## Usage + + +From ROOT command line, or in a ROOT macro: + + using namespace TMVA::Experimental; + SOFIE::RModelParser_ONNX parser; + SOFIE::RModel model = parser.Parse(“./example_model.onnx”); + model.Generate(); + model.OutputGenerated(“./example_output.hxx”); + +And an C++ header file will be generated. You can also use + + model.PrintRequiredInputTensors(); + +to check the required size and type of input tensor for that particular model, and use + + model.PrintInitializedTensors(); + +to check the tensors (weights) already included in the model. + +To use the generated inference code: + + #include "example_output.hxx" + float input[INPUT_SIZE]; + std::vector out = TMVA_SOFIE_example_model::infer(input); diff --git a/tmva/sofie/inc/LinkDef.h b/tmva/sofie/inc/LinkDef.h new file mode 100644 index 0000000000000..4a634e3793f11 --- /dev/null +++ b/tmva/sofie/inc/LinkDef.h @@ -0,0 +1,15 @@ +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link off all namespaces; + +#pragma link C++ nestedclass; + + +// the classifiers +#pragma link C++ class TMVA::Experimental::SOFIE::RModel+; +#pragma link C++ class TMVA::Experimental::SOFIE::RModelParser_ONNX+; + +#endif diff --git a/tmva/sofie/inc/TMVA/OperatorList.hxx b/tmva/sofie/inc/TMVA/OperatorList.hxx new file mode 100644 index 0000000000000..3b7052c70e267 --- /dev/null +++ b/tmva/sofie/inc/TMVA/OperatorList.hxx @@ -0,0 +1,3 @@ +#include "TMVA/ROperator_Transpose.hxx" +#include "TMVA/ROperator_Gemm.hxx" +#include "TMVA/ROperator_Relu.hxx" diff --git a/tmva/sofie/inc/TMVA/RModel.hxx b/tmva/sofie/inc/TMVA/RModel.hxx new file mode 100644 index 0000000000000..83c152b0bf39d --- /dev/null +++ b/tmva/sofie/inc/TMVA/RModel.hxx @@ -0,0 +1,122 @@ +#ifndef TMVA_SOFIE_RMODEL +#define TMVA_SOFIE_RMODEL + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TMVA/SOFIE_common.hxx" +#include "TMVA/ROperator.hxx" + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +class RModel{ + +private: + + std::unordered_map fInputTensorInfos; //graph input only; not including operator input (intermediate tensors) + std::unordered_map fReadyInputTensorInfos; + std::unordered_map fInitializedTensors; + std::unordered_map fIntermediateTensorInfos; + std::vector fOutputTensorNames; + + std::vector> fOperators; + + std::string fName="UnnamedModel"; + std::string fFileName; //file name of original model file for identification + std::string fParseTime; //UTC date and time string at parsing + + + std::string fGC; //generated code + bool fNeedGemm = true; + + const std::vector fAllowedStdLib = {"algorithm"}; + std::set fNeededStdLib = {"vector"}; + + + +public: + + //explicit move ctor/assn + RModel(RModel&& other); + + RModel& operator=(RModel&& other); + + //disallow copy + RModel(const RModel& other) = delete; + RModel& operator=(const RModel& other) = delete; + + RModel(){} + RModel(std::string name, std::string parsedtime); + + const std::vector& GetTensorShape(std::string name); + const ETensorType& GetTensorType(std::string name); + + bool CheckIfTensorAlreadyExist(std::string tensor_name); + void AddInputTensorInfo(std::string input_name, ETensorType type, std::vector shape); + void AddInputTensorInfo(std::string input_name, ETensorType type, std::vector shape); + void AddOperator(std::unique_ptr op, int order_execution = -1); + void AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector shape, std::shared_ptr data); + void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector shape); + void AddNeededStdLib(std::string libname){ + for (auto& i: fAllowedStdLib){ + if ( i == libname) fNeededStdLib.insert(libname); + } + } + void AddOutputTensorNameList(std::vector outputtensornames){ + fOutputTensorNames = outputtensornames; + } + void UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector shape, std::shared_ptr data); + std::shared_ptr GetInitializedTensorData(std::string tensor_name); + + + void Initialize(); + void Generate(); + + void PrintGenerated(){ + std::cout << fGC; + } + void PrintIntermediateTensors(); + void OutputGenerated(std::string filename = ""); + + +/* + template + void AddInitializedTensor(std::string tensor_name, RTensor new_tensor){ + //a view only + T obj; + if (fInitializedTensors.find(tensor_name) != fInitializedTensors.end()){ + throw std::runtime_error("TMVA-SOFIE: initialized tensor with name " + tensor_name + " already exists \n"); + } + InitializedTensor new_tensor_ {GetTemplatedType(obj), new_tensor.GetShape() , static_cast(new_tensor.GetData())}; + fInitializedTensors[tensor_name] = new_tensor_; + } +*/ + + void PrintRequiredInputTensors(); + void PrintInitializedTensors(); + void HeadInitializedTensors(std::string name, int n_print = 50); + + ~RModel(){ + /* + for (auto& i: fInitializedTensors){ + free(i.second.data); + } + */ + } + +}; + +}//SOFIE +}//Experimental +}//TMVA + +#endif //TMVA_SOFIE_RMODEL diff --git a/tmva/sofie/inc/TMVA/RModelParser_ONNX.hxx b/tmva/sofie/inc/TMVA/RModelParser_ONNX.hxx new file mode 100644 index 0000000000000..7c32c15fbf6f5 --- /dev/null +++ b/tmva/sofie/inc/TMVA/RModelParser_ONNX.hxx @@ -0,0 +1,56 @@ +#ifndef TMVA_SOFIE_RMODELPARSER_ONNX +#define TMVA_SOFIE_RMODELPARSER_ONNX + + + +#include "SOFIE_common.hxx" +#include "RModel.hxx" +#include "OperatorList.hxx" + +#include +#include +#include +#include + +//forward delcaration +namespace onnx{ + class NodeProto; + class GraphProto; +} + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +namespace INTERNAL{ + +std::unique_ptr make_ROperator_Transpose(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type); +std::unique_ptr make_ROperator_Relu(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type); +std::unique_ptr make_ROperator_Gemm(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type); + + +using factoryMethodMap = std::unordered_map (*)(const onnx::NodeProto&, const onnx::GraphProto&, std::unordered_map&)>; +const factoryMethodMap mapOptypeOperator = { + {"Gemm", &make_ROperator_Gemm}, + {"Transpose", &make_ROperator_Transpose}, + {"Relu", &make_ROperator_Relu} + }; + + +std::unique_ptr make_ROperator(size_t idx, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type); +}//INTERNAL + + + +class RModelParser_ONNX{ +public: + RModel Parse(std::string filename); +}; + + + +}//SOFIE +}//Experimental +}//TMVA + +#endif //TMVA_SOFIE_RMODELPARSER_ONNX diff --git a/tmva/sofie/inc/TMVA/ROperator.hxx b/tmva/sofie/inc/TMVA/ROperator.hxx new file mode 100644 index 0000000000000..00e2a228b396c --- /dev/null +++ b/tmva/sofie/inc/TMVA/ROperator.hxx @@ -0,0 +1,45 @@ +#ifndef TMVA_SOFIE_ROPERATOR +#define TMVA_SOFIE_ROPERATOR + +#include +#include + +#include "TMVA/SOFIE_common.hxx" +//#include "RModel.hxx" + + + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +class RModel; + +class ROperator{ + + +public: + virtual std::vector> ShapeInference(std::vector>) = 0; + virtual std::vector TypeInference(std::vector) = 0; + virtual void Initialize(RModel&) = 0; + virtual std::string Generate(std::string OpName) = 0; //expect unique opname for each operator within the same RModel + virtual std::string Header() { return "";} + + + //virtual void Forward_reference() = 0; + //irtual void Forward_blas() = 0; + virtual ~ROperator(){} + + + + +}; + + + +}//SOFIE +}//Experimental +}//TMVA + + +#endif //TMVA_SOFIE_OPERATOR diff --git a/tmva/sofie/inc/TMVA/ROperator_Gemm.hxx b/tmva/sofie/inc/TMVA/ROperator_Gemm.hxx new file mode 100644 index 0000000000000..83337ba415e94 --- /dev/null +++ b/tmva/sofie/inc/TMVA/ROperator_Gemm.hxx @@ -0,0 +1,199 @@ +#ifndef TMVA_SOFIE_ROPERATOR_GEMM +#define TMVA_SOFIE_ROPERATOR_GEMM + + +#include "TMVA/SOFIE_common.hxx" +#include "TMVA/ROperator.hxx" +#include "TMVA/RModel.hxx" + +#include +#include +#include +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + + + template + class ROperator_Gemm final : public ROperator + { + + private: + float fAttrAlpha = 1.0; + float fAttrBeta = 1.0; + int_t fAttrTransA = 0; + int_t fAttrTransB = 0; + + std::string fNA; + std::string fNB; + std::string fNC = ""; + std::string fNY; + std::vector fShapeA; + std::vector fShapeB; + std::vector fShapeC; + std::vector fShapeY; + + std::string fType; + + public: + + ROperator_Gemm() = delete; + ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameY): + fAttrAlpha(alpha), fAttrBeta(beta), fAttrTransA(transA), fAttrTransB(transB), fNA(UTILITY::Clean_name(nameA)), + fNB(UTILITY::Clean_name(nameB)), fNY(UTILITY::Clean_name(nameY)) { + + if (std::is_same::value) { + fType = "float"; + }else{ + throw std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a gemm operator"); + } + } + + ROperator_Gemm(float alpha, float beta, int_t transA, int_t transB, std::string nameA, std::string nameB, std::string nameC, std::string nameY): + fAttrAlpha(alpha), fAttrBeta(beta), fAttrTransA(transA), fAttrTransB(transB), fNA(UTILITY::Clean_name(nameA)), + fNB(UTILITY::Clean_name(nameB)), fNC(UTILITY::Clean_name(nameC)), fNY(UTILITY::Clean_name(nameY)) { + + if (std::is_same::value) { + fType = "float"; + }else{ + throw std::runtime_error("TMVA SOFIE Encountered unsupported type parsing a gemm operator"); + } + } + + std::vector TypeInference(std::vector input){ + ETensorType out = input[0]; + return {out}; + } + + std::vector> ShapeInference(std::vector> input){ + if (input.size() > 3) throw std::runtime_error("TMVA SOFIE Gemm Op Shape Inference only need 2 or 3 input tensor"); + for (auto& i: input){ + if (i.size() > 2){ + throw std::runtime_error("TMVA SOFIE Gemm Op Shape Inference only accept input tensor with 2 dimensions"); + } + } + std::vector> ret; + if (input.size() == 3){ + ret.push_back(input[2]); //shape of C is shape of Y + return ret; + } + std::vector s_a(input[0]); + std::vector s_b(input[1]); + if (fAttrTransA){ + std::reverse(s_a.begin(), s_a.end()); + } + if (fAttrTransB){ + std::reverse(s_b.begin(), s_b.end()); + } + std::vector s_y(2); + s_y[0] = s_a[0]; + s_y[1] = s_b[1]; + ret.push_back(s_y); + return ret; + } + + + + void Initialize(RModel& model){ + //TODO: propagate A or B as specified by ONNX standard + + if ((model.CheckIfTensorAlreadyExist(fNA) == false) || (model.CheckIfTensorAlreadyExist(fNB) == false) ){ //input must be a graph input, or already initialized intermediate tensor + throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor " + fNA + " or " + fNB + " is not found in model"); + } + if (fNC != ""){ + if (model.CheckIfTensorAlreadyExist(fNC) == false){ //input must be a graph input, or already initialized intermediate tensor + throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNC + " is not found in model"); + } + } + fShapeA = model.GetTensorShape(fNA); + if (fShapeA.size() != 2){ + throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNA + " is not of 2 dimensions"); + } + fShapeB = model.GetTensorShape(fNB); + if (fShapeB.size() != 2){ + throw std::runtime_error("TMVA SOFIE Gemm Op Input Tensor" + fNB + " is not of 2 dimensions"); + } + fShapeY = ShapeInference({fShapeA, fShapeB})[0]; + if (fNC != ""){ + fShapeC = model.GetTensorShape(fNC); + + bool broadcast_needed = false; + for (int i =0; i < fShapeC.size(); i++){ + if (fShapeC[i]!=fShapeY[i]){ + broadcast_needed = true; + break; + } + } + + if (broadcast_needed){ + auto original_data = model.GetInitializedTensorData(fNC); + if (fType == "float"){ + + std::shared_ptr new_data_ptr(UTILITY::Unidirectional_broadcast(static_cast(original_data.get()), fShapeC, fShapeY), std::default_delete()); + + + model.UpdateInitializedTensor(fNC, model.GetTensorType(fNC), fShapeY, new_data_ptr); + fShapeC = fShapeY; + } + } + } + + + + + model.AddIntermediateTensor(fNY, model.GetTensorType(fNA), fShapeY); + model.AddNeededStdLib("algorithm"); + + } + + + + std::string Generate(std::string OpName){ + OpName = "op_" + OpName; + if (fShapeA.empty() || fShapeB.empty() || fShapeY.empty() || (fNC != "" && fShapeC.empty())){ + throw std::runtime_error("TMVA SOFIE Gemm Op called to Generate without being initialized first"); + } + std::stringstream out; + out <<"\t" << "char " << OpName << "_transA = " << (fAttrTransA ? "\'t\'" : "\'n\'") << ";\n"; + out <<"\t" << "char " << OpName << "_transB = " << (fAttrTransB ? "\'t\'" : "\'n\'") << ";\n"; + int m = (fAttrTransA ? fShapeA[1] : fShapeA[0]); + int n = (fAttrTransB ? fShapeB[0] : fShapeB[1]); + int k = (fAttrTransA ? fShapeA[0] : fShapeA[1]); + out <<"\t" << "int " << OpName << "_m = " << m << ";\n"; + out <<"\t" << "int " << OpName << "_n = " << n << ";\n"; + out <<"\t" << "int " << OpName << "_k = " << k << ";\n"; + out <<"\t" << "float " << OpName << "_alpha = " << std::setprecision(std::numeric_limits::max_digits10) << fAttrAlpha << ";\n"; + out <<"\t" << "float " << OpName << "_beta = " << std::setprecision(std::numeric_limits::max_digits10) << fAttrBeta << ";\n"; + out <<"\t" << "int " << OpName << "_lda = " << (fAttrTransA ? m : k) << ";\n"; + out <<"\t" << "int " << OpName << "_ldb = " << (fAttrTransB ? k : n) << ";\n"; + if (fNC != ""){ + int length = 1; + for (auto& i: fShapeC){ + length *= i; + } + out << "\t" << "std::copy(" << "tensor_" << fNC << ", " << "tensor_" << fNC << " + " << length << ", " << "tensor_" << fNY << ");\n"; + } + if (fType == "float"){ + out << "\t" << "BLAS::sgemm_(&" << OpName << "_transB, &" << OpName << "_transA, &" << OpName + << "_n, &" << OpName << "_m, &" << OpName << "_k, &" << OpName << "_alpha, " << "tensor_" << fNB + << ", &" << OpName << "_ldb, " << "tensor_" << fNA << ", &" << OpName << "_lda, &" << OpName << "_beta, " << "tensor_" << fNY << ", &" + << OpName << "_n);\n"; + } + + return out.str(); + + } + + + + }; + + +}//SOFIE +}//Experimental +}//TMVA + + +#endif //TMVA_SOFIE_ROPERATOR_GEMM diff --git a/tmva/sofie/inc/TMVA/ROperator_Relu.hxx b/tmva/sofie/inc/TMVA/ROperator_Relu.hxx new file mode 100644 index 0000000000000..82009d8651f2e --- /dev/null +++ b/tmva/sofie/inc/TMVA/ROperator_Relu.hxx @@ -0,0 +1,70 @@ +#ifndef TMVA_SOFIE_ROPERATOR_RELU +#define TMVA_SOFIE_ROPERATOR_RELU + +#include "TMVA/SOFIE_common.hxx" +#include "TMVA/ROperator.hxx" +#include "TMVA/RModel.hxx" + +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +template +class ROperator_Relu final : public ROperator +{ + +private: + + std::string fNX; + std::string fNY; + std::vector fShape; + +public: + ROperator_Relu() = delete; + ROperator_Relu(std::string nameX, std::string nameY): + fNX(UTILITY::Clean_name(nameX)), fNY(UTILITY::Clean_name(nameY)){} + + std::vector TypeInference(std::vector input){ + return input; + } + + std::vector> ShapeInference(std::vector> input){ + auto ret = input; //suggest copy to compiler + return ret; + } + + void Initialize(RModel& model){ + if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor + throw std::runtime_error("TMVA SOFIE Relu Op Input Tensor is not found in model"); + } + fShape = model.GetTensorShape(fNX); + model.AddIntermediateTensor(fNY, model.GetTensorType(fNX), fShape); + } + + + std::string Generate(std::string OpName){ + OpName = "op_" + OpName; + if (fShape.empty()){ + throw std::runtime_error("TMVA SOFIE Transpose Relu called to Generate without being initialized first"); + } + std::stringstream out; + int length = 1; + for(auto& i: fShape){ + length *= i; + } + out << "\t" << "for (int id = 0; id < " << length << " ; id++){\n"; + out << "\t\t" << "tensor_" << fNY << "[id] = ((tensor_" << fNX << "[id] > 0 )? tensor_" << fNX << "[id] : 0);\n"; + out << "\t}\n"; + return out.str(); + } + +}; + +}//SOFIE +}//Experimental +}//TMVA + + +#endif //TMVA_SOFIE_ROPERATOR_TRANSPOSE diff --git a/tmva/sofie/inc/TMVA/ROperator_Transpose.hxx b/tmva/sofie/inc/TMVA/ROperator_Transpose.hxx new file mode 100644 index 0000000000000..e7ca1c6c26580 --- /dev/null +++ b/tmva/sofie/inc/TMVA/ROperator_Transpose.hxx @@ -0,0 +1,120 @@ +#ifndef TMVA_SOFIE_ROPERATOR_TRANSPOSE +#define TMVA_SOFIE_ROPERATOR_TRANSPOSE + +#include "TMVA/SOFIE_common.hxx" +#include "TMVA/ROperator.hxx" +#include "TMVA/RModel.hxx" + +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + + + + +template +class ROperator_Transpose final : public ROperator +{ + +private: + std::vector fAttrPerm; + + std::string fNData; + std::string fNOutput; + std::vector fShapeData; + std::vector fShapeOutput; + +public: + + ROperator_Transpose() = delete; + ROperator_Transpose(std::vector attr_perm, std::string nameData, std::string nameOutput): + fAttrPerm(attr_perm), fNData(UTILITY::Clean_name(nameData)), fNOutput(UTILITY::Clean_name(nameOutput)) { + } + + ROperator_Transpose(std::string nameData, std::string nameOutput): + fNData(UTILITY::Clean_name(nameData)), fNOutput(UTILITY::Clean_name(nameOutput)) { + } + + std::vector TypeInference(std::vector input){ + return input; + } + + std::vector> ShapeInference(std::vector> input){ + if (input.size() > 1) throw std::runtime_error("TMVA SOFIE Tranpose Op Shape Inference only need 1 input tensor"); + auto& data = input[0]; + std::vector output_shape(fAttrPerm.size()); + for (int i = 0; i < fAttrPerm.size(); i++){ + output_shape[fAttrPerm[i]] = data[i]; + } + std::vector> ret; + ret.push_back(output_shape); + return ret; + } + + + void Initialize(RModel& model){ + if (model.CheckIfTensorAlreadyExist(fNData) == false){ //input must be a graph input, or already initialized intermediate tensor + throw std::runtime_error("TMVA SOFIE Tranpose Op Input Tensor is not found in model"); + } + fShapeData = model.GetTensorShape(fNData); + if (fAttrPerm.empty()){ + for (int i = fShapeData.size() - 1; i >= 0; i--){ + fAttrPerm.push_back(i); + } + } + + std::vector output_shape(fAttrPerm.size()); + for (int i = 0; i < fAttrPerm.size(); i++){ + output_shape[fAttrPerm[i]] = fShapeData[i]; + } + + model.AddIntermediateTensor(fNOutput, model.GetTensorType(fNData), output_shape); + fShapeOutput = output_shape; + } + + std::string Generate(std::string OpName){ + OpName = "op_" + OpName; + if (fShapeData.empty() || fShapeOutput.empty()){ + throw std::runtime_error("TMVA SOFIE Transpose Op called to Generate without being initialized first"); + } + int dim = fShapeData.size(); + int length=1; + std::vector sizeofindex(dim); + for (int i = dim - 1; i>=0; i--){ + sizeofindex[i] = length; + length *= fShapeData[i]; + } + std::vector index_goto(dim); + for (int i = 0; i < dim; i++){ + index_goto[fAttrPerm[i]] = i; + } + std::vector new_sizeofindex(dim); + int t = 1; + for (int i = dim - 1; i>=0; i--){ + new_sizeofindex[i] = t; + t *= fShapeOutput[i]; + } + + std::stringstream out; + out << "\t" << "for (int id = 0; id < " << length << " ; id++){\n"; + out << "\t\t " << "tensor_" << fNOutput << "["; + for (int i =0; i < dim; i++){ + out << "id / " << sizeofindex[i] << " % " << fShapeData[i] << " * " << new_sizeofindex[index_goto[i]]; + if (i != dim - 1) out << " + "; + } + out << "] = " << "tensor_" << fNData << "[id];\n"; + out << "\t}\n"; + return out.str(); + } + + +}; + +}//SOFIE +}//Experimental +}//TMVA + + +#endif //TMVA_SOFIE_ROPERATOR_TRANSPOSE diff --git a/tmva/sofie/inc/TMVA/SOFIE_common.hxx b/tmva/sofie/inc/TMVA/SOFIE_common.hxx new file mode 100644 index 0000000000000..9e5dd85178328 --- /dev/null +++ b/tmva/sofie/inc/TMVA/SOFIE_common.hxx @@ -0,0 +1,91 @@ +#ifndef TMVA_SOFIE_SOFIE_COMMON +#define TMVA_SOFIE_SOFIE_COMMON + +#include "TMVA/RTensor.hxx" + +#include +#include +#include +#include +#include +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +//typedef RTensor tensor_t; + +enum class ETensorType{ + UNDEFINED = 0, FLOAT = 1, UNINT8 = 2, INT8 = 3, UINT16 = 4, INT16 = 5, INT32 = 6, INT64 = 7, STRING = 8, BOOL = 9, //order sensitive + FLOAT16 = 10, DOUBLE = 11, UINT32 = 12, UINT64 = 13, COMPLEX64 = 14, COMPLEX28 = 15, BFLOAT16 = 16 +}; + +typedef std::int64_t int_t; + +std::string ConvertTypeToString(ETensorType type); + +struct Dim{ + bool isParam = false; + size_t dim; + std::string param; +}; + +std::vector ConvertShapeToDim(std::vector shape); + + +struct InputTensorInfo{ + ETensorType type; + std::vector shape; +}; + +struct TensorInfo{ + ETensorType type; + std::vector shape; +}; + +std::size_t ConvertShapeToLength(std::vector shape); + +struct InitializedTensor{ + ETensorType type; + std::vector shape; + std::shared_ptr data; + //void* data; +}; + +template +ETensorType GetTemplatedType(T obj){ + if (std::is_same::value) return ETensorType::FLOAT; + if (std::is_same::value) return ETensorType::UNINT8; + if (std::is_same::value) return ETensorType::INT8; + if (std::is_same::value) return ETensorType::UINT16; + if (std::is_same::value) return ETensorType::INT16; + if (std::is_same::value) return ETensorType::INT32; + if (std::is_same::value) return ETensorType::INT64; + if (std::is_same::value) return ETensorType::STRING; + if (std::is_same::value) return ETensorType::BOOL; + //float16 unimplemented + if (std::is_same::value) return ETensorType::DOUBLE; + if (std::is_same::value) return ETensorType::UINT32; + if (std::is_same::value) return ETensorType::UINT64; + //complex 64, 28, bfloat 16 unimplemented +} + +namespace UTILITY{ +template +T* Unidirectional_broadcast(const T* original_data, const std::vector original_shape, const std::vector target_shape); +std::string Clean_name(std::string input_tensor_name); +} + +namespace BLAS{ +extern "C" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k, + const float * alpha, const float * A, const int * lda, const float * B, const int * ldb, + const float * beta, float * C, const int * ldc); +}//BLAS + + +}//SOFIE +}//Experimental +}//TMVA + +#endif //TMVA_SOFIE_RMODEL diff --git a/tmva/sofie/onnx_proto3 b/tmva/sofie/onnx_proto3 new file mode 100644 index 0000000000000..9445d77716b67 --- /dev/null +++ b/tmva/sofie/onnx_proto3 @@ -0,0 +1,717 @@ +// +// WARNING: This file is automatically generated! Please edit onnx.in.proto. +// + + +// Copyright (c) ONNX Project Contributors. +// Licensed under the MIT license. + +syntax = "proto3"; + +package onnx; + +// Overview +// +// ONNX is an open specification that is comprised of the following components: +// +// 1) A definition of an extensible computation graph model. +// 2) Definitions of standard data types. +// 3) Definitions of built-in operators. +// +// This document describes the syntax of models and their computation graphs, +// as well as the standard data types. Together, they are referred to as the ONNX +// Intermediate Representation, or 'IR' for short. +// +// The normative semantic specification of the ONNX IR is found in docs/IR.md. +// Definitions of the built-in neural network operators may be found in docs/Operators.md. + +// Notes +// +// Release +// +// We are still in the very early stage of defining ONNX. The current +// version of ONNX is a starting point. While we are actively working +// towards a complete spec, we would like to get the community involved +// by sharing our working version of ONNX. +// +// Protobuf compatibility +// +// To simplify framework compatibility, ONNX is defined using the subset of protobuf +// that is compatible with both protobuf v2 and v3. This means that we do not use any +// protobuf features that are only available in one of the two versions. +// +// Here are the most notable contortions we have to carry out to work around +// these limitations: +// +// - No 'map' (added protobuf 3.0). We instead represent mappings as lists +// of key-value pairs, where order does not matter and duplicates +// are not allowed. + + +// Versioning +// +// ONNX versioning is specified in docs/IR.md and elaborated on in docs/Versioning.md +// +// To be compatible with both proto2 and proto3, we will use a version number +// that is not defined by the default value but an explicit enum number. +enum Version { + // proto3 requires the first enum value to be zero. + // We add this just to appease the compiler. + _START_VERSION = 0; + // The version field is always serialized and we will use it to store the + // version that the graph is generated from. This helps us set up version + // control. + // For the IR, we are using simple numbers starting with 0x00000001, + // which was the version we published on Oct 10, 2017. + IR_VERSION_2017_10_10 = 0x0000000000000001; + + // IR_VERSION 2 published on Oct 30, 2017 + // - Added type discriminator to AttributeProto to support proto3 users + IR_VERSION_2017_10_30 = 0x0000000000000002; + + // IR VERSION 3 published on Nov 3, 2017 + // - For operator versioning: + // - Added new message OperatorSetIdProto + // - Added opset_import in ModelProto + // - For vendor extensions, added domain in NodeProto + IR_VERSION_2017_11_3 = 0x0000000000000003; + + // IR VERSION 4 published on Jan 22, 2019 + // - Relax constraint that initializers should be a subset of graph inputs + // - Add type BFLOAT16 + IR_VERSION_2019_1_22 = 0x0000000000000004; + + // IR VERSION 5 published on March 18, 2019 + // - Add message TensorAnnotation. + // - Add quantization annotation in GraphProto to map tensor with its scale and zero point quantization parameters. + IR_VERSION_2019_3_18 = 0x0000000000000005; + + // IR VERSION 6 published on Sep 19, 2019 + // - Add support for sparse tensor constants stored in model. + // - Add message SparseTensorProto + // - Add sparse initializers + IR_VERSION_2019_9_19 = 0x0000000000000006; + + // IR VERSION 7 published on + // - Add support to allow function body graph to rely on multiple external opreator sets. + // - Add a list to promote inference graph's initializers to global and + // mutable variables. Global variables are visible in all graphs of the + // stored models. + // - Add message TrainingInfoProto to store initialization + // method and training algorithm. The execution of TrainingInfoProto + // can modify the values of mutable variables. + // - Implicitly add inference graph into each TrainingInfoProto's algorithm. + IR_VERSION = 0x0000000000000007; +} + +// Attributes +// +// A named attribute containing either singular float, integer, string, graph, +// and tensor values, or repeated float, integer, string, graph, and tensor values. +// An AttributeProto MUST contain the name field, and *only one* of the +// following content fields, effectively enforcing a C/C++ union equivalent. +message AttributeProto { + + // Note: this enum is structurally identical to the OpSchema::AttrType + // enum defined in schema.h. If you rev one, you likely need to rev the other. + enum AttributeType { + UNDEFINED = 0; + FLOAT = 1; + INT = 2; + STRING = 3; + TENSOR = 4; + GRAPH = 5; + SPARSE_TENSOR = 11; + + FLOATS = 6; + INTS = 7; + STRINGS = 8; + TENSORS = 9; + GRAPHS = 10; + SPARSE_TENSORS = 12; + } + + // The name field MUST be present for this version of the IR. + string name = 1; // namespace Attribute + + // if ref_attr_name is not empty, ref_attr_name is the attribute name in parent function. + // In this case, this AttributeProto does not contain data, and it's a reference of attribute + // in parent scope. + // NOTE: This should ONLY be used in function (sub-graph). It's invalid to be used in main graph. + string ref_attr_name = 21; + + // A human-readable documentation for this attribute. Markdown is allowed. + string doc_string = 13; + + // The type field MUST be present for this version of the IR. + // For 0.0.1 versions of the IR, this field was not defined, and + // implementations needed to use has_field heuristics to determine + // which value field was in use. For IR_VERSION 0.0.2 or later, this + // field MUST be set and match the f|i|s|t|... field in use. This + // change was made to accommodate proto3 implementations. + AttributeType type = 20; // discriminator that indicates which field below is in use + + // Exactly ONE of the following fields must be present for this version of the IR + float f = 2; // float + int64 i = 3; // int + bytes s = 4; // UTF-8 string + TensorProto t = 5; // tensor value + GraphProto g = 6; // graph + SparseTensorProto sparse_tensor = 22; // sparse tensor value + // Do not use field below, it's deprecated. + // optional ValueProto v = 12; // value - subsumes everything but graph + + repeated float floats = 7; // list of floats + repeated int64 ints = 8; // list of ints + repeated bytes strings = 9; // list of UTF-8 strings + repeated TensorProto tensors = 10; // list of tensors + repeated GraphProto graphs = 11; // list of graph + repeated SparseTensorProto sparse_tensors = 23; // list of sparse tensors +} + +// Defines information on value, including the name, the type, and +// the shape of the value. +message ValueInfoProto { + // This field MUST be present in this version of the IR. + string name = 1; // namespace Value + // This field MUST be present in this version of the IR for + // inputs and outputs of the top-level graph. + TypeProto type = 2; + // A human-readable documentation for this value. Markdown is allowed. + string doc_string = 3; +} + +// Nodes +// +// Computation graphs are made up of a DAG of nodes, which represent what is +// commonly called a "layer" or "pipeline stage" in machine learning frameworks. +// +// For example, it can be a node of type "Conv" that takes in an image, a filter +// tensor and a bias tensor, and produces the convolved output. +message NodeProto { + repeated string input = 1; // namespace Value + repeated string output = 2; // namespace Value + + // An optional identifier for this node in a graph. + // This field MAY be absent in ths version of the IR. + string name = 3; // namespace Node + + // The symbolic identifier of the Operator to execute. + string op_type = 4; // namespace Operator + // The domain of the OperatorSet that specifies the operator named by op_type. + string domain = 7; // namespace Domain + + // Additional named attributes. + repeated AttributeProto attribute = 5; + + // A human-readable documentation for this node. Markdown is allowed. + string doc_string = 6; +} + +// Training information +// TrainingInfoProto stores information for training a model. +// In particular, this defines two functionalities: an initialization-step +// and a training-algorithm-step. Initialization resets the model +// back to its original state as if no training has been performed. +// Training algorithm improves the model based on input data. +// +// The semantics of the initialization-step is that the initializers +// in ModelProto.graph and in TrainingInfoProto.algorithm are first +// initialized as specified by the initializers in the graph, and then +// updated by the "initialization_binding" in every instance in +// ModelProto.training_info. +// +// The field "algorithm" defines a computation graph which represents a +// training algorithm's step. After the execution of a +// TrainingInfoProto.algorithm, the initializers specified by "update_binding" +// may be immediately updated. If the targeted training algorithm contains +// consecutive update steps (such as block coordinate descent methods), +// the user needs to create a TrainingInfoProto for each step. +message TrainingInfoProto { + // This field describes a graph to compute the initial tensors + // upon starting the training process. Initialization graph has no input + // and can have multiple outputs. Usually, trainable tensors in neural + // networks are randomly initialized. To achieve that, for each tensor, + // the user can put a random number operator such as RandomNormal or + // RandomUniform in TrainingInfoProto.initialization.node and assign its + // random output to the specific tensor using "initialization_binding". + // This graph can also set the initializers in "algorithm" in the same + // TrainingInfoProto; a use case is resetting the number of training + // iteration to zero. + // + // By default, this field is an empty graph and its evaluation does not + // produce any output. Thus, no initializer would be changed by default. + GraphProto initialization = 1; + + // This field represents a training algorithm step. Given required inputs, + // it computes outputs to update initializers in its own or inference graph's + // initializer lists. In general, this field contains loss node, gradient node, + // optimizer node, increment of iteration count. + // + // An execution of the training algorithm step is performed by executing the + // graph obtained by combining the inference graph (namely "ModelProto.graph") + // and the "algorithm" graph. That is, the actual the actual + // input/initializer/output/node/value_info/sparse_initializer list of + // the training graph is the concatenation of + // "ModelProto.graph.input/initializer/output/node/value_info/sparse_initializer" + // and "algorithm.input/initializer/output/node/value_info/sparse_initializer" + // in that order. This combined graph must satisfy the normal ONNX conditions. + // Now, let's provide a visualization of graph combination for clarity. + // Let the inference graph (i.e., "ModelProto.graph") be + // tensor_a, tensor_b -> MatMul -> tensor_c -> Sigmoid -> tensor_d + // and the "algorithm" graph be + // tensor_d -> Add -> tensor_e + // The combination process results + // tensor_a, tensor_b -> MatMul -> tensor_c -> Sigmoid -> tensor_d -> Add -> tensor_e + // + // Notice that an input of a node in the "algorithm" graph may reference the + // output of a node in the inference graph (but not the other way round). Also, inference + // node cannot reference inputs of "algorithm". With these restrictions, inference graph + // can always be run independently without training information. + // + // By default, this field is an empty graph and its evaluation does not + // produce any output. Evaluating the default training step never + // update any initializers. + GraphProto algorithm = 2; + + // This field specifies the bindings from the outputs of "initialization" to + // some initializers in "ModelProto.graph.initializer" and + // the "algorithm.initializer" in the same TrainingInfoProto. + // See "update_binding" below for details. + // + // By default, this field is empty and no initializer would be changed + // by the execution of "initialization". + repeated StringStringEntryProto initialization_binding = 3; + + // Gradient-based training is usually an iterative procedure. In one gradient + // descent iteration, we apply + // + // x = x - r * g + // + // where "x" is the optimized tensor, "r" stands for learning rate, and "g" is + // gradient of "x" with respect to a chosen loss. To avoid adding assignments + // into the training graph, we split the update equation into + // + // y = x - r * g + // x = y + // + // The user needs to save "y = x - r * g" into TrainingInfoProto.algorithm. To + // tell that "y" should be assigned to "x", the field "update_binding" may + // contain a key-value pair of strings, "x" (key of StringStringEntryProto) + // and "y" (value of StringStringEntryProto). + // For a neural network with multiple trainable (mutable) tensors, there can + // be multiple key-value pairs in "update_binding". + // + // The initializers appears as keys in "update_binding" are considered + // mutable variables. This implies some behaviors + // as described below. + // + // 1. We have only unique keys in all "update_binding"s so that two + // variables may not have the same name. This ensures that one + // variable is assigned up to once. + // 2. The keys must appear in names of "ModelProto.graph.initializer" or + // "TrainingInfoProto.algorithm.initializer". + // 3. The values must be output names of "algorithm" or "ModelProto.graph.output". + // 4. Mutable variables are initialized to the value specified by the + // corresponding initializer, and then potentially updated by + // "initializer_binding"s and "update_binding"s in "TrainingInfoProto"s. + // + // This field usually contains names of trainable tensors + // (in ModelProto.graph), optimizer states such as momentums in advanced + // stochastic gradient methods (in TrainingInfoProto.graph), + // and number of training iterations (in TrainingInfoProto.graph). + // + // By default, this field is empty and no initializer would be changed + // by the execution of "algorithm". + repeated StringStringEntryProto update_binding = 4; +} + +// Models +// +// ModelProto is a top-level file/container format for bundling a ML model and +// associating its computation graph with metadata. +// +// The semantics of the model are described by the associated GraphProto's. +message ModelProto { + // The version of the IR this model targets. See Version enum above. + // This field MUST be present. + int64 ir_version = 1; + + // The OperatorSets this model relies on. + // All ModelProtos MUST have at least one entry that + // specifies which version of the ONNX OperatorSet is + // being imported. + // + // All nodes in the ModelProto's graph will bind against the operator + // with the same-domain/same-op_type operator with the HIGHEST version + // in the referenced operator sets. + repeated OperatorSetIdProto opset_import = 8; + + // The name of the framework or tool used to generate this model. + // This field SHOULD be present to indicate which implementation/tool/framework + // emitted the model. + string producer_name = 2; + + // The version of the framework or tool used to generate this model. + // This field SHOULD be present to indicate which implementation/tool/framework + // emitted the model. + string producer_version = 3; + + // Domain name of the model. + // We use reverse domain names as name space indicators. For example: + // `com.facebook.fair` or `com.microsoft.cognitiveservices` + // + // Together with `model_version` and GraphProto.name, this forms the unique identity of + // the graph. + string domain = 4; + + // The version of the graph encoded. See Version enum below. + int64 model_version = 5; + + // A human-readable documentation for this model. Markdown is allowed. + string doc_string = 6; + + // The parameterized graph that is evaluated to execute the model. + GraphProto graph = 7; + + // Named metadata values; keys should be distinct. + repeated StringStringEntryProto metadata_props = 14; + + // Training-specific information. Sequentially executing all stored + // `TrainingInfoProto.algorithm`s and assigning their outputs following + // the corresponding `TrainingInfoProto.update_binding`s is one training + // iteration. Similarly, to initialize the model + // (as if training hasn't happened), the user should sequentially execute + // all stored `TrainingInfoProto.initialization`s and assigns their outputs + // using `TrainingInfoProto.initialization_binding`s. + // + // If this field is empty, the training behavior of the model is undefined. + repeated TrainingInfoProto training_info = 20; +}; + +// StringStringEntryProto follows the pattern for cross-proto-version maps. +// See https://developers.google.com/protocol-buffers/docs/proto3#maps +message StringStringEntryProto { + string key = 1; + string value= 2; +}; + +message TensorAnnotation { + string tensor_name = 1; + // pairs to annotate tensor specified by above. + // The keys used in the mapping below must be pre-defined in ONNX spec. + // For example, for 8-bit linear quantization case, 'SCALE_TENSOR', 'ZERO_POINT_TENSOR' will be pre-defined as + // quantization parameter keys. + repeated StringStringEntryProto quant_parameter_tensor_names = 2; +} + + + +// Graphs +// +// A graph defines the computational logic of a model and is comprised of a parameterized +// list of nodes that form a directed acyclic graph based on their inputs and outputs. +// This is the equivalent of the "network" or "graph" in many deep learning +// frameworks. +message GraphProto { + // The nodes in the graph, sorted topologically. + repeated NodeProto node = 1; + + // The name of the graph. + string name = 2; // namespace Graph + + // A list of named tensor values, used to specify constant inputs of the graph. + // Each initializer (both TensorProto as well SparseTensorProto) MUST have a name. + // The name MUST be unique across both initializer and sparse_initializer, + // but the name MAY also appear in the input list. + repeated TensorProto initializer = 5; + + // Initializers (see above) stored in sparse format. + repeated SparseTensorProto sparse_initializer = 15; + + // A human-readable documentation for this graph. Markdown is allowed. + string doc_string = 10; + + // The inputs and outputs of the graph. + repeated ValueInfoProto input = 11; + repeated ValueInfoProto output = 12; + + // Information for the values in the graph. The ValueInfoProto.name's + // must be distinct. It is optional for a value to appear in value_info list. + repeated ValueInfoProto value_info = 13; + + // This field carries information to indicate the mapping among a tensor and its + // quantization parameter tensors. For example: + // For tensor 'a', it may have {'SCALE_TENSOR', 'a_scale'} and {'ZERO_POINT_TENSOR', 'a_zero_point'} annotated, + // which means, tensor 'a_scale' and tensor 'a_zero_point' are scale and zero point of tensor 'a' in the model. + repeated TensorAnnotation quantization_annotation = 14; + + // DO NOT USE the following fields, they were deprecated from earlier versions. + // repeated string input = 3; + // repeated string output = 4; + // optional int64 ir_version = 6; + // optional int64 producer_version = 7; + // optional string producer_tag = 8; + // optional string domain = 9; +} + +// Tensors +// +// A serialized tensor value. +message TensorProto { + enum DataType { + UNDEFINED = 0; + // Basic types. + FLOAT = 1; // float + UINT8 = 2; // uint8_t + INT8 = 3; // int8_t + UINT16 = 4; // uint16_t + INT16 = 5; // int16_t + INT32 = 6; // int32_t + INT64 = 7; // int64_t + STRING = 8; // string + BOOL = 9; // bool + + // IEEE754 half-precision floating-point format (16 bits wide). + // This format has 1 sign bit, 5 exponent bits, and 10 mantissa bits. + FLOAT16 = 10; + + DOUBLE = 11; + UINT32 = 12; + UINT64 = 13; + COMPLEX64 = 14; // complex with float32 real and imaginary components + COMPLEX128 = 15; // complex with float64 real and imaginary components + + // Non-IEEE floating-point format based on IEEE754 single-precision + // floating-point number truncated to 16 bits. + // This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits. + BFLOAT16 = 16; + + // Future extensions go here. + } + + // The shape of the tensor. + repeated int64 dims = 1; + + // The data type of the tensor. + // This field MUST have a valid TensorProto.DataType value + int32 data_type = 2; + + // For very large tensors, we may want to store them in chunks, in which + // case the following fields will specify the segment that is stored in + // the current TensorProto. + message Segment { + int64 begin = 1; + int64 end = 2; + } + Segment segment = 3; + + // Tensor content must be organized in row-major order. + // + // Depending on the data_type field, exactly one of the fields below with + // name ending in _data is used to store the elements of the tensor. + + // For float and complex64 values + // Complex64 tensors are encoded as a single array of floats, + // with the real components appearing in odd numbered positions, + // and the corresponding imaginary component appearing in the + // subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] + // is encoded as [1.0, 2.0 ,3.0 ,4.0] + // When this field is present, the data_type field MUST be FLOAT or COMPLEX64. + repeated float float_data = 4 [packed = true]; + + // For int32, uint8, int8, uint16, int16, bool, and float16 values + // float16 values must be bit-wise converted to an uint16_t prior + // to writing to the buffer. + // When this field is present, the data_type field MUST be + // INT32, INT16, INT8, UINT16, UINT8, BOOL, or FLOAT16 + repeated int32 int32_data = 5 [packed = true]; + + // For strings. + // Each element of string_data is a UTF-8 encoded Unicode + // string. No trailing null, no leading BOM. The protobuf "string" + // scalar type is not used to match ML community conventions. + // When this field is present, the data_type field MUST be STRING + repeated bytes string_data = 6; + + // For int64. + // When this field is present, the data_type field MUST be INT64 + repeated int64 int64_data = 7 [packed = true]; + + // Optionally, a name for the tensor. + string name = 8; // namespace Value + + // A human-readable documentation for this tensor. Markdown is allowed. + string doc_string = 12; + + // Serializations can either use one of the fields above, or use this + // raw bytes field. The only exception is the string case, where one is + // required to store the content in the repeated bytes string_data field. + // + // When this raw_data field is used to store tensor value, elements MUST + // be stored in as fixed-width, little-endian order. + // Floating-point data types MUST be stored in IEEE 754 format. + // Complex64 elements must be written as two consecutive FLOAT values, real component first. + // Complex128 elements must be written as two consecutive DOUBLE values, real component first. + // Boolean type MUST be written one byte per tensor element (00000001 for true, 00000000 for false). + // + // Note: the advantage of specific field rather than the raw_data field is + // that in some cases (e.g. int data), protobuf does a better packing via + // variable length storage, and may lead to smaller binary footprint. + // When this field is present, the data_type field MUST NOT be STRING or UNDEFINED + bytes raw_data = 9; + + // Data can be stored inside the protobuf file using type-specific fields or raw_data. + // Alternatively, raw bytes data can be stored in an external file, using the external_data field. + // external_data stores key-value pairs describing data location. Recognized keys are: + // - "location" (required) - POSIX filesystem path relative to the directory where the ONNX + // protobuf model was stored + // - "offset" (optional) - position of byte at which stored data begins. Integer stored as string. + // Offset values SHOULD be multiples 4096 (page size) to enable mmap support. + // - "length" (optional) - number of bytes containing data. Integer stored as string. + // - "checksum" (optional) - SHA1 digest of file specified in under 'location' key. + repeated StringStringEntryProto external_data = 13; + + // Location of the data for this tensor. MUST be one of: + // - DEFAULT - data stored inside the protobuf message. Data is stored in raw_data (if set) otherwise in type-specified field. + // - EXTERNAL - data stored in an external location as described by external_data field. + enum DataLocation { + DEFAULT = 0; + EXTERNAL = 1; + } + + // If value not set, data is stored in raw_data (if set) otherwise in type-specified field. + DataLocation data_location = 14; + + // For double + // Complex128 tensors are encoded as a single array of doubles, + // with the real components appearing in odd numbered positions, + // and the corresponding imaginary component appearing in the + // subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] + // is encoded as [1.0, 2.0 ,3.0 ,4.0] + // When this field is present, the data_type field MUST be DOUBLE or COMPLEX128 + repeated double double_data = 10 [packed = true]; + + // For uint64 and uint32 values + // When this field is present, the data_type field MUST be + // UINT32 or UINT64 + repeated uint64 uint64_data = 11 [packed = true]; +} + +// A serialized sparse-tensor value +message SparseTensorProto { + // The sequence of non-default values are encoded as a tensor of shape [NNZ]. + // The default-value is zero for numeric tensors, and empty-string for string tensors. + // values must have a non-empty name present which serves as a name for SparseTensorProto + // when used in sparse_initializer list. + TensorProto values = 1; + + // The indices of the non-default values, which may be stored in one of two formats. + // (a) Indices can be a tensor of shape [NNZ, rank] with the [i,j]-th value + // corresponding to the j-th index of the i-th value (in the values tensor). + // (b) Indices can be a tensor of shape [NNZ], in which case the i-th value + // must be the linearized-index of the i-th value (in the values tensor). + // The linearized-index can be converted into an index tuple (k_1,...,k_rank) + // using the shape provided below. + // The indices must appear in ascending order without duplication. + // In the first format, the ordering is lexicographic-ordering: + // e.g., index-value [1,4] must appear before [2,1] + TensorProto indices = 2; + + // The shape of the underlying dense-tensor: [dim_1, dim_2, ... dim_rank] + repeated int64 dims = 3; +} + +// Defines a tensor shape. A dimension can be either an integer value +// or a symbolic variable. A symbolic variable represents an unknown +// dimension. +message TensorShapeProto { + message Dimension { + oneof value { + int64 dim_value = 1; + string dim_param = 2; // namespace Shape + }; + // Standard denotation can optionally be used to denote tensor + // dimensions with standard semantic descriptions to ensure + // that operations are applied to the correct axis of a tensor. + // Refer to https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md#denotation-definition + // for pre-defined dimension denotations. + string denotation = 3; + }; + repeated Dimension dim = 1; +} + +// Types +// +// The standard ONNX data types. +message TypeProto { + + message Tensor { + // This field MUST NOT have the value of UNDEFINED + // This field MUST have a valid TensorProto.DataType value + // This field MUST be present for this version of the IR. + int32 elem_type = 1; + TensorShapeProto shape = 2; + } + + // repeated T + message Sequence { + // The type and optional shape of each element of the sequence. + // This field MUST be present for this version of the IR. + TypeProto elem_type = 1; + }; + + // map + message Map { + // This field MUST have a valid TensorProto.DataType value + // This field MUST be present for this version of the IR. + // This field MUST refer to an integral type ([U]INT{8|16|32|64}) or STRING + int32 key_type = 1; + // This field MUST be present for this version of the IR. + TypeProto value_type = 2; + }; + + + oneof value { + // The type of a tensor. + Tensor tensor_type = 1; + + // NOTE: DNN-only implementations of ONNX MAY elect to not support non-tensor values + // as input and output to graphs and nodes. These types are needed to naturally + // support classical ML operators. DNN operators SHOULD restrict their input + // and output types to tensors. + + // The type of a sequence. + Sequence sequence_type = 4; + + // The type of a map. + Map map_type = 5; + + } + + // An optional denotation can be used to denote the whole + // type with a standard semantic description as to what is + // stored inside. Refer to https://github.com/onnx/onnx/blob/master/docs/TypeDenotation.md#type-denotation-definition + // for pre-defined type denotations. + string denotation = 6; +} + +// Operator Sets +// +// OperatorSets are uniquely identified by a (domain, opset_version) pair. +message OperatorSetIdProto { + // The domain of the operator set being identified. + // The empty string ("") or absence of this field implies the operator + // set that is defined as part of the ONNX specification. + // This field MUST be present in this version of the IR when referring to any other operator set. + string domain = 1; + + // The version of the operator set being identified. + // This field MUST be present in this version of the IR. + int64 version = 2; +} + + +// For using protobuf-lite +option optimize_for = LITE_RUNTIME; + diff --git a/tmva/sofie/src/Prototype.cxx b/tmva/sofie/src/Prototype.cxx new file mode 100644 index 0000000000000..aba5d4ada9095 --- /dev/null +++ b/tmva/sofie/src/Prototype.cxx @@ -0,0 +1,62 @@ +#include + +#include "TMVA/RModel.hxx" +#include "TMVA/RModelParser_ONNX.hxx" + +#include +#include + + +using namespace TMVA::Experimental::SOFIE; + +int main(){ + + + RModelParser_ONNX parser; + RModel model = parser.Parse("./Linear_64.onnx"); + RModel model2 = std::move(model); + model2.PrintRequiredInputTensors(); + model2.PrintInitializedTensors(); + model2.HeadInitializedTensors("18bias"); + model2.HeadInitializedTensors("0weight"); + + std::cout << "===" << std::endl; + + model2.Generate(); + //model2.PrintGenerated(); + //model2.Initialize(); + model2.PrintInitializedTensors(); + model2.HeadInitializedTensors("6bias", 100); + + + std::cout << "===" << std::endl; + + + + //model2.PrintGenerated(); + model2.OutputGenerated(); + //model2.PrintIntermediateTensors(); +/* + std::cout << "===" << std::endl; + + RModel model3; + model3.AddInputTensorInfo("1", ETensorType::FLOAT, {1,2,3,4}); + //auto op = std::make_unique>({3,2,1,0}, "1", "2"); + std::unique_ptrop ( new ROperator_Transpose({3,2,1,0}, "1", "2")) ; + model3.AddOperator(std::move(op)); + //op->Initialize(model3); + //std::cout << (op->Generate("1")); + + model3.AddInputTensorInfo("3", ETensorType::FLOAT, {2,3}); + model3.AddInputTensorInfo("4", ETensorType::FLOAT, {3,2}); + std::unique_ptr op2 (new ROperator_Gemm (1.0, 1.0, 0, 0, "3", "4", "5")); + model3.AddOperator(std::move(op2)); + std::unique_ptr op3 (new ROperator_Relu ("5", "6")); + model3.AddOperator(std::move(op3)); + //op2->Initialize(model3); + //std::cout << (op2->Generate("2")); + + model3.Generate(); + model3.PrintGenerated(); +*/ +} diff --git a/tmva/sofie/src/RModel.cxx b/tmva/sofie/src/RModel.cxx new file mode 100644 index 0000000000000..af6d1fc5d38ec --- /dev/null +++ b/tmva/sofie/src/RModel.cxx @@ -0,0 +1,355 @@ +#include "TMVA/RModel.hxx" + + + + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + + RModel::RModel(RModel&& other){ + fInputTensorInfos = std::move(other.fInputTensorInfos); + fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos); + fOperators = std::move(other.fOperators); + fInitializedTensors = std::move(other.fInitializedTensors); + fName = other.fName; + fFileName = other.fFileName; + fParseTime = other.fParseTime; + fGC = other.fGC; + fNeededStdLib = other.fNeededStdLib; + fOutputTensorNames = other.fOutputTensorNames; + } + + RModel& RModel::operator=(RModel&& other){ + fInputTensorInfos = std::move(other.fInputTensorInfos); + fReadyInputTensorInfos = std::move(other.fReadyInputTensorInfos); + fOperators = std::move(other.fOperators); + fInitializedTensors = std::move(other.fInitializedTensors); + fName = other.fName; + fFileName = other.fFileName; + fParseTime = other.fParseTime; + fGC = other.fGC; + fNeededStdLib = other.fNeededStdLib; + fOutputTensorNames = other.fOutputTensorNames; + return *this; + } + + RModel::RModel(std::string name, std::string parsedtime): fFileName (name), fParseTime(parsedtime) { + fName = fFileName.substr(0, fFileName.rfind(".")); + } + + const std::vector& RModel::GetTensorShape(std::string name){ + auto f = fReadyInputTensorInfos.find(name); + if (f != fReadyInputTensorInfos.end()){ + return f->second.shape; + } + auto f2 = fInitializedTensors.find(name); + if (f2 != fInitializedTensors.end()){ + return f2->second.shape; + } + auto f3 = fInputTensorInfos.find(name); + if (f3 != fInputTensorInfos.end()){ + throw std::runtime_error("TMVA SOFIE tensor [" + name + "] is an input tensor with unspecified dimension parameter"); + } + auto f4 = fIntermediateTensorInfos.find(name); + if (f4 != fIntermediateTensorInfos.end()){ + return f4->second.shape; + } + + throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the shape is requested is not found"); + } + + const ETensorType& RModel::GetTensorType(std::string name){ + auto f = fReadyInputTensorInfos.find(name); + if (f != fReadyInputTensorInfos.end()){ + return f->second.type; + } + auto f2 = fInitializedTensors.find(name); + if (f2 != fInitializedTensors.end()){ + return f2->second.type; + } + auto f3 = fInputTensorInfos.find(name); + if (f3 != fInputTensorInfos.end()){ + return f3->second.type; + } + auto f4 = fIntermediateTensorInfos.find(name); + if (f4 != fIntermediateTensorInfos.end()){ + return f4->second.type; + } + + throw std::runtime_error("TMVA SOFIE tensor [" + name + "] for which the shape is requested is not found"); + } + + bool RModel::CheckIfTensorAlreadyExist(std::string tensor_name){ + if (fReadyInputTensorInfos.find(tensor_name) != fReadyInputTensorInfos.end()) return true; + if (fInitializedTensors.find(tensor_name) != fInitializedTensors.end()) return true; + if (fIntermediateTensorInfos.find(tensor_name) != fIntermediateTensorInfos.end()) return true; + return false; + } + + void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector shape){ + input_name = UTILITY::Clean_name(input_name); + if (CheckIfTensorAlreadyExist(input_name)){ + throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n"); + } + + InputTensorInfo inputInfo { type, shape }; + fInputTensorInfos[input_name] = inputInfo; + } + + void RModel::AddInputTensorInfo(std::string input_name, ETensorType type, std::vector shape){ + input_name = UTILITY::Clean_name(input_name); + if (CheckIfTensorAlreadyExist(input_name)){ + throw std::runtime_error("TMVA-SOFIE: input tensor with name " + input_name + " already exists \n"); + } + TensorInfo inputInfo { type, shape }; + fReadyInputTensorInfos[input_name] = inputInfo; + } + + void RModel::AddOperator(std::unique_ptr op, int order_execution){ + if (order_execution >= 0) { + fOperators.insert(fOperators.begin() + order_execution, std::move(op)); + }else{ + fOperators.push_back(std::move(op)); + } + } + + void RModel::AddInitializedTensor(std::string tensor_name, ETensorType type, std::vector shape, std::shared_ptr data){ + tensor_name = UTILITY::Clean_name(tensor_name); + //NB: own data + if (CheckIfTensorAlreadyExist(tensor_name)){ + throw std::runtime_error("TMVA-SOFIE: initialized tensor with name " + tensor_name + " already exists \n"); + } + InitializedTensor new_tensor {type, shape, data}; + fInitializedTensors[tensor_name] = new_tensor; + + } + + void RModel::AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector shape){ + tensor_name = UTILITY::Clean_name(tensor_name); + if (CheckIfTensorAlreadyExist(tensor_name)){ + throw std::runtime_error("TMVA-SOFIE: intermediate tensor with name " + tensor_name + " already exists \n"); + } + TensorInfo new_tensor {type, shape}; + fIntermediateTensorInfos[tensor_name] = new_tensor; + } + + void RModel::UpdateInitializedTensor(std::string tensor_name, ETensorType type, std::vector shape, std::shared_ptr data){ + tensor_name = UTILITY::Clean_name(tensor_name); + if (not CheckIfTensorAlreadyExist(tensor_name)){ + throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to update it"); + } + InitializedTensor new_tensor {type, shape, data}; + fInitializedTensors[tensor_name] = new_tensor; + } + + std::shared_ptr RModel::GetInitializedTensorData(std::string tensor_name){ + auto f = fInitializedTensors.find(tensor_name); + if (f == fInitializedTensors.end()){ + throw std::runtime_error("TMVA-SOFIE: tensor " + tensor_name + " not found when trying to get its data"); + }else{ + return f->second.data; + } + } + + void RModel::Initialize(){ + for (auto& i : fOperators){ + i->Initialize(*this); + } + } + + void RModel::Generate(){ + Initialize(); + fGC += ("//Code generated automatically by TMVA for Inference of Model file [" + fFileName + "] at [" + fParseTime.substr(0, fParseTime.length()-1) +"] \n"); + for (auto& i: fNeededStdLib){ + fGC += "#include<" + i + ">\n"; + } + fGC += ("namespace TMVA_SOFIE_" + fName + "{\n"); + if (fNeedGemm){ + fGC += ("namespace BLAS{\n" + "\textern \"C\" void sgemm_(const char * transa, const char * transb, const int * m, const int * n, const int * k,\n" + "\t const float * alpha, const float * A, const int * lda, const float * B, const int * ldb,\n" + "\t const float * beta, float * C, const int * ldc);\n" + "}//BLAS\n"); + + for (auto& i: fInitializedTensors){ + if (i.second.type == ETensorType::FLOAT){ + size_t length = 1; + for (auto & dim: i.second.shape){ + length *= dim; + } + fGC += "float tensor_" + i.first + "[" + std::to_string(length) + "] = {"; + std::shared_ptr data = std::static_pointer_cast(i.second.data); + std::stringstream floats; + for (int idx = 0; idx < length-1; idx++){ + floats << std::setprecision(std::numeric_limits::max_digits10) << data.get()[idx] << ", "; + } + floats << std::setprecision(std::numeric_limits::max_digits10) << data.get()[length-1]; + fGC += floats.str() +"};\n"; + } + } + for (auto&i: fIntermediateTensorInfos){ + if (i.second.type == ETensorType::FLOAT){ + size_t length = 1; + for (auto & dim: i.second.shape){ + length *= dim; + } + fGC += "float tensor_" + i.first + "[" + std::to_string(length) + "];\n"; + } + } + + if (fOutputTensorNames.size() == 1){ + auto f = fIntermediateTensorInfos.find(fOutputTensorNames[0]); + if (f == fIntermediateTensorInfos.end()){ + throw std::runtime_error("TMVA-SOFIE: output tensor " + fOutputTensorNames[0] + " not found when trying to get its info"); + }else{ + if (f->second.type == ETensorType::FLOAT){ + fGC += "std::vector "; + } + } + }else{ + std::cout << fOutputTensorNames.size() << std::endl; + throw std::runtime_error("TMVA-SOFIE: More than 1 output tensor is not yet supported"); + } + + fGC += "infer("; + for (auto& i: fReadyInputTensorInfos){ + size_t length = 1; + for (auto& dim: i.second.shape){ + length *= dim; + } + if (i.second.type == ETensorType::FLOAT){ + fGC += "float* tensor_" + i.first + ","; + } + fGC.pop_back(); //remove last "," + } + fGC += "){\n"; + + for (int id = 0; id < fOperators.size() ; id++){ + fGC+= (fOperators[id]->Generate(std::to_string(id))); + } + if (fOutputTensorNames.size() == 1){ + fGC += "\tstd::vector ret (tensor_" + fOutputTensorNames[0] + ", tensor_" + fOutputTensorNames[0] + " + sizeof(tensor_" + + fOutputTensorNames[0] + ") / sizeof(tensor_" + fOutputTensorNames[0] + "[0]));\n"; + fGC += "\treturn ret;\n"; + } + fGC += "}\n"; + } + fGC += ("} //TMVA_SOFIE_" + fName + "\n"); + } + + + + void RModel::PrintRequiredInputTensors(){ + std::cout << "Model requires following inputs:\n"; + for (auto& inputInfo: fInputTensorInfos){ + std::cout << "Parameterised Tensor name: " << inputInfo.first << "\t"; + std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t"; + std::cout << "shape: ["; + for (int i = 0; i < inputInfo.second.shape.size(); i++){ + if (inputInfo.second.shape[i].isParam){ + std::cout << inputInfo.second.shape[i].param; + }else{ + std::cout << inputInfo.second.shape[i].dim ; + } + if (i < inputInfo.second.shape.size() - 1) std::cout << ","; + } + std::cout << "]" << std::endl; + } + + for (auto& inputInfo: fReadyInputTensorInfos){ + std::cout << "Fully Specified Tensor name: " << inputInfo.first << "\t"; + std::cout << "type: " << ConvertTypeToString(inputInfo.second.type) << "\t"; + std::cout << "shape: ["; + for (int i = 0; i < inputInfo.second.shape.size(); i++){ + std::cout << inputInfo.second.shape[i]; + if (i < inputInfo.second.shape.size() - 1) std::cout << ","; + } + std::cout << "]" << std::endl; + } + + } + + void RModel::PrintInitializedTensors(){ + std::cout << "Model initialized the following tensors:\n"; + for (auto& it: fInitializedTensors){ + std::cout << "Tensor name: \"" << it.first << "\"\t"; + std::cout << "type: " << ConvertTypeToString(it.second.type) << "\t"; + std::cout << "shape: ["; + for (int i = 0; i < it.second.shape.size(); i++){ + std::cout << it.second.shape[i]; + if (i < it.second.shape.size() - 1) std::cout << ","; + } + std::cout << "]" << std::endl; + } + } + + void RModel::PrintIntermediateTensors(){ + std::cout << "Model specify the following intermediate tensors:\n"; + for (auto& it: fIntermediateTensorInfos){ + std::cout << "Tensor name: \"" << it.first << "\"\t"; + std::cout << "type: " << ConvertTypeToString(it.second.type) << "\t"; + std::cout << "shape: ["; + for (int i = 0; i < it.second.shape.size(); i++){ + std::cout << it.second.shape[i]; + if (i < it.second.shape.size() - 1) std::cout << ","; + } + std::cout << "]" << std::endl; + } + } + + void RModel::HeadInitializedTensors(std::string name, int n_print){ + auto it = fInitializedTensors.find(name); + if (it == fInitializedTensors.end()){ + std::cout << "Tensor " << name << " not found in model's intiialized tensor list" << std::endl; + return; + } + + std::cout << "Tensor name: " << it->first << "\t"; + std::cout << "type: " << ConvertTypeToString(it->second.type) << "\t"; + std::size_t length =1; + std::cout << "shape: ["; + for (int i = 0; i < it->second.shape.size(); i++){ + std::cout << it->second.shape[i]; + length *= it->second.shape[i]; + if (i < it->second.shape.size() - 1) std::cout << ","; + } + std::cout << "]" << std::endl; + bool ellipsis = true; + if (n_print > length){ + n_print = length; + ellipsis = false; + } + + std::cout << "data: [" << std::endl; + switch(it->second.type){ + case ETensorType::FLOAT : { + auto converted_data = std::static_pointer_cast(it->second.data).get(); + for (int i =0; i < n_print; i++){ + std::cout << converted_data[i]; + if (i < n_print - 1) std::cout << " ,"; + } + break; + } + } + if (ellipsis) std::cout << ", ..."; + std::cout << "]" << std::endl; + + } + + void RModel::OutputGenerated(std::string filename){ + if (filename == ""){ + filename = fName + ".hxx"; + } + std::ofstream f; + f.open(filename); + if (!f.is_open()){ + throw std::runtime_error("tmva-sofie failed to open file for output generated inference code"); + } + f << fGC; + f.close(); + } + +}//SOFIE +}//Experimental +}//TMVA diff --git a/tmva/sofie/src/RModelParser_ONNX.cxx b/tmva/sofie/src/RModelParser_ONNX.cxx new file mode 100644 index 0000000000000..51cbacfd6f168 --- /dev/null +++ b/tmva/sofie/src/RModelParser_ONNX.cxx @@ -0,0 +1,299 @@ +#include "TMVA/RModelParser_ONNX.hxx" +#include "onnx_proto3.pb.h" + +#include +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +namespace INTERNAL{ + +std::unique_ptr make_ROperator(size_t idx, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type){ + const auto& nodeproto = graphproto.node(idx); + auto find = mapOptypeOperator.find(nodeproto.op_type()); + if (find == mapOptypeOperator.end()){ + throw std::runtime_error("TMVA::SOFIE - Operator type " + nodeproto.op_type() + " is not yet supported"); + }else{ + return (find->second)(nodeproto, graphproto, tensor_type); + } +} + +std::unique_ptr make_ROperator_Transpose(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type){ + + ETensorType input_type; + + auto input_name = nodeproto.input(0); + auto it = tensor_type.find(input_name); + if (it != tensor_type.end()){ + input_type = it->second; + }else{ + throw std::runtime_error("TMVA::SOFIE ONNX Parser tranpose op has input tensor" + input_name + " but its type is not yet registered"); + } + + std::unique_ptr op; + std::vector attr_perm; + + if (nodeproto.attribute_size() == 1){ + attr_perm.assign(nodeproto.attribute(0).ints().begin(), nodeproto.attribute(0).ints().end()); + } + + switch(input_type){ + case ETensorType::FLOAT: + if (!attr_perm.empty()){ + op.reset(new ROperator_Transpose(attr_perm, nodeproto.input(0), nodeproto.output(0))); + }else{ + op.reset(new ROperator_Transpose (nodeproto.input(0), nodeproto.output(0))); + } + break; + default: + throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Transpose does not yet support input type " + std::to_string(static_cast(input_type))); + } + + ETensorType output_type = (op->TypeInference({input_type}))[0]; + auto it2 = tensor_type.find(nodeproto.output(0)); + if (it2 == tensor_type.end()){ + tensor_type[nodeproto.output(0)] = output_type; + } + + + return std::move(op); +} + +std::unique_ptr make_ROperator_Relu(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type){ + + ETensorType input_type; + + auto input_name = nodeproto.input(0); + auto it = tensor_type.find(input_name); + if (it != tensor_type.end()){ + input_type = it->second; + }else{ + throw std::runtime_error("TMVA::SOFIE ONNX Parser relu op has input tensor" + input_name + " but its type is not yet registered"); + } + + std::unique_ptr op; + + + switch(input_type){ + case ETensorType::FLOAT: + op.reset(new ROperator_Relu(nodeproto.input(0), nodeproto.output(0))); + break; + default: + throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Relu does not yet support input type " + std::to_string(static_cast(input_type))); + } + + ETensorType output_type = (op->TypeInference({input_type}))[0]; + auto it2 = tensor_type.find(nodeproto.output(0)); + if (it2 == tensor_type.end()){ + tensor_type[nodeproto.output(0)] = output_type; + } + + return std::move(op); +} + +std::unique_ptr make_ROperator_Gemm(const onnx::NodeProto& nodeproto, const onnx::GraphProto& graphproto, std::unordered_map& tensor_type){ + + ETensorType input_type; + + auto input_name = nodeproto.input(0); + auto it = tensor_type.find(input_name); + if (it != tensor_type.end()){ + input_type = it->second; + }else{ + throw std::runtime_error("TMVA::SOFIE ONNX Parser gemm op has input tensor" + input_name + " but its type is not yet registered"); + } + + std::unique_ptr op; + + float attr_alpha =1.0; + float attr_beta =1.0; + int_t attr_transA =0; + int_t attr_transB =0; + + for (int i = 0; i < nodeproto.attribute_size(); i++){ + std::string attribute_name = nodeproto.attribute(i).name(); + if (attribute_name == "alpha"){ + attr_alpha = nodeproto.attribute(i).f(); + }else if(attribute_name == "beta"){ + attr_beta = nodeproto.attribute(i).f(); + }else if(attribute_name == "transA"){ + attr_transA = nodeproto.attribute(i).i(); + if (attr_transA != 0 && attr_transA != 1) throw std::runtime_error("TMVA::SOFIE Error - Model Loading - attribute transA in Operator Gemm not 0/1"); + }else if(attribute_name == "transB"){ + attr_transB = nodeproto.attribute(i).i(); + if (attr_transB != 0 && attr_transB != 1) throw std::runtime_error("TMVA::SOFIE Error - Model Loading - attribute transB in Operator Gemm not 0/1"); + }else{ + std::cout << "TMVA::SOFIE Warning - Model Loading - Attribute " << attribute_name << " in OperatorNode " << nodeproto.name() << " is not defined in ONNX IR and not applied!\n"; + } + } + + + switch(input_type){ + case ETensorType::FLOAT: + if (nodeproto.input_size() == 2){ + op.reset(new ROperator_Gemm(attr_alpha, attr_beta, attr_transA, attr_transB, nodeproto.input(0), nodeproto.input(1), nodeproto.output(0))); + }else{ + op.reset(new ROperator_Gemm(attr_alpha, attr_beta, attr_transA, attr_transB, nodeproto.input(0), nodeproto.input(1), nodeproto.input(2), nodeproto.output(0))); + } + break; + default: + throw std::runtime_error("TMVA::SOFIE - Unsupported - Operator Relu does not yet support input type " + std::to_string(static_cast(input_type))); + } + + ETensorType output_type = (op->TypeInference({input_type, input_type}))[0]; + auto it2 = tensor_type.find(nodeproto.output(0)); + if (it2 == tensor_type.end()){ + tensor_type[nodeproto.output(0)] = output_type; + } + + + return std::move(op); +} + +} //INTERNAL + + + +RModel RModelParser_ONNX::Parse(std::string filename){ + char sep = '/'; + #ifdef _WIN32 + sep = '\\'; + #endif + size_t i = filename.rfind(sep, filename.length()); + std::string modelname; + if (i != std::string::npos){ + filename = (filename.substr(i+1, filename.length() - i)); + } + + + + std::time_t ttime = std::time(0); + std::tm* gmt_time = std::gmtime(&ttime); + std::string parsetime (std::asctime(gmt_time)); + + + + + GOOGLE_PROTOBUF_VERIFY_VERSION; + //model I/O + onnx::ModelProto model; + RModel rmodel(filename, parsetime); + + std::unordered_map tensor_type; + + std::fstream input(filename, std::ios::in | std::ios::binary); + if (!model.ParseFromIstream(&input)){ + throw std::runtime_error("TMVA::SOFIE - Failed to parse onnx file"); + } + + const onnx::GraphProto& graph = model.graph(); //not a memory leak. model freed automatically at the end. + google::protobuf::ShutdownProtobufLibrary(); + + std::unordered_set initializer_names; + for (int i=0; i < graph.initializer_size(); i++){ + initializer_names.insert(graph.initializer(i).name()); + } + + + for (int i=0; i < graph.input_size(); i++){ + + tensor_type[graph.input(i).name()] = static_cast(graph.input(i).type().tensor_type().elem_type()); + + if (initializer_names.find(graph.input(i).name()) != initializer_names.end()) continue; + + //input datanode is not a weight node (has no initializer) + const onnx::ValueInfoProto& valueinfoproto = graph.input(i); + std::string input_name = valueinfoproto.name(); + ETensorType type = static_cast(valueinfoproto.type().tensor_type().elem_type()); + if (type != ETensorType::FLOAT){ + throw std::runtime_error("TMVA::SOFIE Data type in input tensor " + input_name + " not supported!\n"); + } + + std::vector fShape; + bool existParam = false; + if (!valueinfoproto.type().tensor_type().has_shape()) throw std::runtime_error("TMVA::SOFIE datanode with no shape restrictions is not supported yet"); + for (int i = 0; i < valueinfoproto.type().tensor_type().shape().dim_size(); i++){ + Dim dim; + if (valueinfoproto.type().tensor_type().shape().dim(i).value_case() == onnx::TensorShapeProto_Dimension::ValueCase::kDimValue){ + dim.dim = valueinfoproto.type().tensor_type().shape().dim(i).dim_value(); + }else if (valueinfoproto.type().tensor_type().shape().dim(i).value_case() == onnx::TensorShapeProto_Dimension::ValueCase::kDimParam){ + dim.isParam = true; + existParam = true; + dim.param = valueinfoproto.type().tensor_type().shape().dim(i).dim_param(); + }else{ + throw std::runtime_error("TMVA::SOFIE ONNX file error: Valueinfoproto " + input_name + " has neither dim_value nor dim_param! \n"); + } + fShape.push_back(dim); + } + if (valueinfoproto.type().tensor_type().shape().dim_size() == 0){ + Dim dim; + dim.dim = 1; + fShape.push_back(dim); + } //in case this TensorShapeProto has no dimension message: ONNX IR defines this to be a scalar + + if (!existParam){ + std::vector fShape_sizet; + for (auto& i: fShape){ + fShape_sizet.push_back(i.dim); + } + + rmodel.AddInputTensorInfo(input_name, type, fShape_sizet); + }else{ + rmodel.AddInputTensorInfo(input_name, type, fShape); + } + + } + + for (int i=0; i < graph.initializer_size(); i++){ + onnx::TensorProto* tensorproto = const_cast(&graph.initializer(i)); + std::vector fShape; + std::size_t fLength = 1; + for (int i = 0; i < tensorproto->dims_size(); i++){ + fShape.push_back(tensorproto->dims(i)); + fLength *= tensorproto->dims(i); + } + + std::string input_name = graph.initializer(i).name(); + + switch(static_cast(graph.initializer(i).data_type())){ + case ETensorType::FLOAT : { + //void* data = malloc (fLength * sizeof(float)); + std::shared_ptr data(malloc(fLength * sizeof(float)), free); + + if (tensorproto->raw_data().empty() == false){ + auto raw_data_ptr = reinterpret_cast(const_cast(tensorproto->raw_data().c_str())); + std::memcpy(data.get(), raw_data_ptr, fLength * sizeof(float)); + }else{ + tensorproto->mutable_float_data()->ExtractSubrange(0, tensorproto->float_data_size(), static_cast(data.get())); + } + + rmodel.AddInitializedTensor(input_name, ETensorType::FLOAT, fShape, data); + break; + } + default: throw std::runtime_error("Data type in weight tensor " + graph.initializer(i).name() + " not supported!\n"); + } + } + + + + for (int i=0; i < graph.node_size(); i++){ + rmodel.AddOperator(std::move(INTERNAL::make_ROperator(i, graph, tensor_type))); + } + + std::vector outputnames; + for (int i=0; i < graph.output_size(); i++){ + outputnames.push_back(graph.output(i).name()); + } + rmodel.AddOutputTensorNameList(outputnames); + + return rmodel; + +} + + + +}//SOFIE +}//Experimental +}//TMVA diff --git a/tmva/sofie/src/SOFIE_common.cxx b/tmva/sofie/src/SOFIE_common.cxx new file mode 100644 index 0000000000000..7c683d6dfedb5 --- /dev/null +++ b/tmva/sofie/src/SOFIE_common.cxx @@ -0,0 +1,107 @@ +#include "TMVA/SOFIE_common.hxx" +#include + +namespace TMVA{ +namespace Experimental{ +namespace SOFIE{ + +std::vector ConvertShapeToDim(std::vector shape){ + std::vector fshape(shape.size()); + for (int i =0; i < shape.size(); i++){ + fshape[i].dim = shape[i]; + } + return fshape; +} + +std::size_t ConvertShapeToLength(std::vector shape){ + std::size_t fLength = 1; + for (auto& dim: shape) fLength *= dim; + return fLength; +} + +std::string ConvertTypeToString(ETensorType type){ + switch(type){ + case ETensorType::FLOAT : { + return "float"; + } + default:{ + return "other"; + } + } +} + +namespace{ +template +static inline void copy_vector_data(int_t no_of_copies, int_t input_size, T* input, T* target){ //only visible within this translation unit + std::memcpy(target, input, input_size * sizeof(T)); + int_t already_copied = 1; + + while (already_copied * 2 <= no_of_copies){ + std::memcpy(target + already_copied * input_size, target, already_copied * input_size * sizeof(T)); + already_copied *= 2; + } + + if (already_copied < no_of_copies){ + std::memcpy(target + already_copied * input_size, target, (no_of_copies - already_copied) * input_size * sizeof(T)); + } +} +} + +template +T* UTILITY::Unidirectional_broadcast(const T* original_data, const std::vector original_shape, const std::vector target_shape) +{ + + std::vector current_shape(original_shape); + int original_length = 1; + int target_length = 1; + for (int i = 0; i < original_shape.size(); i++){ + original_length *= original_shape[i]; + } + for (int i = 0; i < target_shape.size(); i++){ + target_length *= target_shape[i]; + } + if (original_shape.size() > target_shape.size()) throw std::runtime_error("TMVA::SOFIE Error in Broadcasting Tensor : original array has more dimensions than target shape "); + auto it = current_shape.begin(); + while (current_shape.size() < target_shape.size()){ + it = current_shape.insert(it, 1); + } + + T* new_datavector = new T[target_length]; + std::memcpy(new_datavector, original_data, original_length * sizeof(T)); + + for (int dim = target_shape.size() - 1; dim >= 0; dim--){ + if (current_shape[dim] != target_shape[dim]){ + if (current_shape[dim] != 1) throw std::runtime_error ("TMVA::SOFIE Error in Broadcasting Tensor at least one dimension to be broadcast of the original array is not 1"); + + int_t group_size = 1; + int_t no_of_groups = 1; + int_t no_of_copies = target_shape[dim]; + + for (int i = dim + 1; i < target_shape.size(); i++){ + group_size *= current_shape[i]; + } + for (int i = 0; i < dim; i++){ + no_of_groups *= current_shape[i]; + } + + for (int curr_group = no_of_groups - 1; curr_group >= 0; curr_group--){ + copy_vector_data(no_of_copies, group_size, new_datavector + curr_group * group_size,new_datavector + curr_group * group_size * no_of_copies); + } + + current_shape[dim] = target_shape[dim]; + } + } + return new_datavector; +} + +std::string UTILITY::Clean_name(std::string input_tensor_name){ + std::string s (input_tensor_name); + s.erase(std::remove_if(s.begin(), s.end(), []( char const& c ) -> bool { return !std::isalnum(c); } ), s.end()); + return s; +} + +template float* UTILITY::Unidirectional_broadcast(const float* original_data, const std::vector original_shape, const std::vector target_shape); + +}//SOFIE +}//Experimental +}//TMVA From 5b41ad1d9ac272f5d7dcd0b7edd8d0b43da2e9e8 Mon Sep 17 00:00:00 2001 From: Max Orok Date: Wed, 9 Jun 2021 20:18:21 -0400 Subject: [PATCH 160/309] [ntuple][doc] Add some RNTupleReader doc examples * Open (1/2) * GetEntryRange * PrintInfo --- tree/ntuple/v7/inc/ROOT/RNTuple.hxx | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx index 6a442002180b9..f0f7a685ec917 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx @@ -87,6 +87,16 @@ An input ntuple provides data from storage as C++ objects. The ntuple model can or it can be imposed by the user. The latter case allows users to read into a specialized ntuple model that covers only a subset of the fields in the ntuple. The ntuple model is used when reading complete entries. Individual fields can be read as well by instantiating a tree view. + +~~~ {.cpp} +#include +using ROOT::Experimental::RNTupleReader; + +#include + +auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); +std::cout << "myNTuple has " << ntuple->GetNEntries() << " entries\n"; +~~~ */ // clang-format on class RNTupleReader { @@ -148,6 +158,20 @@ public: std::string_view ntupleName, std::string_view storage, const RNTupleReadOptions &options = RNTupleReadOptions()); + /// Open an RNTuple for reading. + /// + /// Throws an RException if there is no RNTuple with the given name. + /// + /// **Example: open an RNTuple and print the number of entries** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// std::cout << "myNTuple has " << ntuple->GetNEntries() << " entries\n"; + /// ~~~ static std::unique_ptr Open(std::string_view ntupleName, std::string_view storage, const RNTupleReadOptions &options = RNTupleReadOptions()); @@ -173,6 +197,31 @@ public: const RNTupleDescriptor &GetDescriptor() const { return fSource->GetDescriptor(); } /// Prints a detailed summary of the ntuple, including a list of fields. + /// + /// **Example: print summary information to stdout** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::ENTupleInfo; + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// ntuple->PrintInfo(); + /// // or, equivalently: + /// ntuple->PrintInfo(ENTupleInfo::kSummary, std::cout); + /// ~~~ + /// **Example: print detailed column storage data to stderr** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::ENTupleInfo; + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// ntuple->PrintInfo(ENTupleInfo::kStorageDetails, std::cerr); + /// ~~~ void PrintInfo(const ENTupleInfo what = ENTupleInfo::kSummary, std::ostream &output = std::cout); /// Shows the values of the i-th entry/row, starting with 0 for the first entry. By default, @@ -198,6 +247,20 @@ public: } } + /// Returns an iterator over the entry indices of the RNTuple. + /// + /// **Example: iterate over all entries and print each entry in JSON format** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// for (auto i : ntuple->GetEntryRange()) { + /// ntuple->Show(i); + /// } + /// ~~~ RNTupleGlobalRange GetEntryRange() { return RNTupleGlobalRange(0, GetNEntries()); } /// Provides access to an individual field that can contain either a scalar value or a collection, e.g. From 5d633ab396e05c209bc18c3898253ac282a2a37e Mon Sep 17 00:00:00 2001 From: Max Orok Date: Thu, 10 Jun 2021 11:21:46 -0400 Subject: [PATCH 161/309] [ntuple][doc] Add Reader::EnableMetrics example --- tree/ntuple/v7/inc/ROOT/RNTuple.hxx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx index f0f7a685ec917..b4b6bfe399ec8 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx @@ -222,6 +222,8 @@ public: /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); /// ntuple->PrintInfo(ENTupleInfo::kStorageDetails, std::cerr); /// ~~~ + /// + /// For use of ENTupleInfo::kMetrics, see #EnableMetrics. void PrintInfo(const ENTupleInfo what = ENTupleInfo::kSummary, std::ostream &output = std::cout); /// Shows the values of the i-th entry/row, starting with 0 for the first entry. By default, @@ -293,6 +295,25 @@ public: RIterator begin() { return RIterator(0); } RIterator end() { return RIterator(GetNEntries()); } + /// Enable performance measurements (decompression time, bytes read from storage, etc.) + /// + /// **Example: inspect the reader metrics after loading every entry** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::ENTupleInfo; + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// // metrics must be turned on beforehand + /// ntuple->EnableMetrics(); + /// + /// for (auto i : ntuple->GetEntryRange()) { + /// ntuple->LoadEntry(i); + /// } + /// ntuple->PrintInfo(ENTupleInfo::kMetrics); + /// ~~~ void EnableMetrics() { fMetrics.Enable(); } const Detail::RNTupleMetrics &GetMetrics() const { return fMetrics; } }; From 348603d3b4673f05905cfefe4619d5d78d96973a Mon Sep 17 00:00:00 2001 From: Max Orok Date: Thu, 10 Jun 2021 17:07:23 -0400 Subject: [PATCH 162/309] [ntuple][doc] Fix Show usage in example --- tree/ntuple/v7/inc/ROOT/RNTuple.hxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx index b4b6bfe399ec8..61fc51eef9afb 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx @@ -254,13 +254,14 @@ public: /// **Example: iterate over all entries and print each entry in JSON format** /// ~~~ {.cpp} /// #include + /// using ROOT::Experimental::ENTupleShowFormat; /// using ROOT::Experimental::RNTupleReader; /// /// #include /// /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); /// for (auto i : ntuple->GetEntryRange()) { - /// ntuple->Show(i); + /// ntuple->Show(i, ENTupleShowFormat::kCompleteJSON); /// } /// ~~~ RNTupleGlobalRange GetEntryRange() { return RNTupleGlobalRange(0, GetNEntries()); } From 41fb91bac21d30d362ce8c919924241c8c71b470 Mon Sep 17 00:00:00 2001 From: Max Orok Date: Thu, 10 Jun 2021 17:15:20 -0400 Subject: [PATCH 163/309] [ntuple][doc] Add GetView example Also improve GetViewCollection exception doc --- tree/ntuple/v7/inc/ROOT/RNTuple.hxx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx index 61fc51eef9afb..9473d854d4ae2 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTuple.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTuple.hxx @@ -271,6 +271,21 @@ public: /// field of a collection itself, like GetView("particle"). /// /// Raises an exception if there is no field with the given name. + /// + /// **Example: iterate over a field named "pt" of type `float`** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleReader; + /// + /// #include + /// + /// auto ntuple = RNTupleReader::Open("myNTuple", "some/file.root"); + /// auto pt = ntuple->GetView("pt"); + /// + /// for (auto i : ntuple->GetEntryRange()) { + /// std::cout << i << ": " << pt(i) << "\n"; + /// } + /// ~~~ template RNTupleView GetView(std::string_view fieldName) { auto fieldId = fSource->GetDescriptor().FindFieldId(fieldName); @@ -282,7 +297,9 @@ public: return RNTupleView(fieldId, fSource.get()); } - /// Raises an exception if there is no field with the given name. + /// Raises an exception if: + /// * there is no field with the given name or, + /// * the field is not a collection RNTupleViewCollection GetViewCollection(std::string_view fieldName) { auto fieldId = fSource->GetDescriptor().FindFieldId(fieldName); if (fieldId == kInvalidDescriptorId) { From c16ca689a48290e6194da1dc8bde02861667deff Mon Sep 17 00:00:00 2001 From: Max Orok Date: Thu, 10 Jun 2021 17:16:12 -0400 Subject: [PATCH 164/309] [ntuple][doc] Add RNTupleModel::MakeField examples --- tree/ntuple/v7/inc/ROOT/RNTupleModel.hxx | 43 ++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleModel.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleModel.hxx index 4ce1d59e67015..7533d24e057d6 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleModel.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleModel.hxx @@ -68,6 +68,38 @@ public: static std::unique_ptr Create() { return std::make_unique(); } /// Creates a new field and a corresponding tree value that is managed by a shared pointer. + /// + /// **Example: create some fields and fill an %RNTuple** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleModel; + /// using ROOT::Experimental::RNTupleWriter; + /// + /// #include + /// + /// auto model = RNTupleModel::Create(); + /// auto pt = model->MakeField("pt"); + /// auto vec = model->MakeField>("vec"); + /// + /// // The RNTuple is written to disk when the RNTupleWriter goes out of scope + /// { + /// auto ntuple = RNTupleWriter::Recreate(std::move(model), "myNTuple", "myFile.root"); + /// for (int i = 0; i < 100; i++) { + /// *pt = static_cast(i); + /// *vec = {i, i+1, i+2}; + /// ntuple->Fill(); + /// } + /// } + /// ~~~ + /// **Example: create a field with an initial value** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleModel; + /// + /// auto model = RNTupleModel::Create(); + /// // pt's initial value is 42.0 + /// auto pt = model->MakeField("pt", 42.0); + /// ~~~ template std::shared_ptr MakeField(std::string_view fieldName, ArgsT&&... args) { return MakeField({fieldName, ""}, std::forward(args)...); @@ -75,6 +107,17 @@ public: /// Creates a new field given a `{name, description}` pair and a corresponding tree value that /// is managed by a shared pointer. + /// + /// **Example: create a field with a description** + /// ~~~ {.cpp} + /// #include + /// using ROOT::Experimental::RNTupleModel; + /// + /// auto model = RNTupleModel::Create(); + /// auto hadronFlavour = model->MakeField({ + /// "hadronFlavour", "flavour from hadron ghost clustering" + /// }); + /// ~~~ template std::shared_ptr MakeField(std::pair fieldNameDesc, ArgsT&&... args) From 661baafca71037d7b34463688b887f47d3199acd Mon Sep 17 00:00:00 2001 From: ponyisi Date: Fri, 11 Jun 2021 10:32:56 -0500 Subject: [PATCH 165/309] Do not fire any RecursiveRemove calls by accident in TH1::LabelsInflate (#8390) Do not fire any RecursiveRemove calls by accident LabelsInflate creates a temporary histogram which has its properties copied from the original histogram (via TNamed::Copy -> TObject::Copy), including the state of kMustCleanup. But this temporary histogram is immediately detached from any directory and the deletion of the temporary shouldn't trigger a recursive cleanup. --- hist/hist/src/TH1.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index c3317dd2542bf..52d5131563202 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -5255,9 +5255,10 @@ void TH1::LabelsInflate(Option_t *ax) if (iaxis == 3) axis = GetZaxis(); if (!axis) return; - TH1 *hold = (TH1*)IsA()->New();; + TH1 *hold = (TH1*)IsA()->New(); hold->SetDirectory(0); Copy(*hold); + hold->ResetBit(kMustCleanup); Bool_t timedisp = axis->GetTimeDisplay(); Int_t nbins = axis->GetNbins(); From 78a2ef7b9b9e3e543031eb16a325ad89e85d10a8 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 11 Jun 2021 10:07:27 +0200 Subject: [PATCH 166/309] [DF] Allow using RDF Fill with types that do not inherit from TH1 This fixes ROOT-9737 . Co-authored-by: Axel Naumann --- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 52 +++++++++++++++---- tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 15 ++++-- .../inc/ROOT/RDF/RMergeableValue.hxx | 25 +++++++-- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index e6889969dfeca..33e88dd09f566 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -327,6 +327,39 @@ template class FillParHelper : public RActionImpl> { std::vector fObjects; + void UnsetDirectoryIfPossible(TH1 *h) { + h->SetDirectory(nullptr); + } + + void UnsetDirectoryIfPossible(...) {} + + // Merge overload for types with Merge(TCollection*), like TH1s + template ::value, int>::type> + auto Merge(std::vector &objs, int /*toincreaseoverloadpriority*/) + -> decltype(objs[0]->Merge((TCollection *)nullptr), void()) + { + TList l; + for (auto it = ++objs.begin(); it != objs.end(); ++it) + l.Add(*it); + objs[0]->Merge(&l); + } + + // Merge overload for types with Merge(const std::vector&) + template + auto Merge(std::vector &objs, double /*toloweroverloadpriority*/) + -> decltype(objs[0]->Merge(std::vector{}), void()) + { + objs[0]->Merge({++objs.begin(), objs.end()}); + } + + // Merge overload to error out in case no valid HIST::Merge method was detected + template + void Merge(T, ...) + { + static_assert(sizeof(T) < 0, + "The type passed to Fill does not provide a Merge(TCollection*) or Merge(const std::vector&) method."); + } + public: FillParHelper(FillParHelper &&) = default; FillParHelper(const FillParHelper &) = delete; @@ -337,9 +370,7 @@ public: // Initialise all other slots for (unsigned int i = 1; i < nSlots; ++i) { fObjects[i] = new HIST(*fObjects[0]); - if (auto objAsHist = dynamic_cast(fObjects[i])) { - objAsHist->SetDirectory(nullptr); - } + UnsetDirectoryIfPossible(fObjects[i]); } } @@ -487,15 +518,14 @@ public: void Finalize() { - auto resObj = fObjects[0]; - const auto nSlots = fObjects.size(); - TList l; - l.SetOwner(); // The list will free the memory associated to its elements upon destruction - for (unsigned int slot = 1; slot < nSlots; ++slot) { - l.Add(fObjects[slot]); - } + if (fObjects.size() == 1) + return; + + Merge(fObjects, /*toselectcorrectoverload=*/0); - resObj->Merge(&l); + // delete the copies we created for the slots other than the first + for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it) + delete *it; } HIST &PartialUpdate(unsigned int slot) { return *fObjects[slot]; } diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx index f3596266d8b9d..f75c309ea8e07 100644 --- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx @@ -1628,9 +1628,15 @@ public: //////////////////////////////////////////////////////////////////////////// /// \brief Return an object of type T on which `T::Fill` will be called once per event (*lazy action*). /// - /// T must be a type that provides a copy- or move-constructor and a `T::Fill` method that takes as many arguments - /// as the column names pass as columnList. The arguments of `T::Fill` must have type equal to the one of the - /// specified columns (these types are passed as template parameters to this method). + /// Type T must provide at least: + /// - a copy-constructor + /// - a `Fill` method that accepts as many arguments and with same types as the column names passed as columnList + /// (these types can also be passed as template parameters to this method) + /// - a `Merge` method with signature `Merge(TCollection *)` or `Merge(const std::vector&)` that merges the + /// objects assed as argument into the object on which `Merge` was called (an analogous of TH1::Merge). Note that + /// if the signature that takes a `TCollection*` is used, then T must inherit from TObject (to allow insertion in + /// the TCollection*). + /// /// \tparam FirstColumn The first type of the column the values of which are used to fill the object. Inferred together with OtherColumns if not present. /// \tparam OtherColumns A list of the other types of the columns the values of which are used to fill the object. /// \tparam T The type of the object to fill. Automatically deduced. @@ -1660,7 +1666,8 @@ public: if (!RDFInternal::HistoUtils::HasAxisLimits(*h)) { throw std::runtime_error("The absence of axes limits is not supported yet."); } - return CreateAction(columnList, h, h, columnList.size()); + return CreateAction(columnList, h, h, + columnList.size()); } //////////////////////////////////////////////////////////////////////////// diff --git a/tree/dataframe/inc/ROOT/RDF/RMergeableValue.hxx b/tree/dataframe/inc/ROOT/RDF/RMergeableValue.hxx index 5833843dd5b9f..1268e8f97cecb 100644 --- a/tree/dataframe/inc/ROOT/RDF/RMergeableValue.hxx +++ b/tree/dataframe/inc/ROOT/RDF/RMergeableValue.hxx @@ -231,6 +231,27 @@ actions: */ template class RMergeableFill final : public RMergeableValue { + + // RDataFrame's generic Fill method supports two possible signatures for Merge. + // Templated to create a dependent type to SFINAE on - in reality, `U` will always be `T`. + // This overload handles Merge(TCollection*)... + template ::value, int>::type> + auto DoMerge(const RMergeableFill &other, int /*toincreaseoverloadpriority*/) + -> decltype(((U &)this->fValue).Merge((TCollection *)nullptr), void()) + { + TList l; // The `Merge` method accepts a TList + l.Add(const_cast(&other.fValue)); // Ugly but needed because of the signature of TList::Add + this->fValue.Merge(&l); // if `T == TH1D` Eventually calls TH1::ExtendAxis that creates new instances of TH1D + } + + // ...and this one handles Merge(const std::vector &) + template + auto DoMerge(const RMergeableFill &other, double /*todecreaseoverloadpriority*/) + -> decltype(this->fValue.Merge(std::vector{}), void()) + { + this->fValue.Merge({const_cast(&other.fValue)}); + } + ///////////////////////////////////////////////////////////////////////////// /// \brief Aggregate the information contained in another RMergeableValue /// into this. @@ -250,9 +271,7 @@ class RMergeableFill final : public RMergeableValue { { try { const auto &othercast = dynamic_cast &>(other); - TList l; // The `Merge` method accepts a TList - l.Add(const_cast(&(othercast.fValue))); // Ugly but needed because of the signature of TList::Add - this->fValue.Merge(&l); // if `T == TH1D` Eventually calls TH1::ExtendAxis that creates new instances of TH1D + DoMerge(othercast, /*toselecttherightoverload=*/0); } catch (const std::bad_cast &) { throw std::invalid_argument("Results from different actions cannot be merged together."); } From 3842bc7a875b189f159ed09a5bd68cb7334942ba Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Fri, 11 Jun 2021 10:06:25 +0200 Subject: [PATCH 167/309] [DF] Add test for Fill with custom type --- tree/dataframe/test/CMakeLists.txt | 3 ++- tree/dataframe/test/DataFrameSimpleLinkDef.h | 6 +++++ tree/dataframe/test/MaxSlotHelperLinkDef.h | 5 ---- tree/dataframe/test/SimpleFiller.h | 26 ++++++++++++++++++++ tree/dataframe/test/dataframe_simple.cxx | 17 +++++++++++++ 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 tree/dataframe/test/DataFrameSimpleLinkDef.h delete mode 100644 tree/dataframe/test/MaxSlotHelperLinkDef.h create mode 100644 tree/dataframe/test/SimpleFiller.h diff --git a/tree/dataframe/test/CMakeLists.txt b/tree/dataframe/test/CMakeLists.txt index e30fd1906f03c..f4fcb5dd70e2f 100644 --- a/tree/dataframe/test/CMakeLists.txt +++ b/tree/dataframe/test/CMakeLists.txt @@ -24,7 +24,8 @@ ROOT_ADD_GTEST(dataframe_redefine dataframe_redefine.cxx LIBRARIES ROOTDataFrame if(NOT MSVC OR win_broken_tests) ROOT_ADD_GTEST(dataframe_simple dataframe_simple.cxx LIBRARIES ROOTDataFrame) target_include_directories(dataframe_simple PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - ROOT_GENERATE_DICTIONARY(MaxSlotHelperDict MaxSlotHelper.h MODULE dataframe_simple LINKDEF MaxSlotHelperLinkDef.h OPTIONS -inlineInputHeader DEPENDENCIES ROOTDataFrame) + ROOT_GENERATE_DICTIONARY(DataFrameSimpleDict MaxSlotHelper.h SimpleFiller.h MODULE dataframe_simple + LINKDEF DataFrameSimpleLinkDef.h OPTIONS -inlineInputHeader DEPENDENCIES ROOTDataFrame Hist) if(NOT (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES arm64) OR M1_BROKEN_TESTS) ROOT_ADD_GTEST(dataframe_snapshot dataframe_snapshot.cxx LIBRARIES ROOTDataFrame) endif() diff --git a/tree/dataframe/test/DataFrameSimpleLinkDef.h b/tree/dataframe/test/DataFrameSimpleLinkDef.h new file mode 100644 index 0000000000000..4c1c404380791 --- /dev/null +++ b/tree/dataframe/test/DataFrameSimpleLinkDef.h @@ -0,0 +1,6 @@ +#ifdef __CLING__ + +#pragma link C++ class MaxSlotHelper-; +#pragma link C++ class SimpleFiller-; + +#endif diff --git a/tree/dataframe/test/MaxSlotHelperLinkDef.h b/tree/dataframe/test/MaxSlotHelperLinkDef.h deleted file mode 100644 index 8a5a4c105ddeb..0000000000000 --- a/tree/dataframe/test/MaxSlotHelperLinkDef.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef __ROOTCLING__ - -#pragma link C++ class MaxSlotHelper-; - -#endif diff --git a/tree/dataframe/test/SimpleFiller.h b/tree/dataframe/test/SimpleFiller.h new file mode 100644 index 0000000000000..24121f812955b --- /dev/null +++ b/tree/dataframe/test/SimpleFiller.h @@ -0,0 +1,26 @@ +#ifndef RDF_TEST_SIMPLEFILLER +#define RDF_TEST_SIMPLEFILLER + +#include + +class SimpleFiller { + TH1D fHisto; + +public: + SimpleFiller() : fHisto("", "", 128, 0., 0.) {} + SimpleFiller(const SimpleFiller &) = default; + SimpleFiller(SimpleFiller &&) = default; + + void Fill(double x) { fHisto.Fill(x); } + void Merge(const std::vector &others) + { + TList l; + for (auto *o : others) + l.Add(&o->GetHisto()); + fHisto.Merge(&l); + } + + TH1D &GetHisto() { return fHisto; } +}; + +#endif // RDF_TEST_SIMPLEFILLER diff --git a/tree/dataframe/test/dataframe_simple.cxx b/tree/dataframe/test/dataframe_simple.cxx index b6eab650f101b..057fa47038b8b 100644 --- a/tree/dataframe/test/dataframe_simple.cxx +++ b/tree/dataframe/test/dataframe_simple.cxx @@ -20,6 +20,7 @@ #include #include "MaxSlotHelper.h" +#include "SimpleFiller.h" using namespace ROOT; using namespace ROOT::RDF; @@ -959,6 +960,22 @@ TEST_P(RDFSimpleTests, WritingToFundamentalType) EXPECT_THROW(ROOT::RDataFrame(1).Define("x", [] { return 1; }).Filter("x = 42"), std::runtime_error); } +TEST_P(RDFSimpleTests, FillWithCustomClass) +{ + auto simplefilled = ROOT::RDataFrame(10).Define("x", [] { return 42.; }).Fill(SimpleFiller{}, {"x"}); + auto &h = simplefilled->GetHisto(); + EXPECT_DOUBLE_EQ(h.GetMean(), 42.); + EXPECT_EQ(h.GetEntries(), 10); +} + +TEST_P(RDFSimpleTests, FillWithCustomClassJitted) +{ + auto simplefilled = ROOT::RDataFrame(10).Define("x", [] { return 42.; }).Fill(SimpleFiller{}, {"x"}); + auto &h = simplefilled->GetHisto(); + EXPECT_DOUBLE_EQ(h.GetMean(), 42.); + EXPECT_EQ(h.GetEntries(), 10); +} + // run single-thread tests INSTANTIATE_TEST_SUITE_P(Seq, RDFSimpleTests, ::testing::Values(false)); From ecbd6cefe0a5eee4249e9e99d64034fac6f2a62c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 20:39:43 +0200 Subject: [PATCH 168/309] [RF] New STL-compatible `add` and `overlaps` for RooAbsCollection --- roofit/roofitcore/inc/RooAbsCollection.h | 42 ++++++++++++++++++++-- roofit/roofitcore/src/RooAbsCollection.cxx | 34 ------------------ 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/roofit/roofitcore/inc/RooAbsCollection.h b/roofit/roofitcore/inc/RooAbsCollection.h index a695ca2e74741..ac4bfd94fab22 100644 --- a/roofit/roofitcore/inc/RooAbsCollection.h +++ b/roofit/roofitcore/inc/RooAbsCollection.h @@ -26,6 +26,8 @@ #include #include +#include "ROOT/RSpan.hxx" + class RooCmdArg; class RooAbsCollection : public TObject, public RooPrintable { @@ -70,6 +72,9 @@ class RooAbsCollection : public TObject, public RooPrintable { return _sizeThresholdForMapSearch; } + /// Const access to the underlying stl container. + Storage_t const& get() const { return _list; } + // List content management virtual Bool_t add(const RooAbsArg& var, Bool_t silent=kFALSE) ; virtual Bool_t addOwned(RooAbsArg& var, Bool_t silent=kFALSE); @@ -78,7 +83,23 @@ class RooAbsCollection : public TObject, public RooPrintable { virtual Bool_t remove(const RooAbsArg& var, Bool_t silent=kFALSE, Bool_t matchByNameOnly=kFALSE) ; virtual void removeAll() ; - virtual Bool_t add(const RooAbsCollection& list, Bool_t silent=kFALSE) ; + template::value_type>, + typename = std::enable_if::value> > + bool add(Iterator_t beginIt, Iterator_t endIt, bool silent=false) { + bool result = false ; + _list.reserve(_list.size() + std::distance(beginIt, endIt)); + for (auto it = beginIt; it != endIt; ++it) { + result |= add(**it,silent); + } + return result; + } + //////////////////////////////////////////////////////////////////////////////// + /// Add a collection of arguments to this collection by calling add() + /// for each element in the source collection + bool add(const RooAbsCollection& list, bool silent=kFALSE) { + return add(list._list.begin(), list._list.end(), silent); + } virtual Bool_t addOwned(const RooAbsCollection& list, Bool_t silent=kFALSE); virtual void addClone(const RooAbsCollection& list, Bool_t silent=kFALSE); Bool_t replace(const RooAbsCollection &other); @@ -132,7 +153,24 @@ class RooAbsCollection : public TObject, public RooPrintable { RooAbsCollection* selectByName(const char* nameList, Bool_t verbose=kFALSE) const ; Bool_t equals(const RooAbsCollection& otherColl) const ; bool hasSameLayout(const RooAbsCollection& other) const; - Bool_t overlaps(const RooAbsCollection& otherColl) const ; + + template::value_type>, + typename = std::enable_if::value> > + bool overlaps(Iterator_t otherCollBegin, Iterator_t otherCollEnd) const { + for (auto it = otherCollBegin; it != otherCollEnd; ++it) { + if (find(**it)) { + return true ; + } + } + return false ; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Check if this and other collection have common entries + bool overlaps(const RooAbsCollection& otherColl) const { + return overlaps(otherColl._list.begin(), otherColl._list.end()); + } /// TIterator-style iteration over contained elements. /// \note These iterators are slow. Use begin() and end() or diff --git a/roofit/roofitcore/src/RooAbsCollection.cxx b/roofit/roofitcore/src/RooAbsCollection.cxx index 391cd0f2acce1..422ba0f129ab4 100644 --- a/roofit/roofitcore/src/RooAbsCollection.cxx +++ b/roofit/roofitcore/src/RooAbsCollection.cxx @@ -469,25 +469,6 @@ Bool_t RooAbsCollection::add(const RooAbsArg& var, Bool_t silent) } - -//////////////////////////////////////////////////////////////////////////////// -/// Add a collection of arguments to this collection by calling add() -/// for each element in the source collection - -Bool_t RooAbsCollection::add(const RooAbsCollection& list, Bool_t silent) -{ - Bool_t result(false) ; - _list.reserve(_list.size() + list._list.size()); - - for (auto item : list._list) { - result |= add(*item,silent); - } - - return result; -} - - - //////////////////////////////////////////////////////////////////////////////// /// Add a collection of arguments to this collection by calling addOwned() /// for each element in the source collection @@ -807,21 +788,6 @@ Bool_t RooAbsCollection::equals(const RooAbsCollection& otherColl) const } - - -//////////////////////////////////////////////////////////////////////////////// -/// Check if this and other collection have common entries - -Bool_t RooAbsCollection::overlaps(const RooAbsCollection& otherColl) const -{ - for (auto arg : _list) { - if (otherColl.find(*arg)) { - return kTRUE ; - } - } - return kFALSE ; -} - namespace { //////////////////////////////////////////////////////////////////////////////// /// Linear search through list of stored objects. From 3378ecae72e972e8c0299ca6760cbc350b655aad Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sat, 5 Jun 2021 02:26:54 +0200 Subject: [PATCH 169/309] [RF] Add unit test for RooProdPdf::getPartIntList --- roofit/roofitcore/inc/RooProdPdf.h | 13 ++-- roofit/roofitcore/src/RooProdPdf.cxx | 68 +++++++++++++----- roofit/roofitcore/test/CMakeLists.txt | 1 + roofit/roofitcore/test/testRooProdPdf.cxx | 86 +++++++++++++++++++++++ 4 files changed, 145 insertions(+), 23 deletions(-) create mode 100644 roofit/roofitcore/test/testRooProdPdf.cxx diff --git a/roofit/roofitcore/inc/RooProdPdf.h b/roofit/roofitcore/inc/RooProdPdf.h index 0dada1bc87a95..3739a07830d74 100644 --- a/roofit/roofitcore/inc/RooProdPdf.h +++ b/roofit/roofitcore/inc/RooProdPdf.h @@ -98,6 +98,7 @@ class RooProdPdf : public RooAbsPdf { RooArgSet* findPdfNSet(RooAbsPdf& pdf) const ; + void writeCacheToStream(std::ostream& os, RooArgSet const* nset) const; private: @@ -132,10 +133,10 @@ class RooProdPdf : public RooAbsPdf { virtual void setCacheAndTrackHints(RooArgSet&) ; // The cache object - class CacheElem : public RooAbsCacheElement { + class CacheElem final : public RooAbsCacheElement { public: CacheElem() : _isRearranged(kFALSE) { } - virtual ~CacheElem() = default; + ~CacheElem() override = default; // Payload RooArgList _partList ; RooArgList _numList ; @@ -146,13 +147,13 @@ class RooProdPdf : public RooAbsPdf { std::unique_ptr _rearrangedNum{}; std::unique_ptr _rearrangedDen{}; // Cache management functions - virtual RooArgList containedArgs(Action) ; - virtual void printCompactTreeHook(std::ostream&, const char *, Int_t, Int_t) ; - private: - CacheElem(const CacheElem&) ; + RooArgList containedArgs(Action) override ; + void printCompactTreeHook(std::ostream&, const char *, Int_t, Int_t) override ; + void writeToStream(std::ostream& os) const ; } ; mutable RooObjCacheManager _cacheMgr ; // The cache manager + CacheElem* getCacheElem(RooArgSet const* nset) const ; void rearrangeProduct(CacheElem&) const; RooAbsReal* specializeIntegral(RooAbsReal& orig, const char* targetRangeName) const ; RooAbsReal* specializeRatio(RooFormulaVar& input, const char* targetRangeName) const ; diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 577b07a0092a7..f7e007a902d16 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -59,6 +59,7 @@ have to appear in any specific place in the list. #include "RooRealIntegral.h" #include "RooTrace.h" #include "RooBatchCompute.h" +#include "RooHelpers.h" #include "strtok.h" #include @@ -444,23 +445,25 @@ RooProdPdf::~RooProdPdf() } - -//////////////////////////////////////////////////////////////////////////////// -/// Calculate current value of object - -Double_t RooProdPdf::evaluate() const -{ - Int_t code ; - CacheElem* cache = (CacheElem*) _cacheMgr.getObj(_normSet, 0, &code) ; +RooProdPdf::CacheElem* RooProdPdf::getCacheElem(RooArgSet const* nset) const { + int code ; + auto cache = static_cast(_cacheMgr.getObj(nset, 0, &code)) ; // If cache doesn't have our configuration, recalculate here if (!cache) { - code = getPartIntList(_normSet, nullptr) ; - cache = (CacheElem*) _cacheMgr.getObj(_normSet, 0, &code) ; + code = getPartIntList(nset, nullptr) ; + cache = static_cast(_cacheMgr.getObj(nset, 0, &code)) ; } + return cache; +} - return calculate(*cache) ; +//////////////////////////////////////////////////////////////////////////////// +/// Calculate current value of object + +Double_t RooProdPdf::evaluate() const +{ + return calculate(*getCacheElem(_normSet)) ; } @@ -1972,12 +1975,9 @@ void RooProdPdf::CacheElem::printCompactTreeHook(ostream& os, const char* indent os << indent << "RooProdPdf begin partial integral cache" << endl ; } - RooFIter iter = _partList.fwdIterator() ; - RooAbsArg* arg ; - TString indent2(indent) ; - indent2 += Form("[%d] ",curElem) ; - while((arg=(RooAbsArg*)iter.next())) { - arg->printCompactTree(os,indent2) ; + auto indent2 = std::string(indent) + "[" + std::to_string(curElem) + "]"; + for(auto const& arg : _partList) { + arg->printCompactTree(os,indent2.c_str()) ; } if (curElem==maxElem) { @@ -2311,3 +2311,37 @@ Bool_t RooProdPdf::redirectServersHook(const RooAbsCollection& /*newServerList*/ } return kFALSE ; } + +void RooProdPdf::CacheElem::writeToStream(std::ostream& os) const { + using namespace RooHelpers; + os << "_partList\n"; + os << getColonSeparatedNameString(_partList) << "\n"; + os << "_numList\n"; + os << getColonSeparatedNameString(_numList) << "\n"; + os << "_denList\n"; + os << getColonSeparatedNameString(_denList) << "\n"; + os << "_ownedList\n"; + os << getColonSeparatedNameString(_ownedList) << "\n"; + os << "_normList\n"; + for(auto const& set : _normList) { + os << getColonSeparatedNameString(*set) << "\n"; + } + os << "_isRearranged" << "\n"; + os << _isRearranged << "\n"; + os << "_rearrangedNum" << "\n"; + if(_rearrangedNum) { + os << getColonSeparatedNameString(*_rearrangedNum) << "\n"; + } else { + os << "nullptr" << "\n"; + } + os << "_rearrangedDen" << "\n"; + if(_rearrangedDen) { + os << getColonSeparatedNameString(*_rearrangedDen) << "\n"; + } else { + os << "nullptr" << "\n"; + } +} + +void RooProdPdf::writeCacheToStream(std::ostream& os, RooArgSet const* nset) const { + getCacheElem(nset)->writeToStream(os); +} diff --git a/roofit/roofitcore/test/CMakeLists.txt b/roofit/roofitcore/test/CMakeLists.txt index 85e69a85a6afc..9ec4dd851a82a 100644 --- a/roofit/roofitcore/test/CMakeLists.txt +++ b/roofit/roofitcore/test/CMakeLists.txt @@ -22,6 +22,7 @@ ROOT_ADD_GTEST(testRooAbsPdf testRooAbsPdf.cxx LIBRARIES RooFitCore RooFit) ROOT_ADD_GTEST(testRooAbsCollection testRooAbsCollection.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testRooDataSet testRooDataSet.cxx LIBRARIES Tree RooFitCore) ROOT_ADD_GTEST(testRooFormula testRooFormula.cxx LIBRARIES RooFitCore) +ROOT_ADD_GTEST(testRooProdPdf testRooProdPdf.cxx LIBRARIES RooFitCore RooFit) ROOT_ADD_GTEST(testProxiesAndCategories testProxiesAndCategories.cxx LIBRARIES RooFitCore COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/testProxiesAndCategories_1.root diff --git a/roofit/roofitcore/test/testRooProdPdf.cxx b/roofit/roofitcore/test/testRooProdPdf.cxx new file mode 100644 index 0000000000000..39cfbf017a8b0 --- /dev/null +++ b/roofit/roofitcore/test/testRooProdPdf.cxx @@ -0,0 +1,86 @@ +// Tests for the RooProdPdf +// Author: Jonas Rembser, CERN, June 2021 + +#include "RooArgList.h" +#include "RooArgSet.h" +#include "RooPoisson.h" +#include "RooProdPdf.h" +#include "RooRealVar.h" + +#include "gtest/gtest.h" + +#include +#include +#include + +std::vector> allPossibleSubset(RooAbsCollection const &arr) +{ + std::vector> out; + std::size_t n = arr.size(); + + std::size_t count = std::pow(2, n); + for (std::size_t i = 0; i < count; i++) { + out.emplace_back(); + auto &back = out.back(); + for (std::size_t j = 0; j < n; j++) { + if ((i & (1 << j)) != 0) { + back.push_back(arr[j]); + } + } + } + return out; +} + +// Hash the integral configuration for all possible normalization sets. +unsigned int hashRooProduct(RooProdPdf const &prod) +{ + RooArgSet params; + prod.getParameters(nullptr, params); + auto subsets = allPossibleSubset(params); + + std::stringstream ss; + + for (auto const &subset : subsets) { + // this can't be on the stack, otherwise we will always get the same + // address and therefore get wrong cache hits! + auto nset = std::make_unique(subset.begin(), subset.end()); + prod.writeCacheToStream(ss, nset.get()); + } + + std::string s = ss.str(); + return TString::Hash(s.c_str(), s.size()); +} + +TEST(RooProdPdf, TestGetPartIntList) +{ + // This test checks if RooProdPdf::getPartIntList factorizes the integrals + // as expected. + // Instead of trying to construct tests for all possible cases by hand, + // this test creates a product where the factors have different patters of + // overlapping parameters. To make sure all possible cases are covered, we + // are using all possible subsets of the parameters one after the other to + // create the reference test result. + + RooRealVar x{"x", "x", 1., 0, 10}; + RooRealVar y{"y", "y", 1., 0, 10}; + RooRealVar z{"z", "z", 1., 0, 10}; + + RooRealVar m1{"m1", "m1", 1., 0, 10}; + RooRealVar m2{"m2", "m2", 1., 0, 10}; + RooRealVar m3{"m3", "m3", 1., 0, 10}; + + RooPoisson gauss1{"gauss1", "gauss1", x, m1}; + RooPoisson gauss2{"gauss2", "gauss2", x, m2}; + RooPoisson gauss3{"gauss3", "gauss3", y, m3}; + RooPoisson gauss4{"gauss4", "gauss4", z, m1}; + RooPoisson gauss5{"gauss5", "gauss5", x, m1}; + + // Product of all the Gaussians. + RooProdPdf prod{"prod", "prod", RooArgList{gauss1, gauss2, gauss3, gauss4, gauss5}}; + + // We hash the string serializations of caches for all possible + // normalization sets and compare it to the expected hash. + // This value must be updated if the convention for integral names in + // RooProdPdf changes. + EXPECT_EQ(hashRooProduct(prod), 2448666198); +} From cee6cb5712725d6a52b4629b5246f35c1ca15c5d Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 12:11:38 +0200 Subject: [PATCH 170/309] [RF] Replace a nested RooLinkedList with std::list This commit replaces a nested RooLinkedList in RooProdPdf with a std::list. --- roofit/roofitcore/inc/RooProdPdf.h | 3 +- roofit/roofitcore/src/RooProdPdf.cxx | 57 ++++++++++++---------------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/roofit/roofitcore/inc/RooProdPdf.h b/roofit/roofitcore/inc/RooProdPdf.h index 3739a07830d74..1cee15291b05c 100644 --- a/roofit/roofitcore/inc/RooProdPdf.h +++ b/roofit/roofitcore/inc/RooProdPdf.h @@ -36,6 +36,7 @@ typedef RooLinkedList* pRooLinkedList ; class RooProdPdf : public RooAbsPdf { public: + RooProdPdf() ; RooProdPdf(const char *name, const char *title, Double_t cutOff=0); RooProdPdf(const char *name, const char *title, @@ -116,7 +117,7 @@ class RooProdPdf : public RooAbsPdf { RooLinkedList& impDepList, RooLinkedList& crossDepList, RooLinkedList& intList) const; std::string makeRGPPName(const char* pfx, const RooArgSet& term, const RooArgSet& iset, const RooArgSet& nset, const char* isetRangeName) const ; - void groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outerIntDeps, + void groupProductTerms(std::list& groupedTerms, RooArgSet& outerIntDeps, const RooLinkedList& terms, const RooLinkedList& norms, const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& cross) const ; diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index f7e007a902d16..7f1f2c68ef1c1 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -772,22 +772,20 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c RooArgSet *norm, *integ, *xdeps, *imps; // Group irriducible terms that need to be (partially) integrated together - RooLinkedList groupedList; + std::list groupedList; RooArgSet outerIntDeps; // cout << "RooProdPdf::getPIL -- now calling groupProductTerms()" << endl; groupProductTerms(groupedList, outerIntDeps, terms, norms, imp, ints, cross); - RooFIter gIter = groupedList.fwdIterator(); - RooLinkedList* group; // Loop over groups // cout<<"FK: pdf("< ratioTerms; - while ((group = (RooLinkedList*) gIter.next())) { - if (1 == group->GetSize()) { + for (auto const& group : groupedList) { + if (1 == group.GetSize()) { // cout<<"FK: Starting Single Term"<At(0); + RooArgSet* term = (RooArgSet*) group.At(0); Int_t termIdx = terms.IndexOf(term); norm=(RooArgSet*) norms.At(termIdx); @@ -833,7 +831,7 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c // cout<<"FK: Starting Composite Term"<fwdIterator(); + RooFIter tIter = group.fwdIterator(); RooArgSet* term; while ((term = (RooArgSet*) tIter.next())) { @@ -875,10 +873,9 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c // Find groups with y as termNSet // Replace G(y) with (G(y),ratio) - gIter = groupedList.fwdIterator(); - while ((group = (RooLinkedList*) gIter.next())) { - if (1 == group->GetSize()) { - RooArgSet* term = (RooArgSet*) group->At(0); + for (auto const& group : groupedList) { + if (1 == group.GetSize()) { + RooArgSet* term = (RooArgSet*) group.At(0); Int_t termIdx = terms.IndexOf(term); norm = (RooArgSet*) norms.At(termIdx); @@ -893,7 +890,7 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c } } else { RooArgSet compTermSet, compTermNorm; - RooFIter tIter = group->fwdIterator(); + RooFIter tIter = group.fwdIterator(); RooArgSet* term; while ((term = (RooArgSet*) tIter.next())) { Int_t termIdx = terms.IndexOf(term); @@ -911,14 +908,13 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c } } - gIter = groupedList.fwdIterator(); - while ((group = (RooLinkedList*) gIter.next())) { + for (auto const& group : groupedList) { // cout << GetName() << ":now processing group" << endl; // group->Print("1"); - if (1 == group->GetSize()) { + if (1 == group.GetSize()) { // cout << "processing atomic item" << endl; - RooArgSet* term = (RooArgSet*) group->At(0); + RooArgSet* term = (RooArgSet*) group.At(0); Int_t termIdx = terms.IndexOf(term); norm = (RooArgSet*) norms.At(termIdx); @@ -959,7 +955,7 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c } else { // cout << "processing composite item" << endl; RooArgSet compTermSet, compTermNorm, compTermNum, compTermDen; - RooFIter tIter = group->fwdIterator(); + RooFIter tIter = group.fwdIterator(); RooArgSet* term; while ((term = (RooArgSet*) tIter.next())) { // cout << GetName() << ": processing term " << (*term) << " of composite item" << endl ; @@ -1079,7 +1075,6 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c } // We own contents of all lists filled by factorizeProduct() - groupedList.Delete(); terms.Delete(); ints.Delete(); imp.Delete(); @@ -1428,7 +1423,7 @@ RooAbsReal* RooProdPdf::specializeIntegral(RooAbsReal& input, const char* target //////////////////////////////////////////////////////////////////////////////// /// Group product into terms that can be calculated independently -void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outerIntDeps, +void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooArgSet& outerIntDeps, const RooLinkedList& terms, const RooLinkedList& norms, const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& /*cross*/) const { @@ -1436,9 +1431,8 @@ void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outer RooFIter tIter = terms.fwdIterator() ; RooArgSet* term ; while((term=(RooArgSet*)tIter.next())) { - RooLinkedList* group = new RooLinkedList ; - group->Add(term) ; - groupedTerms.Add(group) ; + groupedTerms.emplace_back(); + groupedTerms.back().Add(term) ; } // Make list of imported dependents that occur in any term @@ -1471,10 +1465,10 @@ void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outer RooLinkedList* newGroup = 0 ; // Loop over groups - RooLinkedList* group ; - RooFIter glIter = groupedTerms.fwdIterator() ; Bool_t needMerge = kFALSE ; - while((group=(RooLinkedList*)glIter.next())) { + auto group = groupedTerms.begin(); + auto nGroups = groupedTerms.size(); + for (size_t iGroup = 0; iGroup < nGroups; ++iGroup) { // See if any term in this group depends in any ay on outerDepInt RooArgSet* term2 ; @@ -1496,8 +1490,8 @@ void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outer if (needMerge) { // Create composite group if not yet existing - if (newGroup==0) { - newGroup = new RooLinkedList ; + if (newGroup==nullptr) { + newGroup = &groupedTerms.emplace_back() ; } // Add terms of this group to new term @@ -1507,14 +1501,11 @@ void RooProdPdf::groupProductTerms(RooLinkedList& groupedTerms, RooArgSet& outer } // Remove this group from list and delete it (but not its contents) - groupedTerms.Remove(group) ; - delete group ; + group = groupedTerms.erase(group); + } else { + ++group; } } - // If a new group has been created to merge terms dependent on current outerIntDep, add it to group list - if (newGroup) { - groupedTerms.Add(newGroup) ; - } } } From 1814f13c402fe27dcb499f731f9247cd9550354a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 20:54:41 +0200 Subject: [PATCH 171/309] [RF] Reduce calls to RooAbsArg::treeNodeServerList in RooProdPdf This commit reduces the number of calls to RooAbsArg::treeNodeServerList in RooProdPdf::factorizeProduct. Before, it got called three times for each pdf indirectly via RooAbsPdf::getObservables. Now it is only called once for each pdf. --- roofit/roofitcore/src/RooProdPdf.cxx | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 7f1f2c68ef1c1..d2d55e40abbd5 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -582,18 +582,34 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int pdf = (RooAbsPdf*) pdfIter.next()); ) { RooArgSet* pdfNSet, *pdfCSet; + // Make iterator over tree leaf node list to get the observables. + // This code is borrowed from RooAgsPdf::getObservables. + // RooAbsArg::treeNodeServer list is relatively expensive, so we only do it + // once and use it in a lambda function. + RooArgSet pdfLeafList("leafNodeServerList") ; + pdf->treeNodeServerList(&pdfLeafList,0,kFALSE,kTRUE,true) ; + auto getObservables = [&pdfLeafList](const RooArgSet& dataList) { + RooArgSet* out = new RooArgSet("dependents") ; + for (const auto arg : pdfLeafList) { + if (arg->dependsOnValue(dataList) && arg->isLValue()) { + out->add(*arg) ; + } + } + return out; + }; + // Reduce pdfNSet to actual dependents if (0 == strcmp("nset", pdfNSetOrig->GetName())) { - pdfNSet = pdf->getObservables(*pdfNSetOrig); + pdfNSet = getObservables(*pdfNSetOrig); pdfCSet = new RooArgSet; } else if (0 == strcmp("cset", pdfNSetOrig->GetName())) { - RooArgSet* tmp = pdf->getObservables(normSet); + RooArgSet* tmp = getObservables(normSet); tmp->remove(*pdfNSetOrig, kTRUE, kTRUE); pdfCSet = pdfNSetOrig; pdfNSet = tmp; } else { // Legacy mode. Interpret at NSet for backward compatibility - pdfNSet = pdf->getObservables(*pdfNSetOrig); + pdfNSet = getObservables(*pdfNSetOrig); pdfCSet = new RooArgSet; } @@ -602,7 +618,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int RooArgSet pdfAllDeps; // All dependents of this PDF // Make list of all dependents of this PDF - RooArgSet* tmp = pdf->getObservables(normSet); + RooArgSet* tmp = getObservables(normSet); pdfAllDeps.add(*tmp); delete tmp; @@ -622,7 +638,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // cout << GetName() << ": pdfNormDeps for " << pdf->GetName() << " = " << pdfNormDeps << endl; - RooArgSet* pdfIntSet = pdf->getObservables(intSet) ; + RooArgSet* pdfIntSet = getObservables(intSet) ; // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet if (0 == pdfNormDeps.getSize() && pdfCSet->getSize() > 0) { From ec3db507c49afe3a512a71e8b91f613c68287598 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 13:08:04 +0200 Subject: [PATCH 172/309] [RF] Make depIntNoNormList in RooProdPdf::factorizeProduct a std::vector --- roofit/roofitcore/src/RooProdPdf.cxx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index d2d55e40abbd5..66d69c642ae92 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -564,7 +564,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int { // List of all term dependents: normalization and imported RooLinkedList depAllList; - RooLinkedList depIntNoNormList; + std::vector depIntNoNormList; // Setup lists for factorization terms and their dependents RooArgSet* term(0); @@ -693,7 +693,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int termNormDeps = new RooArgSet("termNormDeps"); termAllDeps = new RooArgSet("termAllDeps"); termIntDeps = new RooArgSet("termIntDeps"); - termIntNoNormDeps = new RooArgSet("termIntNoNormDeps"); + termIntNoNormDeps = &depIntNoNormList.emplace_back("termIntNoNormDeps"); term->add(*pdf); termNormDeps->add(pdfNormDeps, kFALSE); @@ -705,7 +705,6 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int normList.Add(termNormDeps); depAllList.Add(termAllDeps); intList.Add(termIntDeps); - depIntNoNormList.Add(termIntNoNormDeps); } } @@ -718,15 +717,14 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int } // Loop over list of terms again to determine 'imported' observables - RooArgSet *normDeps, *allDeps, *intNoNormDeps; + int i = 0; + RooArgSet *normDeps, *allDeps; for (RooFIter lIter = termList.fwdIterator(), ldIter = normList.fwdIterator(), - laIter = depAllList.fwdIterator(), - innIter = depIntNoNormList.fwdIterator(); + laIter = depAllList.fwdIterator(); (normDeps = (RooArgSet*) ldIter.next(), allDeps = (RooArgSet*) laIter.next(), - intNoNormDeps = (RooArgSet*) innIter.next(), - term=(RooArgSet*)lIter.next()); ) { + term=(RooArgSet*)lIter.next()); ++i) { // Make list of wholly imported dependents RooArgSet impDeps(*allDeps); impDeps.remove(*normDeps, kTRUE, kTRUE); @@ -735,14 +733,13 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Make list of cross dependents (term is self contained for these dependents, // but components import dependents from other components) - RooArgSet* crossDeps = (RooArgSet*) intNoNormDeps->selectCommon(*normDeps); + RooArgSet* crossDeps = (RooArgSet*) depIntNoNormList[i].selectCommon(*normDeps); crossDepList.Add(crossDeps->snapshot()); // cout << GetName() << ": list of cross dependents for term " << (*term) << " set to " << *crossDeps << endl ; delete crossDeps; } depAllList.Delete(); - depIntNoNormList.Delete(); return; } From 540b1f29008e9da6442c93dc4abce35fedbba5e8 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 13:27:32 +0200 Subject: [PATCH 173/309] [RF] Make depAllList in RooProdPdf::factorizeProduct a std::vector --- roofit/roofitcore/src/RooProdPdf.cxx | 34 +++++++++------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 66d69c642ae92..a4530ee5d1949 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -563,13 +563,12 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int RooLinkedList& intList) const { // List of all term dependents: normalization and imported - RooLinkedList depAllList; + std::vector depAllList; std::vector depIntNoNormList; // Setup lists for factorization terms and their dependents RooArgSet* term(0); RooArgSet* termNormDeps(0); - RooArgSet* termAllDeps(0); RooArgSet* termIntDeps(0); RooArgSet* termIntNoNormDeps(0); @@ -618,9 +617,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int RooArgSet pdfAllDeps; // All dependents of this PDF // Make list of all dependents of this PDF - RooArgSet* tmp = getObservables(normSet); - pdfAllDeps.add(*tmp); - delete tmp; + pdfAllDeps.add(*std::unique_ptr{getObservables(normSet)}); // cout << GetName() << ": pdf = " << pdf->GetName() << " pdfAllDeps = " << pdfAllDeps << " pdfNSet = " << *pdfNSet << " pdfCSet = " << *pdfCSet << endl; @@ -628,9 +625,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Make list of normalization dependents for this PDF; if (pdfNSet->getSize() > 0) { // PDF is conditional - RooArgSet* tmp2 = (RooArgSet*) pdfAllDeps.selectCommon(*pdfNSet); - pdfNormDeps.add(*tmp2); - delete tmp2; + pdfNormDeps.add(*std::unique_ptr{static_cast(pdfAllDeps.selectCommon(*pdfNSet))}); } else { // PDF is regular pdfNormDeps.add(pdfAllDeps); @@ -653,12 +648,11 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Check if this PDF has dependents overlapping with one of the existing terms Bool_t done(kFALSE); + int j = 0; for (RooFIter lIter = termList.fwdIterator(), - ldIter = normList.fwdIterator(), - laIter = depAllList.fwdIterator(); + ldIter = normList.fwdIterator(); (termNormDeps = (RooArgSet*) ldIter.next(), - termAllDeps = (RooArgSet*) laIter.next(), - term = (RooArgSet*) lIter.next()); ) { + term = (RooArgSet*) lIter.next()); ++j) { // PDF should be added to existing term if // 1) It has overlapping normalization dependents with any other PDF in existing term // 2) It has overlapping dependents of any class for which integration is requested @@ -673,7 +667,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int term->add(*pdf); termNormDeps->add(pdfNormDeps, kFALSE); - termAllDeps->add(pdfAllDeps, kFALSE); + depAllList[j].add(pdfAllDeps, kFALSE); if (termIntDeps) { termIntDeps->add(*pdfIntSet, kFALSE); } @@ -691,19 +685,17 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // cout << GetName() << ": creating new term" << endl; term = new RooArgSet("term"); termNormDeps = new RooArgSet("termNormDeps"); - termAllDeps = new RooArgSet("termAllDeps"); termIntDeps = new RooArgSet("termIntDeps"); termIntNoNormDeps = &depIntNoNormList.emplace_back("termIntNoNormDeps"); term->add(*pdf); termNormDeps->add(pdfNormDeps, kFALSE); - termAllDeps->add(pdfAllDeps, kFALSE); + depAllList.emplace_back("termAllDeps").add(pdfAllDeps, kFALSE); termIntDeps->add(*pdfIntSet, kFALSE); termIntNoNormDeps->add(pdfIntNoNormDeps, kFALSE); termList.Add(term); normList.Add(termNormDeps); - depAllList.Add(termAllDeps); intList.Add(termIntDeps); } } @@ -718,15 +710,13 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Loop over list of terms again to determine 'imported' observables int i = 0; - RooArgSet *normDeps, *allDeps; + RooArgSet *normDeps; for (RooFIter lIter = termList.fwdIterator(), - ldIter = normList.fwdIterator(), - laIter = depAllList.fwdIterator(); + ldIter = normList.fwdIterator(); (normDeps = (RooArgSet*) ldIter.next(), - allDeps = (RooArgSet*) laIter.next(), term=(RooArgSet*)lIter.next()); ++i) { // Make list of wholly imported dependents - RooArgSet impDeps(*allDeps); + RooArgSet impDeps(depAllList[i]); impDeps.remove(*normDeps, kTRUE, kTRUE); impDepList.Add(impDeps.snapshot()); // cout << GetName() << ": list of imported dependents for term " << (*term) << " set to " << impDeps << endl ; @@ -739,8 +729,6 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int delete crossDeps; } - depAllList.Delete(); - return; } From bdf75028147226c13b7fe0ed28b66575a7771c21 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 16 Apr 2021 14:45:28 +0200 Subject: [PATCH 174/309] [RF] Avoid construction RooArgSets in RooProdPdf::factorizeProduct The construction of RooArgSets is rather expensive in RooProdPdf::factorizeProduct. This commits replaces the RooArgSets with std::vectors that are only created once such that manual memory allocation is avoided. --- roofit/roofitcore/src/RooProdPdf.cxx | 130 +++++++++++++++++---------- 1 file changed, 84 insertions(+), 46 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index a4530ee5d1949..18fab69a47bb3 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -554,6 +554,44 @@ RooSpan RooProdPdf::evaluateSpan(RooBatchCompute::RunContext& evalData, } } +namespace { + +template +void eraseNullptrs(std::vector& v) { + v.erase(std::remove_if(v.begin(), v.end(), [](T* x){ return x == nullptr; } ), v.end()); +} + +void removeCommon(std::vector &v, std::span other) { + + for (auto const& arg : other) { + auto namePtrMatch = [&arg](const RooAbsArg* elm) { + return elm->namePtr() == arg->namePtr(); + }; + + auto found = std::find_if(v.begin(), v.end(), namePtrMatch); + if(found != v.end()) { + *found = nullptr; + } + } + eraseNullptrs(v); +} + +void addCommon(std::vector &v, std::vector const& o1, std::vector const& o2) { + + for (auto const& arg : o1) { + auto namePtrMatch = [&arg](const RooAbsArg* elm) { + return elm->namePtr() == arg->namePtr(); + }; + + if(std::find_if(o2.begin(), o2.end(), namePtrMatch) != o2.end()) { + v.push_back(arg); + } + } +} + +} + + //////////////////////////////////////////////////////////////////////////////// /// Factorize product in irreducible terms for given choice of integration/normalization @@ -572,6 +610,13 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int RooArgSet* termIntDeps(0); RooArgSet* termIntNoNormDeps(0); + std::vector pdfIntNoNormDeps; + std::vector pdfIntSet; + std::vector pdfNSet; + std::vector pdfCSet; + std::vector pdfNormDeps; // Dependents to be normalized for the PDF + std::vector pdfAllDeps; // All dependents of this PDF + // Loop over the PDFs RooAbsPdf* pdf; RooArgSet* pdfNSetOrig; @@ -579,7 +624,8 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int nIter = _pdfNSetList.fwdIterator(); (pdfNSetOrig = (RooArgSet*) nIter.next(), pdf = (RooAbsPdf*) pdfIter.next()); ) { - RooArgSet* pdfNSet, *pdfCSet; + pdfNSet.clear(); + pdfCSet.clear(); // Make iterator over tree leaf node list to get the observables. // This code is borrowed from RooAgsPdf::getObservables. @@ -587,62 +633,61 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // once and use it in a lambda function. RooArgSet pdfLeafList("leafNodeServerList") ; pdf->treeNodeServerList(&pdfLeafList,0,kFALSE,kTRUE,true) ; - auto getObservables = [&pdfLeafList](const RooArgSet& dataList) { - RooArgSet* out = new RooArgSet("dependents") ; + auto getObservables = [&pdfLeafList]( + std::vector & out, + const RooArgSet& dataList) { for (const auto arg : pdfLeafList) { if (arg->dependsOnValue(dataList) && arg->isLValue()) { - out->add(*arg) ; + out.push_back(arg) ; } } - return out; }; // Reduce pdfNSet to actual dependents if (0 == strcmp("nset", pdfNSetOrig->GetName())) { - pdfNSet = getObservables(*pdfNSetOrig); - pdfCSet = new RooArgSet; + getObservables(pdfNSet, *pdfNSetOrig); } else if (0 == strcmp("cset", pdfNSetOrig->GetName())) { - RooArgSet* tmp = getObservables(normSet); - tmp->remove(*pdfNSetOrig, kTRUE, kTRUE); - pdfCSet = pdfNSetOrig; - pdfNSet = tmp; + getObservables(pdfNSet, normSet); + removeCommon(pdfNSet, pdfNSetOrig->get()); + pdfCSet = pdfNSetOrig->get(); } else { // Legacy mode. Interpret at NSet for backward compatibility - pdfNSet = getObservables(*pdfNSetOrig); - pdfCSet = new RooArgSet; + getObservables(pdfNSet, *pdfNSetOrig); } - RooArgSet pdfNormDeps; // Dependents to be normalized for the PDF - RooArgSet pdfAllDeps; // All dependents of this PDF + pdfNormDeps.clear(); + pdfAllDeps.clear(); // Make list of all dependents of this PDF - pdfAllDeps.add(*std::unique_ptr{getObservables(normSet)}); + getObservables(pdfAllDeps, normSet); // cout << GetName() << ": pdf = " << pdf->GetName() << " pdfAllDeps = " << pdfAllDeps << " pdfNSet = " << *pdfNSet << " pdfCSet = " << *pdfCSet << endl; // Make list of normalization dependents for this PDF; - if (pdfNSet->getSize() > 0) { + if (!pdfNSet.empty()) { // PDF is conditional - pdfNormDeps.add(*std::unique_ptr{static_cast(pdfAllDeps.selectCommon(*pdfNSet))}); + addCommon(pdfNormDeps, pdfAllDeps, pdfNSet); } else { // PDF is regular - pdfNormDeps.add(pdfAllDeps); + pdfNormDeps = pdfAllDeps; } // cout << GetName() << ": pdfNormDeps for " << pdf->GetName() << " = " << pdfNormDeps << endl; - RooArgSet* pdfIntSet = getObservables(intSet) ; + pdfIntSet.clear(); + getObservables(pdfIntSet, intSet) ; // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet - if (0 == pdfNormDeps.getSize() && pdfCSet->getSize() > 0) { - pdfIntSet->remove(*pdfCSet, kTRUE, kTRUE); + if (pdfNormDeps.empty() && !pdfCSet.empty()) { + removeCommon(pdfIntSet, pdfCSet); // cout << GetName() << ": have no norm deps, removing conditional observables from intset" << endl; } - RooArgSet pdfIntNoNormDeps(*pdfIntSet); - pdfIntNoNormDeps.remove(pdfNormDeps, kTRUE, kTRUE); + pdfIntNoNormDeps.clear(); + pdfIntNoNormDeps = pdfIntSet; + removeCommon(pdfIntNoNormDeps, pdfNormDeps); // cout << GetName() << ": pdf = " << pdf->GetName() << " intset = " << *pdfIntSet << " pdfIntNoNormDeps = " << pdfIntNoNormDeps << endl; @@ -659,20 +704,20 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // 3) If normalization happens over multiple ranges, and those ranges are both defined // in either observable - Bool_t normOverlap = pdfNormDeps.overlaps(*termNormDeps); + bool normOverlap = termNormDeps->overlaps(pdfNormDeps.begin(), pdfNormDeps.end()); //Bool_t intOverlap = pdfIntSet->overlaps(*termAllDeps); if (normOverlap) { // cout << GetName() << ": this term overlaps with term " << (*term) << " in normalization observables" << endl; term->add(*pdf); - termNormDeps->add(pdfNormDeps, kFALSE); - depAllList[j].add(pdfAllDeps, kFALSE); + termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false); + depAllList[j].add(pdfAllDeps.begin(), pdfAllDeps.end(), false); if (termIntDeps) { - termIntDeps->add(*pdfIntSet, kFALSE); + termIntDeps->add(pdfIntSet.begin(), pdfIntSet.end(), false); } if (termIntNoNormDeps) { - termIntNoNormDeps->add(pdfIntNoNormDeps, kFALSE); + termIntNoNormDeps->add(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), false); } done = kTRUE; } @@ -680,19 +725,18 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // If not, create a new term if (!done) { - if (!(0 == pdfNormDeps.getSize() && 0 == pdfAllDeps.getSize() && - 0 == pdfIntSet->getSize()) || 0 == normSet.getSize()) { + if (!(pdfNormDeps.empty() && pdfAllDeps.empty() && + pdfIntSet.empty()) || 0 == normSet.getSize()) { // cout << GetName() << ": creating new term" << endl; term = new RooArgSet("term"); termNormDeps = new RooArgSet("termNormDeps"); - termIntDeps = new RooArgSet("termIntDeps"); - termIntNoNormDeps = &depIntNoNormList.emplace_back("termIntNoNormDeps"); + depAllList.emplace_back(pdfAllDeps.begin(), pdfAllDeps.end(), "termAllDeps"); + termIntDeps = new RooArgSet(pdfIntSet.begin(), pdfIntSet.end(), "termIntDeps"); + depIntNoNormList.emplace_back(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), "termIntNoNormDeps"); + termIntNoNormDeps = &depIntNoNormList.back(); term->add(*pdf); - termNormDeps->add(pdfNormDeps, kFALSE); - depAllList.emplace_back("termAllDeps").add(pdfAllDeps, kFALSE); - termIntDeps->add(*pdfIntSet, kFALSE); - termIntNoNormDeps->add(pdfIntNoNormDeps, kFALSE); + termNormDeps->add(pdfNormDeps.begin(), pdfNormDeps.end(), false); termList.Add(term); normList.Add(termNormDeps); @@ -700,12 +744,6 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int } } - // We own the reduced version of pdfNSet - delete pdfNSet; - delete pdfIntSet; - if (pdfCSet != pdfNSetOrig) { - delete pdfCSet; - } } // Loop over list of terms again to determine 'imported' observables @@ -723,10 +761,9 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Make list of cross dependents (term is self contained for these dependents, // but components import dependents from other components) - RooArgSet* crossDeps = (RooArgSet*) depIntNoNormList[i].selectCommon(*normDeps); + auto crossDeps = std::unique_ptr{static_cast(depIntNoNormList[i].selectCommon(*normDeps))}; crossDepList.Add(crossDeps->snapshot()); // cout << GetName() << ": list of cross dependents for term " << (*term) << " set to " << *crossDeps << endl ; - delete crossDeps; } return; @@ -1492,7 +1529,8 @@ void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooAr if (needMerge) { // Create composite group if not yet existing if (newGroup==nullptr) { - newGroup = &groupedTerms.emplace_back() ; + groupedTerms.emplace_back() ; + newGroup = &groupedTerms.back() ; } // Add terms of this group to new term From 650713897a24524853eda51ea7b8b618f2ca5a2c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 20 Apr 2021 22:03:37 +0200 Subject: [PATCH 175/309] [RF] Turn groupedTerms in RooProdPdf into a STL collection Change type of groupedTerms from std::list to std::list>. --- roofit/roofitcore/inc/RooProdPdf.h | 2 +- roofit/roofitcore/src/RooProdPdf.cxx | 41 +++++++++++----------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/roofit/roofitcore/inc/RooProdPdf.h b/roofit/roofitcore/inc/RooProdPdf.h index 1cee15291b05c..5934d06afff7a 100644 --- a/roofit/roofitcore/inc/RooProdPdf.h +++ b/roofit/roofitcore/inc/RooProdPdf.h @@ -117,7 +117,7 @@ class RooProdPdf : public RooAbsPdf { RooLinkedList& impDepList, RooLinkedList& crossDepList, RooLinkedList& intList) const; std::string makeRGPPName(const char* pfx, const RooArgSet& term, const RooArgSet& iset, const RooArgSet& nset, const char* isetRangeName) const ; - void groupProductTerms(std::list& groupedTerms, RooArgSet& outerIntDeps, + void groupProductTerms(std::list>& groupedTerms, RooArgSet& outerIntDeps, const RooLinkedList& terms, const RooLinkedList& norms, const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& cross) const ; diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 18fab69a47bb3..36d33b4ad4a8c 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -810,7 +810,7 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c RooArgSet *norm, *integ, *xdeps, *imps; // Group irriducible terms that need to be (partially) integrated together - std::list groupedList; + std::list> groupedList; RooArgSet outerIntDeps; // cout << "RooProdPdf::getPIL -- now calling groupProductTerms()" << endl; groupProductTerms(groupedList, outerIntDeps, terms, norms, imp, ints, cross); @@ -820,10 +820,10 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c // Find groups of type F(x|y), i.e. termImpSet!=0, construct ratio object map ratioTerms; for (auto const& group : groupedList) { - if (1 == group.GetSize()) { + if (1 == group.size()) { // cout<<"FK: Starting Single Term"<Print("1"); - if (1 == group.GetSize()) { + if (1 == group.size()) { // cout << "processing atomic item" << endl; - RooArgSet* term = (RooArgSet*) group.At(0); + RooArgSet* term = group[0]; Int_t termIdx = terms.IndexOf(term); norm = (RooArgSet*) norms.At(termIdx); @@ -993,9 +989,7 @@ Int_t RooProdPdf::getPartIntList(const RooArgSet* nset, const RooArgSet* iset, c } else { // cout << "processing composite item" << endl; RooArgSet compTermSet, compTermNorm, compTermNum, compTermDen; - RooFIter tIter = group.fwdIterator(); - RooArgSet* term; - while ((term = (RooArgSet*) tIter.next())) { + for (auto const& term : group) { // cout << GetName() << ": processing term " << (*term) << " of composite item" << endl ; Int_t termIdx = terms.IndexOf(term); norm = (RooArgSet*) norms.At(termIdx); @@ -1461,7 +1455,7 @@ RooAbsReal* RooProdPdf::specializeIntegral(RooAbsReal& input, const char* target //////////////////////////////////////////////////////////////////////////////// /// Group product into terms that can be calculated independently -void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooArgSet& outerIntDeps, +void RooProdPdf::groupProductTerms(std::list>& groupedTerms, RooArgSet& outerIntDeps, const RooLinkedList& terms, const RooLinkedList& norms, const RooLinkedList& imps, const RooLinkedList& ints, const RooLinkedList& /*cross*/) const { @@ -1470,7 +1464,7 @@ void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooAr RooArgSet* term ; while((term=(RooArgSet*)tIter.next())) { groupedTerms.emplace_back(); - groupedTerms.back().Add(term) ; + groupedTerms.back().emplace_back(term) ; } // Make list of imported dependents that occur in any term @@ -1500,7 +1494,7 @@ void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooAr while ((outerIntDep =(RooAbsArg*)oidIter.next())) { // Collect groups that feature this dependent - RooLinkedList* newGroup = 0 ; + std::vector* newGroup = nullptr ; // Loop over groups Bool_t needMerge = kFALSE ; @@ -1509,9 +1503,7 @@ void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooAr for (size_t iGroup = 0; iGroup < nGroups; ++iGroup) { // See if any term in this group depends in any ay on outerDepInt - RooArgSet* term2 ; - RooFIter tIter2 = group->fwdIterator() ; - while((term2=(RooArgSet*)tIter2.next())) { + for (auto const& term2 : *group) { Int_t termIdx = terms.IndexOf(term2) ; RooArgSet* termNormDeps = (RooArgSet*) norms.At(termIdx) ; @@ -1534,9 +1526,8 @@ void RooProdPdf::groupProductTerms(std::list& groupedTerms, RooAr } // Add terms of this group to new term - tIter2 = group->fwdIterator() ; - while((term2=(RooArgSet*)tIter2.next())) { - newGroup->Add(term2) ; + for (auto& term2 : *group) { + newGroup->emplace_back(term2) ; } // Remove this group from list and delete it (but not its contents) From 8c4e06c94a6e9e3649703c06c307cc4c6a9c57df Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 20 Apr 2021 22:33:43 +0200 Subject: [PATCH 176/309] [RF] Some code modernization in RooProdPdf --- roofit/roofitcore/src/RooProdPdf.cxx | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 36d33b4ad4a8c..c3287f79c23a5 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -620,10 +620,10 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Loop over the PDFs RooAbsPdf* pdf; RooArgSet* pdfNSetOrig; - for (RooFIter pdfIter = _pdfList.fwdIterator(), - nIter = _pdfNSetList.fwdIterator(); - (pdfNSetOrig = (RooArgSet*) nIter.next(), - pdf = (RooAbsPdf*) pdfIter.next()); ) { + for (RooLinkedListIter pdfIter = _pdfList.iterator(), + nIter = _pdfNSetList.iterator(); + (pdfNSetOrig = static_cast(nIter.Next()), + pdf = static_cast(pdfIter.Next())); ) { pdfNSet.clear(); pdfCSet.clear(); @@ -692,12 +692,12 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // cout << GetName() << ": pdf = " << pdf->GetName() << " intset = " << *pdfIntSet << " pdfIntNoNormDeps = " << pdfIntNoNormDeps << endl; // Check if this PDF has dependents overlapping with one of the existing terms - Bool_t done(kFALSE); + bool done = false; int j = 0; - for (RooFIter lIter = termList.fwdIterator(), - ldIter = normList.fwdIterator(); - (termNormDeps = (RooArgSet*) ldIter.next(), - term = (RooArgSet*) lIter.next()); ++j) { + for (RooLinkedListIter lIter = termList.iterator(), + ldIter = normList.iterator(); + (termNormDeps = static_cast(ldIter.Next()), + term = static_cast(lIter.Next())); ++j) { // PDF should be added to existing term if // 1) It has overlapping normalization dependents with any other PDF in existing term // 2) It has overlapping dependents of any class for which integration is requested @@ -719,7 +719,8 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int if (termIntNoNormDeps) { termIntNoNormDeps->add(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), false); } - done = kTRUE; + termIntNoNormDeps->add(pdfIntNoNormDeps.begin(), pdfIntNoNormDeps.end(), false); + done = true; } } @@ -749,10 +750,10 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Loop over list of terms again to determine 'imported' observables int i = 0; RooArgSet *normDeps; - for (RooFIter lIter = termList.fwdIterator(), - ldIter = normList.fwdIterator(); - (normDeps = (RooArgSet*) ldIter.next(), - term=(RooArgSet*)lIter.next()); ++i) { + for (RooLinkedListIter lIter = termList.iterator(), + ldIter = normList.iterator(); + (normDeps = static_cast(ldIter.Next()), + term= static_cast(lIter.Next())); ++i) { // Make list of wholly imported dependents RooArgSet impDeps(depAllList[i]); impDeps.remove(*normDeps, kTRUE, kTRUE); @@ -761,7 +762,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Make list of cross dependents (term is self contained for these dependents, // but components import dependents from other components) - auto crossDeps = std::unique_ptr{static_cast(depIntNoNormList[i].selectCommon(*normDeps))}; + auto crossDeps = std::unique_ptr{depIntNoNormList[i].selectCommon(*normDeps)}; crossDepList.Add(crossDeps->snapshot()); // cout << GetName() << ": list of cross dependents for term " << (*term) << " set to " << *crossDeps << endl ; } From c550567b9e4d49a5882dd91f16d60a5d9dd14e81 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 11 Jun 2021 12:29:06 +0200 Subject: [PATCH 177/309] [RF] Use RooHelpers::tokenise in RooAbsData::createHistogram() To avoid having to include "strlcpy.h" again. --- roofit/roofitcore/src/RooAbsData.cxx | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/roofit/roofitcore/src/RooAbsData.cxx b/roofit/roofitcore/src/RooAbsData.cxx index 2c1a372f4c4fb..0da4ad0189203 100644 --- a/roofit/roofitcore/src/RooAbsData.cxx +++ b/roofit/roofitcore/src/RooAbsData.cxx @@ -1362,22 +1362,7 @@ TH1 *RooAbsData::fillHistogram(TH1 *hist, const RooArgList &plotVars, const char } // Parse cutRange specification - vector cutVec ; - if (cutRange && strlen(cutRange)>0) { - if (strchr(cutRange,',')==0) { - cutVec.push_back(cutRange) ; - } else { - const size_t bufSize = strlen(cutRange)+1; - char* buf = new char[bufSize] ; - strlcpy(buf,cutRange,bufSize) ; - const char* oneRange = strtok(buf,",") ; - while(oneRange) { - cutVec.push_back(oneRange) ; - oneRange = strtok(0,",") ; - } - delete[] buf ; - } - } + const auto cutVec = RooHelpers::tokenise(cutRange ? cutRange : "", ",", /*returnEmptyToken =*/ false); // Loop over events and fill the histogram if (hist->GetSumw2()->fN==0) { From 9cb05fd843c5f788a759474d0c78722b934ad08f Mon Sep 17 00:00:00 2001 From: "Harshal.S" Date: Fri, 11 Jun 2021 10:33:13 +0530 Subject: [PATCH 178/309] [RF] Pythonized RooSimultaneous --- .../ROOT/pythonization/_roofit/__init__.py | 3 +- .../pythonization/_roofit/_roosimultaneous.py | 60 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py index 4eba77fab894e..92062145b0956 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py @@ -22,10 +22,11 @@ from ._rooarglist import RooArgList from ._rooargset import RooArgSet from ._rooworkspace import RooWorkspace +from ._roosimultaneous import RooSimultaneous # list of python classes that are used to pythonize RooFit classes -python_classes = [RooAbsCollection, RooAbsData, RooAbsPdf, RooAbsReal, RooArgList, RooArgSet, RooWorkspace] +python_classes = [RooAbsCollection, RooAbsData, RooAbsPdf, RooAbsReal, RooArgList, RooArgSet, RooSimultaneous, RooWorkspace] # create a dictionary for convenient access to python classes python_classes_dict = dict() diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py new file mode 100644 index 0000000000000..cb8ce60a0a991 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py @@ -0,0 +1,60 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r''' +/** +\class RooSimultaneous +\brief \parblock \endparblock +\htmlonly +

+\endhtmlonly +*/ +''' + + +from ._utils import _getter + +class RooSimultaneous(object): + def plotOn(self, *args, **kwargs): + """ + Docstring + """ + # Redefinition of `RooSimultaneous.plotOn` for keyword arguments. + # the keywords must correspond to the CmdArg of the `plotOn` function. + # Parameters: + # self: instance of `RooSimultaneous` class + # *args: arguments passed to `plotOn` + # **kwargs: keyword arguments passed to `plotOn` + if not kwargs: + return self._plotOn(*args) + else: + nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) + return self._plotOn(*nargs) From ab04b4e40ef060f855c19590ad3876aaa7f6348f Mon Sep 17 00:00:00 2001 From: "Harshal.S" Date: Fri, 11 Jun 2021 11:20:54 +0530 Subject: [PATCH 179/309] [RF] Pythonized RooFit tutorial files --- tutorials/roofit/rf101_basics.py | 2 +- tutorials/roofit/rf103_interprfuncs.py | 16 +--- tutorials/roofit/rf104_classfactory.py | 4 +- tutorials/roofit/rf106_plotdecoration.py | 3 +- tutorials/roofit/rf107_plotstyles.py | 24 ++---- tutorials/roofit/rf108_plotbinning.py | 7 +- tutorials/roofit/rf111_derivatives.py | 12 +-- tutorials/roofit/rf201_composite.py | 19 ++--- tutorials/roofit/rf202_extendedmlfit.py | 13 +--- tutorials/roofit/rf203_ranges.py | 10 +-- tutorials/roofit/rf204_extrangefit.py | 24 +++--- tutorials/roofit/rf204a_extendedLikelihood.py | 12 +-- tutorials/roofit/rf205_compplot.py | 37 ++------- tutorials/roofit/rf208_convolution.py | 2 +- tutorials/roofit/rf209_anaconv.py | 4 +- tutorials/roofit/rf210_angularconv.py | 4 +- tutorials/roofit/rf211_paramconv.py | 2 +- tutorials/roofit/rf306_condpereventerrors.py | 7 +- tutorials/roofit/rf309_ndimplot.py | 33 ++++---- tutorials/roofit/rf310_sliceplot.py | 8 +- tutorials/roofit/rf311_rangeplot.py | 4 +- tutorials/roofit/rf312_multirangefit.py | 9 +-- tutorials/roofit/rf314_paramfitrange.py | 5 +- tutorials/roofit/rf315_projectpdf.py | 2 +- tutorials/roofit/rf316_llratioplot.py | 2 +- tutorials/roofit/rf402_datahandling.py | 7 +- tutorials/roofit/rf405_realtocatfuncs.py | 11 +-- tutorials/roofit/rf501_simultaneouspdf.py | 13 ++-- tutorials/roofit/rf505_asciicfg.py | 2 +- tutorials/roofit/rf506_msgservice.py | 4 +- tutorials/roofit/rf507_debugtools.py | 4 +- tutorials/roofit/rf509_wsinteractive.py | 5 +- tutorials/roofit/rf510_wsnamedsets.py | 14 ++-- tutorials/roofit/rf511_wsfactory_basic.py | 2 +- tutorials/roofit/rf601_intminuit.py | 6 +- tutorials/roofit/rf603_multicpu.py | 4 +- tutorials/roofit/rf604_constraints.py | 11 +-- tutorials/roofit/rf605_profilell.py | 4 +- tutorials/roofit/rf606_nllerrorhandling.py | 10 +-- tutorials/roofit/rf607_fitresult.py | 2 +- tutorials/roofit/rf608_fitresultaspdf.py | 2 +- tutorials/roofit/rf609_xychi2fit.py | 5 +- tutorials/roofit/rf610_visualerror.py | 72 ++++++----------- tutorials/roofit/rf701_efficiencyfit.py | 14 +--- tutorials/roofit/rf702_efficiencyfit_2D.py | 4 +- tutorials/roofit/rf703_effpdfprod.py | 4 +- tutorials/roofit/rf704_amplitudefit.py | 12 +-- tutorials/roofit/rf705_linearmorph.py | 22 +++--- tutorials/roofit/rf707_kernelestimation.py | 5 +- tutorials/roofit/rf708_bphysics.py | 77 +++++++------------ tutorials/roofit/rf801_mcstudy.py | 8 +- tutorials/roofit/rf902_numgenconfig.py | 9 +-- tutorials/roofit/rf903_numintcache.py | 5 +- 53 files changed, 225 insertions(+), 378 deletions(-) diff --git a/tutorials/roofit/rf101_basics.py b/tutorials/roofit/rf101_basics.py index 116215778f62a..56b15204fc680 100644 --- a/tutorials/roofit/rf101_basics.py +++ b/tutorials/roofit/rf101_basics.py @@ -33,7 +33,7 @@ sigma.setVal(3) # Plot gauss in frame (i.e. in x) and draw frame on canvas -gauss.plotOn(xframe, ROOT.RooFit.LineColor(ROOT.kRed)) +gauss.plotOn(xframe, LineColor = ROOT.kRed) # Generate events # ----------------------------- diff --git a/tutorials/roofit/rf103_interprfuncs.py b/tutorials/roofit/rf103_interprfuncs.py index 7e0ecca93e17c..4da258fadb607 100644 --- a/tutorials/roofit/rf103_interprfuncs.py +++ b/tutorials/roofit/rf103_interprfuncs.py @@ -23,13 +23,7 @@ # it by a numeric integral of the expresssion over x in the range [-20,20] # alpha = ROOT.RooRealVar("alpha", "alpha", 5, 0.1, 10) -genpdf = ROOT.RooGenericPdf( - "genpdf", - "genpdf", - "(1+0.1*abs(x)+sin(sqrt(abs(x*alpha+0.1))))", - ROOT.RooArgList( - x, - alpha)) +genpdf = ROOT.RooGenericPdf("genpdf", "genpdf", "(1+0.1*abs(x)+sin(sqrt(abs(x*alpha+0.1))))", ROOT.RooArgList(x, alpha)) # Sample, fit and plot generic pdf # --------------------------------------------------------------- @@ -57,8 +51,7 @@ sigma = ROOT.RooRealVar("sigma", "sigma", 3, 0.1, 10) # Construct interpreted function mean = sqrt(mean^2) -mean = ROOT.RooFormulaVar( - "mean", "mean", "sqrt(mean2)", ROOT.RooArgList(mean2)) +mean = ROOT.RooFormulaVar("mean", "mean", "sqrt(mean2)", ROOT.RooArgList(mean2)) # Construct a gaussian g2(x,sqrt(mean2),sigma) g2 = ROOT.RooGaussian("g2", "h2", x, mean, sigma) @@ -68,15 +61,14 @@ # Construct a separate gaussian g1(x,10,3) to generate a toy Gaussian # dataset with mean 10 and width 3 -g1 = ROOT.RooGaussian("g1", "g1", x, ROOT.RooFit.RooConst( - 10), ROOT.RooFit.RooConst(3)) +g1 = ROOT.RooGaussian("g1", "g1", x, ROOT.RooFit.RooConst(10), ROOT.RooFit.RooConst(3)) data2 = g1.generate(ROOT.RooArgSet(x), 1000) # Fit and plot tailored standard pdf # ------------------------------------------------------------------- # Fit g2 to data from g1 -r = g2.fitTo(data2, ROOT.RooFit.Save()) # ROOT.RooFitResult +r = g2.fitTo(data2, Save=True) # ROOT.RooFitResult r.Print() # Plot data on frame and overlay projection of g2 diff --git a/tutorials/roofit/rf104_classfactory.py b/tutorials/roofit/rf104_classfactory.py index 4ba2f599daff7..1906503bec90c 100644 --- a/tutorials/roofit/rf104_classfactory.py +++ b/tutorials/roofit/rf104_classfactory.py @@ -47,8 +47,8 @@ "x,A,B", "", "A*fabs(x)+pow(x-B,2)", - ROOT.kTRUE, - ROOT.kFALSE, + True, + False, "x:(A/2)*(pow(x.max(rangeName),2)+pow(x.min(rangeName),2))+(1./3)*(pow(x.max(rangeName)-B,3)-pow(x.min(rangeName)-B,3))") # Use instance of created class diff --git a/tutorials/roofit/rf106_plotdecoration.py b/tutorials/roofit/rf106_plotdecoration.py index 5fd4cee22daad..56384d1196266 100644 --- a/tutorials/roofit/rf106_plotdecoration.py +++ b/tutorials/roofit/rf106_plotdecoration.py @@ -30,8 +30,7 @@ # ------------------------------------- # Overlay projection of gauss on data -frame = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title( - "RooPlot with decorations"), ROOT.RooFit.Bins(40)) +frame = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("RooPlot with decorations"), ROOT.RooFit.Bins(40)) data.plotOn(frame) gauss.plotOn(frame) diff --git a/tutorials/roofit/rf107_plotstyles.py b/tutorials/roofit/rf107_plotstyles.py index cbbb8396f3abf..c5ff1a78288cb 100644 --- a/tutorials/roofit/rf107_plotstyles.py +++ b/tutorials/roofit/rf107_plotstyles.py @@ -48,38 +48,28 @@ data.plotOn(frame1, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) # Remove horizontal error bars -data.plotOn(frame2, ROOT.RooFit.XErrorSize(0)) +data.plotOn(frame2, XErrorSize = 0 ) # Blue markers and error bors -data.plotOn(frame3, ROOT.RooFit.MarkerColor( - ROOT.kBlue), ROOT.RooFit.LineColor(ROOT.kBlue)) +data.plotOn(frame3, MarkerColor = ROOT.kBlue, LineColor = ROOT.kBlue) # Filled bar chart -data.plotOn( - frame4, - ROOT.RooFit.DrawOption("B"), - ROOT.RooFit.DataError( - ROOT.RooAbsData.ErrorType(2)), - ROOT.RooFit.XErrorSize(0), - ROOT.RooFit.FillColor( - ROOT.kGray)) +data.plotOn(frame4, DrawOption = "B", DataError = ROOT.RooAbsData.ErrorType(2), XErrorSize = 0, FillColor = ROOT.kGray) # Function plotting styles # ----------------------------------------------- # Change line color to red -gauss.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +gauss.plotOn(frame1, LineColor = ROOT.kRed) # Change line style to dashed -gauss.plotOn(frame2, ROOT.RooFit.LineStyle(ROOT.kDashed)) +gauss.plotOn(frame2, LineStyle = ROOT.kDashed) # Filled shapes in green color -gauss.plotOn(frame3, ROOT.RooFit.DrawOption("F"), - ROOT.RooFit.FillColor(ROOT.kOrange), ROOT.RooFit.MoveToBack()) +gauss.plotOn(frame3, ROOT.RooFit.MoveToBack(), DrawOption = "F", FillColor = ROOT.kOrange) # -gauss.plotOn(frame4, ROOT.RooFit.Range(-8, 3), - ROOT.RooFit.LineColor(ROOT.kMagenta)) +gauss.plotOn(frame4, Range = (-8, 3), LineColor = ROOT.kMagenta) c = ROOT.TCanvas("rf107_plotstyles", "rf107_plotstyles", 800, 800) c.Divide(2, 2) diff --git a/tutorials/roofit/rf108_plotbinning.py b/tutorials/roofit/rf108_plotbinning.py index d9afd43bc0488..f2c928f015bd1 100644 --- a/tutorials/roofit/rf108_plotbinning.py +++ b/tutorials/roofit/rf108_plotbinning.py @@ -61,7 +61,7 @@ # Make plot with specified binning dtframe = dt.frame(ROOT.RooFit.Range(-15, 15), ROOT.RooFit.Title("dt distribution with custom binning")) -data.plotOn(dtframe, ROOT.RooFit.Binning(tbins)) +data.plotOn(dtframe, Binning = tbins) bmix.plotOn(dtframe) # NB: Note that bin density for each bin is adjusted to that of default frame binning as shown @@ -90,11 +90,10 @@ "mixState asymmetry distribution with custom binning")) # Plot mixState asymmetry of data with specified customg binning -data.plotOn(aframe, ROOT.RooFit.Asymmetry( - mixState), ROOT.RooFit.Binning(abins)) +data.plotOn(aframe, Asymmetry = mixState, Binning = abins) # Plot corresponding property of pdf -bmix.plotOn(aframe, ROOT.RooFit.Asymmetry(mixState)) +bmix.plotOn(aframe, Asymmetry = mixState) # Adjust vertical range of plot to sensible values for an asymmetry aframe.SetMinimum(-1.1) diff --git a/tutorials/roofit/rf111_derivatives.py b/tutorials/roofit/rf111_derivatives.py index 7312b93c12f05..ea2ca2cf7db0a 100644 --- a/tutorials/roofit/rf111_derivatives.py +++ b/tutorials/roofit/rf111_derivatives.py @@ -43,9 +43,9 @@ gauss.plotOn(xframe) # Plot derivatives in same frame -dgdx.plotOn(xframe, ROOT.RooFit.LineColor(ROOT.kMagenta)) -d2gdx2.plotOn(xframe, ROOT.RooFit.LineColor(ROOT.kRed)) -d3gdx3.plotOn(xframe, ROOT.RooFit.LineColor(ROOT.kOrange)) +dgdx.plotOn(xframe, LineColor = ROOT.kMagenta) +d2gdx2.plotOn(xframe, LineColor = ROOT.kRed) +d3gdx3.plotOn(xframe, LineColor = ROOT.kOrange) # Create and plot derivatives w.r.t. sigma # ------------------------------------------------------------------------------ @@ -65,9 +65,9 @@ gauss.plotOn(sframe) # Plot derivatives in same frame -dgds.plotOn(sframe, ROOT.RooFit.LineColor(ROOT.kMagenta)) -d2gds2.plotOn(sframe, ROOT.RooFit.LineColor(ROOT.kRed)) -d3gds3.plotOn(sframe, ROOT.RooFit.LineColor(ROOT.kOrange)) +dgds.plotOn(sframe, LineColor = ROOT.kMagenta) +d2gds2.plotOn(sframe, LineColor = ROOT.kRed) +d3gds3.plotOn(sframe, LineColor = ROOT.kOrange) # Draw all frames on a canvas c = ROOT.TCanvas("rf111_derivatives", "rf111_derivatives", 800, 400) diff --git a/tutorials/roofit/rf201_composite.py b/tutorials/roofit/rf201_composite.py index b830775aaeb21..4c29ca6cc6803 100644 --- a/tutorials/roofit/rf201_composite.py +++ b/tutorials/roofit/rf201_composite.py @@ -70,13 +70,11 @@ # Overlay the background component of model with a dashed line ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(xframe, ROOT.RooFit.Components(ras_bkg), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(xframe, Components = ras_bkg, LineStyle = ROOT.kDashed) # Overlay the background+sig2 components of model with a dotted line ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn(xframe, ROOT.RooFit.Components(ras_bkg_sig2), - ROOT.RooFit.LineStyle(ROOT.kDotted)) +model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted) # Print structure of composite pdf model.Print("t") @@ -98,7 +96,7 @@ ROOT.RooArgList( bkgfrac, sig1frac), - ROOT.kTRUE) + True) # NB: Each coefficient is interpreted as the fraction of the # left-hand component of the i-th recursive sum, i.e. @@ -109,15 +107,8 @@ # Plot recursive addition model # --------------------------------------------------------- -model2.plotOn(xframe, ROOT.RooFit.LineColor(ROOT.kRed), - ROOT.RooFit.LineStyle(ROOT.kDashed)) -model2.plotOn( - xframe, - ROOT.RooFit.Components(ras_bkg_sig2), - ROOT.RooFit.LineColor( - ROOT.kRed), - ROOT.RooFit.LineStyle( - ROOT.kDashed)) +model2.plotOn(xframe, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) +model2.plotOn(xframe, Components = ras_bkg_sig2, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) model2.Print("t") # Draw the frame on the canvas diff --git a/tutorials/roofit/rf202_extendedmlfit.py b/tutorials/roofit/rf202_extendedmlfit.py index 90eb8dd87b616..8709cc478f5cd 100644 --- a/tutorials/roofit/rf202_extendedmlfit.py +++ b/tutorials/roofit/rf202_extendedmlfit.py @@ -68,22 +68,15 @@ # rather than observed number of events (==data.numEntries()) xframe = x.frame(ROOT.RooFit.Title("extended ML fit example")) data.plotOn(xframe) -model.plotOn(xframe, ROOT.RooFit.Normalization( - 1.0, ROOT.RooAbsReal.RelativeExpected)) +model.plotOn(xframe, Normalization= dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) # Overlay the background component of model with a dashed line ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn( - xframe, ROOT.RooFit.Components(ras_bkg), ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.Normalization( - 1.0, ROOT.RooAbsReal.RelativeExpected)) +model.plotOn(xframe, Components = ras_bkg, LineStyle = ROOT.kDotted, Normalization = dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) # Overlay the background+sig2 components of model with a dotted line ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn( - xframe, ROOT.RooFit.Components(ras_bkg_sig2), ROOT.RooFit.LineStyle( - ROOT.kDotted), ROOT.RooFit.Normalization( - 1.0, ROOT.RooAbsReal.RelativeExpected)) +model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted, Normalization = dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) # Print structure of composite pdf model.Print("t") diff --git a/tutorials/roofit/rf203_ranges.py b/tutorials/roofit/rf203_ranges.py index a324555bb352d..6c345df9a75ae 100644 --- a/tutorials/roofit/rf203_ranges.py +++ b/tutorials/roofit/rf203_ranges.py @@ -36,7 +36,7 @@ # --------------------------- # Fit pdf to all data -r_full = model.fitTo(modelData, ROOT.RooFit.Save(ROOT.kTRUE)) +r_full = model.fitTo(modelData, Save = True) # Fit partial range # ---------------------------------- @@ -45,8 +45,7 @@ x.setRange("signal", -3, 3) # Fit pdf only to data in "signal" range -r_sig = model.fitTo(modelData, ROOT.RooFit.Save( - ROOT.kTRUE), ROOT.RooFit.Range("signal")) +r_sig = model.fitTo(modelData, Save = True, Range = "signal") # Plot/print results # --------------------------------------- @@ -54,10 +53,7 @@ # Make plot frame in x and add data and fitted model frame = x.frame(ROOT.RooFit.Title("Fitting a sub range")) modelData.plotOn(frame) -model.plotOn( - frame, ROOT.RooFit.Range("Full"), ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.LineColor( - ROOT.kRed)) # Add shape in full ranged dashed +model.plotOn(frame, Range = "Full", LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) # Add shape in full ranged dashed model.plotOn(frame) # By default only fitted range is shown # Print fit results diff --git a/tutorials/roofit/rf204_extrangefit.py b/tutorials/roofit/rf204_extrangefit.py index 18d6e56c9358d..1d4b5dfb22a40 100644 --- a/tutorials/roofit/rf204_extrangefit.py +++ b/tutorials/roofit/rf204_extrangefit.py @@ -27,15 +27,13 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Construct extended comps with range spec # ------------------------------------------------------------------------------ @@ -45,14 +43,10 @@ # Associated nsig/nbkg as expected number of events with sig/bkg # _in_the_range_ "signalRange" -nsig = ROOT.RooRealVar( - "nsig", "number of signal events in signalRange", 500, 0., 10000) -nbkg = ROOT.RooRealVar( - "nbkg", "number of background events in signalRange", 500, 0, 10000) -esig = ROOT.RooExtendPdf( - "esig", "extended signal pdf", sig, nsig, "signalRange") -ebkg = ROOT.RooExtendPdf( - "ebkg", "extended background pdf", bkg, nbkg, "signalRange") +nsig = ROOT.RooRealVar("nsig", "number of signal events in signalRange", 500, 0.0, 10000) +nbkg = ROOT.RooRealVar("nbkg", "number of background events in signalRange", 500, 0, 10000) +esig = ROOT.RooExtendPdf("esig", "extended signal pdf", sig, nsig, "signalRange") +ebkg = ROOT.RooExtendPdf("ebkg", "extended background pdf", bkg, nbkg, "signalRange") # Sum extended components # --------------------------------------------- @@ -68,5 +62,5 @@ data = model.generate(ROOT.RooArgSet(x), 1000) # Perform unbinned extended ML fit to data -r = model.fitTo(data, ROOT.RooFit.Extended(ROOT.kTRUE), ROOT.RooFit.Save()) +r = model.fitTo(data, Extended=True, Save=True) r.Print() diff --git a/tutorials/roofit/rf204a_extendedLikelihood.py b/tutorials/roofit/rf204a_extendedLikelihood.py index 9b8e742e2c09b..5e58a5c0d56a1 100644 --- a/tutorials/roofit/rf204a_extendedLikelihood.py +++ b/tutorials/roofit/rf204a_extendedLikelihood.py @@ -69,12 +69,12 @@ canv.cd(1) model1 = ROOT.RooAddPdf(model) -r = model1.fitTo(data, ROOT.RooFit.Save()) +r = model1.fitTo(data, Save = True) r.Print() frame = x.frame(ROOT.RooFit.Title("Full range fitted")) data.plotOn(frame) -model1.plotOn(frame, ROOT.RooFit.VisualizeError(r)) +model1.plotOn(frame, VisualizeError = r) model1.plotOn(frame) model1.paramOn(frame) frame.Draw() @@ -88,12 +88,12 @@ x.setRange("right", 6., 10.) model2 = ROOT.RooAddPdf(model) -r2 = model2.fitTo(data, ROOT.RooFit.Range("left,right"), ROOT.RooFit.Save()) +r2 = model2.fitTo(data, Range = "left,right", Save = True) r2.Print() frame2 = x.frame(ROOT.RooFit.Title("Fit in left/right sideband")) data.plotOn(frame2) -model2.plotOn(frame2, ROOT.RooFit.VisualizeError(r2)) +model2.plotOn(frame2, VisualizeError = r2) model2.plotOn(frame2) model2.paramOn(frame2) frame2.Draw() @@ -108,12 +108,12 @@ x.setRange("leftToMiddle", 0., 5.) model3 = ROOT.RooAddPdf(model) -r3 = model3.fitTo(data, ROOT.RooFit.Range("leftToMiddle"),ROOT.RooFit.Save()) +r3 = model3.fitTo(data, Range = "leftToMiddle", Save = True) r3.Print() frame3 = x.frame(ROOT.RooFit.Title("Fit from left to middle")) data.plotOn(frame3) -model3.plotOn(frame3, ROOT.RooFit.VisualizeError(r3)) +model3.plotOn(frame3, VisualizeError = r3) model3.plotOn(frame3) model3.paramOn(frame3) frame3.Draw() diff --git a/tutorials/roofit/rf205_compplot.py b/tutorials/roofit/rf205_compplot.py index 4edefb08a701d..fd8da39adb0b9 100644 --- a/tutorials/roofit/rf205_compplot.py +++ b/tutorials/roofit/rf205_compplot.py @@ -71,57 +71,34 @@ # Plot single background component specified by object reference ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(xframe, ROOT.RooFit.Components( - ras_bkg), ROOT.RooFit.LineColor(ROOT.kRed)) +model.plotOn(xframe, Components = ras_bkg, LineColor = ROOT.kRed) # Plot single background component specified by object reference ras_bkg2 = ROOT.RooArgSet(bkg2) -model.plotOn(xframe, ROOT.RooFit.Components(ras_bkg2), ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.LineColor(ROOT.kRed)) +model.plotOn(xframe, Components = ras_bkg2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) # Plot multiple background components specified by object reference # Note that specified components may occur at any level in object tree # (e.g bkg is component of 'model' and 'sig2' is component 'sig') ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn(xframe, ROOT.RooFit.Components(ras_bkg_sig2), - ROOT.RooFit.LineStyle(ROOT.kDotted)) +model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted) # Make component by name/regexp # ------------------------------------------------------------ # Plot single background component specified by name -model.plotOn(xframe2, ROOT.RooFit.Components( - "bkg"), ROOT.RooFit.LineColor(ROOT.kCyan)) +model.plotOn(xframe2, Components = "bkg", LineColor = ROOT.kCyan) # Plot multiple background components specified by name -model.plotOn( - xframe2, - ROOT.RooFit.Components("bkg1,sig2"), - ROOT.RooFit.LineStyle( - ROOT.kDotted), - ROOT.RooFit.LineColor( - ROOT.kCyan)) +model.plotOn(xframe2, Components = "bkg1,sig2", LineStyle = ROOT.kDotted, LineColor = ROOT.kCyan) # Plot multiple background components specified by regular expression on # name -model.plotOn( - xframe2, - ROOT.RooFit.Components("sig*"), - ROOT.RooFit.LineStyle( - ROOT.kDashed), - ROOT.RooFit.LineColor( - ROOT.kCyan)) +model.plotOn( xframe2, Components = "sig*", LineStyle = ROOT.kDashed, LineColor = ROOT.kCyan) # Plot multiple background components specified by multiple regular # expressions on name -model.plotOn( - xframe2, - ROOT.RooFit.Components("bkg1,sig*"), - ROOT.RooFit.LineStyle( - ROOT.kDashed), - ROOT.RooFit.LineColor( - ROOT.kYellow), - ROOT.RooFit.Invisible()) +model.plotOn(xframe2, Invisible=True, Components = "bkg1,sig*", LineStyle = ROOT.kDashed, LineColor= ROOT.kYellow) # Draw the frame on the canvas c = ROOT.TCanvas("rf205_compplot", "rf205_compplot", 800, 400) diff --git a/tutorials/roofit/rf208_convolution.py b/tutorials/roofit/rf208_convolution.py index b756d71a0e444..8c86978f3afda 100644 --- a/tutorials/roofit/rf208_convolution.py +++ b/tutorials/roofit/rf208_convolution.py @@ -53,7 +53,7 @@ frame = t.frame(ROOT.RooFit.Title("landau (x) gauss convolution")) data.plotOn(frame) lxg.plotOn(frame) -landau.plotOn(frame, ROOT.RooFit.LineStyle(ROOT.kDashed)) +landau.plotOn(frame, LineStyle = ROOT.kDashed) # Draw frame on canvas c = ROOT.TCanvas("rf208_convolution", "rf208_convolution", 600, 600) diff --git a/tutorials/roofit/rf209_anaconv.py b/tutorials/roofit/rf209_anaconv.py index 379946314d4ce..766010858fa36 100644 --- a/tutorials/roofit/rf209_anaconv.py +++ b/tutorials/roofit/rf209_anaconv.py @@ -33,7 +33,7 @@ # Plot pdf (dashed) frame = dt.frame(ROOT.RooFit.Title("Bdecay (x) resolution")) -decay_tm.plotOn(frame, ROOT.RooFit.LineStyle(ROOT.kDashed)) +decay_tm.plotOn(frame, LineStyle = ROOT.kDashed) # B-physics pdf with Gaussian resolution # ---------------------------------------------------------------------------- @@ -73,7 +73,7 @@ "decay_gmsum", "decay", dt, tau, gmsum, ROOT.RooDecay.DoubleSided) # Plot pdf (red) -decay_gmsum.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kRed)) +decay_gmsum.plotOn(frame, LineColor = ROOT.kRed) # Draw all frames on canvas c = ROOT.TCanvas("rf209_anaconv", "rf209_anaconv", 600, 600) diff --git a/tutorials/roofit/rf210_angularconv.py b/tutorials/roofit/rf210_angularconv.py index be868d7072b5f..45c632af76c1c 100644 --- a/tutorials/roofit/rf210_angularconv.py +++ b/tutorials/roofit/rf210_angularconv.py @@ -65,7 +65,7 @@ Mpsi.plotOn(frame1) # Overlay comparison to unsmeared physics p.d.f ROOT.T(psi) -Tpsi.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +Tpsi.plotOn(frame1, LineColor = ROOT.kRed) # Construct convolution pdf in cos(psi) # -------------------------------------------------------------------------- @@ -98,7 +98,7 @@ Mcpsi.plotOn(frame2) # Overlay comparison to unsmeared physics p.d.f ROOT.Tf(cpsi) -Tcpsi.plotOn(frame2, ROOT.RooFit.LineColor(ROOT.kRed)) +Tcpsi.plotOn(frame2, LineColor = ROOT.kRed) # Draw frame on canvas c = ROOT.TCanvas("rf210_angularconv", "rf210_angularconv", 800, 400) diff --git a/tutorials/roofit/rf211_paramconv.py b/tutorials/roofit/rf211_paramconv.py index 783f93bf18396..54229bbf52c21 100644 --- a/tutorials/roofit/rf211_paramconv.py +++ b/tutorials/roofit/rf211_paramconv.py @@ -46,7 +46,7 @@ d = projModel.generateBinned(ROOT.RooArgSet(x), 1000) # Fit p.d.f. to toy data -projModel.fitTo(d, ROOT.RooFit.Verbose()) +projModel.fitTo(d, Verbose = True) # Plot data and fitted p.d.f. frame = x.frame(ROOT.RooFit.Bins(25)) diff --git a/tutorials/roofit/rf306_condpereventerrors.py b/tutorials/roofit/rf306_condpereventerrors.py index 76b850755a41d..a54faacf28942 100644 --- a/tutorials/roofit/rf306_condpereventerrors.py +++ b/tutorials/roofit/rf306_condpereventerrors.py @@ -50,8 +50,7 @@ # --------------------------------------------------------------------- # Specify dterr as conditional observable -decay_gm.fitTo(data, ROOT.RooFit.ConditionalObservables( - ROOT.RooArgSet(dterr))) +decay_gm.fitTo(data, ConditionalObservables = ROOT.RooArgSet(dterr)) # Plot conditional decay_dm(dt|dterr) # --------------------------------------------------------------------- @@ -66,7 +65,7 @@ "Slices of decay(dt|dterr) at various dterr")) for ibin in range(0, 100, 20): dterr.setBin(ibin) - decay_gm.plotOn(frame, ROOT.RooFit.Normalization(5.)) + decay_gm.plotOn(frame, Normalization = 5.) # Make projection of data an dt frame2 = dt.frame(ROOT.RooFit.Title("Projection of decay(dt|dterr) on dt")) @@ -77,7 +76,7 @@ # Instead of integrating out dterr, a weighted average of curves # at values dterr_i as given in the external dataset. # (The kTRUE argument bins the data before projection to speed up the process) -decay_gm.plotOn(frame2, ROOT.RooFit.ProjWData(expDataDterr, ROOT.kTRUE)) +decay_gm.plotOn(frame2, ProjWData = (expDataDterr, True)) # Draw all frames on canvas c = ROOT.TCanvas("rf306_condpereventerrors", diff --git a/tutorials/roofit/rf309_ndimplot.py b/tutorials/roofit/rf309_ndimplot.py index b3665e20a37ed..c5d2c11671f3d 100644 --- a/tutorials/roofit/rf309_ndimplot.py +++ b/tutorials/roofit/rf309_ndimplot.py @@ -23,12 +23,10 @@ sigma = ROOT.RooRealVar("sigma", "width of gaussian", 1.5) # Create interpreted function f(y) = a0 - a1*sqrt(10*abs(y)) -fy = ROOT.RooFormulaVar("fy", "a0-a1*sqrt(10*abs(y))", - ROOT.RooArgList(y, a0, a1)) +fy = ROOT.RooFormulaVar("fy", "a0-a1*sqrt(10*abs(y))", ROOT.RooArgList(y, a0, a1)) # Create gauss(x,f(y),s) -model = ROOT.RooGaussian( - "model", "Gaussian with shifting mean", x, fy, sigma) +model = ROOT.RooGaussian("model", "Gaussian with shifting mean", x, fy, sigma) # Sample dataset from gauss(x,y) data = model.generate(ROOT.RooArgSet(x, y), 10000) @@ -40,8 +38,9 @@ # hh_data = data.createHistogram("hh_data",x, ROOT.RooFit.Binning(20), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20))) # hh_data = data.createHistogram("x,y", 20, 20) # does not work, see # https://root.cern.ch/phpBB3/viewtopic.php?t=16648 -hh_data = ROOT.RooAbsData.createHistogram(data, "x,y", x, ROOT.RooFit.Binning( - 20), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20))) +hh_data = ROOT.RooAbsData.createHistogram( + data, "x,y", x, ROOT.RooFit.Binning(20), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20)) +) # Create and fill ROOT 2D histogram (50x50 bins) with sampling of pdf # hh_pdf = model.createHistogram("hh_model",x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) @@ -54,8 +53,7 @@ # Create observables z = ROOT.RooRealVar("z", "z", -5, 5) -gz = ROOT.RooGaussian( - "gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(2)) +gz = ROOT.RooGaussian("gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(2)) model3 = ROOT.RooProdPdf("model3", "model3", ROOT.RooArgList(model, gz)) data3 = model3.generate(ROOT.RooArgSet(x, y, z), 10000) @@ -66,15 +64,22 @@ # Create and fill ROOT 2D histogram (8x8x8 bins) with contents of dataset # hh_data3 = data3.createHistogram("hh_data3", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)), ROOT.RooFit.ZVar(z, ROOT.RooFit.Binning(8))) hh_data3 = ROOT.RooAbsData.createHistogram( - data3, "hh_data3", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar( - y, ROOT.RooFit.Binning(8)), ROOT.RooFit.ZVar( - z, ROOT.RooFit.Binning(8))) + data3, + "hh_data3", + x, + ROOT.RooFit.Binning(8), + ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)), + ROOT.RooFit.ZVar(z, ROOT.RooFit.Binning(8)), +) # Create and fill ROOT 2D histogram (20x20x20 bins) with sampling of pdf hh_pdf3 = model3.createHistogram( - "hh_model3", x, ROOT.RooFit.Binning(20), ROOT.RooFit.YVar( - y, ROOT.RooFit.Binning(20)), ROOT.RooFit.ZVar( - z, ROOT.RooFit.Binning(20))) + "hh_model3", + x, + ROOT.RooFit.Binning(20), + ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20)), + ROOT.RooFit.ZVar(z, ROOT.RooFit.Binning(20)), +) hh_pdf3.SetFillColor(ROOT.kBlue) c1 = ROOT.TCanvas("rf309_2dimplot", "rf309_2dimplot", 800, 800) diff --git a/tutorials/roofit/rf310_sliceplot.py b/tutorials/roofit/rf310_sliceplot.py index eba9f7e85f37b..dbae6b325bc7a 100644 --- a/tutorials/roofit/rf310_sliceplot.py +++ b/tutorials/roofit/rf310_sliceplot.py @@ -70,20 +70,20 @@ # Create frame, data (mixed only) frame2 = dt.frame(ROOT.RooFit.Title("Decay distribution of mixed events")) -data.plotOn(frame2, ROOT.RooFit.Cut("mixState==mixState::mixed")) +data.plotOn(frame2, Cut = "mixState==mixState::mixed") # Position slice in mixState at "mixed" and plot slice of pdf in mixstate # over data (integrated over tagFlav) -bmix_gm1.plotOn(frame2, ROOT.RooFit.Slice(mixState, "mixed")) +bmix_gm1.plotOn(frame2, Slice = (mixState, "mixed")) # Create frame, data (unmixed only) frame3 = dt.frame(ROOT.RooFit.Title( "Decay distribution of unmixed events")) -data.plotOn(frame3, ROOT.RooFit.Cut("mixState==mixState::unmixed")) +data.plotOn(frame3, Cut = "mixState==mixState::unmixed") # Position slice in mixState at "unmixed" and plot slice of pdf in # mixstate over data (integrated over tagFlav) -bmix_gm1.plotOn(frame3, ROOT.RooFit.Slice(mixState, "unmixed")) +bmix_gm1.plotOn(frame3, Slice = (mixState, "unmixed")) c = ROOT.TCanvas("rf310_sliceplot", "rf310_sliceplot", 1200, 400) c.Divide(3) diff --git a/tutorials/roofit/rf311_rangeplot.py b/tutorials/roofit/rf311_rangeplot.py index f0e003bfdacfd..8d5052badea26 100644 --- a/tutorials/roofit/rf311_rangeplot.py +++ b/tutorials/roofit/rf311_rangeplot.py @@ -67,10 +67,10 @@ # For observables that do not have an explicit "sigRegion" range defined (e.g. observable) # an implicit definition is used that is identical to the full range (i.e. # [-5,5] for x) -data.plotOn(frame2, ROOT.RooFit.CutRange("sigRegion")) +data.plotOn(frame2, CutRange = "sigRegion") # Project model on x, projected observables (y,z) only in "sigRegion" -model.plotOn(frame2, ROOT.RooFit.ProjectionRange("sigRegion")) +model.plotOn(frame2, ProjectionRange = "sigRegion") c = ROOT.TCanvas("rf311_rangeplot", "rf310_rangeplot", 800, 400) c.Divide(2) diff --git a/tutorials/roofit/rf312_multirangefit.py b/tutorials/roofit/rf312_multirangefit.py index f820da312ed8d..fd05d57b77f7b 100644 --- a/tutorials/roofit/rf312_multirangefit.py +++ b/tutorials/roofit/rf312_multirangefit.py @@ -77,21 +77,18 @@ # Perform fit in SideBand1 region (ROOT.RooAddPdf coefficients will be # interpreted in full range) -r_sb1 = model.fitTo(modelData, ROOT.RooFit.Range( - "SB1"), ROOT.RooFit.Save()) +r_sb1 = model.fitTo(modelData, Range = "SB1", Save = True) # Perform fit in SideBand2 region (ROOT.RooAddPdf coefficients will be # interpreted in full range) -r_sb2 = model.fitTo(modelData, ROOT.RooFit.Range( - "SB2"), ROOT.RooFit.Save()) +r_sb2 = model.fitTo(modelData, Range = "SB2", Save = True) # Perform fits in joint sideband regions # ----------------------------------------------------------------------------- # Now perform fit to joint 'L-shaped' sideband region 'SB1|SB2' # (ROOT.RooAddPdf coefficients will be interpreted in full range) -r_sb12 = model.fitTo(modelData, ROOT.RooFit.Range( - "SB1,SB2"), ROOT.RooFit.Save()) +r_sb12 = model.fitTo(modelData, Range = "SB1,SB2", Save = True) # Print results for comparison r_sb1.Print() diff --git a/tutorials/roofit/rf314_paramfitrange.py b/tutorials/roofit/rf314_paramfitrange.py index aea5802ba5099..822f34e00df4d 100644 --- a/tutorials/roofit/rf314_paramfitrange.py +++ b/tutorials/roofit/rf314_paramfitrange.py @@ -46,15 +46,14 @@ # Fit pdf to data in acceptance region # ----------------------------------------------------------------------- -r = model.fitTo(dacc, ROOT.RooFit.Save()) +r = model.fitTo(dacc, Save = True) # Plot fitted pdf on full and accepted data # --------------------------------------------------------------------------------- # Make plot frame, datasets and overlay model frame = t.frame(ROOT.RooFit.Title("Fit to data with per-event acceptance")) -dall.plotOn(frame, ROOT.RooFit.MarkerColor(ROOT.kRed), - ROOT.RooFit.LineColor(ROOT.kRed)) +dall.plotOn(frame, MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) model.plotOn(frame) dacc.plotOn(frame) diff --git a/tutorials/roofit/rf315_projectpdf.py b/tutorials/roofit/rf315_projectpdf.py index 2a378fc9fd8ad..c72b81af3c7e2 100644 --- a/tutorials/roofit/rf315_projectpdf.py +++ b/tutorials/roofit/rf315_projectpdf.py @@ -63,7 +63,7 @@ data = modelx.generateBinned(ROOT.RooArgSet(x), 1000) # Fit modelx to toy data -modelx.fitTo(data, ROOT.RooFit.Verbose()) +modelx.fitTo(data, Verbose = True) # Plot modelx over data frame = x.frame(40) diff --git a/tutorials/roofit/rf316_llratioplot.py b/tutorials/roofit/rf316_llratioplot.py index db06ea476b2c4..922215abcc6b1 100644 --- a/tutorials/roofit/rf316_llratioplot.py +++ b/tutorials/roofit/rf316_llratioplot.py @@ -95,7 +95,7 @@ # Project model on x, projected observables (y,z) with Monte Carlo technique # on set of events with the same llratio cut as was applied to data -model.plotOn(frame2, ROOT.RooFit.ProjWData(mcprojDataSel)) +model.plotOn(frame2, ProjWData = mcprojDataSel) c = ROOT.TCanvas("rf316_llratioplot", "rf316_llratioplot", 800, 400) c.Divide(2) diff --git a/tutorials/roofit/rf402_datahandling.py b/tutorials/roofit/rf402_datahandling.py index 3871b3e59fb52..ec504dd1d768c 100644 --- a/tutorials/roofit/rf402_datahandling.py +++ b/tutorials/roofit/rf402_datahandling.py @@ -122,9 +122,9 @@ # Examine the statistics of a binned dataset print(">> number of bins in dh : ", dh.numEntries()) -print(">> sum of weights in dh : ", dh.sum(ROOT.kFALSE)) +print(">> sum of weights in dh : ", dh.sum(False)) # accounts for bin volume -print(">> integral over histogram: ", dh.sum(ROOT.kTRUE)) +print(">> integral over histogram: ", dh.sum(True)) # Locate a bin from a set of coordinates and retrieve its properties x.setVal(0.3) @@ -144,8 +144,7 @@ dh2.Print("v") # Add dh2 to yframe and redraw -dh2.plotOn(yframe, ROOT.RooFit.LineColor(ROOT.kRed), - ROOT.RooFit.MarkerColor(ROOT.kRed)) +dh2.plotOn(yframe, ROOT.RooFit.LineColor(ROOT.kRed), ROOT.RooFit.MarkerColor(ROOT.kRed)) # Saving and loading from file # ------------------------------------------------------- diff --git a/tutorials/roofit/rf405_realtocatfuncs.py b/tutorials/roofit/rf405_realtocatfuncs.py index 8230bc5bb6950..390003d1f9626 100644 --- a/tutorials/roofit/rf405_realtocatfuncs.py +++ b/tutorials/roofit/rf405_realtocatfuncs.py @@ -57,13 +57,7 @@ data.plotOn(xframe) # Use calculated category to select sideband data -data.plotOn( - xframe, - ROOT.RooFit.Cut("xRegion==xRegion::SideBand"), - ROOT.RooFit.MarkerColor( - ROOT.kRed), - ROOT.RooFit.LineColor( - ROOT.kRed)) +data.plotOn(xframe, Cut = "xRegion==xRegion::SideBand", MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) # Create a binning real -> cat function # ---------------------------------------------------------------------- @@ -97,8 +91,7 @@ # 5000 events and plot it on the frame dataSel = data.reduce(ROOT.RooFit.CutRange( "alt"), ROOT.RooFit.EventRange(0, 5000)) -dataSel.plotOn(xframe, ROOT.RooFit.MarkerColor(ROOT.kGreen), - ROOT.RooFit.LineColor(ROOT.kGreen)) +dataSel.plotOn(xframe, MarkerColor = ROOT.kGreen, LineColor = ROOT.kGreen) c = ROOT.TCanvas("rf405_realtocatfuncs", "rf405_realtocatfuncs", 600, 600) xframe.SetMinimum(0.01) diff --git a/tutorials/roofit/rf501_simultaneouspdf.py b/tutorials/roofit/rf501_simultaneouspdf.py index da1bedf130613..17d3e28bcd2f3 100644 --- a/tutorials/roofit/rf501_simultaneouspdf.py +++ b/tutorials/roofit/rf501_simultaneouspdf.py @@ -109,7 +109,7 @@ frame1 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Physics sample")) # Plot all data tagged as physics sample -combData.plotOn(frame1, ROOT.RooFit.Cut("sample==sample::physics")) +combData.plotOn(frame1, Cut = "sample==sample::physics") # Plot "physics" slice of simultaneous pdf. # NB: You *must* project the sample index category with data using ProjWData @@ -118,16 +118,13 @@ # NB2: The sampleSet *must* be named. It will not work to pass this as a temporary # because python will delete it. The same holds for fitTo() and plotOn() below. sampleSet = ROOT.RooArgSet(sample) -simPdf.plotOn(frame1, ROOT.RooFit.Slice(sample, "physics"), ROOT.RooFit.Components( - "px"), ROOT.RooFit.ProjWData(sampleSet, combData), ROOT.RooFit.LineStyle(ROOT.kDashed)) +simPdf.plotOn(frame1, Slice = (sample, "physics"), Components = "px", ProjWData = (sampleSet, combData), LineStyle = ROOT.kDashed) # The same plot for the control sample slice frame2 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Control sample")) -combData.plotOn(frame2, ROOT.RooFit.Cut("sample==sample::control")) -simPdf.plotOn(frame2, ROOT.RooFit.Slice(sample, "control"), - ROOT.RooFit.ProjWData(sampleSet, combData)) -simPdf.plotOn(frame2, ROOT.RooFit.Slice(sample, "control"), ROOT.RooFit.Components( - "px_ctl"), ROOT.RooFit.ProjWData(sampleSet, combData), ROOT.RooFit.LineStyle(ROOT.kDashed)) +combData.plotOn(frame2, Cut = "sample==sample::control") +simPdf.plotOn(frame2, Slice = (sample, "control"), ProjWData = (sampleSet, combData)) +simPdf.plotOn(frame2, Slice = (sample, "control"), Components = "px_ctl", ProjWData = (sampleSet, combData), LineStyle = ROOT.kDashed) c = ROOT.TCanvas("rf501_simultaneouspdf", "rf501_simultaneouspdf", 800, 400) diff --git a/tutorials/roofit/rf505_asciicfg.py b/tutorials/roofit/rf505_asciicfg.py index b9ce535c8f59a..5717a38f1b9fc 100644 --- a/tutorials/roofit/rf505_asciicfg.py +++ b/tutorials/roofit/rf505_asciicfg.py @@ -64,7 +64,7 @@ # Print the list of parameters that were not read from Section3 print("The following parameters of the were _not_ read from Section3: ", - params.selectByAttrib("READ", ROOT.kFALSE)) + params.selectByAttrib("READ", False)) # Read parameters from section 'Section4' of file, contains # 'include file' statement of rf505_asciicfg_example.txt diff --git a/tutorials/roofit/rf506_msgservice.py b/tutorials/roofit/rf506_msgservice.py index df6b007d8d0ca..658a9b4d729dd 100644 --- a/tutorials/roofit/rf506_msgservice.py +++ b/tutorials/roofit/rf506_msgservice.py @@ -66,7 +66,7 @@ ROOT.RooFit.ClassName("RooGaussian")) # Perform a fit to generate some tracing messages -model.fitTo(data, ROOT.RooFit.Verbose(ROOT.kTRUE)) +model.fitTo(data, Verbose = True) # Reset message service to default stream configuration ROOT.RooMsgService.instance().reset() @@ -80,7 +80,7 @@ ROOT.RooFit.OutputFile("rf506_debug.log")) # Perform a fit to generate some tracing messages -model.fitTo(data, ROOT.RooFit.Verbose(ROOT.kTRUE)) +model.fitTo(data, Verbose = True) # Reset message service to default stream configuration ROOT.RooMsgService.instance().reset() diff --git a/tutorials/roofit/rf507_debugtools.py b/tutorials/roofit/rf507_debugtools.py index 741d60b17cc41..cee13ffedc64f 100644 --- a/tutorials/roofit/rf507_debugtools.py +++ b/tutorials/roofit/rf507_debugtools.py @@ -12,7 +12,7 @@ # Activate ROOT.RooFit memory tracing -ROOT.RooTrace.active(ROOT.kTRUE) +ROOT.RooTrace.active(True) # Construct gauss(x,m,s) x = ROOT.RooRealVar("x", "x", -10, 10) @@ -24,7 +24,7 @@ ROOT.RooTrace.dump() # Activate verbose mode -ROOT.RooTrace.verbose(ROOT.kTRUE) +ROOT.RooTrace.verbose(True) # Construct poly(x,p0) p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0., 1.) diff --git a/tutorials/roofit/rf509_wsinteractive.py b/tutorials/roofit/rf509_wsinteractive.py index 1d4bd3488cda9..6ecebeaec6327 100644 --- a/tutorials/roofit/rf509_wsinteractive.py +++ b/tutorials/roofit/rf509_wsinteractive.py @@ -63,7 +63,7 @@ def fillWorkspace(w): # but self does not work anymore in CLING. # so self tutorial is an example on how to # change the code -w = ROOT.RooWorkspace("w", ROOT.kTRUE) +w = ROOT.RooWorkspace("w", True) # Fill workspace with pdf and data in a separate function fillWorkspace(w) @@ -107,8 +107,7 @@ def fillWorkspace(w): bkg = w.pdf("bkg") model.plotOn(frame) ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(frame, ROOT.RooFit.Components(ras_bkg), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame, Components = ras_bkg, LineStyle = ROOT.kDashed) # Draw the frame on the canvas c = ROOT.TCanvas("rf509_wsinteractive", "rf509_wsinteractive", 600, 600) diff --git a/tutorials/roofit/rf510_wsnamedsets.py b/tutorials/roofit/rf510_wsnamedsets.py index fc0ef9e3d1e1b..842d0ca0016d8 100644 --- a/tutorials/roofit/rf510_wsnamedsets.py +++ b/tutorials/roofit/rf510_wsnamedsets.py @@ -77,21 +77,21 @@ def fillWorkspace(w): # Do a dummy fit to a (supposedly) reference dataset here and store the results # of that fit into a snapshot refData = model.generate(ROOT.RooArgSet(x), 10000) - model.fitTo(refData, ROOT.RooFit.PrintLevel(-1)) + model.fitTo(refData, PrintLevel = -1) # The kTRUE flag imports the values of the objects in (*params) into the workspace # If not set, present values of the workspace parameters objects are stored - w.saveSnapshot("reference_fit", params, ROOT.kTRUE) + w.saveSnapshot("reference_fit", params, True) # Make another fit with the signal componentforced to zero # and save those parameters too bkgfrac.setVal(1) - bkgfrac.setConstant(ROOT.kTRUE) + bkgfrac.setConstant(True) bkgfrac.removeError() - model.fitTo(refData, ROOT.RooFit.PrintLevel(-1)) + model.fitTo(refData, PrintLevel = -1) - w.saveSnapshot("reference_fit_bkgonly", params, ROOT.kTRUE) + w.saveSnapshot("reference_fit_bkgonly", params, True) # Create model and dataset @@ -117,9 +117,9 @@ def fillWorkspace(w): # Overlay plot with model with reference parameters as stored in snapshots w.loadSnapshot("reference_fit") -model.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kRed)) +model.plotOn(frame, LineColor = ROOT.kRed) w.loadSnapshot("reference_fit_bkgonly") -model.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kRed), ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) # Draw the frame on the canvas c = ROOT.TCanvas("rf510_wsnamedsets", "rf503_wsnamedsets", 600, 600) diff --git a/tutorials/roofit/rf511_wsfactory_basic.py b/tutorials/roofit/rf511_wsfactory_basic.py index d523f966e9e31..e81899aa6c755 100644 --- a/tutorials/roofit/rf511_wsfactory_basic.py +++ b/tutorials/roofit/rf511_wsfactory_basic.py @@ -12,7 +12,7 @@ import ROOT -compact = ROOT.kFALSE +compact = False w = ROOT.RooWorkspace("w") # Creating and adding basic pdfs diff --git a/tutorials/roofit/rf601_intminuit.py b/tutorials/roofit/rf601_intminuit.py index a9af15e466919..9adba1986afe1 100644 --- a/tutorials/roofit/rf601_intminuit.py +++ b/tutorials/roofit/rf601_intminuit.py @@ -46,7 +46,7 @@ m = ROOT.RooMinimizer(nll) # Activate verbose logging of MINUIT parameter space stepping -m.setVerbose(ROOT.kTRUE) +m.setVerbose(True) # Call MIGRAD to minimize the likelihood m.migrad() @@ -56,7 +56,7 @@ model.getParameters(ROOT.RooArgSet(x)).Print("s") # Disable verbose logging -m.setVerbose(ROOT.kFALSE) +m.setVerbose(False) # Run HESSE to calculate errors from d2L/dp2 m.hesse() @@ -102,7 +102,7 @@ frac.Print() # Now fix sigma_g2 -sigma_g2.setConstant(ROOT.kTRUE) +sigma_g2.setConstant(True) # Rerun MIGRAD,HESSE m.migrad() diff --git a/tutorials/roofit/rf603_multicpu.py b/tutorials/roofit/rf603_multicpu.py index 8209e771830d8..4cfd34801148e 100644 --- a/tutorials/roofit/rf603_multicpu.py +++ b/tutorials/roofit/rf603_multicpu.py @@ -52,7 +52,7 @@ # it back to MINUIT. # Use four processes and time results both in wall time and CPU time -model.fitTo(data, ROOT.RooFit.NumCPU(4), ROOT.RooFit.Timer(ROOT.kTRUE)) +model.fitTo(data, NumCPU = 4, Timer = True) # Parallel MC projections # ---------------------------------------------- @@ -81,7 +81,7 @@ # final result # Use four processes -model.plotOn(frame, ROOT.RooFit.ProjWData(dataSel), ROOT.RooFit.NumCPU(4)) +model.plotOn(frame, ProjWData = dataSel, NumCPU = 4) c = ROOT.TCanvas("rf603_multicpu", "rf603_multicpu", 600, 600) ROOT.gPad.SetLeftMargin(0.15) diff --git a/tutorials/roofit/rf604_constraints.py b/tutorials/roofit/rf604_constraints.py index 5b897ce7dacda..206f810e5cbad 100644 --- a/tutorials/roofit/rf604_constraints.py +++ b/tutorials/roofit/rf604_constraints.py @@ -62,14 +62,10 @@ "modelc", "model with constraint", ROOT.RooArgList(model, fconstraint)) # Fit model (without use of constraint term) -r1 = model.fitTo(d, ROOT.RooFit.Save()) +r1 = model.fitTo(d, Save = True) # Fit modelc with constraint term on parameter f -r2 = modelc.fitTo( - d, - ROOT.RooFit.Constrain( - ROOT.RooArgSet(f)), - ROOT.RooFit.Save()) +r2 = modelc.fitTo(d, Constrain = ROOT.RooArgSet(f), Save = True) # Method 2 - specify external constraint when fitting # ------------------------------------------------------------------------------------------ @@ -80,8 +76,7 @@ 0.2), ROOT.RooFit.RooConst(0.1)) # Fit with external constraint -r3 = model.fitTo(d, ROOT.RooFit.ExternalConstraints( - ROOT.RooArgSet(fconstext)), ROOT.RooFit.Save()) +r3 = model.fitTo(d, ExternalConstraints = ROOT.RooArgSet(fconstext), Save = True) # Print the fit results print("fit result without constraint (data generated at f=0.5)") diff --git a/tutorials/roofit/rf605_profilell.py b/tutorials/roofit/rf605_profilell.py index 9330cd21635b5..4a0c9566caf3f 100644 --- a/tutorials/roofit/rf605_profilell.py +++ b/tutorials/roofit/rf605_profilell.py @@ -64,7 +64,7 @@ pll_frac = nll.createProfile(ROOT.RooArgSet(frac)) # Plot the profile likelihood in frac -pll_frac.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +pll_frac.plotOn(frame1, LineColor = ROOT.kRed) # Adjust frame maximum for visual clarity frame1.SetMinimum(0) @@ -78,7 +78,7 @@ pll_sigmag2 = nll.createProfile(ROOT.RooArgSet(sigma_g2)) # Plot the profile likelihood in sigma_g2 -pll_sigmag2.plotOn(frame2, ROOT.RooFit.LineColor(ROOT.kRed)) +pll_sigmag2.plotOn(frame2, LineColor = ROOT.kRed) # Adjust frame maximum for visual clarity frame2.SetMinimum(0) diff --git a/tutorials/roofit/rf606_nllerrorhandling.py b/tutorials/roofit/rf606_nllerrorhandling.py index 0841c4849be85..b7d8fbc1052eb 100644 --- a/tutorials/roofit/rf606_nllerrorhandling.py +++ b/tutorials/roofit/rf606_nllerrorhandling.py @@ -52,7 +52,7 @@ # is to return a very high value of the likelihood to MINUIT if errors occur, # which will force MINUIT to retreat from the problematic area -argus.fitTo(data, ROOT.RooFit.PrintEvalErrors(10)) +argus.fitTo(data, PrintEvalErrors = 10) # Peform another fit. In self configuration only the number of errors per # likelihood evaluation is shown, it is greater than zero. The @@ -66,7 +66,7 @@ # illustrated in the second plot m0.setError(0.1) -argus.fitTo(data, ROOT.RooFit.PrintEvalErrors(0), ROOT.RooFit.EvalErrorWall(ROOT.kFALSE)) +argus.fitTo(data, PrintEvalErrors = 0, EvalErrorWall = False) # Plot likelihood as function of m0 # ------------------------------------------------------------------ @@ -82,10 +82,10 @@ frame2 = m0.frame(ROOT.RooFit.Range(5.288, 5.293), ROOT.RooFit.Title("-log(L) scan vs m0, regions masked")) nll.plotOn( frame2, - ROOT.RooFit.PrintEvalErrors(-1), ROOT.RooFit.ShiftToZero(), - ROOT.RooFit.EvalErrorValue(nll.getVal() + 10), - ROOT.RooFit.LineColor(ROOT.kRed), + PrintEvalErrors = -1, + EvalErrorValue= (nll.getVal() + 10), + LineColor = ROOT.kRed ) frame2.SetMaximum(15) frame2.SetMinimum(0) diff --git a/tutorials/roofit/rf607_fitresult.py b/tutorials/roofit/rf607_fitresult.py index e007852de898e..5d9d3f5e0c8c1 100644 --- a/tutorials/roofit/rf607_fitresult.py +++ b/tutorials/roofit/rf607_fitresult.py @@ -50,7 +50,7 @@ # ------------------------------------------------------------- # Perform fit and save result -r = model.fitTo(data, ROOT.RooFit.Save()) +r = model.fitTo(data, Save = True) # Print fit results # --------------------------------- diff --git a/tutorials/roofit/rf608_fitresultaspdf.py b/tutorials/roofit/rf608_fitresultaspdf.py index 7f7820abf948b..421670d73ce20 100644 --- a/tutorials/roofit/rf608_fitresultaspdf.py +++ b/tutorials/roofit/rf608_fitresultaspdf.py @@ -37,7 +37,7 @@ # Fit model to data # ---------------------------------- -r = model.fitTo(data, ROOT.RooFit.Save()) +r = model.fitTo(data, Save = True) # Create MV Gaussian pdf of fitted parameters # ------------------------------------------------------------------------------------ diff --git a/tutorials/roofit/rf609_xychi2fit.py b/tutorials/roofit/rf609_xychi2fit.py index 493be025b13a4..c4db49b1fd42b 100644 --- a/tutorials/roofit/rf609_xychi2fit.py +++ b/tutorials/roofit/rf609_xychi2fit.py @@ -62,11 +62,10 @@ # Alternative: fit chi^2 integrating f(x) over ranges defined by X errors, rather # than taking point at center of bin -f.chi2FitTo(dxy, ROOT.RooFit.YVar(y), ROOT.RooFit.Integrate(ROOT.kTRUE)) +f.chi2FitTo(dxy, ROOT.RooFit.YVar(y), ROOT.RooFit.Integrate(True)) # Overlay alternate fit result -f.plotOn(frame, ROOT.RooFit.LineStyle(ROOT.kDashed), - ROOT.RooFit.LineColor(ROOT.kRed)) +f.plotOn(frame, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) # Draw the plot on a canvas c = ROOT.TCanvas("rf609_xychi2fit", "rf609_xychi2fit", 600, 600) diff --git a/tutorials/roofit/rf610_visualerror.py b/tutorials/roofit/rf610_visualerror.py index 3a2f19a095cc9..2802798f03b67 100644 --- a/tutorials/roofit/rf610_visualerror.py +++ b/tutorials/roofit/rf610_visualerror.py @@ -34,7 +34,7 @@ d = model.generateBinned(ROOT.RooArgSet(x), 1000) # Perform fit and save fit result -r = model.fitTo(d, ROOT.RooFit.Save()) +r = model.fitTo(d, Save = True) # Visualize fit error # ------------------------------------- @@ -61,8 +61,7 @@ # but may not be accurate in the presence of strong correlations (~>0.9) and at Z>2 due to linear and # Gaussian approximations made # -model.plotOn(frame, ROOT.RooFit.VisualizeError( - r, 1), ROOT.RooFit.FillColor(ROOT.kOrange)) +model.plotOn(frame, VisualizeError = (r, 1), FillColor = ROOT.kOrange) # Calculate error using sampling method and visualize as dashed red line. # @@ -76,40 +75,26 @@ # (much) longer to calculate model.plotOn( frame, - ROOT.RooFit.VisualizeError( - r, - 1, - ROOT.kFALSE), - ROOT.RooFit.DrawOption("L"), - ROOT.RooFit.LineWidth(2), - ROOT.RooFit.LineColor( - ROOT.kRed)) + VisualizeError = (r, 1, False), + DrawOption = "L", + LineWidth = 2, + LineColor = ROOT.kRed) # Perform the same type of error visualization on the background component only. # The VisualizeError() option can generally applied to _any_ kind of # plot (components, asymmetries, etc..) -model.plotOn( - frame, ROOT.RooFit.VisualizeError( - r, 1), ROOT.RooFit.FillColor( - ROOT.kOrange), ROOT.RooFit.Components("bkg")) -model.plotOn( - frame, - ROOT.RooFit.VisualizeError( - r, - 1, - ROOT.kFALSE), - ROOT.RooFit.DrawOption("L"), - ROOT.RooFit.LineWidth(2), - ROOT.RooFit.LineColor( - ROOT.kRed), - ROOT.RooFit.Components("bkg"), - ROOT.RooFit.LineStyle( - ROOT.kDashed)) +model.plotOn(frame, VisualizeError = (r, 1), FillColor = ROOT.kOrange, Components = "bkg") +model.plotOn(frame, + VisualizeError = (r, 1, False), + DrawOption = "L", + LineWidth = 2, + LineColor = ROOT.kRed, + Components = "bkg", + LineStyle = ROOT.kDashed) # Overlay central value model.plotOn(frame) -model.plotOn(frame, ROOT.RooFit.Components("bkg"), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame, Components = "bkg", LineStyle = ROOT.kDashed) d.plotOn(frame) frame.SetMinimum(0) @@ -132,14 +117,11 @@ # Propagate partial error due to shape parameters (m,m2) using linear and # sampling method -model.plotOn(frame2, ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(m, m2), 2), ROOT.RooFit.FillColor(ROOT.kCyan)) -model.plotOn(frame2, ROOT.RooFit.Components("bkg"), ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(m, m2), 2), ROOT.RooFit.FillColor(ROOT.kCyan)) +model.plotOn(frame2, VisualizeError = (r, ROOT.RooArgSet(m, m2), 2), FillColor = ROOT.kCyan) +model.plotOn(frame2, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(m, m2), 2), FillColor = ROOT.kCyan) model.plotOn(frame2) -model.plotOn(frame2, ROOT.RooFit.Components("bkg"), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame2, Components = "bkg", LineStyle = ROOT.kDashed) frame2.SetMinimum(0) # Make plot frame @@ -148,14 +130,11 @@ # Propagate partial error due to yield parameter using linear and sampling # method -model.plotOn(frame3, ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(s, s2), 2), ROOT.RooFit.FillColor(ROOT.kGreen)) -model.plotOn(frame3, ROOT.RooFit.Components("bkg"), ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(s, s2), 2), ROOT.RooFit.FillColor(ROOT.kGreen)) +model.plotOn(frame3, VisualizeError = (r, ROOT.RooArgSet(s, s2), 2), FillColor = ROOT.kGreen) +model.plotOn(frame3, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kGreen) model.plotOn(frame3) -model.plotOn(frame3, ROOT.RooFit.Components("bkg"), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame3, Components = "bkg", LineStyle = ROOT.kDashed) frame3.SetMinimum(0) # Make plot frame @@ -164,14 +143,11 @@ # Propagate partial error due to yield parameter using linear and sampling # method -model.plotOn(frame4, ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(fsig), 2), ROOT.RooFit.FillColor(ROOT.kMagenta)) -model.plotOn(frame4, ROOT.RooFit.Components("bkg"), ROOT.RooFit.VisualizeError( - r, ROOT.RooArgSet(fsig), 2), ROOT.RooFit.FillColor(ROOT.kMagenta)) +model.plotOn(frame4, VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kMagenta) +model.plotOn(frame4, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kMagenta) model.plotOn(frame4) -model.plotOn(frame4, ROOT.RooFit.Components("bkg"), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame4, Components = "bkg", LineStyle = ROOT.kDashed) frame4.SetMinimum(0) c = ROOT.TCanvas("rf610_visualerror", "rf610_visualerror", 800, 800) diff --git a/tutorials/roofit/rf701_efficiencyfit.py b/tutorials/roofit/rf701_efficiencyfit.py index 9f8f4a4b81d91..e32b4a691e04e 100644 --- a/tutorials/roofit/rf701_efficiencyfit.py +++ b/tutorials/roofit/rf701_efficiencyfit.py @@ -60,7 +60,7 @@ # -------------------------------------------------------------------------- # Fit conditional efficiency pdf to data -effPdf.fitTo(data, ROOT.RooFit.ConditionalObservables(ROOT.RooArgSet(x))) +effPdf.fitTo(data, ConditionalObservables = ROOT.RooArgSet(x)) # Plot fitted, data efficiency # -------------------------------------------------------- @@ -69,19 +69,13 @@ frame1 = x.frame(ROOT.RooFit.Bins( 20), ROOT.RooFit.Title("Data (all, accepted)")) data.plotOn(frame1) -data.plotOn( - frame1, - ROOT.RooFit.Cut("cut==cut::accept"), - ROOT.RooFit.MarkerColor( - ROOT.kRed), - ROOT.RooFit.LineColor( - ROOT.kRed)) +data.plotOn(frame1, Cut = "cut==cut::accept", MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) # Plot accept/reject efficiency on data overlay fitted efficiency curve frame2 = x.frame(ROOT.RooFit.Bins( 20), ROOT.RooFit.Title("Fitted efficiency")) -data.plotOn(frame2, ROOT.RooFit.Efficiency(cut)) # needs ROOT version >= 5.21 -effFunc.plotOn(frame2, ROOT.RooFit.LineColor(ROOT.kRed)) +data.plotOn(frame2, Efficiency = cut) # needs ROOT version >= 5.21 +effFunc.plotOn(frame2, LineColor = ROOT.kRed) # Draw all frames on a canvas ca = ROOT.TCanvas("rf701_efficiency", "rf701_efficiency", 800, 400) diff --git a/tutorials/roofit/rf702_efficiencyfit_2D.py b/tutorials/roofit/rf702_efficiencyfit_2D.py index 9c034734c84e5..67598423ec54c 100644 --- a/tutorials/roofit/rf702_efficiencyfit_2D.py +++ b/tutorials/roofit/rf702_efficiencyfit_2D.py @@ -13,7 +13,7 @@ import ROOT -flat = ROOT.kFALSE +flat = False # Construct efficiency function e(x,y) # ----------------------------------------------------------------------- @@ -89,7 +89,7 @@ # -------------------------------------------------------------------------- # Fit conditional efficiency pdf to data -effPdf.fitTo(data, ROOT.RooFit.ConditionalObservables(ROOT.RooArgSet(x, y))) +effPdf.fitTo(data, ConditionalObservables = ROOT.RooArgSet(x, y)) # Plot fitted, data efficiency # -------------------------------------------------------- diff --git a/tutorials/roofit/rf703_effpdfprod.py b/tutorials/roofit/rf703_effpdfprod.py index 9bdf59cd718a1..23da613b672bb 100644 --- a/tutorials/roofit/rf703_effpdfprod.py +++ b/tutorials/roofit/rf703_effpdfprod.py @@ -40,11 +40,11 @@ # ---------------------------------------- frame1 = t.frame(ROOT.RooFit.Title("Efficiency")) -eff.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +eff.plotOn(frame1, LineColor = ROOT.kRed) frame2 = t.frame(ROOT.RooFit.Title("Pdf with and without efficiency")) -model.plotOn(frame2, ROOT.RooFit.LineStyle(ROOT.kDashed)) +model.plotOn(frame2, LineStyle = ROOT.kDashed) modelEff.plotOn(frame2) # Generate toy data, fit model eff to data diff --git a/tutorials/roofit/rf704_amplitudefit.py b/tutorials/roofit/rf704_amplitudefit.py index 94db0a14ed1e4..d45a7cadcb34d 100644 --- a/tutorials/roofit/rf704_amplitudefit.py +++ b/tutorials/roofit/rf704_amplitudefit.py @@ -95,11 +95,9 @@ pdf.plotOn(frame1) # workaround, see https://root.cern.ch/phpBB3/viewtopic.php?t=7764 ras_ampl1 = ROOT.RooArgSet(ampl1) -pdf.plotOn(frame1, ROOT.RooFit.Components(ras_ampl1), - ROOT.RooFit.LineStyle(ROOT.kDashed)) +pdf.plotOn(frame1, Components = ras_ampl1, LineStyle = ROOT.kDashed) ras_ampl2 = ROOT.RooArgSet(ampl2) -pdf.plotOn(frame1, ROOT.RooFit.Components(ras_ampl2), ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.LineColor(ROOT.kRed)) +pdf.plotOn(frame1, Components = ras_ampl2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) # Make projection on cosa, data, and its components # Note that components projection may be larger than sum because @@ -107,10 +105,8 @@ frame2 = cosa.frame() data.plotOn(frame2) pdf.plotOn(frame2) -pdf.plotOn(frame2, ROOT.RooFit.Components(ras_ampl1), - ROOT.RooFit.LineStyle(ROOT.kDashed)) -pdf.plotOn(frame2, ROOT.RooFit.Components(ras_ampl2), ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.LineColor(ROOT.kRed)) +pdf.plotOn(frame2, Components = ras_ampl1, LineStyle = ROOT.kDashed) +pdf.plotOn(frame2, Components = ras_ampl2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) c = ROOT.TCanvas("rf704_amplitudefit", "rf704_amplitudefit", 800, 800) c.Divide(2, 2) diff --git a/tutorials/roofit/rf705_linearmorph.py b/tutorials/roofit/rf705_linearmorph.py index 4c5b178d4b539..cc82e3c3790a4 100644 --- a/tutorials/roofit/rf705_linearmorph.py +++ b/tutorials/roofit/rf705_linearmorph.py @@ -53,21 +53,21 @@ # Show interpolated shapes in red alpha.setVal(0.125) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.25) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.375) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.50) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.625) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.75) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.875) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) alpha.setVal(0.95) -lmorph.plotOn(frame1, ROOT.RooFit.LineColor(ROOT.kRed)) +lmorph.plotOn(frame1, LineColor = ROOT.kRed) # Show 2D distribution of pdf(x,alpha) # ----------------------------------------------------------------------- @@ -84,8 +84,8 @@ data = lmorph.generate(ROOT.RooArgSet(x), 1000) # Fit pdf to toy data -lmorph.setCacheAlpha(ROOT.kTRUE) -lmorph.fitTo(data, ROOT.RooFit.Verbose(ROOT.kTRUE)) +lmorph.setCacheAlpha(True) +lmorph.fitTo(data, Verbose = True) # Plot fitted pdf and data overlaid frame2 = x.frame(ROOT.RooFit.Bins(100)) @@ -102,7 +102,7 @@ nll = ROOT.RooNLLVar("nll", "nll", lmorph, data) nll.plotOn(frame3, ROOT.RooFit.ShiftToZero()) -lmorph.setCacheAlpha(ROOT.kFALSE) +lmorph.setCacheAlpha(False) c = ROOT.TCanvas("rf705_linearmorph", "rf705_linearmorph", 800, 800) c.Divide(2, 2) diff --git a/tutorials/roofit/rf707_kernelestimation.py b/tutorials/roofit/rf707_kernelestimation.py index 90eab7cbdaa72..9b923f1891d08 100644 --- a/tutorials/roofit/rf707_kernelestimation.py +++ b/tutorials/roofit/rf707_kernelestimation.py @@ -47,14 +47,13 @@ ROOT.RooFit.Bins(20)) data1.plotOn(frame) kest1.plotOn(frame) -kest2.plotOn(frame, ROOT.RooFit.LineStyle( - ROOT.kDashed), ROOT.RooFit.LineColor(ROOT.kRed)) +kest2.plotOn(frame, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) # Plot kernel estimation pdfs with regular and increased bandwidth frame2 = x.frame(ROOT.RooFit.Title( "Adaptive kernel estimation pdf with regular, bandwidth")) kest1.plotOn(frame2) -kest3.plotOn(frame2, ROOT.RooFit.LineColor(ROOT.kMagenta)) +kest3.plotOn(frame2, LineColor = ROOT.kMagenta) # Create low status 2D dataset # ------------------------------------------------------- diff --git a/tutorials/roofit/rf708_bphysics.py b/tutorials/roofit/rf708_bphysics.py index 8d1465c39fdda..d0d21c956f177 100644 --- a/tutorials/roofit/rf708_bphysics.py +++ b/tutorials/roofit/rf708_bphysics.py @@ -64,47 +64,30 @@ frame1 = dt.frame(ROOT.RooFit.Title( "B decay distribution with mixing (B0/B0bar)")) -data.plotOn(frame1, ROOT.RooFit.Cut("tagFlav==tagFlav::B0")) -bmix.plotOn(frame1, ROOT.RooFit.Slice(tagFlav, "B0")) +data.plotOn(frame1, Cut = "tagFlav==tagFlav::B0") +bmix.plotOn(frame1, Slice = (tagFlav, "B0")) -data.plotOn(frame1, ROOT.RooFit.Cut("tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor(ROOT.kCyan)) -bmix.plotOn(frame1, ROOT.RooFit.Slice(tagFlav, "B0bar"), - ROOT.RooFit.LineColor(ROOT.kCyan)) +data.plotOn(frame1, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bmix.plotOn(frame1, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) # Plot mixed slice for B0 and B0bar tagged data separately frame2 = dt.frame(ROOT.RooFit.Title( "B decay distribution of mixed events (B0/B0bar)")) -data.plotOn(frame2, ROOT.RooFit.Cut( - "mixState==mixState::mixed&&tagFlav==tagFlav::B0")) -bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0"), - ROOT.RooFit.Slice(mixState, "mixed")) +data.plotOn(frame2, Cut = "mixState==mixState::mixed&&tagFlav==tagFlav::B0") +bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0"),Slice = (mixState, "mixed")) -data.plotOn( - frame2, - ROOT.RooFit.Cut("mixState==mixState::mixed&&tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor( - ROOT.kCyan)) -bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0bar"), ROOT.RooFit.Slice( - mixState, "mixed"), ROOT.RooFit.LineColor(ROOT.kCyan)) +data.plotOn(frame2, Cut = "mixState==mixState::mixed&&tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice = (mixState, "mixed"), LineColor = ROOT.kCyan) # Plot unmixed slice for B0 and B0bar tagged data separately -frame3 = dt.frame(ROOT.RooFit.Title( - "B decay distribution of unmixed events (B0/B0bar)")) - -data.plotOn(frame3, ROOT.RooFit.Cut( - "mixState==mixState::unmixed&&tagFlav==tagFlav::B0")) -bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0"), - ROOT.RooFit.Slice(mixState, "unmixed")) - -data.plotOn( - frame3, - ROOT.RooFit.Cut("mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor( - ROOT.kCyan)) -bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0bar"), ROOT.RooFit.Slice( - mixState, "unmixed"), ROOT.RooFit.LineColor(ROOT.kCyan)) +frame3 = dt.frame(ROOT.RooFit.Title("B decay distribution of unmixed events (B0/B0bar)")) + +data.plotOn(frame3, Cut = "mixState==mixState::unmixed&&tagFlav==tagFlav::B0") +bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0"), Slice = (mixState, "unmixed")) + +data.plotOn(frame3, Cut = "mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice = (mixState, "unmixed"), LineColor = ROOT.kCyan) # B-decay with CP violation # ------------------------- @@ -145,13 +128,11 @@ frame4 = dt.frame(ROOT.RooFit.Title( "B decay distribution with CPV(|l|=1,Im(l)=0.7) (B0/B0bar)")) -data2.plotOn(frame4, ROOT.RooFit.Cut("tagFlav==tagFlav::B0")) -bcp.plotOn(frame4, ROOT.RooFit.Slice(tagFlav, "B0")) +data2.plotOn(frame4, Cut = "tagFlav==tagFlav::B0") +bcp.plotOn(frame4, Slice = (tagFlav, "B0")) -data2.plotOn(frame4, ROOT.RooFit.Cut("tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor(ROOT.kCyan)) -bcp.plotOn(frame4, ROOT.RooFit.Slice(tagFlav, "B0bar"), - ROOT.RooFit.LineColor(ROOT.kCyan)) +data2.plotOn(frame4, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bcp.plotOn(frame4, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) # # Plot scenario 2 - sin(2b)=0.7, |l|=0.7 # ------------------------------------------------------------------------------- @@ -166,13 +147,11 @@ frame5 = dt.frame(ROOT.RooFit.Title( "B decay distribution with CPV(|l|=0.7,Im(l)=0.7) (B0/B0bar)")) -data3.plotOn(frame5, ROOT.RooFit.Cut("tagFlav==tagFlav::B0")) -bcp.plotOn(frame5, ROOT.RooFit.Slice(tagFlav, "B0")) +data3.plotOn(frame5, Cut = "tagFlav==tagFlav::B0") +bcp.plotOn(frame5, Slice = (tagFlav, "B0")) -data3.plotOn(frame5, ROOT.RooFit.Cut("tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor(ROOT.kCyan)) -bcp.plotOn(frame5, ROOT.RooFit.Slice(tagFlav, "B0bar"), - ROOT.RooFit.LineColor(ROOT.kCyan)) +data3.plotOn(frame5, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bcp.plotOn(frame5, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) # Generic B-decay with user coefficients @@ -213,13 +192,11 @@ frame6 = dt.frame(ROOT.RooFit.Title( "B decay distribution with CPV(Im(l)=0.7,Re(l)=0.7,|l|=1,dG/G=0.5) (B0/B0bar)")) -data4.plotOn(frame6, ROOT.RooFit.Cut("tagFlav==tagFlav::B0")) -bcpg.plotOn(frame6, ROOT.RooFit.Slice(tagFlav, "B0")) +data4.plotOn(frame6, Cut = "tagFlav==tagFlav::B0") +bcpg.plotOn(frame6, Slice = (tagFlav, "B0")) -data4.plotOn(frame6, ROOT.RooFit.Cut("tagFlav==tagFlav::B0bar"), - ROOT.RooFit.MarkerColor(ROOT.kCyan)) -bcpg.plotOn(frame6, ROOT.RooFit.Slice(tagFlav, "B0bar"), - ROOT.RooFit.LineColor(ROOT.kCyan)) +data4.plotOn(frame6, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) +bcpg.plotOn(frame6, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) c = ROOT.TCanvas("rf708_bphysics", "rf708_bphysics", 1200, 800) c.Divide(3, 2) diff --git a/tutorials/roofit/rf801_mcstudy.py b/tutorials/roofit/rf801_mcstudy.py index ef22737fc22bf..7ef43ea6c1044 100644 --- a/tutorials/roofit/rf801_mcstudy.py +++ b/tutorials/roofit/rf801_mcstudy.py @@ -66,13 +66,11 @@ mcstudy = ROOT.RooMCStudy( model, ROOT.RooArgSet(x), - ROOT.RooFit.Binned( - ROOT.kTRUE), + ROOT.RooFit.Binned(True), ROOT.RooFit.Silence(), ROOT.RooFit.Extended(), ROOT.RooFit.FitOptions( - ROOT.RooFit.Save( - ROOT.kTRUE), + ROOT.RooFit.Save(True), ROOT.RooFit.PrintEvalErrors(0))) # Generate and fit events @@ -89,7 +87,7 @@ frame1 = mcstudy.plotParam(mean, ROOT.RooFit.Bins(40)) frame2 = mcstudy.plotError(mean, ROOT.RooFit.Bins(40)) frame3 = mcstudy.plotPull(mean, ROOT.RooFit.Bins( - 40), ROOT.RooFit.FitGauss(ROOT.kTRUE)) + 40), ROOT.RooFit.FitGauss(True)) # Plot distribution of minimized likelihood frame4 = mcstudy.plotNLL(ROOT.RooFit.Bins(40)) diff --git a/tutorials/roofit/rf902_numgenconfig.py b/tutorials/roofit/rf902_numgenconfig.py index 2880a7deb7d9a..7539d9172812c 100644 --- a/tutorials/roofit/rf902_numgenconfig.py +++ b/tutorials/roofit/rf902_numgenconfig.py @@ -25,12 +25,10 @@ # ( an interface to the ROOT.TFoam MC generator with adaptive subdivisioning strategy ) to ROOT.RooAcceptReject, # a plain accept/reject sampling algorithm [ ROOT.RooFit default before # ROOT 5.23/04 ] -ROOT.RooAbsPdf.defaultGeneratorConfig().method1D( - ROOT.kFALSE, ROOT.kFALSE).setLabel("RooAcceptReject") +ROOT.RooAbsPdf.defaultGeneratorConfig().method1D(False, False).setLabel("RooAcceptReject") # Generate 10Kevt using ROOT.RooAcceptReject -data_ar = model.generate(ROOT.RooArgSet( - x), 10000, ROOT.RooFit.Verbose(ROOT.kTRUE)) +data_ar = model.generate(ROOT.RooArgSet(x), 10000, verbose = True) data_ar.Print() # Adjusting default config for a specific pdf @@ -39,8 +37,7 @@ # Another possibility: associate custom MC sampling configuration as default for object 'model' # The kTRUE argument will install a clone of the default configuration as specialized configuration # for self model if none existed so far -model.specialGeneratorConfig(ROOT.kTRUE).method1D( - ROOT.kFALSE, ROOT.kFALSE).setLabel("RooFoamGenerator") +model.specialGeneratorConfig(True).method1D(False, False).setLabel("RooFoamGenerator") # Adjusting parameters of a specific technique # --------------------------------------------------------------------------------------- diff --git a/tutorials/roofit/rf903_numintcache.py b/tutorials/roofit/rf903_numintcache.py index 932e9fa01d5de..b7da5a3d5e6f7 100644 --- a/tutorials/roofit/rf903_numintcache.py +++ b/tutorials/roofit/rf903_numintcache.py @@ -93,10 +93,7 @@ def getWorkspace(mode): 1000) # ROOT.This is slow in mode 0, fast in mode 1 -w.pdf("model").fitTo( - d, ROOT.RooFit.Verbose( - ROOT.kTRUE), ROOT.RooFit.Timer( - ROOT.kTRUE)) +w.pdf("model").fitTo(d, Verbose = True, Timer = True) # Projection on x (always slow as 2D integral over Y, at fitted value of a # is not cached) From e8ae2ce5a222202c1a11a663e26f4b32491ad055 Mon Sep 17 00:00:00 2001 From: "Harshal.S" Date: Fri, 11 Jun 2021 11:21:33 +0530 Subject: [PATCH 180/309] [RF] Format code of RooFit python tutorials --- tutorials/roofit/rf101_basics.py | 5 +- tutorials/roofit/rf104_classfactory.py | 13 +-- tutorials/roofit/rf107_plotstyles.py | 28 +++-- tutorials/roofit/rf108_plotbinning.py | 17 ++- tutorials/roofit/rf110_normintegration.py | 6 +- tutorials/roofit/rf111_derivatives.py | 15 ++- tutorials/roofit/rf201_composite.py | 38 ++----- tutorials/roofit/rf202_extendedmlfit.py | 41 ++++--- tutorials/roofit/rf203_ranges.py | 11 +- tutorials/roofit/rf204a_extendedLikelihood.py | 54 ++++----- tutorials/roofit/rf205_compplot.py | 41 +++---- tutorials/roofit/rf206_treevistools.py | 24 ++-- tutorials/roofit/rf208_convolution.py | 2 +- tutorials/roofit/rf209_anaconv.py | 21 +--- tutorials/roofit/rf210_angularconv.py | 4 +- tutorials/roofit/rf211_paramconv.py | 2 +- tutorials/roofit/rf301_composition.py | 6 +- tutorials/roofit/rf302_utilfuncs.py | 35 +++--- tutorials/roofit/rf304_uncorrprod.py | 3 +- tutorials/roofit/rf305_condcorrprod.py | 18 +-- tutorials/roofit/rf306_condpereventerrors.py | 32 +++--- tutorials/roofit/rf307_fullpereventerrors.py | 31 ++--- tutorials/roofit/rf308_normintegration2d.py | 15 +-- tutorials/roofit/rf310_sliceplot.py | 29 ++--- tutorials/roofit/rf311_rangeplot.py | 31 ++--- tutorials/roofit/rf312_multirangefit.py | 12 +- tutorials/roofit/rf313_paramranges.py | 14 +-- tutorials/roofit/rf314_paramfitrange.py | 9 +- tutorials/roofit/rf315_projectpdf.py | 17 +-- tutorials/roofit/rf316_llratioplot.py | 32 ++---- tutorials/roofit/rf402_datahandling.py | 5 +- tutorials/roofit/rf404_categories.py | 3 +- tutorials/roofit/rf405_realtocatfuncs.py | 20 ++-- tutorials/roofit/rf406_cattocatfuncs.py | 9 +- tutorials/roofit/rf407_latextables.py | 27 ++--- tutorials/roofit/rf501_simultaneouspdf.py | 44 +++----- tutorials/roofit/rf502_wspacewrite.py | 16 +-- tutorials/roofit/rf504_simwstool.py | 13 +-- tutorials/roofit/rf505_asciicfg.py | 10 +- tutorials/roofit/rf506_msgservice.py | 26 ++--- tutorials/roofit/rf507_debugtools.py | 7 +- tutorials/roofit/rf509_wsinteractive.py | 27 ++--- tutorials/roofit/rf510_wsnamedsets.py | 8 +- tutorials/roofit/rf511_wsfactory_basic.py | 4 +- tutorials/roofit/rf513_wsfactory_tools.py | 9 +- tutorials/roofit/rf603_multicpu.py | 30 ++--- tutorials/roofit/rf604_constraints.py | 29 ++--- tutorials/roofit/rf605_profilell.py | 4 +- tutorials/roofit/rf606_nllerrorhandling.py | 10 +- tutorials/roofit/rf607_fitresult.py | 21 ++-- tutorials/roofit/rf608_fitresultaspdf.py | 9 +- tutorials/roofit/rf609_xychi2fit.py | 14 +-- tutorials/roofit/rf610_visualerror.py | 64 +++++------ tutorials/roofit/rf701_efficiencyfit.py | 28 ++--- tutorials/roofit/rf702_efficiencyfit_2D.py | 57 ++++------ tutorials/roofit/rf703_effpdfprod.py | 9 +- tutorials/roofit/rf704_amplitudefit.py | 60 ++++------ tutorials/roofit/rf705_linearmorph.py | 18 +-- tutorials/roofit/rf706_histpdf.py | 11 +- tutorials/roofit/rf707_kernelestimation.py | 50 ++++----- tutorials/roofit/rf708_bphysics.py | 106 +++++++----------- tutorials/roofit/rf801_mcstudy.py | 30 ++--- tutorials/roofit/rf901_numintconfig.py | 57 ++++------ tutorials/roofit/rf902_numgenconfig.py | 13 +-- tutorials/roofit/rf903_numintcache.py | 19 ++-- 65 files changed, 573 insertions(+), 900 deletions(-) diff --git a/tutorials/roofit/rf101_basics.py b/tutorials/roofit/rf101_basics.py index 56b15204fc680..021e84be3208d 100644 --- a/tutorials/roofit/rf101_basics.py +++ b/tutorials/roofit/rf101_basics.py @@ -33,7 +33,7 @@ sigma.setVal(3) # Plot gauss in frame (i.e. in x) and draw frame on canvas -gauss.plotOn(xframe, LineColor = ROOT.kRed) +gauss.plotOn(xframe, LineColor=ROOT.kRed) # Generate events # ----------------------------- @@ -42,8 +42,7 @@ # Make a second plot frame in x and draw both the # data and the pdf in the frame -xframe2 = x.frame(ROOT.RooFit.Title( - "Gaussian pdf with data")) # RooPlot +xframe2 = x.frame(ROOT.RooFit.Title("Gaussian pdf with data")) # RooPlot data.plotOn(xframe2) gauss.plotOn(xframe2) diff --git a/tutorials/roofit/rf104_classfactory.py b/tutorials/roofit/rf104_classfactory.py index 1906503bec90c..3e4b4b35dc4a7 100644 --- a/tutorials/roofit/rf104_classfactory.py +++ b/tutorials/roofit/rf104_classfactory.py @@ -31,8 +31,7 @@ # To use this class, # - Compile and link class with '.x MyPdfV2.cxx+' # -ROOT.RooClassFactory.makePdf( - "MyPdfV2", "x,A,B", "", "A*fabs(x)+pow(x-B,2)") +ROOT.RooClassFactory.makePdf("MyPdfV2", "x,A,B", "", "A*fabs(x)+pow(x-B,2)") # With added analytical integral expression # --------------------------------------------------------------------------------- @@ -49,7 +48,8 @@ "A*fabs(x)+pow(x-B,2)", True, False, - "x:(A/2)*(pow(x.max(rangeName),2)+pow(x.min(rangeName),2))+(1./3)*(pow(x.max(rangeName)-B,3)-pow(x.min(rangeName)-B,3))") + "x:(A/2)*(pow(x.max(rangeName),2)+pow(x.min(rangeName),2))+(1./3)*(pow(x.max(rangeName)-B,3)-pow(x.min(rangeName)-B,3))", +) # Use instance of created class # --------------------------------------------------------- @@ -83,11 +83,8 @@ alpha = ROOT.RooRealVar("alpha", "alpha", 5, 0.1, 10) genpdf = ROOT.RooClassFactory.makePdfInstance( - "GenPdf", - "(1+0.1*fabs(x)+sin(sqrt(fabs(x*alpha+0.1))))", - ROOT.RooArgList( - x, - alpha)) + "GenPdf", "(1+0.1*fabs(x)+sin(sqrt(fabs(x*alpha+0.1))))", ROOT.RooArgList(x, alpha) +) # Generate a toy dataset from the interpreted pdf data2 = genpdf.generate(ROOT.RooArgSet(x), 50000) diff --git a/tutorials/roofit/rf107_plotstyles.py b/tutorials/roofit/rf107_plotstyles.py index c5ff1a78288cb..19397e881bfa1 100644 --- a/tutorials/roofit/rf107_plotstyles.py +++ b/tutorials/roofit/rf107_plotstyles.py @@ -32,14 +32,12 @@ # ------------------------------- # Make four plot frames to demonstrate various plotting features -frame1 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title( - "Red Curve / SumW2 Histo errors"), ROOT.RooFit.Bins(20)) -frame2 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title( - "Dashed Curve / No XError bars"), ROOT.RooFit.Bins(20)) -frame3 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title( - "Filled Curve / Blue Histo"), ROOT.RooFit.Bins(20)) -frame4 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title( - "Partial Range / Filled Bar chart"), ROOT.RooFit.Bins(20)) +frame1 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Red Curve / SumW2 Histo errors"), ROOT.RooFit.Bins(20)) +frame2 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Dashed Curve / No XError bars"), ROOT.RooFit.Bins(20)) +frame3 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Filled Curve / Blue Histo"), ROOT.RooFit.Bins(20)) +frame4 = x.frame( + ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Partial Range / Filled Bar chart"), ROOT.RooFit.Bins(20) +) # Data plotting styles # --------------------------------------- @@ -48,28 +46,28 @@ data.plotOn(frame1, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) # Remove horizontal error bars -data.plotOn(frame2, XErrorSize = 0 ) +data.plotOn(frame2, XErrorSize=0) # Blue markers and error bors -data.plotOn(frame3, MarkerColor = ROOT.kBlue, LineColor = ROOT.kBlue) +data.plotOn(frame3, MarkerColor=ROOT.kBlue, LineColor=ROOT.kBlue) # Filled bar chart -data.plotOn(frame4, DrawOption = "B", DataError = ROOT.RooAbsData.ErrorType(2), XErrorSize = 0, FillColor = ROOT.kGray) +data.plotOn(frame4, DrawOption="B", DataError=ROOT.RooAbsData.ErrorType(2), XErrorSize=0, FillColor=ROOT.kGray) # Function plotting styles # ----------------------------------------------- # Change line color to red -gauss.plotOn(frame1, LineColor = ROOT.kRed) +gauss.plotOn(frame1, LineColor=ROOT.kRed) # Change line style to dashed -gauss.plotOn(frame2, LineStyle = ROOT.kDashed) +gauss.plotOn(frame2, LineStyle=ROOT.kDashed) # Filled shapes in green color -gauss.plotOn(frame3, ROOT.RooFit.MoveToBack(), DrawOption = "F", FillColor = ROOT.kOrange) +gauss.plotOn(frame3, ROOT.RooFit.MoveToBack(), DrawOption="F", FillColor=ROOT.kOrange) # -gauss.plotOn(frame4, Range = (-8, 3), LineColor = ROOT.kMagenta) +gauss.plotOn(frame4, Range=(-8, 3), LineColor=ROOT.kMagenta) c = ROOT.TCanvas("rf107_plotstyles", "rf107_plotstyles", 800, 800) c.Divide(2, 2) diff --git a/tutorials/roofit/rf108_plotbinning.py b/tutorials/roofit/rf108_plotbinning.py index f2c928f015bd1..0ee52099a790f 100644 --- a/tutorials/roofit/rf108_plotbinning.py +++ b/tutorials/roofit/rf108_plotbinning.py @@ -18,7 +18,7 @@ dm = ROOT.RooRealVar("dm", "dm", 0.472) tau = ROOT.RooRealVar("tau", "tau", 1.547) w = ROOT.RooRealVar("w", "mistag rate", 0.1) -dw = ROOT.RooRealVar("dw", "delta mistag rate", 0.) +dw = ROOT.RooRealVar("dw", "delta mistag rate", 0.0) mixState = ROOT.RooCategory("mixState", "B0/B0bar mixing state") mixState.defineType("mixed", -1) @@ -34,8 +34,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct Bdecay (x) gauss -bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, - tau, dm, w, dw, gm1, ROOT.RooBMixDecay.DoubleSided) +bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, ROOT.RooBMixDecay.DoubleSided) # Sample data from model # -------------------------------------------- @@ -59,9 +58,8 @@ tbins.addUniform(15, 0, 15) # Make plot with specified binning -dtframe = dt.frame(ROOT.RooFit.Range(-15, 15), - ROOT.RooFit.Title("dt distribution with custom binning")) -data.plotOn(dtframe, Binning = tbins) +dtframe = dt.frame(ROOT.RooFit.Range(-15, 15), ROOT.RooFit.Title("dt distribution with custom binning")) +data.plotOn(dtframe, Binning=tbins) bmix.plotOn(dtframe) # NB: Note that bin density for each bin is adjusted to that of default frame binning as shown @@ -86,14 +84,13 @@ abins.addBoundaryPair(6) # Create plot frame in dt -aframe = dt.frame(ROOT.RooFit.Range(-10, 10), ROOT.RooFit.Title( - "mixState asymmetry distribution with custom binning")) +aframe = dt.frame(ROOT.RooFit.Range(-10, 10), ROOT.RooFit.Title("mixState asymmetry distribution with custom binning")) # Plot mixState asymmetry of data with specified customg binning -data.plotOn(aframe, Asymmetry = mixState, Binning = abins) +data.plotOn(aframe, Asymmetry=mixState, Binning=abins) # Plot corresponding property of pdf -bmix.plotOn(aframe, Asymmetry = mixState) +bmix.plotOn(aframe, Asymmetry=mixState) # Adjust vertical range of plot to sensible values for an asymmetry aframe.SetMinimum(-1.1) diff --git a/tutorials/roofit/rf110_normintegration.py b/tutorials/roofit/rf110_normintegration.py index 016a3d344dde2..c36afc44df7a0 100644 --- a/tutorials/roofit/rf110_normintegration.py +++ b/tutorials/roofit/rf110_normintegration.py @@ -19,8 +19,7 @@ x = ROOT.RooRealVar("x", "x", -10, 10) # Create pdf gaussx(x,-2,3) -gx = ROOT.RooGaussian( - "gx", "gx", x, ROOT.RooFit.RooConst(-2), ROOT.RooFit.RooConst(3)) +gx = ROOT.RooGaussian("gx", "gx", x, ROOT.RooFit.RooConst(-2), ROOT.RooFit.RooConst(3)) # Retrieve raw & normalized values of RooFit pdfs # -------------------------------------------------------------------------------------------------- @@ -62,8 +61,7 @@ gx_cdf.plotOn(frame) # Draw plot on canvas -c = ROOT.TCanvas("rf110_normintegration", - "rf110_normintegration", 600, 600) +c = ROOT.TCanvas("rf110_normintegration", "rf110_normintegration", 600, 600) ROOT.gPad.SetLeftMargin(0.15) frame.GetYaxis().SetTitleOffset(1.6) frame.Draw() diff --git a/tutorials/roofit/rf111_derivatives.py b/tutorials/roofit/rf111_derivatives.py index ea2ca2cf7db0a..6644385fc0504 100644 --- a/tutorials/roofit/rf111_derivatives.py +++ b/tutorials/roofit/rf111_derivatives.py @@ -43,9 +43,9 @@ gauss.plotOn(xframe) # Plot derivatives in same frame -dgdx.plotOn(xframe, LineColor = ROOT.kMagenta) -d2gdx2.plotOn(xframe, LineColor = ROOT.kRed) -d3gdx3.plotOn(xframe, LineColor = ROOT.kOrange) +dgdx.plotOn(xframe, LineColor=ROOT.kMagenta) +d2gdx2.plotOn(xframe, LineColor=ROOT.kRed) +d3gdx3.plotOn(xframe, LineColor=ROOT.kOrange) # Create and plot derivatives w.r.t. sigma # ------------------------------------------------------------------------------ @@ -58,16 +58,15 @@ d3gds3 = gauss.derivative(sigma, 3) # Construct plot frame in 'sigma' -sframe = sigma.frame(ROOT.RooFit.Title( - "d(Gauss)/d(sigma)"), ROOT.RooFit.Range(0., 2.)) +sframe = sigma.frame(ROOT.RooFit.Title("d(Gauss)/d(sigma)"), ROOT.RooFit.Range(0.0, 2.0)) # Plot gauss in frame (i.e. in x) gauss.plotOn(sframe) # Plot derivatives in same frame -dgds.plotOn(sframe, LineColor = ROOT.kMagenta) -d2gds2.plotOn(sframe, LineColor = ROOT.kRed) -d3gds3.plotOn(sframe, LineColor = ROOT.kOrange) +dgds.plotOn(sframe, LineColor=ROOT.kMagenta) +d2gds2.plotOn(sframe, LineColor=ROOT.kRed) +d3gds3.plotOn(sframe, LineColor=ROOT.kOrange) # Draw all frames on a canvas c = ROOT.TCanvas("rf111_derivatives", "rf111_derivatives", 800, 400) diff --git a/tutorials/roofit/rf201_composite.py b/tutorials/roofit/rf201_composite.py index 4c29ca6cc6803..364396e995c9a 100644 --- a/tutorials/roofit/rf201_composite.py +++ b/tutorials/roofit/rf201_composite.py @@ -30,8 +30,8 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) @@ -40,18 +40,15 @@ # Add signal components # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList( - sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Add signal and background # ------------------------------------------------ # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Sample, fit and plot model # --------------------------------------------------- @@ -63,18 +60,17 @@ model.fitTo(data) # Plot data and PDF overlaid -xframe = x.frame(ROOT.RooFit.Title( - "Example of composite pdf=(sig1+sig2)+bkg")) +xframe = x.frame(ROOT.RooFit.Title("Example of composite pdf=(sig1+sig2)+bkg")) data.plotOn(xframe) model.plotOn(xframe) # Overlay the background component of model with a dashed line ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(xframe, Components = ras_bkg, LineStyle = ROOT.kDashed) +model.plotOn(xframe, Components=ras_bkg, LineStyle=ROOT.kDashed) # Overlay the background+sig2 components of model with a dotted line ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted) +model.plotOn(xframe, Components=ras_bkg_sig2, LineStyle=ROOT.kDotted) # Print structure of composite pdf model.Print("t") @@ -86,17 +82,7 @@ # # model2 = bkg + (sig1 + sig2) # -model2 = ROOT.RooAddPdf( - "model", - "g1+g2+a", - ROOT.RooArgList( - bkg, - sig1, - sig2), - ROOT.RooArgList( - bkgfrac, - sig1frac), - True) +model2 = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig1, sig2), ROOT.RooArgList(bkgfrac, sig1frac), True) # NB: Each coefficient is interpreted as the fraction of the # left-hand component of the i-th recursive sum, i.e. @@ -107,8 +93,8 @@ # Plot recursive addition model # --------------------------------------------------------- -model2.plotOn(xframe, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) -model2.plotOn(xframe, Components = ras_bkg_sig2, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) +model2.plotOn(xframe, LineColor=ROOT.kRed, LineStyle=ROOT.kDashed) +model2.plotOn(xframe, Components=ras_bkg_sig2, LineColor=ROOT.kRed, LineStyle=ROOT.kDashed) model2.Print("t") # Draw the frame on the canvas diff --git a/tutorials/roofit/rf202_extendedmlfit.py b/tutorials/roofit/rf202_extendedmlfit.py index 8709cc478f5cd..72ed7192b15e5 100644 --- a/tutorials/roofit/rf202_extendedmlfit.py +++ b/tutorials/roofit/rf202_extendedmlfit.py @@ -26,33 +26,22 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Method 1 - Construct extended composite model # ------------------------------------------------------------------- # Sum the composite signal and background into an extended pdf # nsig*sig+nbkg*bkg -nsig = ROOT.RooRealVar("nsig", "number of signal events", 500, 0., 10000) -nbkg = ROOT.RooRealVar( - "nbkg", "number of background events", 500, 0, 10000) -model = ROOT.RooAddPdf( - "model", - "(g1+g2)+a", - ROOT.RooArgList( - bkg, - sig), - ROOT.RooArgList( - nbkg, - nsig)) +nsig = ROOT.RooRealVar("nsig", "number of signal events", 500, 0.0, 10000) +nbkg = ROOT.RooRealVar("nbkg", "number of background events", 500, 0, 10000) +model = ROOT.RooAddPdf("model", "(g1+g2)+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(nbkg, nsig)) # Sample, fit and plot extended model # --------------------------------------------------------------------- @@ -68,15 +57,25 @@ # rather than observed number of events (==data.numEntries()) xframe = x.frame(ROOT.RooFit.Title("extended ML fit example")) data.plotOn(xframe) -model.plotOn(xframe, Normalization= dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) +model.plotOn(xframe, Normalization=dict(scaleFactor=1.0, scaleType=ROOT.RooAbsReal.RelativeExpected)) # Overlay the background component of model with a dashed line ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(xframe, Components = ras_bkg, LineStyle = ROOT.kDotted, Normalization = dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) +model.plotOn( + xframe, + Components=ras_bkg, + LineStyle=ROOT.kDotted, + Normalization=dict(scaleFactor=1.0, scaleType=ROOT.RooAbsReal.RelativeExpected), +) # Overlay the background+sig2 components of model with a dotted line ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted, Normalization = dict(scaleFactor = 1.0, scaleType = ROOT.RooAbsReal.RelativeExpected)) +model.plotOn( + xframe, + Components=ras_bkg_sig2, + LineStyle=ROOT.kDotted, + Normalization=dict(scaleFactor=1.0, scaleType=ROOT.RooAbsReal.RelativeExpected), +) # Print structure of composite pdf model.Print("t") diff --git a/tutorials/roofit/rf203_ranges.py b/tutorials/roofit/rf203_ranges.py index 6c345df9a75ae..c6a1ad90f8221 100644 --- a/tutorials/roofit/rf203_ranges.py +++ b/tutorials/roofit/rf203_ranges.py @@ -25,9 +25,8 @@ px = ROOT.RooPolynomial("px", "px", x) # model = f*gx + (1-f)px -f = ROOT.RooRealVar("f", "f", 0., 1.) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList(gx, px), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gx, px), ROOT.RooArgList(f)) # Generated 10000 events in (x,y) from pdf model modelData = model.generate(ROOT.RooArgSet(x), 10000) @@ -36,7 +35,7 @@ # --------------------------- # Fit pdf to all data -r_full = model.fitTo(modelData, Save = True) +r_full = model.fitTo(modelData, Save=True) # Fit partial range # ---------------------------------- @@ -45,7 +44,7 @@ x.setRange("signal", -3, 3) # Fit pdf only to data in "signal" range -r_sig = model.fitTo(modelData, Save = True, Range = "signal") +r_sig = model.fitTo(modelData, Save=True, Range="signal") # Plot/print results # --------------------------------------- @@ -53,7 +52,7 @@ # Make plot frame in x and add data and fitted model frame = x.frame(ROOT.RooFit.Title("Fitting a sub range")) modelData.plotOn(frame) -model.plotOn(frame, Range = "Full", LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) # Add shape in full ranged dashed +model.plotOn(frame, Range="Full", LineColor=ROOT.kRed, LineStyle=ROOT.kDashed) # Add shape in full ranged dashed model.plotOn(frame) # By default only fitted range is shown # Print fit results diff --git a/tutorials/roofit/rf204a_extendedLikelihood.py b/tutorials/roofit/rf204a_extendedLikelihood.py index 5e58a5c0d56a1..0ce965a63d922 100644 --- a/tutorials/roofit/rf204a_extendedLikelihood.py +++ b/tutorials/roofit/rf204a_extendedLikelihood.py @@ -15,47 +15,47 @@ # --------------------- # Declare observable x -x = ROOT.RooRealVar("x","x",0,11) +x = ROOT.RooRealVar("x", "x", 0, 11) # Create two Gaussian PDFs g1(x,mean1,sigma) anf g2(x,mean2,sigma) and their parameters -mean = ROOT.RooRealVar("mean","mean of gaussians",5) -sigma1 = ROOT.RooRealVar("sigma1","width of gaussians",0.5) -sigma2 = ROOT.RooRealVar("sigma2","width of gaussians",1) +mean = ROOT.RooRealVar("mean", "mean of gaussians", 5) +sigma1 = ROOT.RooRealVar("sigma1", "width of gaussians", 0.5) +sigma2 = ROOT.RooRealVar("sigma2", "width of gaussians", 1) -sig1 = ROOT.RooGaussian("sig1","Signal component 1",x,mean,sigma1) -sig2 = ROOT.RooGaussian("sig2","Signal component 2",x,mean,sigma2) +sig1 = ROOT.RooGaussian("sig1", "Signal component 1", x, mean, sigma1) +sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0","a0",0.5,0.,1.) -a1 = ROOT.RooRealVar("a1","a1",0.2,0.,1.) -bkg = ROOT.RooChebychev("bkg","Background",x,ROOT.RooArgSet(a0,a1)) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", 0.2, 0.0, 1.0) +bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgSet(a0, a1)) -#Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar("sig1frac","fraction of component 1 in signal",0.8,0.,1.) -sig = ROOT.RooAddPdf("sig","Signal",ROOT.RooArgList(sig1,sig2),sig1frac) +# Sum the signal components into a composite signal pdf +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), sig1frac) # Extend the pdfs # ----------------------------- # Define signal range in which events counts are to be defined -x.setRange("signalRange",4,6) +x.setRange("signalRange", 4, 6) # Associated nsig/nbkg as expected number of events with sig/bkg _in_the_range_ "signalRange" -nsig = ROOT.RooRealVar("nsig","number of signal events in signalRange",500,0.,10000) -nbkg = ROOT.RooRealVar("nbkg","number of background events in signalRange",500,0,10000) +nsig = ROOT.RooRealVar("nsig", "number of signal events in signalRange", 500, 0.0, 10000) +nbkg = ROOT.RooRealVar("nbkg", "number of background events in signalRange", 500, 0, 10000) # Use AddPdf to extend the model. Giving as many coefficients as pdfs switches on extension. -model = ROOT.RooAddPdf("model","(g1+g2)+a", ROOT.RooArgList(bkg,sig), ROOT.RooArgList(nbkg,nsig)) +model = ROOT.RooAddPdf("model", "(g1+g2)+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(nbkg, nsig)) # Sample data, fit model # ------------------------------------------- # Generate 1000 events from model so that nsig,nbkg come out to numbers <<500 in fit -data = model.generate(x,1000) +data = model.generate(x, 1000) canv = ROOT.TCanvas("Canvas", "Canvas", 1500, 600) -canv.Divide(3,1) +canv.Divide(3, 1) # Fit full range # ------------------------------------------- @@ -69,12 +69,12 @@ canv.cd(1) model1 = ROOT.RooAddPdf(model) -r = model1.fitTo(data, Save = True) +r = model1.fitTo(data, Save=True) r.Print() frame = x.frame(ROOT.RooFit.Title("Full range fitted")) data.plotOn(frame) -model1.plotOn(frame, VisualizeError = r) +model1.plotOn(frame, VisualizeError=r) model1.plotOn(frame) model1.paramOn(frame) frame.Draw() @@ -84,16 +84,16 @@ # ------------------------------------------- canv.cd(2) -x.setRange("left", 0., 4.) -x.setRange("right", 6., 10.) +x.setRange("left", 0.0, 4.0) +x.setRange("right", 6.0, 10.0) model2 = ROOT.RooAddPdf(model) -r2 = model2.fitTo(data, Range = "left,right", Save = True) +r2 = model2.fitTo(data, Range="left,right", Save=True) r2.Print() frame2 = x.frame(ROOT.RooFit.Title("Fit in left/right sideband")) data.plotOn(frame2) -model2.plotOn(frame2, VisualizeError = r2) +model2.plotOn(frame2, VisualizeError=r2) model2.plotOn(frame2) model2.paramOn(frame2) frame2.Draw() @@ -105,15 +105,15 @@ # the fit uncertainty canv.cd(3) -x.setRange("leftToMiddle", 0., 5.) +x.setRange("leftToMiddle", 0.0, 5.0) model3 = ROOT.RooAddPdf(model) -r3 = model3.fitTo(data, Range = "leftToMiddle", Save = True) +r3 = model3.fitTo(data, Range="leftToMiddle", Save=True) r3.Print() frame3 = x.frame(ROOT.RooFit.Title("Fit from left to middle")) data.plotOn(frame3) -model3.plotOn(frame3, VisualizeError = r3) +model3.plotOn(frame3, VisualizeError=r3) model3.plotOn(frame3) model3.paramOn(frame3) frame3.Draw() diff --git a/tutorials/roofit/rf205_compplot.py b/tutorials/roofit/rf205_compplot.py index fd8da39adb0b9..bffa3d55a30da 100644 --- a/tutorials/roofit/rf205_compplot.py +++ b/tutorials/roofit/rf205_compplot.py @@ -25,31 +25,25 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) -bkg1 = ROOT.RooChebychev("bkg1", "Background 1", - x, ROOT.RooArgList(a0, a1)) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +bkg1 = ROOT.RooChebychev("bkg1", "Background 1", x, ROOT.RooArgList(a0, a1)) # Build expontential pdf alpha = ROOT.RooRealVar("alpha", "alpha", -1) bkg2 = ROOT.RooExponential("bkg2", "Background 2", x, alpha) # Sum the background components into a composite background pdf -bkg1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in background", 0.2, 0., 1.) -bkg = ROOT.RooAddPdf( - "bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(sig1frac)) +bkg1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in background", 0.2, 0.0, 1.0) +bkg = ROOT.RooAddPdf("bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Set up basic plot with data and full pdf # ------------------------------------------------------------------------------ @@ -58,8 +52,7 @@ data = model.generate(ROOT.RooArgSet(x), 1000) # Plot data and complete PDF overlaid -xframe = x.frame(ROOT.RooFit.Title( - "Component plotting of pdf=(sig1+sig2)+(bkg1+bkg2)")) +xframe = x.frame(ROOT.RooFit.Title("Component plotting of pdf=(sig1+sig2)+(bkg1+bkg2)")) data.plotOn(xframe) model.plotOn(xframe) @@ -71,34 +64,34 @@ # Plot single background component specified by object reference ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(xframe, Components = ras_bkg, LineColor = ROOT.kRed) +model.plotOn(xframe, Components=ras_bkg, LineColor=ROOT.kRed) # Plot single background component specified by object reference ras_bkg2 = ROOT.RooArgSet(bkg2) -model.plotOn(xframe, Components = ras_bkg2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) +model.plotOn(xframe, Components=ras_bkg2, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) # Plot multiple background components specified by object reference # Note that specified components may occur at any level in object tree # (e.g bkg is component of 'model' and 'sig2' is component 'sig') ras_bkg_sig2 = ROOT.RooArgSet(bkg, sig2) -model.plotOn(xframe, Components = ras_bkg_sig2, LineStyle = ROOT.kDotted) +model.plotOn(xframe, Components=ras_bkg_sig2, LineStyle=ROOT.kDotted) # Make component by name/regexp # ------------------------------------------------------------ # Plot single background component specified by name -model.plotOn(xframe2, Components = "bkg", LineColor = ROOT.kCyan) +model.plotOn(xframe2, Components="bkg", LineColor=ROOT.kCyan) # Plot multiple background components specified by name -model.plotOn(xframe2, Components = "bkg1,sig2", LineStyle = ROOT.kDotted, LineColor = ROOT.kCyan) +model.plotOn(xframe2, Components="bkg1,sig2", LineStyle=ROOT.kDotted, LineColor=ROOT.kCyan) # Plot multiple background components specified by regular expression on # name -model.plotOn( xframe2, Components = "sig*", LineStyle = ROOT.kDashed, LineColor = ROOT.kCyan) +model.plotOn(xframe2, Components="sig*", LineStyle=ROOT.kDashed, LineColor=ROOT.kCyan) # Plot multiple background components specified by multiple regular # expressions on name -model.plotOn(xframe2, Invisible=True, Components = "bkg1,sig*", LineStyle = ROOT.kDashed, LineColor= ROOT.kYellow) +model.plotOn(xframe2, Invisible=True, Components="bkg1,sig*", LineStyle=ROOT.kDashed, LineColor=ROOT.kYellow) # Draw the frame on the canvas c = ROOT.TCanvas("rf205_compplot", "rf205_compplot", 800, 400) diff --git a/tutorials/roofit/rf206_treevistools.py b/tutorials/roofit/rf206_treevistools.py index 06297a91a77ce..c5c41d9b3f5b2 100644 --- a/tutorials/roofit/rf206_treevistools.py +++ b/tutorials/roofit/rf206_treevistools.py @@ -25,31 +25,25 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) -bkg1 = ROOT.RooChebychev("bkg1", "Background 1", - x, ROOT.RooArgList(a0, a1)) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +bkg1 = ROOT.RooChebychev("bkg1", "Background 1", x, ROOT.RooArgList(a0, a1)) # Build expontential pdf alpha = ROOT.RooRealVar("alpha", "alpha", -1) bkg2 = ROOT.RooExponential("bkg2", "Background 2", x, alpha) # Sum the background components into a composite background pdf -bkg1frac = ROOT.RooRealVar( - "bkg1frac", "fraction of component 1 in background", 0.2, 0., 1.) -bkg = ROOT.RooAddPdf( - "bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(bkg1frac)) +bkg1frac = ROOT.RooRealVar("bkg1frac", "fraction of component 1 in background", 0.2, 0.0, 1.0) +bkg = ROOT.RooAddPdf("bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(bkg1frac)) # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Print composite tree in ASCII # ----------------------------------------------------------- diff --git a/tutorials/roofit/rf208_convolution.py b/tutorials/roofit/rf208_convolution.py index 8c86978f3afda..df56107a5e9f6 100644 --- a/tutorials/roofit/rf208_convolution.py +++ b/tutorials/roofit/rf208_convolution.py @@ -53,7 +53,7 @@ frame = t.frame(ROOT.RooFit.Title("landau (x) gauss convolution")) data.plotOn(frame) lxg.plotOn(frame) -landau.plotOn(frame, LineStyle = ROOT.kDashed) +landau.plotOn(frame, LineStyle=ROOT.kDashed) # Draw frame on canvas c = ROOT.TCanvas("rf208_convolution", "rf208_convolution", 600, 600) diff --git a/tutorials/roofit/rf209_anaconv.py b/tutorials/roofit/rf209_anaconv.py index 766010858fa36..05f33cbcf6484 100644 --- a/tutorials/roofit/rf209_anaconv.py +++ b/tutorials/roofit/rf209_anaconv.py @@ -28,12 +28,11 @@ tm = ROOT.RooTruthModel("tm", "truth model", dt) # Construct decay(t) (x) delta(t) -decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, - tau, tm, ROOT.RooDecay.DoubleSided) +decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, tau, tm, ROOT.RooDecay.DoubleSided) # Plot pdf (dashed) frame = dt.frame(ROOT.RooFit.Title("Bdecay (x) resolution")) -decay_tm.plotOn(frame, LineStyle = ROOT.kDashed) +decay_tm.plotOn(frame, LineStyle=ROOT.kDashed) # B-physics pdf with Gaussian resolution # ---------------------------------------------------------------------------- @@ -44,8 +43,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct decay(t) (x) gauss1(t) -decay_gm1 = ROOT.RooDecay("decay_gm1", "decay", - dt, tau, gm1, ROOT.RooDecay.DoubleSided) +decay_gm1 = ROOT.RooDecay("decay_gm1", "decay", dt, tau, gm1, ROOT.RooDecay.DoubleSided) # Plot pdf decay_gm1.plotOn(frame) @@ -60,20 +58,13 @@ # Build a composite resolution model f*gm1+(1-f)*gm2 gm1frac = ROOT.RooRealVar("gm1frac", "fraction of gm1", 0.5) -gmsum = ROOT.RooAddModel( - "gmsum", - "sum of gm1 and gm2", - ROOT.RooArgList( - gm1, - gm2), - ROOT.RooArgList(gm1frac)) +gmsum = ROOT.RooAddModel("gmsum", "sum of gm1 and gm2", ROOT.RooArgList(gm1, gm2), ROOT.RooArgList(gm1frac)) # Construct decay(t) (x) (f*gm1 + (1-f)*gm2) -decay_gmsum = ROOT.RooDecay( - "decay_gmsum", "decay", dt, tau, gmsum, ROOT.RooDecay.DoubleSided) +decay_gmsum = ROOT.RooDecay("decay_gmsum", "decay", dt, tau, gmsum, ROOT.RooDecay.DoubleSided) # Plot pdf (red) -decay_gmsum.plotOn(frame, LineColor = ROOT.kRed) +decay_gmsum.plotOn(frame, LineColor=ROOT.kRed) # Draw all frames on canvas c = ROOT.TCanvas("rf209_anaconv", "rf209_anaconv", 600, 600) diff --git a/tutorials/roofit/rf210_angularconv.py b/tutorials/roofit/rf210_angularconv.py index 45c632af76c1c..5b953488d7986 100644 --- a/tutorials/roofit/rf210_angularconv.py +++ b/tutorials/roofit/rf210_angularconv.py @@ -65,7 +65,7 @@ Mpsi.plotOn(frame1) # Overlay comparison to unsmeared physics p.d.f ROOT.T(psi) -Tpsi.plotOn(frame1, LineColor = ROOT.kRed) +Tpsi.plotOn(frame1, LineColor=ROOT.kRed) # Construct convolution pdf in cos(psi) # -------------------------------------------------------------------------- @@ -98,7 +98,7 @@ Mcpsi.plotOn(frame2) # Overlay comparison to unsmeared physics p.d.f ROOT.Tf(cpsi) -Tcpsi.plotOn(frame2, LineColor = ROOT.kRed) +Tcpsi.plotOn(frame2, LineColor=ROOT.kRed) # Draw frame on canvas c = ROOT.TCanvas("rf210_angularconv", "rf210_angularconv", 800, 400) diff --git a/tutorials/roofit/rf211_paramconv.py b/tutorials/roofit/rf211_paramconv.py index 54229bbf52c21..f1e5f0268c13e 100644 --- a/tutorials/roofit/rf211_paramconv.py +++ b/tutorials/roofit/rf211_paramconv.py @@ -46,7 +46,7 @@ d = projModel.generateBinned(ROOT.RooArgSet(x), 1000) # Fit p.d.f. to toy data -projModel.fitTo(d, Verbose = True) +projModel.fitTo(d, Verbose=True) # Plot data and fitted p.d.f. frame = x.frame(ROOT.RooFit.Bins(25)) diff --git a/tutorials/roofit/rf301_composition.py b/tutorials/roofit/rf301_composition.py index 72939983addfa..ba56d2f18e4cc 100644 --- a/tutorials/roofit/rf301_composition.py +++ b/tutorials/roofit/rf301_composition.py @@ -27,8 +27,7 @@ # Creat gauss(x,f(y),s) sigma = ROOT.RooRealVar("sigma", "width of gaussian", 0.5) -model = ROOT.RooGaussian( - "model", "Gaussian with shifting mean", x, fy, sigma) +model = ROOT.RooGaussian("model", "Gaussian with shifting mean", x, fy, sigma) # Sample data, plot data and pdf on x and y # --------------------------------------------------------------------------------- @@ -49,8 +48,7 @@ model.plotOn(yframe) # Make two-dimensional plot in x vs y -hh_model = model.createHistogram("hh_model", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) +hh_model = model.createHistogram("hh_model", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) hh_model.SetLineColor(ROOT.kBlue) # Make canvas and draw ROOT.RooPlots diff --git a/tutorials/roofit/rf302_utilfuncs.py b/tutorials/roofit/rf302_utilfuncs.py index f51b840ca42d9..63360d72e8d68 100644 --- a/tutorials/roofit/rf302_utilfuncs.py +++ b/tutorials/roofit/rf302_utilfuncs.py @@ -27,12 +27,10 @@ # ----------------------------------------------------------------------- # Create interpreted function f(y) = a0 - a1*sqrt(10*abs(y)) -fy_1 = ROOT.RooFormulaVar( - "fy_1", "a0-a1*sqrt(10*abs(y))", ROOT.RooArgList(y, a0, a1)) +fy_1 = ROOT.RooFormulaVar("fy_1", "a0-a1*sqrt(10*abs(y))", ROOT.RooArgList(y, a0, a1)) # Create gauss(x,f(y),s) -model_1 = ROOT.RooGaussian( - "model_1", "Gaussian with shifting mean", x, fy_1, sigma) +model_1 = ROOT.RooGaussian("model_1", "Gaussian with shifting mean", x, fy_1, sigma) # Using RooPolyVar to tailor pdf # ----------------------------------------------------------------------- @@ -41,8 +39,7 @@ fy_2 = ROOT.RooPolyVar("fy_2", "fy_2", y, ROOT.RooArgList(a0, a1)) # Create gauss(x,f(y),s) -model_2 = ROOT.RooGaussian( - "model_2", "Gaussian with shifting mean", x, fy_2, sigma) +model_2 = ROOT.RooGaussian("model_2", "Gaussian with shifting mean", x, fy_2, sigma) # Using RooAddition to tailor pdf # ----------------------------------------------------------------------- @@ -51,8 +48,7 @@ fy_3 = ROOT.RooAddition("fy_3", "a0+y", ROOT.RooArgList(a0, y)) # Create gauss(x,f(y),s) -model_3 = ROOT.RooGaussian( - "model_3", "Gaussian with shifting mean", x, fy_3, sigma) +model_3 = ROOT.RooGaussian("model_3", "Gaussian with shifting mean", x, fy_3, sigma) # Using RooProduct to tailor pdf # ----------------------------------------------------------------------- @@ -61,21 +57,24 @@ fy_4 = ROOT.RooProduct("fy_4", "a1*y", ROOT.RooArgList(a1, y)) # Create gauss(x,f(y),s) -model_4 = ROOT.RooGaussian( - "model_4", "Gaussian with shifting mean", x, fy_4, sigma) +model_4 = ROOT.RooGaussian("model_4", "Gaussian with shifting mean", x, fy_4, sigma) # Plot all pdfs # ---------------------------- # Make two-dimensional plots in x vs y -hh_model_1 = model_1.createHistogram("hh_model_1", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) -hh_model_2 = model_2.createHistogram("hh_model_2", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) -hh_model_3 = model_3.createHistogram("hh_model_3", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) -hh_model_4 = model_4.createHistogram("hh_model_4", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) +hh_model_1 = model_1.createHistogram( + "hh_model_1", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) +) +hh_model_2 = model_2.createHistogram( + "hh_model_2", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) +) +hh_model_3 = model_3.createHistogram( + "hh_model_3", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) +) +hh_model_4 = model_4.createHistogram( + "hh_model_4", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) +) hh_model_1.SetLineColor(ROOT.kBlue) hh_model_2.SetLineColor(ROOT.kBlue) hh_model_3.SetLineColor(ROOT.kBlue) diff --git a/tutorials/roofit/rf304_uncorrprod.py b/tutorials/roofit/rf304_uncorrprod.py index 087b81bc3a0a9..4e7bf726ac78b 100644 --- a/tutorials/roofit/rf304_uncorrprod.py +++ b/tutorials/roofit/rf304_uncorrprod.py @@ -33,8 +33,7 @@ # ------------------------------------------------------------------- # Multiply gaussx and gaussy into a two-dimensional pdf gaussxy -gaussxy = ROOT.RooProdPdf( - "gaussxy", "gaussx*gaussy", ROOT.RooArgList(gaussx, gaussy)) +gaussxy = ROOT.RooProdPdf("gaussxy", "gaussx*gaussy", ROOT.RooArgList(gaussx, gaussy)) # Sample pdf, plot projection on x and y # --------------------------------------------------------------------------- diff --git a/tutorials/roofit/rf305_condcorrprod.py b/tutorials/roofit/rf305_condcorrprod.py index ea121f2ce517e..a5ae6a8f01ac8 100644 --- a/tutorials/roofit/rf305_condcorrprod.py +++ b/tutorials/roofit/rf305_condcorrprod.py @@ -26,19 +26,13 @@ # Create gaussx(x,f(y),sx) sigmax = ROOT.RooRealVar("sigma", "width of gaussian", 0.5) -gaussx = ROOT.RooGaussian( - "gaussx", "Gaussian in x with shifting mean in y", x, fy, sigmax) +gaussx = ROOT.RooGaussian("gaussx", "Gaussian in x with shifting mean in y", x, fy, sigmax) # Create pdf gy(y) # ----------------------------------------------------------- # Create gaussy(y,0,5) -gaussy = ROOT.RooGaussian( - "gaussy", - "Gaussian in y", - y, - ROOT.RooFit.RooConst(0), - ROOT.RooFit.RooConst(3)) +gaussy = ROOT.RooGaussian("gaussy", "Gaussian in y", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(3)) # Create product gx(x|y)*gy(y) # ------------------------------------------------------- @@ -48,9 +42,8 @@ "model", "gaussx(x|y)*gaussy(y)", ROOT.RooArgSet(gaussy), - ROOT.RooFit.Conditional( - ROOT.RooArgSet(gaussx), - ROOT.RooArgSet(x))) + ROOT.RooFit.Conditional(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)), +) # Sample, fit and plot product pdf # --------------------------------------------------------------- @@ -71,8 +64,7 @@ model.plotOn(yframe) # Make two-dimensional plot in x vs y -hh_model = model.createHistogram("hh_model", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) +hh_model = model.createHistogram("hh_model", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) hh_model.SetLineColor(ROOT.kBlue) # Make canvas and draw ROOT.RooPlots diff --git a/tutorials/roofit/rf306_condpereventerrors.py b/tutorials/roofit/rf306_condpereventerrors.py index a54faacf28942..0c9570709eb9b 100644 --- a/tutorials/roofit/rf306_condpereventerrors.py +++ b/tutorials/roofit/rf306_condpereventerrors.py @@ -20,22 +20,18 @@ # Build a gaussian resolution model scaled by the per-error = # gauss(dt,bias,sigma*dterr) bias = ROOT.RooRealVar("bias", "bias", 0, -10, 10) -sigma = ROOT.RooRealVar( - "sigma", "per-event error scale factor", 1, 0.1, 10) -gm = ROOT.RooGaussModel( - "gm1", "gauss model scaled bt per-event error", dt, bias, sigma, dterr) +sigma = ROOT.RooRealVar("sigma", "per-event error scale factor", 1, 0.1, 10) +gm = ROOT.RooGaussModel("gm1", "gauss model scaled bt per-event error", dt, bias, sigma, dterr) # Construct decay(dt) (x) gauss1(dt|dterr) tau = ROOT.RooRealVar("tau", "tau", 1.548) -decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, - tau, gm, ROOT.RooDecay.DoubleSided) +decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, ROOT.RooDecay.DoubleSided) # Construct fake 'external' data with per-event error # ------------------------------------------------------------------------------------------------------ # Use landau pdf to get somewhat realistic distribution with long tail -pdfDtErr = ROOT.RooLandau("pdfDtErr", "pdfDtErr", dterr, ROOT.RooFit.RooConst( - 1), ROOT.RooFit.RooConst(0.25)) +pdfDtErr = ROOT.RooLandau("pdfDtErr", "pdfDtErr", dterr, ROOT.RooFit.RooConst(1), ROOT.RooFit.RooConst(0.25)) expDataDterr = pdfDtErr.generate(ROOT.RooArgSet(dterr), 10000) # Sample data from conditional decay_gm(dt|dterr) @@ -43,29 +39,28 @@ # Specify external dataset with dterr values to use decay_dm as # conditional pdf -data = decay_gm.generate(ROOT.RooArgSet( - dt), ROOT.RooFit.ProtoData(expDataDterr)) +data = decay_gm.generate(ROOT.RooArgSet(dt), ROOT.RooFit.ProtoData(expDataDterr)) # Fit conditional decay_dm(dt|dterr) # --------------------------------------------------------------------- # Specify dterr as conditional observable -decay_gm.fitTo(data, ConditionalObservables = ROOT.RooArgSet(dterr)) +decay_gm.fitTo(data, ConditionalObservables=ROOT.RooArgSet(dterr)) # Plot conditional decay_dm(dt|dterr) # --------------------------------------------------------------------- # Make two-dimensional plot of conditional pdf in (dt,dterr) -hh_decay = decay_gm.createHistogram("hh_decay", dt, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50))) +hh_decay = decay_gm.createHistogram( + "hh_decay", dt, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50)) +) hh_decay.SetLineColor(ROOT.kBlue) # Plot decay_gm(dt|dterr) at various values of dterr -frame = dt.frame(ROOT.RooFit.Title( - "Slices of decay(dt|dterr) at various dterr")) +frame = dt.frame(ROOT.RooFit.Title("Slices of decay(dt|dterr) at various dterr")) for ibin in range(0, 100, 20): dterr.setBin(ibin) - decay_gm.plotOn(frame, Normalization = 5.) + decay_gm.plotOn(frame, Normalization=5.0) # Make projection of data an dt frame2 = dt.frame(ROOT.RooFit.Title("Projection of decay(dt|dterr) on dt")) @@ -76,11 +71,10 @@ # Instead of integrating out dterr, a weighted average of curves # at values dterr_i as given in the external dataset. # (The kTRUE argument bins the data before projection to speed up the process) -decay_gm.plotOn(frame2, ProjWData = (expDataDterr, True)) +decay_gm.plotOn(frame2, ProjWData=(expDataDterr, True)) # Draw all frames on canvas -c = ROOT.TCanvas("rf306_condpereventerrors", - "rf306_condperventerrors", 1200, 400) +c = ROOT.TCanvas("rf306_condpereventerrors", "rf306_condperventerrors", 1200, 400) c.Divide(3) c.cd(1) ROOT.gPad.SetLeftMargin(0.20) diff --git a/tutorials/roofit/rf307_fullpereventerrors.py b/tutorials/roofit/rf307_fullpereventerrors.py index 60aa6d96bea3f..8bd3d4e0bc411 100644 --- a/tutorials/roofit/rf307_fullpereventerrors.py +++ b/tutorials/roofit/rf307_fullpereventerrors.py @@ -20,28 +20,23 @@ # Build a gaussian resolution model scaled by the per-error = # gauss(dt,bias,sigma*dterr) bias = ROOT.RooRealVar("bias", "bias", 0, -10, 10) -sigma = ROOT.RooRealVar( - "sigma", "per-event error scale factor", 1, 0.1, 10) -gm = ROOT.RooGaussModel( - "gm1", "gauss model scaled bt per-event error", dt, bias, sigma, dterr) +sigma = ROOT.RooRealVar("sigma", "per-event error scale factor", 1, 0.1, 10) +gm = ROOT.RooGaussModel("gm1", "gauss model scaled bt per-event error", dt, bias, sigma, dterr) # Construct decay(dt) (x) gauss1(dt|dterr) tau = ROOT.RooRealVar("tau", "tau", 1.548) -decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, - tau, gm, ROOT.RooDecay.DoubleSided) +decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, ROOT.RooDecay.DoubleSided) # Construct empirical pdf for per-event error # ----------------------------------------------------------------- # Use landau pdf to get empirical distribution with long tail -pdfDtErr = ROOT.RooLandau("pdfDtErr", "pdfDtErr", dterr, ROOT.RooFit.RooConst( - 1), ROOT.RooFit.RooConst(0.25)) +pdfDtErr = ROOT.RooLandau("pdfDtErr", "pdfDtErr", dterr, ROOT.RooFit.RooConst(1), ROOT.RooFit.RooConst(0.25)) expDataDterr = pdfDtErr.generate(ROOT.RooArgSet(dterr), 10000) # Construct a histogram pdf to describe the shape of the dtErr distribution expHistDterr = expDataDterr.binnedClone() -pdfErr = ROOT.RooHistPdf( - "pdfErr", "pdfErr", ROOT.RooArgSet(dterr), expHistDterr) +pdfErr = ROOT.RooHistPdf("pdfErr", "pdfErr", ROOT.RooArgSet(dterr), expHistDterr) # Construct conditional product decay_dm(dt|dterr)*pdf(dterr) # ---------------------------------------------------------------------------------------------------------------------- @@ -49,12 +44,8 @@ # Construct production of conditional decay_dm(dt|dterr) with empirical # pdfErr(dterr) model = ROOT.RooProdPdf( - "model", - "model", - ROOT.RooArgSet(pdfErr), - ROOT.RooFit.Conditional( - ROOT.RooArgSet(decay_gm), - ROOT.RooArgSet(dt))) + "model", "model", ROOT.RooArgSet(pdfErr), ROOT.RooFit.Conditional(ROOT.RooArgSet(decay_gm), ROOT.RooArgSet(dt)) +) # (Alternatively you could also use the landau shape pdfDtErr) # ROOT.RooProdPdf model("model", "model",pdfDtErr, @@ -77,8 +68,9 @@ # --------------------------------------------------------------------- # Make two-dimensional plot of conditional pdf in (dt,dterr) -hh_model = model.createHistogram("hh_model", dt, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50))) +hh_model = model.createHistogram( + "hh_model", dt, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50)) +) hh_model.SetLineColor(ROOT.kBlue) # Make projection of data an dt @@ -87,8 +79,7 @@ model.plotOn(frame) # Draw all frames on canvas -c = ROOT.TCanvas("rf307_fullpereventerrors", - "rf307_fullpereventerrors", 800, 400) +c = ROOT.TCanvas("rf307_fullpereventerrors", "rf307_fullpereventerrors", 800, 400) c.Divide(2) c.cd(1) ROOT.gPad.SetLeftMargin(0.20) diff --git a/tutorials/roofit/rf308_normintegration2d.py b/tutorials/roofit/rf308_normintegration2d.py index dcda79628b4e1..6da702e117869 100644 --- a/tutorials/roofit/rf308_normintegration2d.py +++ b/tutorials/roofit/rf308_normintegration2d.py @@ -20,10 +20,8 @@ y = ROOT.RooRealVar("y", "y", -10, 10) # Create pdf gaussx(x,-2,3), gaussy(y,2,2) -gx = ROOT.RooGaussian( - "gx", "gx", x, ROOT.RooFit.RooConst(-2), ROOT.RooFit.RooConst(3)) -gy = ROOT.RooGaussian( - "gy", "gy", y, ROOT.RooFit.RooConst(+2), ROOT.RooFit.RooConst(2)) +gx = ROOT.RooGaussian("gx", "gx", x, ROOT.RooFit.RooConst(-2), ROOT.RooFit.RooConst(3)) +gy = ROOT.RooGaussian("gy", "gy", y, ROOT.RooFit.RooConst(+2), ROOT.RooFit.RooConst(2)) # gxy = gx(x)*gy(y) gxy = ROOT.RooProdPdf("gxy", "gxy", ROOT.RooArgList(gx, gy)) @@ -67,8 +65,7 @@ # ROOT.This is the fraction of of pdf gxy_Norm[x,y] which is in the # range named "signal" -igxy_sig = gxy.createIntegral(x_and_y, ROOT.RooFit.NormSet( - x_and_y), ROOT.RooFit.Range("signal")) +igxy_sig = gxy.createIntegral(x_and_y, ROOT.RooFit.NormSet(x_and_y), ROOT.RooFit.Range("signal")) print("gx_Int[x,y|signal]_Norm[x,y] = ", igxy_sig.getVal()) # Construct cumulative distribution function from pdf @@ -79,12 +76,10 @@ gxy_cdf = gxy.createCdf(ROOT.RooArgSet(x, y)) # Plot cdf of gx versus x -hh_cdf = gxy_cdf.createHistogram("hh_cdf", x, ROOT.RooFit.Binning( - 40), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(40))) +hh_cdf = gxy_cdf.createHistogram("hh_cdf", x, ROOT.RooFit.Binning(40), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(40))) hh_cdf.SetLineColor(ROOT.kBlue) -c = ROOT.TCanvas("rf308_normintegration2d", - "rf308_normintegration2d", 600, 600) +c = ROOT.TCanvas("rf308_normintegration2d", "rf308_normintegration2d", 600, 600) ROOT.gPad.SetLeftMargin(0.15) hh_cdf.GetZaxis().SetTitleOffset(1.8) hh_cdf.Draw("surf") diff --git a/tutorials/roofit/rf310_sliceplot.py b/tutorials/roofit/rf310_sliceplot.py index dbae6b325bc7a..790f905da1d0b 100644 --- a/tutorials/roofit/rf310_sliceplot.py +++ b/tutorials/roofit/rf310_sliceplot.py @@ -28,11 +28,10 @@ tagFlav.defineType("B0bar", -1) # Model parameters -dm = ROOT.RooRealVar("dm", "delta m(B)", 0.472, 0., 1.0) +dm = ROOT.RooRealVar("dm", "delta m(B)", 0.472, 0.0, 1.0) tau = ROOT.RooRealVar("tau", "B0 decay time", 1.547, 1.0, 2.0) w = ROOT.RooRealVar("w", "Flavor Mistag rate", 0.03, 0.0, 1.0) -dw = ROOT.RooRealVar( - "dw", "Flavor Mistag rate difference between B0 and B0bar", 0.01) +dw = ROOT.RooRealVar("dw", "Flavor Mistag rate difference between B0 and B0bar", 0.01) # Build a gaussian resolution model bias1 = ROOT.RooRealVar("bias1", "bias1", 0) @@ -40,18 +39,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct a decay pdf, with single gaussian resolution model -bmix_gm1 = ROOT.RooBMixDecay( - "bmix", - "decay", - dt, - mixState, - tagFlav, - tau, - dm, - w, - dw, - gm1, - ROOT.RooBMixDecay.DoubleSided) +bmix_gm1 = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, ROOT.RooBMixDecay.DoubleSided) # Generate BMixing data with above set of event errors data = bmix_gm1.generate(ROOT.RooArgSet(dt, tagFlav, mixState), 20000) @@ -70,20 +58,19 @@ # Create frame, data (mixed only) frame2 = dt.frame(ROOT.RooFit.Title("Decay distribution of mixed events")) -data.plotOn(frame2, Cut = "mixState==mixState::mixed") +data.plotOn(frame2, Cut="mixState==mixState::mixed") # Position slice in mixState at "mixed" and plot slice of pdf in mixstate # over data (integrated over tagFlav) -bmix_gm1.plotOn(frame2, Slice = (mixState, "mixed")) +bmix_gm1.plotOn(frame2, Slice=(mixState, "mixed")) # Create frame, data (unmixed only) -frame3 = dt.frame(ROOT.RooFit.Title( - "Decay distribution of unmixed events")) -data.plotOn(frame3, Cut = "mixState==mixState::unmixed") +frame3 = dt.frame(ROOT.RooFit.Title("Decay distribution of unmixed events")) +data.plotOn(frame3, Cut="mixState==mixState::unmixed") # Position slice in mixState at "unmixed" and plot slice of pdf in # mixstate over data (integrated over tagFlav) -bmix_gm1.plotOn(frame3, Slice = (mixState, "unmixed")) +bmix_gm1.plotOn(frame3, Slice=(mixState, "unmixed")) c = ROOT.TCanvas("rf310_sliceplot", "rf310_sliceplot", 1200, 400) c.Divide(3) diff --git a/tutorials/roofit/rf311_rangeplot.py b/tutorials/roofit/rf311_rangeplot.py index 8d5052badea26..a422b589a873f 100644 --- a/tutorials/roofit/rf311_rangeplot.py +++ b/tutorials/roofit/rf311_rangeplot.py @@ -19,27 +19,20 @@ z = ROOT.RooRealVar("z", "z", -5, 5) # Create signal pdf gauss(x)*gauss(y)*gauss(z) -gx = ROOT.RooGaussian( - "gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gy = ROOT.RooGaussian( - "gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gz = ROOT.RooGaussian( - "gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gx = ROOT.RooGaussian("gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gy = ROOT.RooGaussian("gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gz = ROOT.RooGaussian("gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) sig = ROOT.RooProdPdf("sig", "sig", ROOT.RooArgList(gx, gy, gz)) # Create background pdf poly(x)*poly(y)*poly(z) -px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList( - ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) -py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList( - ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) +px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) +py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList(ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) pz = ROOT.RooPolynomial("pz", "pz", z) bkg = ROOT.RooProdPdf("bkg", "bkg", ROOT.RooArgList(px, py, pz)) # Create composite pdf sig+bkg -fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0., 1.) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList( - sig, bkg), ROOT.RooArgList(fsig)) +fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(fsig)) data = model.generate(ROOT.RooArgSet(x, y, z), 20000) @@ -47,8 +40,7 @@ # ------------------------------------------------- # Make plain projection of data and pdf on x observable -frame = x.frame(ROOT.RooFit.Title( - "Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) +frame = x.frame(ROOT.RooFit.Title("Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) data.plotOn(frame) model.plotOn(frame) @@ -60,17 +52,16 @@ z.setRange("sigRegion", -1, 1) # Make plot frame -frame2 = x.frame(ROOT.RooFit.Title( - "Same projection on X in signal range of (Y,Z)"), ROOT.RooFit.Bins(40)) +frame2 = x.frame(ROOT.RooFit.Title("Same projection on X in signal range of (Y,Z)"), ROOT.RooFit.Bins(40)) # Plot subset of data in which all observables are inside "sigRegion" # For observables that do not have an explicit "sigRegion" range defined (e.g. observable) # an implicit definition is used that is identical to the full range (i.e. # [-5,5] for x) -data.plotOn(frame2, CutRange = "sigRegion") +data.plotOn(frame2, CutRange="sigRegion") # Project model on x, projected observables (y,z) only in "sigRegion" -model.plotOn(frame2, ProjectionRange = "sigRegion") +model.plotOn(frame2, ProjectionRange="sigRegion") c = ROOT.TCanvas("rf311_rangeplot", "rf310_rangeplot", 800, 400) c.Divide(2) diff --git a/tutorials/roofit/rf312_multirangefit.py b/tutorials/roofit/rf312_multirangefit.py index fd05d57b77f7b..5ed656e4f6aa4 100644 --- a/tutorials/roofit/rf312_multirangefit.py +++ b/tutorials/roofit/rf312_multirangefit.py @@ -33,10 +33,8 @@ bkg = ROOT.RooProdPdf("bkg", "bkg", px, py) # Construct the composite model sig+bkg -f = ROOT.RooRealVar("f", "f", 0., 1.) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList( - sig, bkg), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(f)) # Sample 10000 events in (x,y) from the model modelData = model.generate(ROOT.RooArgSet(x, y), 10000) @@ -77,18 +75,18 @@ # Perform fit in SideBand1 region (ROOT.RooAddPdf coefficients will be # interpreted in full range) -r_sb1 = model.fitTo(modelData, Range = "SB1", Save = True) +r_sb1 = model.fitTo(modelData, Range="SB1", Save=True) # Perform fit in SideBand2 region (ROOT.RooAddPdf coefficients will be # interpreted in full range) -r_sb2 = model.fitTo(modelData, Range = "SB2", Save = True) +r_sb2 = model.fitTo(modelData, Range="SB2", Save=True) # Perform fits in joint sideband regions # ----------------------------------------------------------------------------- # Now perform fit to joint 'L-shaped' sideband region 'SB1|SB2' # (ROOT.RooAddPdf coefficients will be interpreted in full range) -r_sb12 = model.fitTo(modelData, Range = "SB1,SB2", Save = True) +r_sb12 = model.fitTo(modelData, Range="SB1,SB2", Save=True) # Print results for comparison r_sb1.Print() diff --git a/tutorials/roofit/rf313_paramranges.py b/tutorials/roofit/rf313_paramranges.py index 7632214a763bf..be66e54dd74c4 100644 --- a/tutorials/roofit/rf313_paramranges.py +++ b/tutorials/roofit/rf313_paramranges.py @@ -22,12 +22,8 @@ # Define 3 dimensional pdf z0 = ROOT.RooRealVar("z0", "z0", -0.1, 1) -px = ROOT.RooPolynomial( - "px", "px", x, ROOT.RooArgList( - ROOT.RooFit.RooConst(0))) -py = ROOT.RooPolynomial( - "py", "py", y, ROOT.RooArgList( - ROOT.RooFit.RooConst(0))) +px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList(ROOT.RooFit.RooConst(0))) +py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList(ROOT.RooFit.RooConst(0))) pz = ROOT.RooPolynomial("pz", "pz", z, ROOT.RooArgList(z0)) pxyz = ROOT.RooProdPdf("pxyz", "pxyz", ROOT.RooArgList(px, py, pz)) @@ -52,12 +48,10 @@ # ---------------------------------------------------------------------------------- # Create integral over normalized pdf model over x,y, in "R" region -intPdf = pxyz.createIntegral(ROOT.RooArgSet( - x, y, z), ROOT.RooArgSet(x, y, z), "R") +intPdf = pxyz.createIntegral(ROOT.RooArgSet(x, y, z), ROOT.RooArgSet(x, y, z), "R") # Plot value of integral as function of pdf parameter z0 -frame = z0.frame(ROOT.RooFit.Title( - "Integral of pxyz over x,y, in region R")) +frame = z0.frame(ROOT.RooFit.Title("Integral of pxyz over x,y, in region R")) intPdf.plotOn(frame) c = ROOT.TCanvas("rf313_paramranges", "rf313_paramranges", 600, 600) diff --git a/tutorials/roofit/rf314_paramfitrange.py b/tutorials/roofit/rf314_paramfitrange.py index 822f34e00df4d..8a2d44a29ecbe 100644 --- a/tutorials/roofit/rf314_paramfitrange.py +++ b/tutorials/roofit/rf314_paramfitrange.py @@ -37,8 +37,9 @@ dall = model.generate(ROOT.RooArgSet(t), 10000) # Generate a (fake) prototype dataset for acceptance limit values -tmp = ROOT.RooGaussian("gmin", "gmin", tmin, ROOT.RooFit.RooConst( - 0), ROOT.RooFit.RooConst(0.5)).generate(ROOT.RooArgSet(tmin), 5000) +tmp = ROOT.RooGaussian("gmin", "gmin", tmin, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(0.5)).generate( + ROOT.RooArgSet(tmin), 5000 +) # Generate dataset with t values that observe (t>tmin) dacc = model.generate(ROOT.RooArgSet(t), ROOT.RooFit.ProtoData(tmp)) @@ -46,14 +47,14 @@ # Fit pdf to data in acceptance region # ----------------------------------------------------------------------- -r = model.fitTo(dacc, Save = True) +r = model.fitTo(dacc, Save=True) # Plot fitted pdf on full and accepted data # --------------------------------------------------------------------------------- # Make plot frame, datasets and overlay model frame = t.frame(ROOT.RooFit.Title("Fit to data with per-event acceptance")) -dall.plotOn(frame, MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) +dall.plotOn(frame, MarkerColor=ROOT.kRed, LineColor=ROOT.kRed) model.plotOn(frame) dacc.plotOn(frame) diff --git a/tutorials/roofit/rf315_projectpdf.py b/tutorials/roofit/rf315_projectpdf.py index c72b81af3c7e2..b593ef5235dd0 100644 --- a/tutorials/roofit/rf315_projectpdf.py +++ b/tutorials/roofit/rf315_projectpdf.py @@ -30,25 +30,18 @@ # Create gaussx(x,f(y),sx) sigmax = ROOT.RooRealVar("sigmax", "width of gaussian", 0.5) -gaussx = ROOT.RooGaussian( - "gaussx", "Gaussian in x with shifting mean in y", x, fy, sigmax) +gaussx = ROOT.RooGaussian("gaussx", "Gaussian in x with shifting mean in y", x, fy, sigmax) # Create gaussy(y,0,2) -gaussy = ROOT.RooGaussian( - "gaussy", - "Gaussian in y", - y, - ROOT.RooFit.RooConst(0), - ROOT.RooFit.RooConst(2)) +gaussy = ROOT.RooGaussian("gaussy", "Gaussian in y", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(2)) # Create gaussx(x,sx|y) * gaussy(y) model = ROOT.RooProdPdf( "model", "gaussx(x|y)*gaussy(y)", ROOT.RooArgSet(gaussy), - ROOT.RooFit.Conditional( - ROOT.RooArgSet(gaussx), - ROOT.RooArgSet(x))) + ROOT.RooFit.Conditional(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)), +) # Marginalize m(x,y) to m(x) # ---------------------------------------------------- @@ -63,7 +56,7 @@ data = modelx.generateBinned(ROOT.RooArgSet(x), 1000) # Fit modelx to toy data -modelx.fitTo(data, Verbose = True) +modelx.fitTo(data, Verbose=True) # Plot modelx over data frame = x.frame(40) diff --git a/tutorials/roofit/rf316_llratioplot.py b/tutorials/roofit/rf316_llratioplot.py index 922215abcc6b1..9f717f50a0e41 100644 --- a/tutorials/roofit/rf316_llratioplot.py +++ b/tutorials/roofit/rf316_llratioplot.py @@ -21,27 +21,20 @@ z = ROOT.RooRealVar("z", "z", -5, 5) # Create signal pdf gauss(x)*gauss(y)*gauss(z) -gx = ROOT.RooGaussian( - "gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gy = ROOT.RooGaussian( - "gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gz = ROOT.RooGaussian( - "gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gx = ROOT.RooGaussian("gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gy = ROOT.RooGaussian("gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gz = ROOT.RooGaussian("gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) sig = ROOT.RooProdPdf("sig", "sig", ROOT.RooArgList(gx, gy, gz)) # Create background pdf poly(x)*poly(y)*poly(z) -px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList( - ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) -py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList( - ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) +px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) +py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList(ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) pz = ROOT.RooPolynomial("pz", "pz", z) bkg = ROOT.RooProdPdf("bkg", "bkg", ROOT.RooArgList(px, py, pz)) # Create composite pdf sig+bkg -fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0., 1.) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList( - sig, bkg), ROOT.RooArgList(fsig)) +fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(fsig)) data = model.generate(ROOT.RooArgSet(x, y, z), 20000) @@ -49,8 +42,7 @@ # ------------------------------------------------- # Make plain projection of data and pdf on x observable -frame = x.frame(ROOT.RooFit.Title( - "Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) +frame = x.frame(ROOT.RooFit.Title("Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) data.plotOn(frame) model.plotOn(frame) @@ -63,8 +55,7 @@ totyz = model.createProjection(ROOT.RooArgSet(x)) # Construct the log of the signal / signal+background probability -llratio_func = ROOT.RooFormulaVar( - "llratio", "log10(@0)-log10(@1)", ROOT.RooArgList(sigyz, totyz)) +llratio_func = ROOT.RooFormulaVar("llratio", "log10(@0)-log10(@1)", ROOT.RooArgList(sigyz, totyz)) # Plot data with a LL ratio cut # ------------------------------------------------------- @@ -76,8 +67,7 @@ dataSel = data.reduce(ROOT.RooFit.Cut("llratio>0.7")) # Make plot frame -frame2 = x.frame(ROOT.RooFit.Title( - "Same projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) +frame2 = x.frame(ROOT.RooFit.Title("Same projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) # Plot select data on frame dataSel.plotOn(frame2) @@ -95,7 +85,7 @@ # Project model on x, projected observables (y,z) with Monte Carlo technique # on set of events with the same llratio cut as was applied to data -model.plotOn(frame2, ProjWData = mcprojDataSel) +model.plotOn(frame2, ProjWData=mcprojDataSel) c = ROOT.TCanvas("rf316_llratioplot", "rf316_llratioplot", 800, 400) c.Divide(2) diff --git a/tutorials/roofit/rf402_datahandling.py b/tutorials/roofit/rf402_datahandling.py index ec504dd1d768c..75c37dd6cba31 100644 --- a/tutorials/roofit/rf402_datahandling.py +++ b/tutorials/roofit/rf402_datahandling.py @@ -40,7 +40,7 @@ for i in range(1000): x.setVal(i / 50 - 10) y.setVal(math.sqrt(1.0 * i)) - if (i % 2): + if i % 2: c.setLabel("Plus") else: c.setLabel("Minus") @@ -116,8 +116,7 @@ dh = ROOT.RooDataHist("dh", "binned version of d", ROOT.RooArgSet(x, y), d) dh.Print("v") -yframe = y.frame(ROOT.RooFit.Bins(10), ROOT.RooFit.Title( - "Operations on binned datasets")) +yframe = y.frame(ROOT.RooFit.Bins(10), ROOT.RooFit.Title("Operations on binned datasets")) dh.plotOn(yframe) # plot projection of 2D binned data on y # Examine the statistics of a binned dataset diff --git a/tutorials/roofit/rf404_categories.py b/tutorials/roofit/rf404_categories.py index 6e389ef3990d0..4a5959d31fdda 100644 --- a/tutorials/roofit/rf404_categories.py +++ b/tutorials/roofit/rf404_categories.py @@ -37,8 +37,7 @@ # Generate a dummy dataset x = ROOT.RooRealVar("x", "x", 0, 10) -data = ROOT.RooPolynomial("p", "p", x).generate( - ROOT.RooArgSet(x, b0flav, tagCat), 10000) +data = ROOT.RooPolynomial("p", "p", x).generate(ROOT.RooArgSet(x, b0flav, tagCat), 10000) # Print tables of category contents of datasets # -------------------------------------------------- diff --git a/tutorials/roofit/rf405_realtocatfuncs.py b/tutorials/roofit/rf405_realtocatfuncs.py index 390003d1f9626..299d4b7b11d53 100644 --- a/tutorials/roofit/rf405_realtocatfuncs.py +++ b/tutorials/roofit/rf405_realtocatfuncs.py @@ -16,8 +16,7 @@ # Define a dummy PDF in x x = ROOT.RooRealVar("x", "x", 0, 10) -a = ROOT.RooArgusBG("a", "argus(x)", x, ROOT.RooFit.RooConst( - 10), ROOT.RooFit.RooConst(-1)) +a = ROOT.RooArgusBG("a", "argus(x)", x, ROOT.RooFit.RooConst(10), ROOT.RooFit.RooConst(-1)) # Generate a dummy dataset data = a.generate(ROOT.RooArgSet(x), 10000) @@ -29,8 +28,7 @@ # input observable observables to state names. At construction time a 'default' # state name must be specified to which all values of x are mapped that are not # otherwise assigned -xRegion = ROOT.RooThresholdCategory( - "xRegion", "region of x", x, "Background") +xRegion = ROOT.RooThresholdCategory("xRegion", "region of x", x, "Background") # Specify thresholds and state assignments one-by-one. # Each statement specifies that all values _below_ the given value @@ -52,12 +50,11 @@ data.addColumn(xRegion) # Make plot of data in x -xframe = x.frame(ROOT.RooFit.Title( - "Demo of threshold and binning mapping functions")) +xframe = x.frame(ROOT.RooFit.Title("Demo of threshold and binning mapping functions")) data.plotOn(xframe) # Use calculated category to select sideband data -data.plotOn(xframe, Cut = "xRegion==xRegion::SideBand", MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) +data.plotOn(xframe, Cut="xRegion==xRegion::SideBand", MarkerColor=ROOT.kRed, LineColor=ROOT.kRed) # Create a binning real -> cat function # ---------------------------------------------------------------------- @@ -83,15 +80,12 @@ xb = data.addColumn(xBins) # Define range "alt" as including bins 1,3,5,7,9 -xb.setRange( - "alt", - "x_coarse_bin1,x_coarse_bin3,x_coarse_bin5,x_coarse_bin7,x_coarse_bin9") +xb.setRange("alt", "x_coarse_bin1,x_coarse_bin3,x_coarse_bin5,x_coarse_bin7,x_coarse_bin9") # Construct subset of data matching range "alt" but only for the first # 5000 events and plot it on the frame -dataSel = data.reduce(ROOT.RooFit.CutRange( - "alt"), ROOT.RooFit.EventRange(0, 5000)) -dataSel.plotOn(xframe, MarkerColor = ROOT.kGreen, LineColor = ROOT.kGreen) +dataSel = data.reduce(ROOT.RooFit.CutRange("alt"), ROOT.RooFit.EventRange(0, 5000)) +dataSel.plotOn(xframe, MarkerColor=ROOT.kGreen, LineColor=ROOT.kGreen) c = ROOT.TCanvas("rf405_realtocatfuncs", "rf405_realtocatfuncs", 600, 600) xframe.SetMinimum(0.01) diff --git a/tutorials/roofit/rf406_cattocatfuncs.py b/tutorials/roofit/rf406_cattocatfuncs.py index b6edd0dfc7185..9760f31229e11 100644 --- a/tutorials/roofit/rf406_cattocatfuncs.py +++ b/tutorials/roofit/rf406_cattocatfuncs.py @@ -39,8 +39,7 @@ # A RooMappedCategory is category.category mapping function based on string expression # The constructor takes an input category an a default state name to which unassigned # states are mapped -tcatType = ROOT.RooMappedCategory( - "tcatType", "tagCat type", tagCat, "Cut based") +tcatType = ROOT.RooMappedCategory("tcatType", "tagCat type", tagCat, "Cut based") # Enter fully specified state mappings tcatType.map("Lepton", "Cut based") @@ -58,8 +57,7 @@ # A SUPER-category is 'product' of _lvalue_ categories. The state names of a super # category is a composite of the state labels of the input categories -b0Xtcat = ROOT.RooSuperCategory( - "b0Xtcat", "b0flav X tagCat", ROOT.RooArgSet(b0flav, tagCat)) +b0Xtcat = ROOT.RooSuperCategory("b0Xtcat", "b0flav X tagCat", ROOT.RooArgSet(b0flav, tagCat)) # Make a table of the product category state multiplicity in data stable = data.table(b0Xtcat) @@ -70,8 +68,7 @@ # A MULTI-category is a 'product' of any category (function). The state names of a super # category is a composite of the state labels of the input categories -b0Xttype = ROOT.RooMultiCategory( - "b0Xttype", "b0flav X tagType", ROOT.RooArgSet(b0flav, tcatType)) +b0Xttype = ROOT.RooMultiCategory("b0Xttype", "b0flav X tagType", ROOT.RooArgSet(b0flav, tcatType)) # Make a table of the product category state multiplicity in data xtable = data.table(b0Xttype) diff --git a/tutorials/roofit/rf407_latextables.py b/tutorials/roofit/rf407_latextables.py index 51aeb04e0c49e..72bc240b4fabe 100644 --- a/tutorials/roofit/rf407_latextables.py +++ b/tutorials/roofit/rf407_latextables.py @@ -26,31 +26,25 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) -bkg1 = ROOT.RooChebychev("bkg1", "Background 1", - x, ROOT.RooArgList(a0, a1)) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +bkg1 = ROOT.RooChebychev("bkg1", "Background 1", x, ROOT.RooArgList(a0, a1)) # Build expontential pdf alpha = ROOT.RooRealVar("alpha", "alpha", -1) bkg2 = ROOT.RooExponential("bkg2", "Background 2", x, alpha) # Sum the background components into a composite background pdf -bkg1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in background", 0.2, 0., 1.) -bkg = ROOT.RooAddPdf( - "bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(sig1frac)) +bkg1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in background", 0.2, 0.0, 1.0) +bkg = ROOT.RooAddPdf("bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Make list of parameters before and after fit # ---------------------------------------------------------------------------------------- @@ -83,5 +77,4 @@ params.printLatex(ROOT.RooFit.Sibling(initParams), ROOT.RooFit.Columns(2)) # Write LaTex table to file -params.printLatex(ROOT.RooFit.Sibling(initParams), - ROOT.RooFit.OutputFile("rf407_latextables.tex")) +params.printLatex(ROOT.RooFit.Sibling(initParams), ROOT.RooFit.OutputFile("rf407_latextables.tex")) diff --git a/tutorials/roofit/rf501_simultaneouspdf.py b/tutorials/roofit/rf501_simultaneouspdf.py index 17d3e28bcd2f3..d591fdd42c12f 100644 --- a/tutorials/roofit/rf501_simultaneouspdf.py +++ b/tutorials/roofit/rf501_simultaneouspdf.py @@ -29,9 +29,8 @@ px = ROOT.RooChebychev("px", "px", x, ROOT.RooArgList(a0, a1)) # Construct composite pdf -f = ROOT.RooRealVar("f", "f", 0.2, 0., 1.) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList(gx, px), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.2, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gx, px), ROOT.RooArgList(f)) # Create model for control sample # -------------------------------------------------------------- @@ -44,18 +43,11 @@ # Construct the background pdf a0_ctl = ROOT.RooRealVar("a0_ctl", "a0_ctl", -0.1, -1, 1) a1_ctl = ROOT.RooRealVar("a1_ctl", "a1_ctl", 0.5, -0.1, 1) -px_ctl = ROOT.RooChebychev( - "px_ctl", "px_ctl", x, ROOT.RooArgList(a0_ctl, a1_ctl)) +px_ctl = ROOT.RooChebychev("px_ctl", "px_ctl", x, ROOT.RooArgList(a0_ctl, a1_ctl)) # Construct the composite model -f_ctl = ROOT.RooRealVar("f_ctl", "f_ctl", 0.5, 0., 1.) -model_ctl = ROOT.RooAddPdf( - "model_ctl", - "model_ctl", - ROOT.RooArgList( - gx_ctl, - px_ctl), - ROOT.RooArgList(f_ctl)) +f_ctl = ROOT.RooRealVar("f_ctl", "f_ctl", 0.5, 0.0, 1.0) +model_ctl = ROOT.RooAddPdf("model_ctl", "model_ctl", ROOT.RooArgList(gx_ctl, px_ctl), ROOT.RooArgList(f_ctl)) # Generate events for both samples # --------------------------------------------------------------- @@ -78,12 +70,9 @@ "combined data", ROOT.RooArgSet(x), ROOT.RooFit.Index(sample), - ROOT.RooFit.Import( - "physics", - data), - ROOT.RooFit.Import( - "control", - data_ctl)) + ROOT.RooFit.Import("physics", data), + ROOT.RooFit.Import("control", data_ctl), +) # Construct a simultaneous pdf in (x, sample) # ----------------------------------------------------------------------------------- @@ -109,7 +98,7 @@ frame1 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Physics sample")) # Plot all data tagged as physics sample -combData.plotOn(frame1, Cut = "sample==sample::physics") +combData.plotOn(frame1, Cut="sample==sample::physics") # Plot "physics" slice of simultaneous pdf. # NB: You *must* project the sample index category with data using ProjWData @@ -118,16 +107,19 @@ # NB2: The sampleSet *must* be named. It will not work to pass this as a temporary # because python will delete it. The same holds for fitTo() and plotOn() below. sampleSet = ROOT.RooArgSet(sample) -simPdf.plotOn(frame1, Slice = (sample, "physics"), Components = "px", ProjWData = (sampleSet, combData), LineStyle = ROOT.kDashed) +simPdf.plotOn( + frame1, Slice=(sample, "physics"), Components="px", ProjWData=(sampleSet, combData), LineStyle=ROOT.kDashed +) # The same plot for the control sample slice frame2 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Control sample")) -combData.plotOn(frame2, Cut = "sample==sample::control") -simPdf.plotOn(frame2, Slice = (sample, "control"), ProjWData = (sampleSet, combData)) -simPdf.plotOn(frame2, Slice = (sample, "control"), Components = "px_ctl", ProjWData = (sampleSet, combData), LineStyle = ROOT.kDashed) +combData.plotOn(frame2, Cut="sample==sample::control") +simPdf.plotOn(frame2, Slice=(sample, "control"), ProjWData=(sampleSet, combData)) +simPdf.plotOn( + frame2, Slice=(sample, "control"), Components="px_ctl", ProjWData=(sampleSet, combData), LineStyle=ROOT.kDashed +) -c = ROOT.TCanvas("rf501_simultaneouspdf", - "rf501_simultaneouspdf", 800, 400) +c = ROOT.TCanvas("rf501_simultaneouspdf", "rf501_simultaneouspdf", 800, 400) c.Divide(2) c.cd(1) ROOT.gPad.SetLeftMargin(0.15) diff --git a/tutorials/roofit/rf502_wspacewrite.py b/tutorials/roofit/rf502_wspacewrite.py index 7d350f12972db..3400f1968d93f 100644 --- a/tutorials/roofit/rf502_wspacewrite.py +++ b/tutorials/roofit/rf502_wspacewrite.py @@ -27,20 +27,17 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Generate a data sample of 1000 events in x from model data = model.generate(ROOT.RooArgSet(x), 1000) @@ -65,4 +62,3 @@ # Save the workspace into a ROOT file w.writeToFile("rf502_workspace.root") - diff --git a/tutorials/roofit/rf504_simwstool.py b/tutorials/roofit/rf504_simwstool.py index 397af11e88c20..6eea420b1be79 100644 --- a/tutorials/roofit/rf504_simwstool.py +++ b/tutorials/roofit/rf504_simwstool.py @@ -22,13 +22,12 @@ gauss = ROOT.RooGaussian("g", "g", x, m, s) # Construct poly(x,p0) -p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0., 1.) +p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0.0, 1.0) poly = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(p0)) # model = f*gauss(x) + (1-f)*poly(x) -f = ROOT.RooRealVar("f", "f", 0.5, 0., 1.) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - gauss, poly), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gauss, poly), ROOT.RooArgList(f)) # Create category observables for splitting # ---------------------------------------------------------------------------------- @@ -63,8 +62,7 @@ # = model_run2(x) if c=="run2" # # Returned pdf is owned by the workspace -model_sim = sct.build("model_sim", "model", - ROOT.RooFit.SplitParam("m", "c")) +model_sim = sct.build("model_sim", "model", ROOT.RooFit.SplitParam("m", "c")) # Print tree structure of model model_sim.Print("t") @@ -80,8 +78,7 @@ # ----------------------------------------------------------------------------------------- # Build another simultaneous pdf using a composite split in states c X d -model_sim2 = sct.build("model_sim2", "model", - ROOT.RooFit.SplitParam("p0", "c,d")) +model_sim2 = sct.build("model_sim2", "model", ROOT.RooFit.SplitParam("p0", "c,d")) # Print tree structure of self model model_sim2.Print("t") diff --git a/tutorials/roofit/rf505_asciicfg.py b/tutorials/roofit/rf505_asciicfg.py index 5717a38f1b9fc..04f4812f3f916 100644 --- a/tutorials/roofit/rf505_asciicfg.py +++ b/tutorials/roofit/rf505_asciicfg.py @@ -22,13 +22,12 @@ gauss = ROOT.RooGaussian("g", "g", x, m, s) # Construct poly(x,p0) -p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0., 1.) +p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0.0, 1.0) poly = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(p0)) # model = f*gauss(x) + (1-f)*poly(x) -f = ROOT.RooRealVar("f", "f", 0.5, 0., 1.) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - gauss, poly), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gauss, poly), ROOT.RooArgList(f)) # Fit model to toy data # ----------------------------------------- @@ -63,8 +62,7 @@ params.readFromFile(configFile, "READ", "Section3") # Print the list of parameters that were not read from Section3 -print("The following parameters of the were _not_ read from Section3: ", - params.selectByAttrib("READ", False)) +print("The following parameters of the were _not_ read from Section3: ", params.selectByAttrib("READ", False)) # Read parameters from section 'Section4' of file, contains # 'include file' statement of rf505_asciicfg_example.txt diff --git a/tutorials/roofit/rf506_msgservice.py b/tutorials/roofit/rf506_msgservice.py index 658a9b4d729dd..6872c55484c44 100644 --- a/tutorials/roofit/rf506_msgservice.py +++ b/tutorials/roofit/rf506_msgservice.py @@ -20,13 +20,12 @@ gauss = ROOT.RooGaussian("g", "g", x, m, s) # Construct poly(x,p0) -p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0., 1.) +p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0.0, 1.0) poly = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(p0)) # model = f*gauss(x) + (1-f)*poly(x) -f = ROOT.RooRealVar("f", "f", 0.5, 0., 1.) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - gauss, poly), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gauss, poly), ROOT.RooArgList(f)) data = model.generate(ROOT.RooArgSet(x), 10) @@ -60,13 +59,11 @@ # Show DEBUG level message on function tracing, ROOT.RooGaussian only ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, - ROOT.RooFit.Topic( - ROOT.RooFit.Tracing), - ROOT.RooFit.ClassName("RooGaussian")) + ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Tracing), ROOT.RooFit.ClassName("RooGaussian") +) # Perform a fit to generate some tracing messages -model.fitTo(data, Verbose = True) +model.fitTo(data, Verbose=True) # Reset message service to default stream configuration ROOT.RooMsgService.instance().reset() @@ -74,13 +71,11 @@ # Show DEBUG level message on function tracing on all objects, output to # file ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, - ROOT.RooFit.Topic( - ROOT.RooFit.Tracing), - ROOT.RooFit.OutputFile("rf506_debug.log")) + ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Tracing), ROOT.RooFit.OutputFile("rf506_debug.log") +) # Perform a fit to generate some tracing messages -model.fitTo(data, Verbose = True) +model.fitTo(data, Verbose=True) # Reset message service to default stream configuration ROOT.RooMsgService.instance().reset() @@ -89,8 +84,7 @@ # --------------------------------------------------------------------- # Show DEBUG level messages on client/server link state management -ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.LinkStateMgmt)) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.LinkStateMgmt)) ROOT.RooMsgService.instance().Print("v") # Clone composite pdf g to trigger some link state management activity diff --git a/tutorials/roofit/rf507_debugtools.py b/tutorials/roofit/rf507_debugtools.py index cee13ffedc64f..e54e075d992c0 100644 --- a/tutorials/roofit/rf507_debugtools.py +++ b/tutorials/roofit/rf507_debugtools.py @@ -27,16 +27,15 @@ ROOT.RooTrace.verbose(True) # Construct poly(x,p0) -p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0., 1.) +p0 = ROOT.RooRealVar("p0", "p0", 0.01, 0.0, 1.0) poly = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(p0)) # Put marker in trace list for future reference ROOT.RooTrace.mark() # model = f*gauss(x) + (1-f)*poly(x) -f = ROOT.RooRealVar("f", "f", 0.5, 0., 1.) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - gauss, poly), ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gauss, poly), ROOT.RooArgList(f)) # Show object added to memory since marker ROOT.RooTrace.printObjectCounts() diff --git a/tutorials/roofit/rf509_wsinteractive.py b/tutorials/roofit/rf509_wsinteractive.py index 6ecebeaec6327..91d981071b5c1 100644 --- a/tutorials/roofit/rf509_wsinteractive.py +++ b/tutorials/roofit/rf509_wsinteractive.py @@ -29,26 +29,17 @@ def fillWorkspace(w): sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf - a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) - a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0., 1.) + a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) + a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf - sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) - sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList( - sig1, sig2), ROOT.RooArgList(sig1frac)) + sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) + sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background - bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) - model = ROOT.RooAddPdf( - "model", - "g1+g2+a", - ROOT.RooArgList( - bkg, - sig), - ROOT.RooArgList(bkgfrac)) + bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) + model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) w.Import(model) @@ -79,8 +70,8 @@ def fillWorkspace(w): # Old syntax to use the name space prefix operator to access the workspace contents # -#d = w.model.generate(w.x,1000) -#r = w.model.fitTo(*d) +# d = w.model.generate(w.x,1000) +# r = w.model.fitTo(*d) # use normal workspace methods model = w.pdf("model") @@ -107,7 +98,7 @@ def fillWorkspace(w): bkg = w.pdf("bkg") model.plotOn(frame) ras_bkg = ROOT.RooArgSet(bkg) -model.plotOn(frame, Components = ras_bkg, LineStyle = ROOT.kDashed) +model.plotOn(frame, Components=ras_bkg, LineStyle=ROOT.kDashed) # Draw the frame on the canvas c = ROOT.TCanvas("rf509_wsinteractive", "rf509_wsinteractive", 600, 600) diff --git a/tutorials/roofit/rf510_wsnamedsets.py b/tutorials/roofit/rf510_wsnamedsets.py index 842d0ca0016d8..5b0474c1be017 100644 --- a/tutorials/roofit/rf510_wsnamedsets.py +++ b/tutorials/roofit/rf510_wsnamedsets.py @@ -77,7 +77,7 @@ def fillWorkspace(w): # Do a dummy fit to a (supposedly) reference dataset here and store the results # of that fit into a snapshot refData = model.generate(ROOT.RooArgSet(x), 10000) - model.fitTo(refData, PrintLevel = -1) + model.fitTo(refData, PrintLevel=-1) # The kTRUE flag imports the values of the objects in (*params) into the workspace # If not set, present values of the workspace parameters objects are stored @@ -89,7 +89,7 @@ def fillWorkspace(w): bkgfrac.setVal(1) bkgfrac.setConstant(True) bkgfrac.removeError() - model.fitTo(refData, PrintLevel = -1) + model.fitTo(refData, PrintLevel=-1) w.saveSnapshot("reference_fit_bkgonly", params, True) @@ -117,9 +117,9 @@ def fillWorkspace(w): # Overlay plot with model with reference parameters as stored in snapshots w.loadSnapshot("reference_fit") -model.plotOn(frame, LineColor = ROOT.kRed) +model.plotOn(frame, LineColor=ROOT.kRed) w.loadSnapshot("reference_fit_bkgonly") -model.plotOn(frame, LineColor = ROOT.kRed, LineStyle = ROOT.kDashed) +model.plotOn(frame, LineColor=ROOT.kRed, LineStyle=ROOT.kDashed) # Draw the frame on the canvas c = ROOT.TCanvas("rf510_wsnamedsets", "rf503_wsnamedsets", 600, 600) diff --git a/tutorials/roofit/rf511_wsfactory_basic.py b/tutorials/roofit/rf511_wsfactory_basic.py index e81899aa6c755..39a8acb11f551 100644 --- a/tutorials/roofit/rf511_wsfactory_basic.py +++ b/tutorials/roofit/rf511_wsfactory_basic.py @@ -41,7 +41,8 @@ w.factory( "SUM::model(bkgfrac[0.5,0.,1.]*Chebychev::bkg(x[-10,10],{a0[0.5,0.,1],a1[-0.2,0.,1.]}), " - "SUM(sig1frac[0.8,0.,1.]*Gaussian(x,mean[5,0,10],0.5), Gaussian(x,mean,1)))") + "SUM(sig1frac[0.8,0.,1.]*Gaussian(x,mean[5,0,10],0.5), Gaussian(x,mean,1)))" + ) # Advanced pdf constructor arguments # ---------------------------------------------------------------- @@ -69,4 +70,3 @@ # Print workspace contents w.Print() - diff --git a/tutorials/roofit/rf513_wsfactory_tools.py b/tutorials/roofit/rf513_wsfactory_tools.py index f1d9b98a7abb1..09dcaa4392313 100644 --- a/tutorials/roofit/rf513_wsfactory_tools.py +++ b/tutorials/roofit/rf513_wsfactory_tools.py @@ -26,12 +26,12 @@ "GaussModel(dt,0,sigmaT[3,10]), " "GaussModel(dt,0,20)},{fracC[0,1],fracT[0,1]}), " "DoubleSided ), " - "Gaussian::sig_m( mes[5.20,5.30], mB0[5.20,5.30], sigmB0[0.01,0.05] ))") + "Gaussian::sig_m( mes[5.20,5.30], mB0[5.20,5.30], sigmB0[0.01,0.05] ))" +) # Make background component: A plain decay function in t times an Argus # function in the reconstructed mass -w.factory("PROD::bkg( Decay::bkg_t( dt, tau, gm, DoubleSided), " - "ArgusBG::bkg_m( mes, 5.291, k[-100,-10]))") +w.factory("PROD::bkg( Decay::bkg_t( dt, tau, gm, DoubleSided), " "ArgusBG::bkg_m( mes, 5.291, k[-100,-10]))") # Make composite model from the signal and background component w.factory("SUM::model( Nsig[5000,0,10000]*sig, NBkg[500,0,10000]*bkg )") @@ -52,8 +52,7 @@ # ROOT.RooSimWSTool is interfaced as meta-type SIMCLONE in the factory. The $SplitParam() # argument maps to the SplitParam() named argument in the # ROOT.RooSimWSTool constructor -w.factory( - "SIMCLONE::model_sim( model, $SplitParam({w,dw,biasC},tagCat[Lep,Kao,NT1,NT2]))") +w.factory("SIMCLONE::model_sim( model, $SplitParam({w,dw,biasC},tagCat[Lep,Kao,NT1,NT2]))") # Example of RooCustomizer interface # ------------------------------------------------------------------- diff --git a/tutorials/roofit/rf603_multicpu.py b/tutorials/roofit/rf603_multicpu.py index 4cfd34801148e..0403cd4709b03 100644 --- a/tutorials/roofit/rf603_multicpu.py +++ b/tutorials/roofit/rf603_multicpu.py @@ -20,26 +20,20 @@ z = ROOT.RooRealVar("z", "z", -5, 5) # Create signal pdf gauss(x)*gauss(y)*gauss(z) -gx = ROOT.RooGaussian( - "gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gy = ROOT.RooGaussian( - "gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) -gz = ROOT.RooGaussian( - "gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gx = ROOT.RooGaussian("gx", "gx", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gy = ROOT.RooGaussian("gy", "gy", y, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) +gz = ROOT.RooGaussian("gz", "gz", z, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(1)) sig = ROOT.RooProdPdf("sig", "sig", ROOT.RooArgList(gx, gy, gz)) # Create background pdf poly(x)*poly(y)*poly(z) -px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList( - ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) -py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList( - ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) +px = ROOT.RooPolynomial("px", "px", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.1), ROOT.RooFit.RooConst(0.004))) +py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList(ROOT.RooFit.RooConst(0.1), ROOT.RooFit.RooConst(-0.004))) pz = ROOT.RooPolynomial("pz", "pz", z) bkg = ROOT.RooProdPdf("bkg", "bkg", ROOT.RooArgList(px, py, pz)) # Create composite pdf sig+bkg -fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0., 1.) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - sig, bkg), ROOT.RooArgList(fsig)) +fsig = ROOT.RooRealVar("fsig", "signal fraction", 0.1, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(fsig)) # Generate large dataset data = model.generate(ROOT.RooArgSet(x, y, z), 200000) @@ -52,7 +46,7 @@ # it back to MINUIT. # Use four processes and time results both in wall time and CPU time -model.fitTo(data, NumCPU = 4, Timer = True) +model.fitTo(data, NumCPU=4, Timer=True) # Parallel MC projections # ---------------------------------------------- @@ -61,8 +55,7 @@ # likelihood ratio sigyz = sig.createProjection(ROOT.RooArgSet(x)) totyz = model.createProjection(ROOT.RooArgSet(x)) -llratio_func = ROOT.RooFormulaVar( - "llratio", "log10(@0)-log10(@1)", ROOT.RooArgList(sigyz, totyz)) +llratio_func = ROOT.RooFormulaVar("llratio", "log10(@0)-log10(@1)", ROOT.RooArgList(sigyz, totyz)) # Calculate likelihood ratio for each event, subset of events with high # signal likelihood @@ -70,8 +63,7 @@ dataSel = data.reduce(ROOT.RooFit.Cut("llratio>0.7")) # Make plot frame and plot data -frame = x.frame(ROOT.RooFit.Title( - "Projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) +frame = x.frame(ROOT.RooFit.Title("Projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) dataSel.plotOn(frame) # Perform parallel projection using MC integration of pdf using given input dataSet. @@ -81,7 +73,7 @@ # final result # Use four processes -model.plotOn(frame, ProjWData = dataSel, NumCPU = 4) +model.plotOn(frame, ProjWData=dataSel, NumCPU=4) c = ROOT.TCanvas("rf603_multicpu", "rf603_multicpu", 600, 600) ROOT.gPad.SetLeftMargin(0.15) diff --git a/tutorials/roofit/rf604_constraints.py b/tutorials/roofit/rf604_constraints.py index 206f810e5cbad..7d5e67b955958 100644 --- a/tutorials/roofit/rf604_constraints.py +++ b/tutorials/roofit/rf604_constraints.py @@ -26,14 +26,8 @@ poly = ROOT.RooPolynomial("poly", "poly(x)", x) # model = f*gauss + (1-f)*poly -f = ROOT.RooRealVar("f", "f", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", - "model", - ROOT.RooArgList( - gauss, - poly), - ROOT.RooArgList(f)) +f = ROOT.RooRealVar("f", "f", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(gauss, poly), ROOT.RooArgList(f)) # Generate small dataset for use in fitting below d = model.generate(ROOT.RooArgSet(x), 50) @@ -43,12 +37,7 @@ # Construct Gaussian constraint pdf on parameter f at 0.8 with # resolution of 0.1 -fconstraint = ROOT.RooGaussian( - "fconstraint", - "fconstraint", - f, - ROOT.RooFit.RooConst(0.8), - ROOT.RooFit.RooConst(0.1)) +fconstraint = ROOT.RooGaussian("fconstraint", "fconstraint", f, ROOT.RooFit.RooConst(0.8), ROOT.RooFit.RooConst(0.1)) # Method 1 - add internal constraint to model # ------------------------------------------------------------------------------------- @@ -58,25 +47,23 @@ # used # Multiply constraint with pdf -modelc = ROOT.RooProdPdf( - "modelc", "model with constraint", ROOT.RooArgList(model, fconstraint)) +modelc = ROOT.RooProdPdf("modelc", "model with constraint", ROOT.RooArgList(model, fconstraint)) # Fit model (without use of constraint term) -r1 = model.fitTo(d, Save = True) +r1 = model.fitTo(d, Save=True) # Fit modelc with constraint term on parameter f -r2 = modelc.fitTo(d, Constrain = ROOT.RooArgSet(f), Save = True) +r2 = modelc.fitTo(d, Constrain=ROOT.RooArgSet(f), Save=True) # Method 2 - specify external constraint when fitting # ------------------------------------------------------------------------------------------ # Construct another Gaussian constraint pdf on parameter f at 0.8 with # resolution of 0.1 -fconstext = ROOT.RooGaussian("fconstext", "fconstext", f, ROOT.RooFit.RooConst( - 0.2), ROOT.RooFit.RooConst(0.1)) +fconstext = ROOT.RooGaussian("fconstext", "fconstext", f, ROOT.RooFit.RooConst(0.2), ROOT.RooFit.RooConst(0.1)) # Fit with external constraint -r3 = model.fitTo(d, ExternalConstraints = ROOT.RooArgSet(fconstext), Save = True) +r3 = model.fitTo(d, ExternalConstraints=ROOT.RooArgSet(fconstext), Save=True) # Print the fit results print("fit result without constraint (data generated at f=0.5)") diff --git a/tutorials/roofit/rf605_profilell.py b/tutorials/roofit/rf605_profilell.py index 4a0c9566caf3f..ce83524042cac 100644 --- a/tutorials/roofit/rf605_profilell.py +++ b/tutorials/roofit/rf605_profilell.py @@ -64,7 +64,7 @@ pll_frac = nll.createProfile(ROOT.RooArgSet(frac)) # Plot the profile likelihood in frac -pll_frac.plotOn(frame1, LineColor = ROOT.kRed) +pll_frac.plotOn(frame1, LineColor=ROOT.kRed) # Adjust frame maximum for visual clarity frame1.SetMinimum(0) @@ -78,7 +78,7 @@ pll_sigmag2 = nll.createProfile(ROOT.RooArgSet(sigma_g2)) # Plot the profile likelihood in sigma_g2 -pll_sigmag2.plotOn(frame2, LineColor = ROOT.kRed) +pll_sigmag2.plotOn(frame2, LineColor=ROOT.kRed) # Adjust frame maximum for visual clarity frame2.SetMinimum(0) diff --git a/tutorials/roofit/rf606_nllerrorhandling.py b/tutorials/roofit/rf606_nllerrorhandling.py index b7d8fbc1052eb..a004ba01e3199 100644 --- a/tutorials/roofit/rf606_nllerrorhandling.py +++ b/tutorials/roofit/rf606_nllerrorhandling.py @@ -52,7 +52,7 @@ # is to return a very high value of the likelihood to MINUIT if errors occur, # which will force MINUIT to retreat from the problematic area -argus.fitTo(data, PrintEvalErrors = 10) +argus.fitTo(data, PrintEvalErrors=10) # Peform another fit. In self configuration only the number of errors per # likelihood evaluation is shown, it is greater than zero. The @@ -66,7 +66,7 @@ # illustrated in the second plot m0.setError(0.1) -argus.fitTo(data, PrintEvalErrors = 0, EvalErrorWall = False) +argus.fitTo(data, PrintEvalErrors=0, EvalErrorWall=False) # Plot likelihood as function of m0 # ------------------------------------------------------------------ @@ -81,11 +81,7 @@ frame2 = m0.frame(ROOT.RooFit.Range(5.288, 5.293), ROOT.RooFit.Title("-log(L) scan vs m0, regions masked")) nll.plotOn( - frame2, - ROOT.RooFit.ShiftToZero(), - PrintEvalErrors = -1, - EvalErrorValue= (nll.getVal() + 10), - LineColor = ROOT.kRed + frame2, ROOT.RooFit.ShiftToZero(), PrintEvalErrors=-1, EvalErrorValue=(nll.getVal() + 10), LineColor=ROOT.kRed ) frame2.SetMaximum(15) frame2.SetMinimum(0) diff --git a/tutorials/roofit/rf607_fitresult.py b/tutorials/roofit/rf607_fitresult.py index 5d9d3f5e0c8c1..1fc6cd9f3af93 100644 --- a/tutorials/roofit/rf607_fitresult.py +++ b/tutorials/roofit/rf607_fitresult.py @@ -28,20 +28,17 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) a1 = ROOT.RooRealVar("a1", "a1", -0.2) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background -bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) # Generate 1000 events data = model.generate(ROOT.RooArgSet(x), 1000) @@ -50,7 +47,7 @@ # ------------------------------------------------------------- # Perform fit and save result -r = model.fitTo(data, Save = True) +r = model.fitTo(data, Save=True) # Print fit results # --------------------------------- @@ -87,10 +84,8 @@ r.floatParsFinal().Print("s") # Access correlation matrix elements -print("correlation between sig1frac and a0 is ", r.correlation( - sig1frac, a0)) -print("correlation between bkgfrac and mean is ", r.correlation( - "bkgfrac", "mean")) +print("correlation between sig1frac and a0 is ", r.correlation(sig1frac, a0)) +print("correlation between bkgfrac and mean is ", r.correlation("bkgfrac", "mean")) # Extract covariance and correlation matrix as ROOT.TMatrixDSym cor = r.correlationMatrix() diff --git a/tutorials/roofit/rf608_fitresultaspdf.py b/tutorials/roofit/rf608_fitresultaspdf.py index 421670d73ce20..9eed5d23cf444 100644 --- a/tutorials/roofit/rf608_fitresultaspdf.py +++ b/tutorials/roofit/rf608_fitresultaspdf.py @@ -27,9 +27,7 @@ g2 = ROOT.RooGaussian("g2", "g2", x, mean, sigma_g2) frac = ROOT.RooRealVar("frac", "frac", 0.5, 0.0, 1.0) -model = ROOT.RooAddPdf( - "model", "model", ROOT.RooArgList( - g1, g2), ROOT.RooArgList(frac)) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(g1, g2), ROOT.RooArgList(frac)) # Generate 1000 events data = model.generate(ROOT.RooArgSet(x), 1000) @@ -37,7 +35,7 @@ # Fit model to data # ---------------------------------- -r = model.fitTo(data, Save = True) +r = model.fitTo(data, Save=True) # Create MV Gaussian pdf of fitted parameters # ------------------------------------------------------------------------------------ @@ -79,8 +77,7 @@ c1.SaveAs("rf608_fitresultaspdf_1.png") # Draw the 2D projections of the 3D pdf -c2 = ROOT.TCanvas("rf608_fitresultaspdf_2", - "rf608_fitresultaspdf_2", 900, 600) +c2 = ROOT.TCanvas("rf608_fitresultaspdf_2", "rf608_fitresultaspdf_2", 900, 600) c2.Divide(3, 2) c2.cd(1) ROOT.gPad.SetLeftMargin(0.15) diff --git a/tutorials/roofit/rf609_xychi2fit.py b/tutorials/roofit/rf609_xychi2fit.py index c4db49b1fd42b..efe434eaf8a01 100644 --- a/tutorials/roofit/rf609_xychi2fit.py +++ b/tutorials/roofit/rf609_xychi2fit.py @@ -25,13 +25,12 @@ x = ROOT.RooRealVar("x", "x", -11, 11) y = ROOT.RooRealVar("y", "y", -10, 200) -dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet( - x, y), ROOT.RooFit.StoreError(ROOT.RooArgSet(x, y))) +dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet(x, y), ROOT.RooFit.StoreError(ROOT.RooArgSet(x, y))) # Fill an example dataset with X,err(X),Y,err(Y) values for i in range(10): x.setVal(-10 + 2 * i) - x.setError((0.5 / 1.) if (i < 5) else (1.0 / 1.)) + x.setError((0.5 / 1.0) if (i < 5) else (1.0 / 1.0)) # Set Y value and error y.setVal(x.getVal() * x.getVal() + 4 * abs(ROOT.gRandom.Gaus())) @@ -45,13 +44,10 @@ # Make fit function a = ROOT.RooRealVar("a", "a", 0.0, -10, 10) b = ROOT.RooRealVar("b", "b", 0.0, -100, 100) -f = ROOT.RooPolyVar( - "f", "f", x, ROOT.RooArgList( - b, a, ROOT.RooFit.RooConst(1))) +f = ROOT.RooPolyVar("f", "f", x, ROOT.RooArgList(b, a, ROOT.RooFit.RooConst(1))) # Plot dataset in X-Y interpretation -frame = x.frame(ROOT.RooFit.Title( - "Chi^2 fit of function set of (X#pmdX,Y#pmdY) values")) +frame = x.frame(ROOT.RooFit.Title("Chi^2 fit of function set of (X#pmdX,Y#pmdY) values")) dxy.plotOnXY(frame, ROOT.RooFit.YVar(y)) # Fit chi^2 using X and Y errors @@ -65,7 +61,7 @@ f.chi2FitTo(dxy, ROOT.RooFit.YVar(y), ROOT.RooFit.Integrate(True)) # Overlay alternate fit result -f.plotOn(frame, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) +f.plotOn(frame, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) # Draw the plot on a canvas c = ROOT.TCanvas("rf609_xychi2fit", "rf609_xychi2fit", 600, 600) diff --git a/tutorials/roofit/rf610_visualerror.py b/tutorials/roofit/rf610_visualerror.py index 2802798f03b67..ee257546c77b8 100644 --- a/tutorials/roofit/rf610_visualerror.py +++ b/tutorials/roofit/rf610_visualerror.py @@ -26,22 +26,20 @@ bkg = ROOT.RooGaussian("bkg", "bkg", x, m2, s2) fsig = ROOT.RooRealVar("fsig", "fsig", 0.33, 0, 1) -model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList( - sig, bkg), ROOT.RooArgList(fsig)) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(fsig)) # Create binned dataset x.setBins(25) d = model.generateBinned(ROOT.RooArgSet(x), 1000) # Perform fit and save fit result -r = model.fitTo(d, Save = True) +r = model.fitTo(d, Save=True) # Visualize fit error # ------------------------------------- # Make plot frame -frame = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title( - "P.d.f with visualized 1-sigma error band")) +frame = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("P.d.f with visualized 1-sigma error band")) d.plotOn(frame) # Visualize 1-sigma error encoded in fit result 'r' as orange band using linear error propagation @@ -61,7 +59,7 @@ # but may not be accurate in the presence of strong correlations (~>0.9) and at Z>2 due to linear and # Gaussian approximations made # -model.plotOn(frame, VisualizeError = (r, 1), FillColor = ROOT.kOrange) +model.plotOn(frame, VisualizeError=(r, 1), FillColor=ROOT.kOrange) # Calculate error using sampling method and visualize as dashed red line. # @@ -73,28 +71,25 @@ # 100 (e.g. Z=1.Ncurve=356, Z=2.Ncurve=2156)) Intervals from the sampling method can be asymmetric, # and may perform better in the presence of strong correlations, may take # (much) longer to calculate -model.plotOn( - frame, - VisualizeError = (r, 1, False), - DrawOption = "L", - LineWidth = 2, - LineColor = ROOT.kRed) +model.plotOn(frame, VisualizeError=(r, 1, False), DrawOption="L", LineWidth=2, LineColor=ROOT.kRed) # Perform the same type of error visualization on the background component only. # The VisualizeError() option can generally applied to _any_ kind of # plot (components, asymmetries, etc..) -model.plotOn(frame, VisualizeError = (r, 1), FillColor = ROOT.kOrange, Components = "bkg") -model.plotOn(frame, - VisualizeError = (r, 1, False), - DrawOption = "L", - LineWidth = 2, - LineColor = ROOT.kRed, - Components = "bkg", - LineStyle = ROOT.kDashed) +model.plotOn(frame, VisualizeError=(r, 1), FillColor=ROOT.kOrange, Components="bkg") +model.plotOn( + frame, + VisualizeError=(r, 1, False), + DrawOption="L", + LineWidth=2, + LineColor=ROOT.kRed, + Components="bkg", + LineStyle=ROOT.kDashed, +) # Overlay central value model.plotOn(frame) -model.plotOn(frame, Components = "bkg", LineStyle = ROOT.kDashed) +model.plotOn(frame, Components="bkg", LineStyle=ROOT.kDashed) d.plotOn(frame) frame.SetMinimum(0) @@ -102,8 +97,7 @@ # ------------------------------------------------------ # Make plot frame -frame2 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title( - "Visualization of 2-sigma partial error from (m,m2)")) +frame2 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from (m,m2)")) # Visualize partial error. For partial error visualization the covariance matrix is first reduced as follows # ___ -1 @@ -117,37 +111,35 @@ # Propagate partial error due to shape parameters (m,m2) using linear and # sampling method -model.plotOn(frame2, VisualizeError = (r, ROOT.RooArgSet(m, m2), 2), FillColor = ROOT.kCyan) -model.plotOn(frame2, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(m, m2), 2), FillColor = ROOT.kCyan) +model.plotOn(frame2, VisualizeError=(r, ROOT.RooArgSet(m, m2), 2), FillColor=ROOT.kCyan) +model.plotOn(frame2, Components="bkg", VisualizeError=(r, ROOT.RooArgSet(m, m2), 2), FillColor=ROOT.kCyan) model.plotOn(frame2) -model.plotOn(frame2, Components = "bkg", LineStyle = ROOT.kDashed) +model.plotOn(frame2, Components="bkg", LineStyle=ROOT.kDashed) frame2.SetMinimum(0) # Make plot frame -frame3 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title( - "Visualization of 2-sigma partial error from (s,s2)")) +frame3 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from (s,s2)")) # Propagate partial error due to yield parameter using linear and sampling # method -model.plotOn(frame3, VisualizeError = (r, ROOT.RooArgSet(s, s2), 2), FillColor = ROOT.kGreen) -model.plotOn(frame3, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kGreen) +model.plotOn(frame3, VisualizeError=(r, ROOT.RooArgSet(s, s2), 2), FillColor=ROOT.kGreen) +model.plotOn(frame3, Components="bkg", VisualizeError=(r, ROOT.RooArgSet(fsig), 2), FillColor=ROOT.kGreen) model.plotOn(frame3) -model.plotOn(frame3, Components = "bkg", LineStyle = ROOT.kDashed) +model.plotOn(frame3, Components="bkg", LineStyle=ROOT.kDashed) frame3.SetMinimum(0) # Make plot frame -frame4 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title( - "Visualization of 2-sigma partial error from fsig")) +frame4 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from fsig")) # Propagate partial error due to yield parameter using linear and sampling # method -model.plotOn(frame4, VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kMagenta) -model.plotOn(frame4, Components = "bkg", VisualizeError = (r, ROOT.RooArgSet(fsig), 2), FillColor = ROOT.kMagenta) +model.plotOn(frame4, VisualizeError=(r, ROOT.RooArgSet(fsig), 2), FillColor=ROOT.kMagenta) +model.plotOn(frame4, Components="bkg", VisualizeError=(r, ROOT.RooArgSet(fsig), 2), FillColor=ROOT.kMagenta) model.plotOn(frame4) -model.plotOn(frame4, Components = "bkg", LineStyle = ROOT.kDashed) +model.plotOn(frame4, Components="bkg", LineStyle=ROOT.kDashed) frame4.SetMinimum(0) c = ROOT.TCanvas("rf610_visualerror", "rf610_visualerror", 800, 800) diff --git a/tutorials/roofit/rf701_efficiencyfit.py b/tutorials/roofit/rf701_efficiencyfit.py index e32b4a691e04e..0f5f134723f01 100644 --- a/tutorials/roofit/rf701_efficiencyfit.py +++ b/tutorials/roofit/rf701_efficiencyfit.py @@ -24,8 +24,7 @@ a = ROOT.RooRealVar("a", "a", 0.4, 0, 1) b = ROOT.RooRealVar("b", "b", 5) c = ROOT.RooRealVar("c", "c", -1, -10, 10) -effFunc = ROOT.RooFormulaVar( - "effFunc", "(1-a)+a*cos((x-c)/b)", ROOT.RooArgList(a, b, c, x)) +effFunc = ROOT.RooFormulaVar("effFunc", "(1-a)+a*cos((x-c)/b)", ROOT.RooArgList(a, b, c, x)) # Construct conditional efficiency pdf E(cut|x) # ------------------------------------------------------------------------------------------ @@ -43,15 +42,10 @@ # Construct global shape pdf shape(x) and product model(x,cut) = eff(cut|x)*shape(x) # (These are _only_ needed to generate some toy MC here to be used later) -shapePdf = ROOT.RooPolynomial( - "shapePdf", "shapePdf", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.095))) +shapePdf = ROOT.RooPolynomial("shapePdf", "shapePdf", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.095))) model = ROOT.RooProdPdf( - "model", - "model", - ROOT.RooArgSet(shapePdf), - ROOT.RooFit.Conditional( - ROOT.RooArgSet(effPdf), - ROOT.RooArgSet(cut))) + "model", "model", ROOT.RooArgSet(shapePdf), ROOT.RooFit.Conditional(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) +) # Generate some toy data from model data = model.generate(ROOT.RooArgSet(x, cut), 10000) @@ -60,22 +54,20 @@ # -------------------------------------------------------------------------- # Fit conditional efficiency pdf to data -effPdf.fitTo(data, ConditionalObservables = ROOT.RooArgSet(x)) +effPdf.fitTo(data, ConditionalObservables=ROOT.RooArgSet(x)) # Plot fitted, data efficiency # -------------------------------------------------------- # Plot distribution of all events and accepted fraction of events on frame -frame1 = x.frame(ROOT.RooFit.Bins( - 20), ROOT.RooFit.Title("Data (all, accepted)")) +frame1 = x.frame(ROOT.RooFit.Bins(20), ROOT.RooFit.Title("Data (all, accepted)")) data.plotOn(frame1) -data.plotOn(frame1, Cut = "cut==cut::accept", MarkerColor = ROOT.kRed, LineColor = ROOT.kRed) +data.plotOn(frame1, Cut="cut==cut::accept", MarkerColor=ROOT.kRed, LineColor=ROOT.kRed) # Plot accept/reject efficiency on data overlay fitted efficiency curve -frame2 = x.frame(ROOT.RooFit.Bins( - 20), ROOT.RooFit.Title("Fitted efficiency")) -data.plotOn(frame2, Efficiency = cut) # needs ROOT version >= 5.21 -effFunc.plotOn(frame2, LineColor = ROOT.kRed) +frame2 = x.frame(ROOT.RooFit.Bins(20), ROOT.RooFit.Title("Fitted efficiency")) +data.plotOn(frame2, Efficiency=cut) # needs ROOT version >= 5.21 +effFunc.plotOn(frame2, LineColor=ROOT.kRed) # Draw all frames on a canvas ca = ROOT.TCanvas("rf701_efficiency", "rf701_efficiency", 800, 400) diff --git a/tutorials/roofit/rf702_efficiencyfit_2D.py b/tutorials/roofit/rf702_efficiencyfit_2D.py index 67598423ec54c..80b89ffd690ba 100644 --- a/tutorials/roofit/rf702_efficiencyfit_2D.py +++ b/tutorials/roofit/rf702_efficiencyfit_2D.py @@ -32,17 +32,8 @@ cy = ROOT.RooRealVar("cy", "cy", -1, -10, 10) effFunc = ROOT.RooFormulaVar( - "effFunc", - "((1-ax)+ax*cos((x-cx)/bx))*((1-ay)+ay*cos((y-cy)/by))", - ROOT.RooArgList( - ax, - bx, - cx, - x, - ay, - by, - cy, - y)) + "effFunc", "((1-ax)+ax*cos((x-cx)/bx))*((1-ay)+ay*cos((y-cy)/by))", ROOT.RooArgList(ax, bx, cx, x, ay, by, cy, y) +) # Acceptance state cut (1 or 0) cut = ROOT.RooCategory("cut", "cutr") @@ -61,26 +52,15 @@ # Construct global shape pdf shape(x) and product model(x,cut) = eff(cut|x)*shape(x) # (These are _only_ needed to generate some toy MC here to be used later) shapePdfX = ROOT.RooPolynomial( - "shapePdfX", "shapePdfX", x, ROOT.RooArgList( - ROOT.RooFit.RooConst( - 0 if flat else -0.095))) + "shapePdfX", "shapePdfX", x, ROOT.RooArgList(ROOT.RooFit.RooConst(0 if flat else -0.095)) +) shapePdfY = ROOT.RooPolynomial( - "shapePdfY", "shapePdfY", y, ROOT.RooArgList( - ROOT.RooFit.RooConst( - 0 if flat else +0.095))) -shapePdf = ROOT.RooProdPdf( - "shapePdf", - "shapePdf", - ROOT.RooArgList( - shapePdfX, - shapePdfY)) + "shapePdfY", "shapePdfY", y, ROOT.RooArgList(ROOT.RooFit.RooConst(0 if flat else +0.095)) +) +shapePdf = ROOT.RooProdPdf("shapePdf", "shapePdf", ROOT.RooArgList(shapePdfX, shapePdfY)) model = ROOT.RooProdPdf( - "model", - "model", - ROOT.RooArgSet(shapePdf), - ROOT.RooFit.Conditional( - ROOT.RooArgSet(effPdf), - ROOT.RooArgSet(cut))) + "model", "model", ROOT.RooArgSet(shapePdf), ROOT.RooFit.Conditional(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) +) # Generate some toy data from model data = model.generate(ROOT.RooArgSet(x, y, cut), 10000) @@ -89,21 +69,24 @@ # -------------------------------------------------------------------------- # Fit conditional efficiency pdf to data -effPdf.fitTo(data, ConditionalObservables = ROOT.RooArgSet(x, y)) +effPdf.fitTo(data, ConditionalObservables=ROOT.RooArgSet(x, y)) # Plot fitted, data efficiency # -------------------------------------------------------- # Make 2D histograms of all data, data and efficiency function hh_data_all = ROOT.RooAbsData.createHistogram( - data, "hh_data_all", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar( - y, ROOT.RooFit.Binning(8))) + data, "hh_data_all", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)) +) hh_data_sel = ROOT.RooAbsData.createHistogram( - data, "hh_data_sel", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar( - y, ROOT.RooFit.Binning(8)), ROOT.RooFit.Cut("cut==cut::accept")) -hh_eff = effFunc.createHistogram( - "hh_eff", x, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) + data, + "hh_data_sel", + x, + ROOT.RooFit.Binning(8), + ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)), + ROOT.RooFit.Cut("cut==cut::accept"), +) +hh_eff = effFunc.createHistogram("hh_eff", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) # Some adjustsment for good visualization hh_data_all.SetMinimum(0) diff --git a/tutorials/roofit/rf703_effpdfprod.py b/tutorials/roofit/rf703_effpdfprod.py index 23da613b672bb..15a210f831b12 100644 --- a/tutorials/roofit/rf703_effpdfprod.py +++ b/tutorials/roofit/rf703_effpdfprod.py @@ -25,10 +25,7 @@ # --------------------------------------------------- # Use error function to simulate turn-on slope -eff = ROOT.RooFormulaVar( - "eff", - "0.5*(TMath::Erf((t-1)/0.5)+1)", - ROOT.RooArgList(t)) +eff = ROOT.RooFormulaVar("eff", "0.5*(TMath::Erf((t-1)/0.5)+1)", ROOT.RooArgList(t)) # Define decay pdf with efficiency # --------------------------------------------------------------- @@ -40,11 +37,11 @@ # ---------------------------------------- frame1 = t.frame(ROOT.RooFit.Title("Efficiency")) -eff.plotOn(frame1, LineColor = ROOT.kRed) +eff.plotOn(frame1, LineColor=ROOT.kRed) frame2 = t.frame(ROOT.RooFit.Title("Pdf with and without efficiency")) -model.plotOn(frame2, LineStyle = ROOT.kDashed) +model.plotOn(frame2, LineStyle=ROOT.kDashed) modelEff.plotOn(frame2) # Generate toy data, fit model eff to data diff --git a/tutorials/roofit/rf704_amplitudefit.py b/tutorials/roofit/rf704_amplitudefit.py index d45a7cadcb34d..f5cc8d724f65f 100644 --- a/tutorials/roofit/rf704_amplitudefit.py +++ b/tutorials/roofit/rf704_amplitudefit.py @@ -15,28 +15,16 @@ # ------------------------------------------------------- # Observables -t = ROOT.RooRealVar("t", "time", -1., 15.) -cosa = ROOT.RooRealVar("cosa", "cos(alpha)", -1., 1.) +t = ROOT.RooRealVar("t", "time", -1.0, 15.0) +cosa = ROOT.RooRealVar("cosa", "cos(alpha)", -1.0, 1.0) # Use ROOT.RooTruthModel to obtain compiled implementation of sinh/cosh # modulated decay functions tau = ROOT.RooRealVar("tau", "#tau", 1.5) deltaGamma = ROOT.RooRealVar("deltaGamma", "deltaGamma", 0.3) tm = ROOT.RooTruthModel("tm", "tm", t) -coshGBasis = ROOT.RooFormulaVar( - "coshGBasis", - "exp(-@0/ @1)*cosh(@0*@2/2)", - ROOT.RooArgList( - t, - tau, - deltaGamma)) -sinhGBasis = ROOT.RooFormulaVar( - "sinhGBasis", - "exp(-@0/ @1)*sinh(@0*@2/2)", - ROOT.RooArgList( - t, - tau, - deltaGamma)) +coshGBasis = ROOT.RooFormulaVar("coshGBasis", "exp(-@0/ @1)*cosh(@0*@2/2)", ROOT.RooArgList(t, tau, deltaGamma)) +sinhGBasis = ROOT.RooFormulaVar("sinhGBasis", "exp(-@0/ @1)*sinh(@0*@2/2)", ROOT.RooArgList(t, tau, deltaGamma)) coshGConv = tm.convolution(coshGBasis, t) sinhGConv = tm.convolution(sinhGBasis, t) @@ -45,19 +33,20 @@ "poly1", "poly1", cosa, - ROOT.RooArgList( - ROOT.RooFit.RooConst(0.5), - ROOT.RooFit.RooConst(0.2), - ROOT.RooFit.RooConst(0.2)), - 0) -poly2 = ROOT.RooPolyVar("poly2", "poly2", cosa, ROOT.RooArgList( - ROOT.RooFit.RooConst(1), ROOT.RooFit.RooConst(-0.2), ROOT.RooFit.RooConst(3)), 0) + ROOT.RooArgList(ROOT.RooFit.RooConst(0.5), ROOT.RooFit.RooConst(0.2), ROOT.RooFit.RooConst(0.2)), + 0, +) +poly2 = ROOT.RooPolyVar( + "poly2", + "poly2", + cosa, + ROOT.RooArgList(ROOT.RooFit.RooConst(1), ROOT.RooFit.RooConst(-0.2), ROOT.RooFit.RooConst(3)), + 0, +) # Construct 2D amplitude as uncorrelated product of amp(t)*amp(cosa) -ampl1 = ROOT.RooProduct("ampl1", "amplitude 1", - ROOT.RooArgList(poly1, coshGConv)) -ampl2 = ROOT.RooProduct("ampl2", "amplitude 2", - ROOT.RooArgList(poly2, sinhGConv)) +ampl1 = ROOT.RooProduct("ampl1", "amplitude 1", ROOT.RooArgList(poly1, coshGConv)) +ampl2 = ROOT.RooProduct("ampl2", "amplitude 2", ROOT.RooArgList(poly2, sinhGConv)) # Construct amplitude sum pdf # ----------------------------------------------------- @@ -67,8 +56,7 @@ f2 = ROOT.RooRealVar("f2", "f2", 0.5, 0, 2) # Construct pdf -pdf = ROOT.RooRealSumPdf("pdf", "pdf", ROOT.RooArgList( - ampl1, ampl2), ROOT.RooArgList(f1, f2)) +pdf = ROOT.RooRealSumPdf("pdf", "pdf", ROOT.RooArgList(ampl1, ampl2), ROOT.RooArgList(f1, f2)) # Generate some toy data from pdf data = pdf.generate(ROOT.RooArgSet(t, cosa), 10000) @@ -80,10 +68,8 @@ # ------------------------------------------- # Make 2D plots of amplitudes -hh_cos = ampl1.createHistogram("hh_cos", t, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) -hh_sin = ampl2.createHistogram("hh_sin", t, ROOT.RooFit.Binning( - 50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) +hh_cos = ampl1.createHistogram("hh_cos", t, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) +hh_sin = ampl2.createHistogram("hh_sin", t, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) hh_cos.SetLineColor(ROOT.kBlue) hh_sin.SetLineColor(ROOT.kRed) @@ -95,9 +81,9 @@ pdf.plotOn(frame1) # workaround, see https://root.cern.ch/phpBB3/viewtopic.php?t=7764 ras_ampl1 = ROOT.RooArgSet(ampl1) -pdf.plotOn(frame1, Components = ras_ampl1, LineStyle = ROOT.kDashed) +pdf.plotOn(frame1, Components=ras_ampl1, LineStyle=ROOT.kDashed) ras_ampl2 = ROOT.RooArgSet(ampl2) -pdf.plotOn(frame1, Components = ras_ampl2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) +pdf.plotOn(frame1, Components=ras_ampl2, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) # Make projection on cosa, data, and its components # Note that components projection may be larger than sum because @@ -105,8 +91,8 @@ frame2 = cosa.frame() data.plotOn(frame2) pdf.plotOn(frame2) -pdf.plotOn(frame2, Components = ras_ampl1, LineStyle = ROOT.kDashed) -pdf.plotOn(frame2, Components = ras_ampl2, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) +pdf.plotOn(frame2, Components=ras_ampl1, LineStyle=ROOT.kDashed) +pdf.plotOn(frame2, Components=ras_ampl2, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) c = ROOT.TCanvas("rf704_amplitudefit", "rf704_amplitudefit", 800, 800) c.Divide(2, 2) diff --git a/tutorials/roofit/rf705_linearmorph.py b/tutorials/roofit/rf705_linearmorph.py index cc82e3c3790a4..9da70ac73a9d1 100644 --- a/tutorials/roofit/rf705_linearmorph.py +++ b/tutorials/roofit/rf705_linearmorph.py @@ -53,21 +53,21 @@ # Show interpolated shapes in red alpha.setVal(0.125) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.25) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.375) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.50) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.625) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.75) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.875) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) alpha.setVal(0.95) -lmorph.plotOn(frame1, LineColor = ROOT.kRed) +lmorph.plotOn(frame1, LineColor=ROOT.kRed) # Show 2D distribution of pdf(x,alpha) # ----------------------------------------------------------------------- @@ -85,7 +85,7 @@ # Fit pdf to toy data lmorph.setCacheAlpha(True) -lmorph.fitTo(data, Verbose = True) +lmorph.fitTo(data, Verbose=True) # Plot fitted pdf and data overlaid frame2 = x.frame(ROOT.RooFit.Bins(100)) diff --git a/tutorials/roofit/rf706_histpdf.py b/tutorials/roofit/rf706_histpdf.py index dafd3cd6da6df..f3fffe7281cc2 100644 --- a/tutorials/roofit/rf706_histpdf.py +++ b/tutorials/roofit/rf706_histpdf.py @@ -15,8 +15,9 @@ # --------------------------------------------- x = ROOT.RooRealVar("x", "x", 0, 20) -p = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(ROOT.RooFit.RooConst( - 0.01), ROOT.RooFit.RooConst(-0.01), ROOT.RooFit.RooConst(0.0004))) +p = ROOT.RooPolynomial( + "p", "p", x, ROOT.RooArgList(ROOT.RooFit.RooConst(0.01), ROOT.RooFit.RooConst(-0.01), ROOT.RooFit.RooConst(0.0004)) +) # Create low stats histogram # --------------------------------------------------- @@ -32,8 +33,7 @@ histpdf1 = ROOT.RooHistPdf("histpdf1", "histpdf1", ROOT.RooArgSet(x), hist1, 0) # Plot unbinned data and histogram pdf overlaid -frame1 = x.frame(ROOT.RooFit.Title( - "Low statistics histogram pdf"), ROOT.RooFit.Bins(100)) +frame1 = x.frame(ROOT.RooFit.Title("Low statistics histogram pdf"), ROOT.RooFit.Bins(100)) data1.plotOn(frame1) histpdf1.plotOn(frame1) @@ -51,8 +51,7 @@ histpdf2 = ROOT.RooHistPdf("histpdf2", "histpdf2", ROOT.RooArgSet(x), hist2, 2) # Plot unbinned data and histogram pdf overlaid -frame2 = x.frame(ROOT.RooFit.Title( - "High stats histogram pdf with interpolation"), ROOT.RooFit.Bins(100)) +frame2 = x.frame(ROOT.RooFit.Title("High stats histogram pdf with interpolation"), ROOT.RooFit.Bins(100)) data2.plotOn(frame2) histpdf2.plotOn(frame2) diff --git a/tutorials/roofit/rf707_kernelestimation.py b/tutorials/roofit/rf707_kernelestimation.py index 9b923f1891d08..e0a471cbf504b 100644 --- a/tutorials/roofit/rf707_kernelestimation.py +++ b/tutorials/roofit/rf707_kernelestimation.py @@ -16,8 +16,9 @@ # Create a toy pdf for sampling x = ROOT.RooRealVar("x", "x", 0, 20) -p = ROOT.RooPolynomial("p", "p", x, ROOT.RooArgList(ROOT.RooFit.RooConst( - 0.01), ROOT.RooFit.RooConst(-0.01), ROOT.RooFit.RooConst(0.0004))) +p = ROOT.RooPolynomial( + "p", "p", x, ROOT.RooArgList(ROOT.RooFit.RooConst(0.01), ROOT.RooFit.RooConst(-0.01), ROOT.RooFit.RooConst(0.0004)) +) # Sample 500 events from p data1 = p.generate(ROOT.RooArgSet(x), 200) @@ -28,40 +29,38 @@ # Create adaptive kernel estimation pdf. In self configuration the input data # is mirrored over the boundaries to minimize edge effects in distribution # that do not fall to zero towards the edges -kest1 = ROOT.RooKeysPdf("kest1", "kest1", x, data1, - ROOT.RooKeysPdf.MirrorBoth) +kest1 = ROOT.RooKeysPdf("kest1", "kest1", x, data1, ROOT.RooKeysPdf.MirrorBoth) # An adaptive kernel estimation pdf on the same data without mirroring option # for comparison -kest2 = ROOT.RooKeysPdf("kest2", "kest2", x, data1, - ROOT.RooKeysPdf.NoMirror) +kest2 = ROOT.RooKeysPdf("kest2", "kest2", x, data1, ROOT.RooKeysPdf.NoMirror) # Adaptive kernel estimation pdf with increased bandwidth scale factor # (promotes smoothness over detail preservation) -kest3 = ROOT.RooKeysPdf("kest1", "kest1", x, data1, - ROOT.RooKeysPdf.MirrorBoth, 2) +kest3 = ROOT.RooKeysPdf("kest1", "kest1", x, data1, ROOT.RooKeysPdf.MirrorBoth, 2) # Plot kernel estimation pdfs with and without mirroring over data -frame = x.frame( - ROOT.RooFit.Title("Adaptive kernel estimation pdf with and w/o mirroring"), - ROOT.RooFit.Bins(20)) +frame = x.frame(ROOT.RooFit.Title("Adaptive kernel estimation pdf with and w/o mirroring"), ROOT.RooFit.Bins(20)) data1.plotOn(frame) kest1.plotOn(frame) -kest2.plotOn(frame, LineStyle = ROOT.kDashed, LineColor = ROOT.kRed) +kest2.plotOn(frame, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) # Plot kernel estimation pdfs with regular and increased bandwidth -frame2 = x.frame(ROOT.RooFit.Title( - "Adaptive kernel estimation pdf with regular, bandwidth")) +frame2 = x.frame(ROOT.RooFit.Title("Adaptive kernel estimation pdf with regular, bandwidth")) kest1.plotOn(frame2) -kest3.plotOn(frame2, LineColor = ROOT.kMagenta) +kest3.plotOn(frame2, LineColor=ROOT.kMagenta) # Create low status 2D dataset # ------------------------------------------------------- # Construct a 2D toy pdf for sampleing y = ROOT.RooRealVar("y", "y", 0, 20) -py = ROOT.RooPolynomial("py", "py", y, ROOT.RooArgList(ROOT.RooFit.RooConst( - 0.01), ROOT.RooFit.RooConst(0.01), ROOT.RooFit.RooConst(-0.0004))) +py = ROOT.RooPolynomial( + "py", + "py", + y, + ROOT.RooArgList(ROOT.RooFit.RooConst(0.01), ROOT.RooFit.RooConst(0.01), ROOT.RooFit.RooConst(-0.0004)), +) pxy = ROOT.RooProdPdf("pxy", "pxy", ROOT.RooArgList(p, py)) data2 = pxy.generate(ROOT.RooArgSet(x, y), 1000) @@ -73,25 +72,20 @@ # Create 2D adaptive kernel estimation pdf with mirroring and double # bandwidth -kest5 = ROOT.RooNDKeysPdf( - "kest5", "kest5", ROOT.RooArgList( - x, y), data2, "am", 2) +kest5 = ROOT.RooNDKeysPdf("kest5", "kest5", ROOT.RooArgList(x, y), data2, "am", 2) # Create a histogram of the data hh_data = ROOT.RooAbsData.createHistogram( - data2, "hh_data", x, ROOT.RooFit.Binning(10), ROOT.RooFit.YVar( - y, ROOT.RooFit.Binning(10))) + data2, "hh_data", x, ROOT.RooFit.Binning(10), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(10)) +) # Create histogram of the 2d kernel estimation pdfs -hh_pdf = kest4.createHistogram("hh_pdf", x, ROOT.RooFit.Binning( - 25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) -hh_pdf2 = kest5.createHistogram("hh_pdf2", x, ROOT.RooFit.Binning( - 25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) +hh_pdf = kest4.createHistogram("hh_pdf", x, ROOT.RooFit.Binning(25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) +hh_pdf2 = kest5.createHistogram("hh_pdf2", x, ROOT.RooFit.Binning(25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) hh_pdf.SetLineColor(ROOT.kBlue) hh_pdf2.SetLineColor(ROOT.kMagenta) -c = ROOT.TCanvas("rf707_kernelestimation", - "rf707_kernelestimation", 800, 800) +c = ROOT.TCanvas("rf707_kernelestimation", "rf707_kernelestimation", 800, 800) c.Divide(2, 2) c.cd(1) ROOT.gPad.SetLeftMargin(0.15) diff --git a/tutorials/roofit/rf708_bphysics.py b/tutorials/roofit/rf708_bphysics.py index d0d21c956f177..f2aacced2d77e 100644 --- a/tutorials/roofit/rf708_bphysics.py +++ b/tutorials/roofit/rf708_bphysics.py @@ -39,18 +39,7 @@ tm = ROOT.RooTruthModel("tm", "truth model", dt) # Construct Bdecay with mixing -bmix = ROOT.RooBMixDecay( - "bmix", - "decay", - dt, - mixState, - tagFlav, - tau, - dm, - w, - dw, - tm, - ROOT.RooBMixDecay.DoubleSided) +bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, tm, ROOT.RooBMixDecay.DoubleSided) # Plot pdf in various slices # --------------------------------------------------- @@ -61,33 +50,31 @@ # Plot B0 and B0bar tagged data separately # For all plots below B0 and B0 tagged data will look somewhat differently # if the flavor tagging mistag rate for B0 and B0 is different (i.e. dw!=0) -frame1 = dt.frame(ROOT.RooFit.Title( - "B decay distribution with mixing (B0/B0bar)")) +frame1 = dt.frame(ROOT.RooFit.Title("B decay distribution with mixing (B0/B0bar)")) -data.plotOn(frame1, Cut = "tagFlav==tagFlav::B0") -bmix.plotOn(frame1, Slice = (tagFlav, "B0")) +data.plotOn(frame1, Cut="tagFlav==tagFlav::B0") +bmix.plotOn(frame1, Slice=(tagFlav, "B0")) -data.plotOn(frame1, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bmix.plotOn(frame1, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) +data.plotOn(frame1, Cut="tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bmix.plotOn(frame1, Slice=(tagFlav, "B0bar"), LineColor=ROOT.kCyan) # Plot mixed slice for B0 and B0bar tagged data separately -frame2 = dt.frame(ROOT.RooFit.Title( - "B decay distribution of mixed events (B0/B0bar)")) +frame2 = dt.frame(ROOT.RooFit.Title("B decay distribution of mixed events (B0/B0bar)")) -data.plotOn(frame2, Cut = "mixState==mixState::mixed&&tagFlav==tagFlav::B0") -bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0"),Slice = (mixState, "mixed")) +data.plotOn(frame2, Cut="mixState==mixState::mixed&&tagFlav==tagFlav::B0") +bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0"), Slice=(mixState, "mixed")) -data.plotOn(frame2, Cut = "mixState==mixState::mixed&&tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice = (mixState, "mixed"), LineColor = ROOT.kCyan) +data.plotOn(frame2, Cut="mixState==mixState::mixed&&tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice=(mixState, "mixed"), LineColor=ROOT.kCyan) # Plot unmixed slice for B0 and B0bar tagged data separately frame3 = dt.frame(ROOT.RooFit.Title("B decay distribution of unmixed events (B0/B0bar)")) -data.plotOn(frame3, Cut = "mixState==mixState::unmixed&&tagFlav==tagFlav::B0") -bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0"), Slice = (mixState, "unmixed")) +data.plotOn(frame3, Cut="mixState==mixState::unmixed&&tagFlav==tagFlav::B0") +bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0"), Slice=(mixState, "unmixed")) -data.plotOn(frame3, Cut = "mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice = (mixState, "unmixed"), LineColor = ROOT.kCyan) +data.plotOn(frame3, Cut="mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice=(mixState, "unmixed"), LineColor=ROOT.kCyan) # B-decay with CP violation # ------------------------- @@ -103,20 +90,8 @@ # Construct Bdecay with CP violation bcp = ROOT.RooBCPEffDecay( - "bcp", - "bcp", - dt, - tagFlav, - tau, - dm, - w, - CPeigen, - absLambda, - argLambda, - effR, - dw, - tm, - ROOT.RooBCPEffDecay.DoubleSided) + "bcp", "bcp", dt, tagFlav, tau, dm, w, CPeigen, absLambda, argLambda, effR, dw, tm, ROOT.RooBCPEffDecay.DoubleSided +) # Plot scenario 1 - sin(2b)=0.7, |l|=1 # --------------------------------------------------------------------------- @@ -125,14 +100,13 @@ data2 = bcp.generate(ROOT.RooArgSet(dt, tagFlav), 10000) # Plot B0 and B0bar tagged data separately -frame4 = dt.frame(ROOT.RooFit.Title( - "B decay distribution with CPV(|l|=1,Im(l)=0.7) (B0/B0bar)")) +frame4 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(|l|=1,Im(l)=0.7) (B0/B0bar)")) -data2.plotOn(frame4, Cut = "tagFlav==tagFlav::B0") -bcp.plotOn(frame4, Slice = (tagFlav, "B0")) +data2.plotOn(frame4, Cut="tagFlav==tagFlav::B0") +bcp.plotOn(frame4, Slice=(tagFlav, "B0")) -data2.plotOn(frame4, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bcp.plotOn(frame4, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) +data2.plotOn(frame4, Cut="tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bcp.plotOn(frame4, Slice=(tagFlav, "B0bar"), LineColor=ROOT.kCyan) # # Plot scenario 2 - sin(2b)=0.7, |l|=0.7 # ------------------------------------------------------------------------------- @@ -144,14 +118,13 @@ # Plot B0 and B0bar tagged data separately (sin2b = 0.7 plus direct CPV # |l|=0.5) -frame5 = dt.frame(ROOT.RooFit.Title( - "B decay distribution with CPV(|l|=0.7,Im(l)=0.7) (B0/B0bar)")) +frame5 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(|l|=0.7,Im(l)=0.7) (B0/B0bar)")) -data3.plotOn(frame5, Cut = "tagFlav==tagFlav::B0") -bcp.plotOn(frame5, Slice = (tagFlav, "B0")) +data3.plotOn(frame5, Cut="tagFlav==tagFlav::B0") +bcp.plotOn(frame5, Slice=(tagFlav, "B0")) -data3.plotOn(frame5, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bcp.plotOn(frame5, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) +data3.plotOn(frame5, Cut="tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bcp.plotOn(frame5, Slice=(tagFlav, "B0bar"), LineColor=ROOT.kCyan) # Generic B-decay with user coefficients @@ -167,20 +140,18 @@ Adel = ROOT.RooRealVar("Adel", "2Re(l)/[1+abs(l)**2]", 0.7) # Derived input parameters for pdf -DG = ROOT.RooFormulaVar("DG", "Delta Gamma", "@1/@0", - ROOT.RooArgList(tau, DGbG)) +DG = ROOT.RooFormulaVar("DG", "Delta Gamma", "@1/@0", ROOT.RooArgList(tau, DGbG)) # Construct coefficient functions for sin,cos, modulations of decay # distribution -fsin = ROOT.RooFormulaVar( - "fsin", "fsin", "@0*@1*(1-2*@2)", ROOT.RooArgList(Amix, tagFlav, w)) -fcos = ROOT.RooFormulaVar( - "fcos", "fcos", "@0*@1*(1-2*@2)", ROOT.RooArgList(Adir, tagFlav, w)) +fsin = ROOT.RooFormulaVar("fsin", "fsin", "@0*@1*(1-2*@2)", ROOT.RooArgList(Amix, tagFlav, w)) +fcos = ROOT.RooFormulaVar("fcos", "fcos", "@0*@1*(1-2*@2)", ROOT.RooArgList(Adir, tagFlav, w)) fsinh = ROOT.RooFormulaVar("fsinh", "fsinh", "@0", ROOT.RooArgList(Adel)) # Construct generic B decay pdf using above user coefficients -bcpg = ROOT.RooBDecay("bcpg", "bcpg", dt, tau, DG, ROOT.RooFit.RooConst( - 1), fsinh, fcos, fsin, dm, tm, ROOT.RooBDecay.DoubleSided) +bcpg = ROOT.RooBDecay( + "bcpg", "bcpg", dt, tau, DG, ROOT.RooFit.RooConst(1), fsinh, fcos, fsin, dm, tm, ROOT.RooBDecay.DoubleSided +) # Plot - Im(l)=0.7, e(l)=0.7 |l|=1, G/G=0.5 # ------------------------------------------------------------------------------------- @@ -189,14 +160,13 @@ data4 = bcpg.generate(ROOT.RooArgSet(dt, tagFlav), 10000) # Plot B0 and B0bar tagged data separately -frame6 = dt.frame(ROOT.RooFit.Title( - "B decay distribution with CPV(Im(l)=0.7,Re(l)=0.7,|l|=1,dG/G=0.5) (B0/B0bar)")) +frame6 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(Im(l)=0.7,Re(l)=0.7,|l|=1,dG/G=0.5) (B0/B0bar)")) -data4.plotOn(frame6, Cut = "tagFlav==tagFlav::B0") -bcpg.plotOn(frame6, Slice = (tagFlav, "B0")) +data4.plotOn(frame6, Cut="tagFlav==tagFlav::B0") +bcpg.plotOn(frame6, Slice=(tagFlav, "B0")) -data4.plotOn(frame6, Cut = "tagFlav==tagFlav::B0bar", MarkerColor = ROOT.kCyan) -bcpg.plotOn(frame6, Slice = (tagFlav, "B0bar"), LineColor = ROOT.kCyan) +data4.plotOn(frame6, Cut="tagFlav==tagFlav::B0bar", MarkerColor=ROOT.kCyan) +bcpg.plotOn(frame6, Slice=(tagFlav, "B0bar"), LineColor=ROOT.kCyan) c = ROOT.TCanvas("rf708_bphysics", "rf708_bphysics", 1200, 800) c.Divide(3, 2) diff --git a/tutorials/roofit/rf801_mcstudy.py b/tutorials/roofit/rf801_mcstudy.py index 7ef43ea6c1044..3cb93f3255040 100644 --- a/tutorials/roofit/rf801_mcstudy.py +++ b/tutorials/roofit/rf801_mcstudy.py @@ -28,22 +28,18 @@ sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) # Build Chebychev polynomial pdf -a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0., 1.) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, -1, 1.) +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, -1, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal pdf -sig1frac = ROOT.RooRealVar( - "sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) -sig = ROOT.RooAddPdf( - "sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) # Sum the composite signal and background -nbkg = ROOT.RooRealVar( - "nbkg", "number of background events, ", 150, 0, 1000) +nbkg = ROOT.RooRealVar("nbkg", "number of background events, ", 150, 0, 1000) nsig = ROOT.RooRealVar("nsig", "number of signal events", 150, 0, 1000) -model = ROOT.RooAddPdf( - "model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(nbkg, nsig)) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(nbkg, nsig)) # Create manager # --------------------------- @@ -69,9 +65,8 @@ ROOT.RooFit.Binned(True), ROOT.RooFit.Silence(), ROOT.RooFit.Extended(), - ROOT.RooFit.FitOptions( - ROOT.RooFit.Save(True), - ROOT.RooFit.PrintEvalErrors(0))) + ROOT.RooFit.FitOptions(ROOT.RooFit.Save(True), ROOT.RooFit.PrintEvalErrors(0)), +) # Generate and fit events # --------------------------------------------- @@ -86,17 +81,14 @@ # mean frame1 = mcstudy.plotParam(mean, ROOT.RooFit.Bins(40)) frame2 = mcstudy.plotError(mean, ROOT.RooFit.Bins(40)) -frame3 = mcstudy.plotPull(mean, ROOT.RooFit.Bins( - 40), ROOT.RooFit.FitGauss(True)) +frame3 = mcstudy.plotPull(mean, ROOT.RooFit.Bins(40), ROOT.RooFit.FitGauss(True)) # Plot distribution of minimized likelihood frame4 = mcstudy.plotNLL(ROOT.RooFit.Bins(40)) # Make some histograms from the parameter dataset -hh_cor_a0_s1f = ROOT.RooAbsData.createHistogram( - mcstudy.fitParDataSet(), "hh", a1, ROOT.RooFit.YVar(sig1frac)) -hh_cor_a0_a1 = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), - "hh", a0, ROOT.RooFit.YVar(a1)) +hh_cor_a0_s1f = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a1, ROOT.RooFit.YVar(sig1frac)) +hh_cor_a0_a1 = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a0, ROOT.RooFit.YVar(a1)) # Access some of the saved fit results from individual toys corrHist000 = mcstudy.fitResult(0).correlationHist("c000") diff --git a/tutorials/roofit/rf901_numintconfig.py b/tutorials/roofit/rf901_numintconfig.py index 7cf15506adf98..352ddcbb1da9d 100644 --- a/tutorials/roofit/rf901_numintconfig.py +++ b/tutorials/roofit/rf901_numintconfig.py @@ -39,13 +39,11 @@ # Construct pdf without support for analytical integrator for # demonstration purposes x = ROOT.RooRealVar("x", "x", -10, 10) -landau = ROOT.RooLandau("landau", "landau", x, - ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(0.1)) +landau = ROOT.RooLandau("landau", "landau", x, ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(0.1)) # Activate debug-level messages for topic integration to be able to follow # actions below -ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Integration)) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Integration)) # Calculate integral over landau with default choice of numeric integrator intLandau = landau.createIntegral(ROOT.RooArgSet(x)) @@ -57,15 +55,13 @@ # Construct a custom configuration which uses the adaptive Gauss-Kronrod technique # for closed 1D integrals -customConfig = ROOT.RooNumIntConfig( - ROOT.RooAbsReal.defaultIntegratorConfig()) +customConfig = ROOT.RooNumIntConfig(ROOT.RooAbsReal.defaultIntegratorConfig()) integratorGKNotExisting = customConfig.method1D().setLabel("RooAdaptiveGaussKronrodIntegrator1D") -if (integratorGKNotExisting) : - print("WARNING: RooAdaptiveGaussKronrodIntegrator is not existing because ROOT is built without Mathmore support") +if integratorGKNotExisting: + print("WARNING: RooAdaptiveGaussKronrodIntegrator is not existing because ROOT is built without Mathmore support") # Calculate integral over landau with custom integral specification -intLandau2 = landau.createIntegral( - ROOT.RooArgSet(x), ROOT.RooFit.NumIntConfig(customConfig)) +intLandau2 = landau.createIntegral(ROOT.RooArgSet(x), ROOT.RooFit.NumIntConfig(customConfig)) val2 = intLandau2.getVal() print(" [2] int_dx landau(x) = ", val2) @@ -84,26 +80,21 @@ # Another possibility: Change global default for 1D numeric integration # strategy on finite domains -if (not integratorGKNotExisting) : - ROOT.RooAbsReal.defaultIntegratorConfig().method1D().setLabel( - "RooAdaptiveGaussKronrodIntegrator1D") - -# Adjusting parameters of a speficic technique -# --------------------------------------------------------------------------------------- - -# Adjust maximum number of steps of ROOT.RooIntegrator1D in the global -# default configuration - ROOT.RooAbsReal.defaultIntegratorConfig().getConfigSection( - "RooIntegrator1D").setRealValue("maxSteps", 30) - -# Example of how to change the parameters of a numeric integrator -# (Each config section is a ROOT.RooArgSet with ROOT.RooRealVars holding real-valued parameters -# and ROOT.RooCategories holding parameters with a finite set of options) - customConfig.getConfigSection( - "RooAdaptiveGaussKronrodIntegrator1D").setRealValue("maxSeg", 50) - customConfig.getConfigSection( - "RooAdaptiveGaussKronrodIntegrator1D").setCatLabel("method", "15Points") - -# Example of how to print set of possible values for "method" category - customConfig.getConfigSection( - "RooAdaptiveGaussKronrodIntegrator1D").find("method").Print("v") +if not integratorGKNotExisting: + ROOT.RooAbsReal.defaultIntegratorConfig().method1D().setLabel("RooAdaptiveGaussKronrodIntegrator1D") + + # Adjusting parameters of a speficic technique + # --------------------------------------------------------------------------------------- + + # Adjust maximum number of steps of ROOT.RooIntegrator1D in the global + # default configuration + ROOT.RooAbsReal.defaultIntegratorConfig().getConfigSection("RooIntegrator1D").setRealValue("maxSteps", 30) + + # Example of how to change the parameters of a numeric integrator + # (Each config section is a ROOT.RooArgSet with ROOT.RooRealVars holding real-valued parameters + # and ROOT.RooCategories holding parameters with a finite set of options) + customConfig.getConfigSection("RooAdaptiveGaussKronrodIntegrator1D").setRealValue("maxSeg", 50) + customConfig.getConfigSection("RooAdaptiveGaussKronrodIntegrator1D").setCatLabel("method", "15Points") + + # Example of how to print set of possible values for "method" category + customConfig.getConfigSection("RooAdaptiveGaussKronrodIntegrator1D").find("method").Print("v") diff --git a/tutorials/roofit/rf902_numgenconfig.py b/tutorials/roofit/rf902_numgenconfig.py index 7539d9172812c..f372365581635 100644 --- a/tutorials/roofit/rf902_numgenconfig.py +++ b/tutorials/roofit/rf902_numgenconfig.py @@ -17,8 +17,9 @@ # Example pdf for use below x = ROOT.RooRealVar("x", "x", 0, 10) -model = ROOT.RooChebychev("model", "model", x, ROOT.RooArgList( - ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(0.5), ROOT.RooFit.RooConst(-0.1))) +model = ROOT.RooChebychev( + "model", "model", x, ROOT.RooArgList(ROOT.RooFit.RooConst(0), ROOT.RooFit.RooConst(0.5), ROOT.RooFit.RooConst(-0.1)) +) # Change global strategy for 1D sampling problems without conditional observable # (1st kFALSE) and without discrete observable (2nd kFALSE) from ROOT.RooFoamGenerator, @@ -28,7 +29,7 @@ ROOT.RooAbsPdf.defaultGeneratorConfig().method1D(False, False).setLabel("RooAcceptReject") # Generate 10Kevt using ROOT.RooAcceptReject -data_ar = model.generate(ROOT.RooArgSet(x), 10000, verbose = True) +data_ar = model.generate(ROOT.RooArgSet(x), 10000, verbose=True) data_ar.Print() # Adjusting default config for a specific pdf @@ -44,14 +45,12 @@ # Adjust maximum number of steps of ROOT.RooIntegrator1D in the global # default configuration -ROOT.RooAbsPdf.defaultGeneratorConfig().getConfigSection( - "RooAcceptReject").setRealValue("nTrial1D", 2000) +ROOT.RooAbsPdf.defaultGeneratorConfig().getConfigSection("RooAcceptReject").setRealValue("nTrial1D", 2000) # Example of how to change the parameters of a numeric integrator # (Each config section is a ROOT.RooArgSet with ROOT.RooRealVars holding real-valued parameters # and ROOT.RooCategories holding parameters with a finite set of options) -model.specialGeneratorConfig().getConfigSection( - "RooFoamGenerator").setRealValue("chatLevel", 1) +model.specialGeneratorConfig().getConfigSection("RooFoamGenerator").setRealValue("chatLevel", 1) # Generate 10Kevt using ROOT.RooFoamGenerator (FOAM verbosity increased # with above chatLevel adjustment for illustration purposes) diff --git a/tutorials/roofit/rf903_numintcache.py b/tutorials/roofit/rf903_numintcache.py index b7da5a3d5e6f7..08af66fdd6834 100644 --- a/tutorials/roofit/rf903_numintcache.py +++ b/tutorials/roofit/rf903_numintcache.py @@ -29,7 +29,8 @@ def getWorkspace(mode): # Make a difficult to normalize pdf in 3 dimensions that is # integrated numerically. w.factory( - "EXPR::model('1/((x-a)*(x-a)+0.01)+1/((y-a)*(y-a)+0.01)+1/((z-a)*(z-a)+0.01)',x[-1,1],y[-1,1],z[-1,1],a[-5,5])") + "EXPR::model('1/((x-a)*(x-a)+0.01)+1/((y-a)*(y-a)+0.01)+1/((z-a)*(z-a)+0.01)',x[-1,1],y[-1,1],z[-1,1],a[-5,5])" + ) if mode == 1: # Instruct model to precalculate normalization integral that integrate at least @@ -46,7 +47,7 @@ def getWorkspace(mode): w.pdf("model").getVal(normSet) w.writeToFile("rf903_numintcache.root") - if (mode == 2): + if mode == 2: # Load preexisting workspace from file in mode==2 f = ROOT.TFile("rf903_numintcache.root") w = f.Get("w") @@ -72,12 +73,11 @@ def getWorkspace(mode): # Show plot of cached integral values hhcache = w.expensiveObjectCache().getObj(1) - if (hhcache): + if hhcache: ROOT.TCanvas("rf903_numintcache", "rf903_numintcache", 600, 600) hhcache.createHistogram("a").Draw() else: - ROOT.RooFit.Error("rf903_numintcache", - "Cached histogram is not existing in workspace") + ROOT.RooFit.Error("rf903_numintcache", "Cached histogram is not existing in workspace") sys.exit() # Use pdf from workspace for generation and fitting @@ -85,15 +85,10 @@ def getWorkspace(mode): # ROOT.This is always slow (need to find maximum function value # empirically in 3D space) -d = w.pdf("model").generate( - ROOT.RooArgSet( - w.var("x"), - w.var("y"), - w.var("z")), - 1000) +d = w.pdf("model").generate(ROOT.RooArgSet(w.var("x"), w.var("y"), w.var("z")), 1000) # ROOT.This is slow in mode 0, fast in mode 1 -w.pdf("model").fitTo(d, Verbose = True, Timer = True) +w.pdf("model").fitTo(d, Verbose=True, Timer=True) # Projection on x (always slow as 2D integral over Y, at fitted value of a # is not cached) From 6a7e31879493ab4585ec88cdb3f6709253648f3e Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Thu, 10 Jun 2021 11:40:56 +0200 Subject: [PATCH 181/309] [ntuple] Add the `RNTupleMetrics::GetLocalCounter()` member function This function searches the RNTupleMetrics instance on which it is called only, i.e. it is the 'get' counterpart of the `Contains()` function. It can be used by a callable fed into a `RNTupleCalcPerf` instance to query sibling counters. --- tree/ntuple/v7/inc/ROOT/RNTupleMetrics.hxx | 5 ++++- tree/ntuple/v7/src/RNTupleMetrics.cxx | 16 ++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleMetrics.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleMetrics.hxx index 83cc892596a43..f1ff2b8cdd602 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleMetrics.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleMetrics.hxx @@ -313,7 +313,10 @@ public: return ptrCounter; } - /// Searches this object and all the observed sub metrics. Returns nullptr if name is not found. + /// Searches counters registered in this object only. Returns nullptr if `name` is not found. + const RNTuplePerfCounter *GetLocalCounter(std::string_view name) const; + /// Searches this object and all the observed sub metrics. `name` must start with the prefix used + /// by this RNTupleMetrics instance. Returns nullptr if `name` is not found. const RNTuplePerfCounter *GetCounter(std::string_view name) const; void ObserveMetrics(RNTupleMetrics &observee); diff --git a/tree/ntuple/v7/src/RNTupleMetrics.cxx b/tree/ntuple/v7/src/RNTupleMetrics.cxx index a47693d760ceb..36da0a2d121c7 100644 --- a/tree/ntuple/v7/src/RNTupleMetrics.cxx +++ b/tree/ntuple/v7/src/RNTupleMetrics.cxx @@ -29,12 +29,18 @@ std::string ROOT::Experimental::Detail::RNTuplePerfCounter::ToString() const } bool ROOT::Experimental::Detail::RNTupleMetrics::Contains(const std::string &name) const +{ + return GetLocalCounter(name) != nullptr; +} + +const ROOT::Experimental::Detail::RNTuplePerfCounter* +ROOT::Experimental::Detail::RNTupleMetrics::GetLocalCounter(std::string_view name) const { for (const auto &c : fCounters) { if (c->GetName() == name) - return true; + return c.get(); } - return false; + return nullptr; } const ROOT::Experimental::Detail::RNTuplePerfCounter* @@ -45,10 +51,8 @@ ROOT::Experimental::Detail::RNTupleMetrics::GetCounter(std::string_view name) co return nullptr; auto innerName = name.substr(prefix.length()); - for (const auto &c : fCounters) { - if (c->GetName() == innerName) - return c.get(); - } + if (auto counter = GetLocalCounter(innerName)) + return counter; for (auto m : fObservedMetrics) { auto counter = m->GetCounter(innerName); From d4e1e022d3599273beb8af1c178020eb7d42c298 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Thu, 10 Jun 2021 12:28:21 +0200 Subject: [PATCH 182/309] [ntuple] Provide a set of default performance counters in RPageSink/RPageSource These counters can be enabled in a subclass by calling `EnableDefaultMetrics()`. This set can be extended later via `fMetrics.MakeCounter<>()`. Alternatively, a subclass might provide its own default metrics object by overriding the `GetMetrics` member function --- tree/ntuple/v7/inc/ROOT/RPageStorage.hxx | 69 +++++++++++++- tree/ntuple/v7/src/RPageStorage.cxx | 116 +++++++++++++++++++++-- 2 files changed, 174 insertions(+), 11 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx index 9ca96d04075f8..e85c8b89336e4 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx @@ -17,6 +17,7 @@ #define ROOT7_RPageStorage #include +#include #include #include #include @@ -44,7 +45,6 @@ class RNTupleCompressor; class RNTupleDecompressor; class RPagePool; class RFieldBase; -class RNTupleMetrics; enum class EPageStorageType { kSink, @@ -128,8 +128,9 @@ public: /// of allocating pages. virtual void ReleasePage(RPage &page) = 0; - /// Returns an empty metrics. Page storage implementations usually have their own metrics. - virtual RNTupleMetrics &GetMetrics(); + /// Page storage implementations have their own metrics. The RPageSink and RPageSource classes provide + /// a default set of metrics. + virtual RNTupleMetrics &GetMetrics() = 0; /// Returns the NTuple name. const std::string &GetNTupleName() const { return fNTupleName; } @@ -149,6 +150,19 @@ up to the given entry number are committed. // clang-format on class RPageSink : public RPageStorage { protected: + /// Default I/O performance counters that get registered in fMetrics + struct RCounters { + RNTupleAtomicCounter &fNPageCommitted; + RNTupleAtomicCounter &fSzWritePayload; + RNTupleAtomicCounter &fSzZip; + RNTupleAtomicCounter &fTimeWallWrite; + RNTupleAtomicCounter &fTimeWallZip; + RNTupleTickCounter &fTimeCpuWrite; + RNTupleTickCounter &fTimeCpuZip; + }; + std::unique_ptr fCounters; + RNTupleMetrics fMetrics; + RNTupleWriteOptions fOptions; /// Helper to zip pages and header/footer; includes a 16MB (kMAXZIPBUF) zip buffer. @@ -186,6 +200,17 @@ protected: static RSealedPage SealPage(const RPage &page, const RColumnElementBase &element, int compressionSetting, void *buf); + /// Enables the default set of metrics provided by RPageSink. `prefix` will be used as the prefix for + /// the counters registered in the internal RNTupleMetrics object. + /// This set of counters can be extended by a subclass by calling `fMetrics.MakeCounter<...>()`. + /// + /// A subclass using the default set of metrics is always responsible for updating the counters + /// appropriately, e.g. `fCounters->fNPageCommited.Inc()` + /// + /// Alternatively, a subclass might provide its own RNTupleMetrics object by overriding the + /// GetMetrics() member function. + void EnableDefaultMetrics(const std::string &prefix); + public: RPageSink(std::string_view ntupleName, const RNTupleWriteOptions &options); @@ -222,6 +247,9 @@ public: /// Get a new, empty page for the given column that can be filled with up to nElements. If nElements is zero, /// the page sink picks an appropriate size. virtual RPage ReservePage(ColumnHandle_t columnHandle, std::size_t nElements = 0) = 0; + + /// Returns the default metrics object. Subclasses might alternatively provide their own metrics object by overriding this. + virtual RNTupleMetrics &GetMetrics() override { return fMetrics; }; }; // clang-format off @@ -240,6 +268,30 @@ public: using ColumnSet_t = std::unordered_set; protected: + /// Default I/O performance counters that get registered in fMetrics + struct RCounters { + RNTupleAtomicCounter &fNReadV; + RNTupleAtomicCounter &fNRead; + RNTupleAtomicCounter &fSzReadPayload; + RNTupleAtomicCounter &fSzReadOverhead; + RNTupleAtomicCounter &fSzUnzip; + RNTupleAtomicCounter &fNClusterLoaded; + RNTupleAtomicCounter &fNPageLoaded; + RNTupleAtomicCounter &fNPagePopulated; + RNTupleAtomicCounter &fTimeWallRead; + RNTupleAtomicCounter &fTimeWallUnzip; + RNTupleTickCounter &fTimeCpuRead; + RNTupleTickCounter &fTimeCpuUnzip; + RNTupleCalcPerf &fBandwidthReadUncompressed; + RNTupleCalcPerf &fBandwidthReadCompressed; + RNTupleCalcPerf &fBandwidthUnzip; + RNTupleCalcPerf &fFractionReadOverhead; + RNTupleCalcPerf &fCompressionRatio; + }; + std::unique_ptr fCounters; + /// Wraps the I/O counters and is observed by the RNTupleReader metrics + RNTupleMetrics fMetrics; + RNTupleReadOptions fOptions; RNTupleDescriptor fDescriptor; /// The active columns are implicitly defined by the model fields or views @@ -261,6 +313,14 @@ protected: /// Usage of this method requires construction of fDecompressor. std::unique_ptr UnsealPage(const RSealedPage &sealedPage, const RColumnElementBase &element); + /// Enables the default set of metrics provided by RPageSource. `prefix` will be used as the prefix for + /// the counters registered in the internal RNTupleMetrics object. + /// A subclass using the default set of metrics is responsible for updating the counters + /// appropriately, e.g. `fCounters->fNRead.Inc()` + /// Alternatively, a subclass might provide its own RNTupleMetrics object by overriding the + /// GetMetrics() member function. + void EnableDefaultMetrics(const std::string &prefix); + public: RPageSource(std::string_view ntupleName, const RNTupleReadOptions &fOptions); RPageSource(const RPageSource&) = delete; @@ -313,6 +373,9 @@ public: /// actual implementation will only run if a task scheduler is set. In practice, a task scheduler is set /// if implicit multi-threading is turned on. void UnzipCluster(RCluster *cluster); + + /// Returns the default metrics object. Subclasses might alternatively override the method and provide their own metrics object. + virtual RNTupleMetrics &GetMetrics() override { return fMetrics; }; }; } // namespace Detail diff --git a/tree/ntuple/v7/src/RPageStorage.cxx b/tree/ntuple/v7/src/RPageStorage.cxx index c8babbd6a1f13..beb029d69999c 100644 --- a/tree/ntuple/v7/src/RPageStorage.cxx +++ b/tree/ntuple/v7/src/RPageStorage.cxx @@ -42,18 +42,12 @@ ROOT::Experimental::Detail::RPageStorage::~RPageStorage() { } -ROOT::Experimental::Detail::RNTupleMetrics &ROOT::Experimental::Detail::RPageStorage::GetMetrics() -{ - static RNTupleMetrics metrics(""); - return metrics; -} - //------------------------------------------------------------------------------ ROOT::Experimental::Detail::RPageSource::RPageSource(std::string_view name, const RNTupleReadOptions &options) - : RPageStorage(name), fOptions(options) + : RPageStorage(name), fMetrics(""), fOptions(options) { } @@ -139,12 +133,103 @@ std::unique_ptr ROOT::Experimental::Detail::RPageSource::Unsea return pageBuffer; } +void ROOT::Experimental::Detail::RPageSource::EnableDefaultMetrics(const std::string &prefix) +{ + fMetrics = RNTupleMetrics(prefix); + fCounters = std::unique_ptr(new RCounters{ + *fMetrics.MakeCounter("nReadV", "", "number of vector read requests"), + *fMetrics.MakeCounter("nRead", "", "number of byte ranges read"), + *fMetrics.MakeCounter("szReadPayload", "B", "volume read from storage (required)"), + *fMetrics.MakeCounter("szReadOverhead", "B", "volume read from storage (overhead)"), + *fMetrics.MakeCounter("szUnzip", "B", "volume after unzipping"), + *fMetrics.MakeCounter("nClusterLoaded", "", + "number of partial clusters preloaded from storage"), + *fMetrics.MakeCounter("nPageLoaded", "", "number of pages loaded from storage"), + *fMetrics.MakeCounter("nPagePopulated", "", "number of populated pages"), + *fMetrics.MakeCounter("timeWallRead", "ns", "wall clock time spent reading"), + *fMetrics.MakeCounter("timeWallUnzip", "ns", "wall clock time spent decompressing"), + *fMetrics.MakeCounter*>("timeCpuRead", "ns", "CPU time spent reading"), + *fMetrics.MakeCounter*> ("timeCpuUnzip", "ns", + "CPU time spent decompressing"), + *fMetrics.MakeCounter ("bwRead", "MB/s", "bandwidth compressed bytes read per second", + fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { + if (const auto szReadPayload = metrics.GetLocalCounter("szReadPayload")) { + if (const auto szReadOverhead = metrics.GetLocalCounter("szReadOverhead")) { + if (const auto timeWallRead = metrics.GetLocalCounter("timeWallRead")) { + if (auto walltime = timeWallRead->GetValueAsInt()) { + double payload = szReadPayload->GetValueAsInt(); + double overhead = szReadOverhead->GetValueAsInt(); + // unit: bytes / nanosecond = GB/s + return {true, (1000. * (payload + overhead) / walltime)}; + } + } + } + } + return {false, -1.}; + } + ), + *fMetrics.MakeCounter ("bwReadUnzip", "MB/s", "bandwidth uncompressed bytes read per second", + fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { + if (const auto szUnzip = metrics.GetLocalCounter("szUnzip")) { + if (const auto timeWallRead = metrics.GetLocalCounter("timeWallRead")) { + if (auto walltime = timeWallRead->GetValueAsInt()) { + double unzip = szUnzip->GetValueAsInt(); + // unit: bytes / nanosecond = GB/s + return {true, 1000. * unzip / walltime}; + } + } + } + return {false, -1.}; + } + ), + *fMetrics.MakeCounter ("bwUnzip", "MB/s", "decompression bandwidth of uncompressed bytes per second", + fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { + if (const auto szUnzip = metrics.GetLocalCounter("szUnzip")) { + if (const auto timeWallUnzip = metrics.GetLocalCounter("timeWallUnzip")) { + if (auto walltime = timeWallUnzip->GetValueAsInt()) { + double unzip = szUnzip->GetValueAsInt(); + // unit: bytes / nanosecond = GB/s + return {true, 1000. * unzip / walltime}; + } + } + } + return {false, -1.}; + } + ), + *fMetrics.MakeCounter ("rtReadEfficiency", "", "ratio of payload over all bytes read", + fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { + if (const auto szReadPayload = metrics.GetLocalCounter("szReadPayload")) { + if (const auto szReadOverhead = metrics.GetLocalCounter("szReadOverhead")) { + if (auto payload = szReadPayload->GetValueAsInt()) { + // r/(r+o) = 1/((r+o)/r) = 1/(1 + o/r) + return {true, 1./(1. + (1. * szReadOverhead->GetValueAsInt()) / payload)}; + } + } + } + return {false, -1.}; + } + ), + *fMetrics.MakeCounter ("rtCompression", "", "ratio of compressed bytes / uncompressed bytes", + fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { + if (const auto szReadPayload = metrics.GetLocalCounter("szReadPayload")) { + if (const auto szUnzip = metrics.GetLocalCounter("szUnzip")) { + if (auto unzip = szUnzip->GetValueAsInt()) { + return {true, (1. * szReadPayload->GetValueAsInt()) / unzip}; + } + } + } + return {false, -1.}; + } + ) + }); +} + //------------------------------------------------------------------------------ ROOT::Experimental::Detail::RPageSink::RPageSink(std::string_view name, const RNTupleWriteOptions &options) - : RPageStorage(name), fOptions(options) + : RPageStorage(name), fMetrics(""), fOptions(options) { } @@ -306,3 +391,18 @@ ROOT::Experimental::Detail::RPageSink::SealPage( R__ASSERT(fCompressor); return SealPage(page, element, compressionSetting, fCompressor->GetZipBuffer()); } + +void ROOT::Experimental::Detail::RPageSink::EnableDefaultMetrics(const std::string &prefix) +{ + fMetrics = RNTupleMetrics(prefix); + fCounters = std::unique_ptr(new RCounters{ + *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage"), + *fMetrics.MakeCounter("szWritePayload", "B", "volume written for committed pages"), + *fMetrics.MakeCounter("szZip", "B", "volume before zipping"), + *fMetrics.MakeCounter("timeWallWrite", "ns", "wall clock time spent writing"), + *fMetrics.MakeCounter("timeWallZip", "ns", "wall clock time spent compressing"), + *fMetrics.MakeCounter*>("timeCpuWrite", "ns", "CPU time spent writing"), + *fMetrics.MakeCounter*> ("timeCpuZip", "ns", + "CPU time spent compressing") + }); +} From b58bc62e7800529ec3597737148c4e251770d133 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Thu, 10 Jun 2021 12:42:50 +0200 Subject: [PATCH 183/309] [ntuple] RPageStorage{File,Daos}: use the performance counters provided by the base class --- tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx | 35 ------- tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx | 41 -------- tree/ntuple/v7/src/RPageStorageDaos.cxx | 29 +----- tree/ntuple/v7/src/RPageStorageFile.cxx | 100 +------------------ 4 files changed, 4 insertions(+), 201 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx index c1a55dc01e65c..a316dc259dcaf 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx @@ -17,7 +17,6 @@ #define ROOT7_RPageStorageDaos #include -#include #include #include @@ -86,18 +85,6 @@ Currently, an object is allocated for each page + 3 additional objects (anchor/h // clang-format on class RPageSinkDaos : public RPageSink { private: - /// I/O performance counters that get registered in fMetrics - struct RCounters { - RNTupleAtomicCounter &fNPageCommitted; - RNTupleAtomicCounter &fSzWritePayload; - RNTupleAtomicCounter &fSzZip; - RNTupleAtomicCounter &fTimeWallWrite; - RNTupleAtomicCounter &fTimeWallZip; - RNTupleTickCounter &fTimeCpuWrite; - RNTupleTickCounter &fTimeCpuZip; - }; - std::unique_ptr fCounters; - RNTupleMetrics fMetrics; std::unique_ptr fPageAllocator; /// \brief Underlying DAOS container. An internal `std::shared_ptr` keep the pool connection alive. @@ -127,8 +114,6 @@ public: RPage ReservePage(ColumnHandle_t columnHandle, std::size_t nElements = 0) final; void ReleasePage(RPage &page) final; - - RNTupleMetrics &GetMetrics() final { return fMetrics; } }; @@ -155,24 +140,6 @@ public: // clang-format on class RPageSourceDaos : public RPageSource { private: - /// I/O performance counters that get registered in fMetrics - struct RCounters { - RNTupleAtomicCounter &fNReadV; - RNTupleAtomicCounter &fNRead; - RNTupleAtomicCounter &fSzReadPayload; - RNTupleAtomicCounter &fSzUnzip; - RNTupleAtomicCounter &fNClusterLoaded; - RNTupleAtomicCounter &fNPageLoaded; - RNTupleAtomicCounter &fNPagePopulated; - RNTupleAtomicCounter &fTimeWallRead; - RNTupleAtomicCounter &fTimeWallUnzip; - RNTupleTickCounter &fTimeCpuRead; - RNTupleTickCounter &fTimeCpuUnzip; - }; - std::unique_ptr fCounters; - /// Wraps the I/O counters and is observed by the RNTupleReader metrics - RNTupleMetrics fMetrics; - /// Populated pages might be shared; the memory buffer is managed by the RPageAllocatorDaos std::unique_ptr fPageAllocator; // TODO: the page pool should probably be handled by the base class. @@ -209,8 +176,6 @@ public: RSealedPage &sealedPage) final; std::unique_ptr LoadCluster(DescriptorId_t clusterId, const ColumnSet_t &columns) final; - - RNTupleMetrics &GetMetrics() final { return fMetrics; } }; diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx index ec78655fadd0a..204f8c6a12ae7 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageFile.hxx @@ -17,7 +17,6 @@ #define ROOT7_RPageStorageFile #include -#include #include #include #include @@ -55,18 +54,6 @@ The written file can be either in ROOT format or in RNTuple bare format. // clang-format on class RPageSinkFile : public RPageSink { private: - /// I/O performance counters that get registered in fMetrics - struct RCounters { - RNTupleAtomicCounter &fNPageCommitted; - RNTupleAtomicCounter &fSzWritePayload; - RNTupleAtomicCounter &fSzZip; - RNTupleAtomicCounter &fTimeWallWrite; - RNTupleAtomicCounter &fTimeWallZip; - RNTupleTickCounter &fTimeCpuWrite; - RNTupleTickCounter &fTimeCpuZip; - }; - std::unique_ptr fCounters; - RNTupleMetrics fMetrics; std::unique_ptr fPageAllocator; std::unique_ptr fWriter; @@ -100,8 +87,6 @@ public: RPage ReservePage(ColumnHandle_t columnHandle, std::size_t nElements = 0) final; void ReleasePage(RPage &page) final; - - RNTupleMetrics &GetMetrics() final { return fMetrics; } }; @@ -132,30 +117,6 @@ public: static constexpr std::size_t kMaxPageSize = 1024 * 1024; private: - /// I/O performance counters that get registered in fMetrics - struct RCounters { - RNTupleAtomicCounter &fNReadV; - RNTupleAtomicCounter &fNRead; - RNTupleAtomicCounter &fSzReadPayload ; - RNTupleAtomicCounter &fSzReadOverhead; - RNTupleAtomicCounter &fSzUnzip; - RNTupleAtomicCounter &fNClusterLoaded; - RNTupleAtomicCounter &fNPageLoaded; - RNTupleAtomicCounter &fNPagePopulated; - RNTupleAtomicCounter &fTimeWallRead; - RNTupleAtomicCounter &fTimeWallUnzip; - RNTupleTickCounter &fTimeCpuRead; - RNTupleTickCounter &fTimeCpuUnzip; - RNTupleCalcPerf &fBandwidthReadUncompressed; - RNTupleCalcPerf &fBandwidthReadCompressed; - RNTupleCalcPerf &fBandwidthUnzip; - RNTupleCalcPerf &fFractionReadOverhead; - RNTupleCalcPerf &fCompressionRatio; - }; - std::unique_ptr fCounters; - /// Wraps the I/O counters and is observed by the RNTupleReader metrics - RNTupleMetrics fMetrics; - /// Populated pages might be shared; there memory buffer is managed by the RPageAllocatorFile std::unique_ptr fPageAllocator; /// The page pool might, at some point, be used by multiple page sources @@ -197,8 +158,6 @@ public: RSealedPage &sealedPage) final; std::unique_ptr LoadCluster(DescriptorId_t clusterId, const ColumnSet_t &columns) final; - - RNTupleMetrics &GetMetrics() final { return fMetrics; } }; diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index 602f0b564f7af..4e1dccc9f38ac 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -108,23 +108,13 @@ ROOT::Experimental::Detail::RDaosNTupleAnchor::Deserialize(const void *buffer) ROOT::Experimental::Detail::RPageSinkDaos::RPageSinkDaos(std::string_view ntupleName, std::string_view uri, const RNTupleWriteOptions &options) : RPageSink(ntupleName, options) - , fMetrics("RPageSinkDaos") , fPageAllocator(std::make_unique()) , fURI(uri) { R__LOG_WARNING(NTupleLog()) << "The DAOS backend is experimental and still under development. " << "Do not store real data with this version of RNTuple!"; - fCounters = std::unique_ptr(new RCounters{ - *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage"), - *fMetrics.MakeCounter("szWritePayload", "B", "volume written for committed pages"), - *fMetrics.MakeCounter("szZip", "B", "volume before zipping"), - *fMetrics.MakeCounter("timeWallWrite", "ns", "wall clock time spent writing"), - *fMetrics.MakeCounter("timeWallZip", "ns", "wall clock time spent compressing"), - *fMetrics.MakeCounter*>("timeCpuWrite", "ns", "CPU time spent writing"), - *fMetrics.MakeCounter*> ("timeCpuZip", "ns", - "CPU time spent compressing") - }); fCompressor = std::make_unique(); + EnableDefaultMetrics("RPageSinkDaos"); } @@ -274,28 +264,13 @@ void ROOT::Experimental::Detail::RPageAllocatorDaos::DeletePage(const RPage& pag ROOT::Experimental::Detail::RPageSourceDaos::RPageSourceDaos(std::string_view ntupleName, std::string_view uri, const RNTupleReadOptions &options) : RPageSource(ntupleName, options) - , fMetrics("RPageSourceDaos") , fPageAllocator(std::make_unique()) , fPagePool(std::make_shared()) , fURI(uri) , fClusterPool(std::make_unique(*this)) { fDecompressor = std::make_unique(); - fCounters = std::unique_ptr(new RCounters{ - *fMetrics.MakeCounter("nReadV", "", "number of vector read requests"), - *fMetrics.MakeCounter("nRead", "", "number of byte ranges read"), - *fMetrics.MakeCounter("szReadPayload", "B", "volume read from container"), - *fMetrics.MakeCounter ("szUnzip", "B", "volume after unzipping"), - *fMetrics.MakeCounter("nClusterLoaded", "", - "number of partial clusters preloaded from storage"), - *fMetrics.MakeCounter ("nPageLoaded", "", "number of pages loaded from storage"), - *fMetrics.MakeCounter ("nPagePopulated", "", "number of populated pages"), - *fMetrics.MakeCounter("timeWallRead", "ns", "wall clock time spent reading"), - *fMetrics.MakeCounter ("timeWallUnzip", "ns", "wall clock time spent decompressing"), - *fMetrics.MakeCounter*>("timeCpuRead", "ns", "CPU time spent reading"), - *fMetrics.MakeCounter*> ("timeCpuUnzip", "ns", - "CPU time spent decompressing") - }); + EnableDefaultMetrics("RPageSourceDaos"); auto args = ParseDaosURI(uri); auto pool = std::make_shared(args.fPoolUuid, args.fSvcReplicas); diff --git a/tree/ntuple/v7/src/RPageStorageFile.cxx b/tree/ntuple/v7/src/RPageStorageFile.cxx index f582732b3f073..ea15f0b2b6738 100644 --- a/tree/ntuple/v7/src/RPageStorageFile.cxx +++ b/tree/ntuple/v7/src/RPageStorageFile.cxx @@ -45,22 +45,12 @@ ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, const RNTupleWriteOptions &options) : RPageSink(ntupleName, options) - , fMetrics("RPageSinkFile") , fPageAllocator(std::make_unique()) { R__LOG_WARNING(NTupleLog()) << "The RNTuple file format will change. " << "Do not store real data with this version of RNTuple!"; - fCounters = std::unique_ptr(new RCounters{ - *fMetrics.MakeCounter("nPageCommitted", "", "number of pages committed to storage"), - *fMetrics.MakeCounter("szWritePayload", "B", "volume written for committed pages"), - *fMetrics.MakeCounter("szZip", "B", "volume before zipping"), - *fMetrics.MakeCounter("timeWallWrite", "ns", "wall clock time spent writing"), - *fMetrics.MakeCounter("timeWallZip", "ns", "wall clock time spent compressing"), - *fMetrics.MakeCounter*>("timeCpuWrite", "ns", "CPU time spent writing"), - *fMetrics.MakeCounter*> ("timeCpuZip", "ns", - "CPU time spent compressing") - }); fCompressor = std::make_unique(); + EnableDefaultMetrics("RPageSinkFile"); } @@ -224,98 +214,12 @@ void ROOT::Experimental::Detail::RPageAllocatorFile::DeletePage(const RPage& pag ROOT::Experimental::Detail::RPageSourceFile::RPageSourceFile(std::string_view ntupleName, const RNTupleReadOptions &options) : RPageSource(ntupleName, options) - , fMetrics("RPageSourceFile") , fPageAllocator(std::make_unique()) , fPagePool(std::make_shared()) , fClusterPool(std::make_unique(*this)) { fDecompressor = std::make_unique(); - fCounters = std::unique_ptr(new RCounters{ - *fMetrics.MakeCounter("nReadV", "", "number of vector read requests"), - *fMetrics.MakeCounter("nRead", "", "number of byte ranges read"), - *fMetrics.MakeCounter("szReadPayload", "B", "volume read from file (required)"), - *fMetrics.MakeCounter("szReadOverhead", "B", "volume read from file (overhead)"), - *fMetrics.MakeCounter("szUnzip", "B", "volume after unzipping"), - *fMetrics.MakeCounter("nClusterLoaded", "", - "number of partial clusters preloaded from storage"), - *fMetrics.MakeCounter("nPageLoaded", "", "number of pages loaded from storage"), - *fMetrics.MakeCounter("nPagePopulated", "", "number of populated pages"), - *fMetrics.MakeCounter("timeWallRead", "ns", "wall clock time spent reading"), - *fMetrics.MakeCounter("timeWallUnzip", "ns", "wall clock time spent decompressing"), - *fMetrics.MakeCounter*>("timeCpuRead", "ns", "CPU time spent reading"), - *fMetrics.MakeCounter*> ("timeCpuUnzip", "ns", - "CPU time spent decompressing"), - *fMetrics.MakeCounter ("bwRead", "MB/s", "bandwidth compressed bytes read per second", - fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { - if (const auto szReadPayload = metrics.GetCounter("RPageSourceFile.szReadPayload")) { - if (const auto szReadOverhead = metrics.GetCounter("RPageSourceFile.szReadOverhead")) { - if (const auto timeWallRead = metrics.GetCounter("RPageSourceFile.timeWallRead")) { - if (auto walltime = timeWallRead->GetValueAsInt()) { - double payload = szReadPayload->GetValueAsInt(); - double overhead = szReadOverhead->GetValueAsInt(); - // unit: bytes / nanosecond = GB/s - return {true, (1000. * (payload + overhead) / walltime)}; - } - } - } - } - return {false, -1.}; - } - ), - *fMetrics.MakeCounter ("bwReadUnzip", "MB/s", "bandwidth uncompressed bytes read per second", - fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { - if (const auto szUnzip = metrics.GetCounter("RPageSourceFile.szUnzip")) { - if (const auto timeWallRead = metrics.GetCounter("RPageSourceFile.timeWallRead")) { - if (auto walltime = timeWallRead->GetValueAsInt()) { - double unzip = szUnzip->GetValueAsInt(); - // unit: bytes / nanosecond = GB/s - return {true, 1000. * unzip / walltime}; - } - } - } - return {false, -1.}; - } - ), - *fMetrics.MakeCounter ("bwUnzip", "MB/s", "decompression bandwidth of uncompressed bytes per second", - fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { - if (const auto szUnzip = metrics.GetCounter("RPageSourceFile.szUnzip")) { - if (const auto timeWallUnzip = metrics.GetCounter("RPageSourceFile.timeWallUnzip")) { - if (auto walltime = timeWallUnzip->GetValueAsInt()) { - double unzip = szUnzip->GetValueAsInt(); - // unit: bytes / nanosecond = GB/s - return {true, 1000. * unzip / walltime}; - } - } - } - return {false, -1.}; - } - ), - *fMetrics.MakeCounter ("rtReadEfficiency", "", "ratio of payload over all bytes read", - fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { - if (const auto szReadPayload = metrics.GetCounter("RPageSourceFile.szReadPayload")) { - if (const auto szReadOverhead = metrics.GetCounter("RPageSourceFile.szReadOverhead")) { - if (auto payload = szReadPayload->GetValueAsInt()) { - // r/(r+o) = 1/((r+o)/r) = 1/(1 + o/r) - return {true, 1./(1. + (1. * szReadOverhead->GetValueAsInt()) / payload)}; - } - } - } - return {false, -1.}; - } - ), - *fMetrics.MakeCounter ("rtCompression", "", "ratio of compressed bytes / uncompressed bytes", - fMetrics, [](const RNTupleMetrics &metrics) -> std::pair { - if (const auto szReadPayload = metrics.GetCounter("RPageSourceFile.szReadPayload")) { - if (const auto szUnzip = metrics.GetCounter("RPageSourceFile.szUnzip")) { - if (auto unzip = szUnzip->GetValueAsInt()) { - return {true, (1. * szReadPayload->GetValueAsInt()) / unzip}; - } - } - } - return {false, -1.}; - } - ) - }); + EnableDefaultMetrics("RPageSourceFile"); } From 89d5c80305e85b68da5d7e0599e038b6e811770a Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Fri, 11 Jun 2021 13:02:16 +0200 Subject: [PATCH 184/309] [ntuple,c++20] Add explicit constructor in RSealedPage; fixes -std=c++20 compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C++20 does not allow aggregate initialization, i.e. `{ ... }`, if a struct/class has explicitly defaulted or deleted constructors. This fixes the following compilation error: ``` tree/ntuple/v7/src/RPageStorageFile.cxx: In member function ‘ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePageFromCluster(ROOT::Experimental::Detail::RPageStorage::ColumnHandle_t, const ROOT::Experimental::RClusterDescriptor&, ROOT::Experimental::RClusterSize::ValueType)’: tree/ntuple/v7/src/RPageStorageFile.cxx:411:30: error: cannot convert ‘’ to ‘const ROOT::Experimental::Detail::RPageStorage::RSealedPage&’ 411 | pageBuffer = UnsealPage({sealedPageBuffer, bytesOnStorage, pageInfo.fNElements}, *element); | ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` --- tree/ntuple/v7/inc/ROOT/RPageStorage.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx index e85c8b89336e4..8fe63cc9c5a78 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx @@ -85,6 +85,7 @@ public: std::uint32_t fNElements = 0; RSealedPage() = default; + RSealedPage(const void *b, std::uint32_t s, std::uint32_t n) : fBuffer(b), fSize(s), fNElements(n) {} RSealedPage(const RSealedPage &other) = delete; RSealedPage& operator =(const RSealedPage &other) = delete; RSealedPage(RSealedPage &&other) = default; From e7b32cfca6e3be966456f7748b120631d187f41f Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 11 Jun 2021 18:04:39 +0200 Subject: [PATCH 185/309] [RF] Make ConditionalObservables accept RooRealVars directly Using ConditionalObservables command argument failed with some Python 3 versions due to ownership problems with the RooArgSet. This commit suggests to always make a copy of the passed RooArgSet, and at the same time to change the function signature such that it can also accept an arbitrary number of observables directly via variadic templates. --- roofit/roofitcore/inc/RooGlobalFunc.h | 23 ++++++++++++++++++----- roofit/roofitcore/src/RooAbsPdf.cxx | 9 ++++++--- roofit/roofitcore/src/RooAbsReal.cxx | 3 ++- roofit/roofitcore/src/RooGlobalFunc.cxx | 4 ---- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/roofit/roofitcore/inc/RooGlobalFunc.h b/roofit/roofitcore/inc/RooGlobalFunc.h index 3e46cf9600e18..ba213ba04cf00 100644 --- a/roofit/roofitcore/inc/RooGlobalFunc.h +++ b/roofit/roofitcore/inc/RooGlobalFunc.h @@ -17,6 +17,7 @@ #define ROO_GLOBAL_FUNC #include "RooCmdArg.h" +#include "RooArgSet.h" #include #include @@ -29,7 +30,6 @@ class RooRealConstant ; class RooMsgService ; class RooFormulaVar ; class RooAbsData ; -class RooArgSet ; class RooCategory ; class RooAbsReal ; class RooAbsBinning ; @@ -206,10 +206,23 @@ RooCmdArg IntegrateBins(double precision); RooCmdArg PrefitDataFraction(Double_t data_ratio = 0.0) ; RooCmdArg FitOptions(const char* opts) ; RooCmdArg Optimize(Int_t flag=2) ; -RooCmdArg ProjectedObservables(const RooArgSet& set) ; // obsolete, for backward compatibility -RooCmdArg ProjectedObservables(RooArgSet && set) ; // obsolete, for backward compatibility -RooCmdArg ConditionalObservables(const RooArgSet& set) ; -RooCmdArg ConditionalObservables(RooArgSet && set) ; + +//////////////////////////////////////////////////////////////////////////////// +/// Create a RooCmdArg to declare conditional observables. +/// \param[in] argsOrArgSet Can either be one or more RooRealVar with the +// observables or a single RooArgSet containing them. +template +RooCmdArg ConditionalObservables(Args_t &&... argsOrArgSet) { + return RooCmdArg("ProjectedObservables",0,0,0,0,0,0, + &RooCmdArg::take(RooArgSet{std::forward(argsOrArgSet)...})); +} + +// obsolete, for backward compatibility +template +RooCmdArg ProjectedObservables(Args_t &&... argsOrArgSet) { + return ConditionalObservables(std::forward(argsOrArgSet)...); +} + RooCmdArg Verbose(Bool_t flag=kTRUE) ; RooCmdArg Save(Bool_t flag=kTRUE) ; RooCmdArg Timer(Bool_t flag=kTRUE) ; diff --git a/roofit/roofitcore/src/RooAbsPdf.cxx b/roofit/roofitcore/src/RooAbsPdf.cxx index b6476161f2524..2550e223df746 100644 --- a/roofit/roofitcore/src/RooAbsPdf.cxx +++ b/roofit/roofitcore/src/RooAbsPdf.cxx @@ -854,7 +854,8 @@ Double_t RooAbsPdf::extendedTerm(Double_t observed, const RooArgSet* nset) const /// /// ///
Type of CmdArg Effect on nll -///
`ConditionalObservables(const RooArgSet& set)` Do not normalize PDF over listed observables +///
`ConditionalObservables(Args_t &&... argsOrArgSet)` Do not normalize PDF over listed observables. +// Arguments can either be multiple RooRealVar or a single RooArgSet containing them. ///
`Extended(Bool_t flag)` Add extended likelihood term, off by default ///
`Range(const char* name)` Fit only data inside range with given name ///
`Range(Double_t lo, Double_t hi)` Fit only data inside given range. A range named "fit" is created on the fly on all observables. @@ -1357,7 +1358,8 @@ int RooAbsPdf::calculateSumW2CorrectedCovMatrix(Minimizer &minimizer, RooAbsReal /// /// ///
Type of CmdArg Options to control construction of -log(L) -///
`ConditionalObservables(const RooArgSet& set)` Do not normalize PDF over listed observables +///
`ConditionalObservables(Args_t &&... argsOrArgSet)` Do not normalize PDF over listed observables. +// Arguments can either be multiple RooRealVar or a single RooArgSet containing them. ///
`Extended(Bool_t flag)` Add extended likelihood term, off by default ///
`Range(const char* name)` Fit only data inside range with given name. Multiple comma-separated range names can be specified. /// In this case, the unnormalized PDF \f$f(x)\f$ is normalized by the integral over all ranges \f$r_i\f$: @@ -1906,7 +1908,8 @@ RooFitResult* RooAbsPdf::chi2FitTo(RooDataHist& data, const RooLinkedList& cmdLi /// myVariable.setRange("range_pi0", 135, 210); /// myVariable.setRange("range_gamma", 50, 210); /// ``` -///
`ConditionalObservables()` Define projected observables +///
`ConditionalObservables(Args_t &&... argsOrArgSet)` Define projected observables. +// Arguments can either be multiple RooRealVar or a single RooArgSet containing them. ///
RooAbsReal* RooAbsPdf::createChi2(RooDataHist& data, const RooCmdArg& arg1, const RooCmdArg& arg2, diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index 769e5420677c8..ee791a340586a 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -1326,7 +1326,8 @@ TH1* RooAbsReal::createHistogram(const char* varNameList, Int_t xbins, Int_t ybi ///
`Binning(const char* name)` Apply binning with given name to x axis of histogram ///
`Binning(RooAbsBinning& binning)` Apply specified binning to x axis of histogram ///
`Binning(int nbins, [double lo, double hi])` Apply specified binning to x axis of histogram -///
`ConditionalObservables(const RooArgSet& set)` Do not normalise PDF over following observables when projecting PDF into histogram +///
`ConditionalObservables(Args_t &&... argsOrArgSet)` Do not normalise PDF over following observables when projecting PDF into histogram. +// Arguments can either be multiple RooRealVar or a single RooArgSet containing them. ///
`Scaling(Bool_t)` Apply density-correction scaling (multiply by bin volume), default is kTRUE ///
`Extended(Bool_t)` Plot event yield instead of probability density (for extended pdfs only) /// diff --git a/roofit/roofitcore/src/RooGlobalFunc.cxx b/roofit/roofitcore/src/RooGlobalFunc.cxx index b2a24952932b9..5ec76d4f6e98c 100644 --- a/roofit/roofitcore/src/RooGlobalFunc.cxx +++ b/roofit/roofitcore/src/RooGlobalFunc.cxx @@ -209,10 +209,6 @@ namespace RooFit { RooCmdArg Minos(Bool_t flag) { return RooCmdArg("Minos",flag,0,0,0,0,0,0,0) ; } RooCmdArg Minos(const RooArgSet& minosArgs) { return RooCmdArg("Minos",kTRUE,0,0,0,0,0,&minosArgs,0) ; } RooCmdArg Minos(RooArgSet && minosArgs) { return Minos(RooCmdArg::take(std::move(minosArgs))); } - RooCmdArg ConditionalObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,&set) ; } - RooCmdArg ConditionalObservables(RooArgSet && set) { return ConditionalObservables(RooCmdArg::take(std::move(set))) ; } - RooCmdArg ProjectedObservables(const RooArgSet& set) { return RooCmdArg("ProjectedObservables",0,0,0,0,0,0,&set) ; } - RooCmdArg ProjectedObservables(RooArgSet && set) { return ProjectedObservables(RooCmdArg::take(std::move(set))) ; } RooCmdArg SplitRange(Bool_t flag) { return RooCmdArg("SplitRange",flag,0,0,0,0,0,0,0) ; } RooCmdArg SumCoefRange(const char* rangeName) { return RooCmdArg("SumCoefRange",0,0,0,0,rangeName,0,0,0) ; } RooCmdArg Constrain(const RooArgSet& params) { return RooCmdArg("Constrain",0,0,0,0,0,0,0,0,0,0,¶ms) ; } From b394d9206c08d7b4b997d3afcb2bb1987bfe9d6a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 10 Jun 2021 19:01:18 +0200 Subject: [PATCH 186/309] [RF] Refactor RooGlobalFuncs that process std::map --- roofit/roofitcore/src/RooGlobalFunc.cxx | 58 +++++++++++++------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/roofit/roofitcore/src/RooGlobalFunc.cxx b/roofit/roofitcore/src/RooGlobalFunc.cxx index 5ec76d4f6e98c..37f0f888ab253 100644 --- a/roofit/roofitcore/src/RooGlobalFunc.cxx +++ b/roofit/roofitcore/src/RooGlobalFunc.cxx @@ -35,6 +35,32 @@ using namespace std; namespace RooFit { + // anonymous namespace for helper functions for the implementation of the global functions + namespace { + + template + RooCmdArg processImportItem(std::pair const& item) { + return Import(item.first.c_str(), *item.second) ; + } + + template + RooCmdArg processLinkItem(std::pair const& item) { + return Link(item.first.c_str(), *item.second) ; + } + + template + RooCmdArg processMap(const char* name, Func_t func, Map_t const& map) { + RooCmdArg container(name,0,0,0,0,0,0,0,0) ; + for (auto const& item : map) { + container.addArg(func(item)) ; + } + container.setProcessRecArgs(true,false) ; + return container ; + } + + } // namespace + + // RooAbsReal::plotOn arguments RooCmdArg DrawOption(const char* opt) { return RooCmdArg("DrawOption",0,0,0,0,opt,0,0,0) ; } RooCmdArg Slice(const RooArgSet& sliceSet) { return RooCmdArg("SliceVars",0,0,0,0,0,0,&sliceSet,0) ; } @@ -110,22 +136,10 @@ namespace RooFit { RooCmdArg Import(TH1& histo, Bool_t importDensity) { return RooCmdArg("ImportHisto",importDensity,0,0,0,0,0,&histo,0) ; } RooCmdArg Import(const std::map& arg) { - RooCmdArg container("ImportDataHistSliceMany",0,0,0,0,0,0,0,0) ; - std::map::const_iterator iter ; - for (iter = arg.begin() ; iter!=arg.end() ; ++iter) { - container.addArg(Import(iter->first.c_str(),*(iter->second))) ; - } - container.setProcessRecArgs(kTRUE,kFALSE) ; - return container ; + return processMap("ImportDataHistSliceMany", processImportItem, arg); } RooCmdArg Import(const std::map& arg) { - RooCmdArg container("ImportHistoSliceMany",0,0,0,0,0,0,0,0) ; - std::map::const_iterator iter ; - for (iter = arg.begin() ; iter!=arg.end() ; ++iter) { - container.addArg(Import(iter->first.c_str(),*(iter->second))) ; - } - container.setProcessRecArgs(kTRUE,kFALSE) ; - return container ; + return processMap("ImportHistoSliceMany", processImportItem, arg); } @@ -144,22 +158,10 @@ namespace RooFit { RooCmdArg OwnLinked() { return RooCmdArg("OwnLinked",1,0,0,0,0,0,0,0,0,0,0) ; } RooCmdArg Import(const std::map& arg) { - RooCmdArg container("ImportDataSliceMany",0,0,0,0,0,0,0,0) ; - std::map::const_iterator iter ; - for (iter = arg.begin() ; iter!=arg.end() ; ++iter) { - container.addArg(Import(iter->first.c_str(),*(iter->second))) ; - } - container.setProcessRecArgs(kTRUE,kFALSE) ; - return container ; + return processMap("ImportDataSliceMany", processImportItem, arg); } RooCmdArg Link(const std::map& arg) { - RooCmdArg container("LinkDataSliceMany",0,0,0,0,0,0,0,0) ; - std::map::const_iterator iter ; - for (iter = arg.begin() ; iter!=arg.end() ; ++iter) { - container.addArg(Link(iter->first.c_str(),*(iter->second))) ; - } - container.setProcessRecArgs(kTRUE,kFALSE) ; - return container ; + return processMap("LinkDataSliceMany", processLinkItem, arg); } From e3500030da1e5e6d1e9babd26eeffb8dfe02f3c1 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 10 Jun 2021 19:51:14 +0200 Subject: [PATCH 187/309] [RF] Add overload of the Slice argument that takes map of categories Before, if one wanted to slice over mulitple categories in `RooAbsReal::plotOn`, one had to repeatedly use the Slice command argument. This is problematic for the keyword pythonizations in pyROOT, because keyword arguments in python can't be repeated. With this change, it is also not necessary anymore to repeat any command arguements in RooFit. This will help to solve Jira issue ROOT-2784, as we can just always throw an error if a RooCmdArg is repeated. --- roofit/roofitcore/inc/RooGlobalFunc.h | 1 + roofit/roofitcore/src/RooAbsReal.cxx | 13 ++++++++++--- roofit/roofitcore/src/RooGlobalFunc.cxx | 7 +++++++ roofit/roofitcore/src/RooSimultaneous.cxx | 4 ++++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/roofit/roofitcore/inc/RooGlobalFunc.h b/roofit/roofitcore/inc/RooGlobalFunc.h index ba213ba04cf00..030a0b15d47fd 100644 --- a/roofit/roofitcore/inc/RooGlobalFunc.h +++ b/roofit/roofitcore/inc/RooGlobalFunc.h @@ -78,6 +78,7 @@ RooCmdArg Normalization(Double_t scaleFactor) ; RooCmdArg Slice(const RooArgSet& sliceSet) ; RooCmdArg Slice(RooArgSet && sliceSet) ; RooCmdArg Slice(RooCategory& cat, const char* label) ; +RooCmdArg Slice(std::map const&) ; RooCmdArg Project(const RooArgSet& projSet) ; RooCmdArg Project(RooArgSet && projSet) ; RooCmdArg ProjWData(const RooAbsData& projData, Bool_t binData=kFALSE) ; diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index ee791a340586a..907e63a16c73e 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -1596,10 +1596,13 @@ void RooAbsReal::plotOnCompSelect(RooArgSet* selNodes) const /// ///
`Slice(RooCategory& cat, const char* label)` Override default projection behaviour by omitting the specified category /// observable from the projection, i.e., by not integrating over all states of this category. -/// The slice is positioned at the given label value. Multiple Slice() commands can be given to specify slices -/// in multiple observables, e.g. +/// The slice is positioned at the given label value. To pass multiple Slice() commands, please use the +/// Slice(std::map const&) argument explained below. +/// +///
`Slice(std::map const&)` Omits multiple categories from the projection, as explianed above. +/// Can be used with initializer lists for convenience, e.g. /// ```{.cpp} -/// pdf.plotOn(frame, Slice(tagCategory, "2tag"), Slice(jetCategory, "3jet")); +/// pdf.plotOn(frame, Slice({{&tagCategory, "2tag"}, {&jetCategory, "3jet"}}); /// ``` /// ///
`Project(const RooArgSet& set)` Override default projection behaviour by projecting over observables @@ -1744,6 +1747,10 @@ RooPlot* RooAbsReal::plotOn(RooPlot* frame, RooLinkedList& argList) const pc.defineInt("scaleType","Normalization",0,Relative) ; pc.defineObject("sliceSet","SliceVars",0) ; pc.defineObject("sliceCatList","SliceCat",0,0,kTRUE) ; + // This dummy is needed for plotOn to recognize the "SliceCatMany" command. + // It is not used directly, but the "SliceCat" commands are nested in it. + // Removing this dummy definition results in "ERROR: unrecognized command: SliceCatMany". + pc.defineObject("dummy1","SliceCatMany",0) ; pc.defineObject("projSet","Project",0) ; pc.defineObject("asymCat","Asymmetry",0) ; pc.defineDouble("precision","Precision",0,1e-3) ; diff --git a/roofit/roofitcore/src/RooGlobalFunc.cxx b/roofit/roofitcore/src/RooGlobalFunc.cxx index 37f0f888ab253..932f6af41fdd2 100644 --- a/roofit/roofitcore/src/RooGlobalFunc.cxx +++ b/roofit/roofitcore/src/RooGlobalFunc.cxx @@ -48,6 +48,10 @@ namespace RooFit { return Link(item.first.c_str(), *item.second) ; } + RooCmdArg processSliceItem(std::pair const& item) { + return Slice(*item.first, item.second.c_str()); + } + template RooCmdArg processMap(const char* name, Func_t func, Map_t const& map) { RooCmdArg container(name,0,0,0,0,0,0,0,0) ; @@ -66,6 +70,9 @@ namespace RooFit { RooCmdArg Slice(const RooArgSet& sliceSet) { return RooCmdArg("SliceVars",0,0,0,0,0,0,&sliceSet,0) ; } RooCmdArg Slice(RooArgSet && sliceSet) { return Slice(RooCmdArg::take(std::move(sliceSet))); } RooCmdArg Slice(RooCategory& cat, const char* label) { return RooCmdArg("SliceCat",0,0,0,0,label,0,&cat,0) ; } + RooCmdArg Slice(std::map const& arg) { + return processMap("SliceCatMany", processSliceItem, arg); + } RooCmdArg Project(const RooArgSet& projSet) { return RooCmdArg("Project",0,0,0,0,0,0,&projSet,0) ; } RooCmdArg Project(RooArgSet && projSet) { return Project(RooCmdArg::take(std::move(projSet))); } diff --git a/roofit/roofitcore/src/RooSimultaneous.cxx b/roofit/roofitcore/src/RooSimultaneous.cxx index 80873c8c2ae1b..dc7ad5a97baba 100644 --- a/roofit/roofitcore/src/RooSimultaneous.cxx +++ b/roofit/roofitcore/src/RooSimultaneous.cxx @@ -598,6 +598,10 @@ RooPlot* RooSimultaneous::plotOn(RooPlot *frame, RooLinkedList& cmdList) const pc.defineDouble("scaleFactor","Normalization",0,1.0) ; pc.defineInt("scaleType","Normalization",0,RooAbsPdf::Relative) ; pc.defineObject("sliceCatList","SliceCat",0,0,kTRUE) ; + // This dummy is needed for plotOn to recognize the "SliceCatMany" command. + // It is not used directly, but the "SliceCat" commands are nested in it. + // Removing this dummy definition results in "ERROR: unrecognized command: SliceCatMany". + pc.defineObject("dummy1","SliceCatMany",0) ; pc.defineObject("projSet","Project",0) ; pc.defineObject("sliceSet","SliceVars",0) ; pc.defineObject("projDataSet","ProjData",0) ; From 2aff5a7570b05bee99dd6f5acd5d4629c5fe2e0c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 10 Jun 2021 19:59:57 +0200 Subject: [PATCH 188/309] [RF][Tutorials] Avoid repeated command args in RooFit Tutorials --- tutorials/roofit/rf501_simultaneouspdf.C | 4 ++-- tutorials/roofit/rf708_bphysics.C | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tutorials/roofit/rf501_simultaneouspdf.C b/tutorials/roofit/rf501_simultaneouspdf.C index 9019928b3c051..249305f1ed568 100644 --- a/tutorials/roofit/rf501_simultaneouspdf.C +++ b/tutorials/roofit/rf501_simultaneouspdf.C @@ -79,8 +79,8 @@ void rf501_simultaneouspdf() sample.defineType("control"); // Construct combined dataset in (x,sample) - RooDataSet combData("combData", "combined data", x, Index(sample), Import("physics", *data), - Import("control", *data_ctl)); + RooDataSet combData("combData", "combined data", x, Index(sample), + Import({{"physics", data}, {"control", data_ctl}})); // C o n s t r u c t a s i m u l t a n e o u s p d f i n ( x , s a m p l e ) // ----------------------------------------------------------------------------------- diff --git a/tutorials/roofit/rf708_bphysics.C b/tutorials/roofit/rf708_bphysics.C index f5fc3a13d996b..73292d5813e43 100644 --- a/tutorials/roofit/rf708_bphysics.C +++ b/tutorials/roofit/rf708_bphysics.C @@ -79,19 +79,19 @@ void rf708_bphysics() RooPlot *frame2 = dt.frame(Title("B decay distribution of mixed events (B0/B0bar)")); data->plotOn(frame2, Cut("mixState==mixState::mixed&&tagFlav==tagFlav::B0")); - bmix.plotOn(frame2, Slice(tagFlav, "B0"), Slice(mixState, "mixed")); + bmix.plotOn(frame2, Slice({{&tagFlav, "B0"}, {&mixState, "mixed"}})); data->plotOn(frame2, Cut("mixState==mixState::mixed&&tagFlav==tagFlav::B0bar"), MarkerColor(kCyan)); - bmix.plotOn(frame2, Slice(tagFlav, "B0bar"), Slice(mixState, "mixed"), LineColor(kCyan)); + bmix.plotOn(frame2, Slice({{&tagFlav, "B0bar"}, {&mixState, "mixed"}}), LineColor(kCyan)); // Plot unmixed slice for B0 and B0bar tagged data separately RooPlot *frame3 = dt.frame(Title("B decay distribution of unmixed events (B0/B0bar)")); data->plotOn(frame3, Cut("mixState==mixState::unmixed&&tagFlav==tagFlav::B0")); - bmix.plotOn(frame3, Slice(tagFlav, "B0"), Slice(mixState, "unmixed")); + bmix.plotOn(frame3, Slice({{&tagFlav, "B0"}, {&mixState, "unmixed"}})); data->plotOn(frame3, Cut("mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar"), MarkerColor(kCyan)); - bmix.plotOn(frame3, Slice(tagFlav, "B0bar"), Slice(mixState, "unmixed"), LineColor(kCyan)); + bmix.plotOn(frame3, Slice({{&tagFlav, "B0bar"}, {&mixState, "unmixed"}}), LineColor(kCyan)); // ------------------------------------------------- // B - D e c a y w i t h C P v i o l a t i o n From afd421d81fd4f513420380ce51c3dbf9209da21a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 10 Jun 2021 20:01:03 +0200 Subject: [PATCH 189/309] [RF] Avoid repeating command arguments in stressRooFit --- test/stressRooFit_tests.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/stressRooFit_tests.h b/test/stressRooFit_tests.h index 78463f54d0b99..865a3a94902ba 100644 --- a/test/stressRooFit_tests.h +++ b/test/stressRooFit_tests.h @@ -3968,7 +3968,7 @@ class TestBasic501 : public RooUnitTest sample.defineType("control") ; // Construct combined dataset in (x,sample) - RooDataSet combData("combData","combined data",x,Index(sample),Import("physics",*data),Import("control",*data_ctl)) ; + RooDataSet combData("combData","combined data",x,Index(sample),Import({{"physics",data}, {"control",data_ctl}})) ; @@ -5851,20 +5851,20 @@ class TestBasic708 : public RooUnitTest RooPlot* frame2 = dt.frame(Title("B decay distribution of mixed events (B0/B0bar)")) ; data->plotOn(frame2,Cut("mixState==mixState::mixed&&tagFlav==tagFlav::B0")) ; - bmix.plotOn(frame2,Slice(tagFlav,"B0"),Slice(mixState,"mixed")) ; + bmix.plotOn(frame2,Slice({{&tagFlav,"B0"}, {&mixState,"mixed"}})) ; data->plotOn(frame2,Cut("mixState==mixState::mixed&&tagFlav==tagFlav::B0bar"),MarkerColor(kCyan)) ; - bmix.plotOn(frame2,Slice(tagFlav,"B0bar"),Slice(mixState,"mixed"),LineColor(kCyan),Name("alt")) ; + bmix.plotOn(frame2,Slice({{&tagFlav,"B0bar"}, {&mixState,"mixed"}}),LineColor(kCyan),Name("alt")) ; // Plot unmixed slice for B0 and B0bar tagged data separately RooPlot* frame3 = dt.frame(Title("B decay distribution of unmixed events (B0/B0bar)")) ; data->plotOn(frame3,Cut("mixState==mixState::unmixed&&tagFlav==tagFlav::B0")) ; - bmix.plotOn(frame3,Slice(tagFlav,"B0"),Slice(mixState,"unmixed")) ; + bmix.plotOn(frame3,Slice({{&tagFlav,"B0"}, {&mixState,"unmixed"}})) ; data->plotOn(frame3,Cut("mixState==mixState::unmixed&&tagFlav==tagFlav::B0bar"),MarkerColor(kCyan)) ; - bmix.plotOn(frame3,Slice(tagFlav,"B0bar"),Slice(mixState,"unmixed"),LineColor(kCyan),Name("alt")) ; + bmix.plotOn(frame3,Slice({{&tagFlav,"B0bar"}, {&mixState,"unmixed"}}),LineColor(kCyan),Name("alt")) ; From d69de724f0e997b1b75cb2a28f2701299bfb7e48 Mon Sep 17 00:00:00 2001 From: YuryYury Date: Mon, 14 Jun 2021 15:10:59 +0300 Subject: [PATCH 190/309] Fixing a few typos in Trees.md (#8419) Fixing a few typos in Trees.md --- documentation/users-guide/Trees.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/users-guide/Trees.md b/documentation/users-guide/Trees.md index bdcab368e0b8d..4283d1bfa95ef 100644 --- a/documentation/users-guide/Trees.md +++ b/documentation/users-guide/Trees.md @@ -2347,7 +2347,7 @@ Same as case 4, but use the method of a data member. The same as case 4: a data member of a data member retrieved by a method. -7. `**tree->Draw("GetHistogram().GetXaxis().GetXmax()");`** +7. **`tree->Draw("GetHistogram().GetXaxis().GetXmax()");`** Same as case 4, but using methods. @@ -2736,7 +2736,7 @@ this entry `Iteration$:` return the current iteration over this formula for this entry (i.e. varies from 0 to `Length$`). -43. T->Draw("fLastTrack.GetPx():fLastTrack.fPx");`** +43. **`tree->Draw("fLastTrack.GetPx():fLastTrack.fPx");`** **`TRef`** and **`TRefArray`** are automatically deferenced and this shows the value of the `fPx` of the track referenced by `fLastTrack`. To @@ -2744,7 +2744,7 @@ access the **`TRef`** object itself use the '`@`' notation (see next example). This auto dereferencing can be extended (via an implementation of **`TVirtualRefProxy`**) to any reference type. -44. T->Scan("((Track*)(fLastTrack@.GetObject())).GetPx()","","");`** +44. **`tree->Scan("((Track*)(fLastTrack@.GetObject())).GetPx()","","");`** Will cast the return value of `GetObject()` (which happens to be **`TObject*`** in this case) before requesting the `GetPx()` member @@ -3393,7 +3393,7 @@ numbers meaning is: 2 lower limit in x-direction -3upper limit in x-direction +3 upper limit in x-direction 4-6 same for y-direction From f22c865f43a707745004848d1c7b8f8bfee69aa9 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Mon, 14 Jun 2021 14:19:40 +0200 Subject: [PATCH 191/309] =?UTF-8?q?[asimage]=20Port=20to=20Win64=20(replac?= =?UTF-8?q?e=20Long=5Ft=20by=20Longptr=5Ft=20+=20pointer=20format=E2=80=A6?= =?UTF-8?q?=20(#8358)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [asimage] Port to Win64 (replace Long_t by Longptr_t + pointer formatting) * Add missing #include (for uintptr_t) --- graf2d/asimage/inc/TASPaletteEditor.h | 2 +- graf2d/asimage/src/TASImage.cxx | 18 +++++++++--------- graf2d/asimage/src/TASPaletteEditor.cxx | 4 ++-- .../asimage/src/libAfterImage/asim_afterbase.h | 5 +++-- graf2d/asimage/src/libAfterImage/asvisual.c | 2 +- graf2d/asimage/src/libAfterImage/scanline.c | 2 +- graf2d/asimage/src/libAfterImage/xpm.c | 4 ++-- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/graf2d/asimage/inc/TASPaletteEditor.h b/graf2d/asimage/inc/TASPaletteEditor.h index 21b6d3d6f54b8..cdc8fc9cff954 100644 --- a/graf2d/asimage/inc/TASPaletteEditor.h +++ b/graf2d/asimage/inc/TASPaletteEditor.h @@ -100,7 +100,7 @@ class TASPaletteEditor : public TPaletteEditor, public TGMainFrame { TASPaletteEditor(TAttImage *attImage, UInt_t w, UInt_t h); virtual ~TASPaletteEditor(); - Bool_t ProcessMessage(Long_t msg, Long_t param1, Long_t param2); + Bool_t ProcessMessage(Longptr_t msg, Longptr_t param1, Longptr_t param2); void UpdateRange(); void CloseWindow(); diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index 23f9d96f4beac..a8744a5e77d0e 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -4785,7 +4785,7 @@ void TASImage::PolyPoint(UInt_t npt, TPoint *ppt, const char *col, TImage::ECoor void TASImage::DrawSegments(UInt_t nseg, Segment_t *seg, const char *col, UInt_t thick) { if (!nseg || !seg) { - Warning("DrawSegments", "Invalid data nseg=%d seg=0x%lx", nseg, (Long_t)seg); + Warning("DrawSegments", "Invalid data nseg=%d seg=0x%zx", nseg, (size_t)seg); return; } @@ -4828,8 +4828,8 @@ void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, const char *co } if (!npt || !ppt || !widths || (stipple && (!w || !h))) { - Warning("FillSpans", "Invalid input data npt=%d ppt=0x%lx col=%s widths=0x%lx stipple=0x%lx w=%d h=%d", - npt, (Long_t)ppt, col, (Long_t)widths, (Long_t)stipple, w, h); + Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx col=%s widths=0x%zx stipple=0x%zx w=%d h=%d", + npt, (size_t)ppt, col, (size_t)widths, (size_t)stipple, w, h); return; } @@ -4886,8 +4886,8 @@ void TASImage::FillSpans(UInt_t npt, TPoint *ppt, UInt_t *widths, TImage *tile) } if (!npt || !ppt || !widths || !tile) { - Warning("FillSpans", "Invalid input data npt=%d ppt=0x%lx widths=0x%lx tile=0x%lx", - npt, (Long_t)ppt, (Long_t)widths, (Long_t)tile); + Warning("FillSpans", "Invalid input data npt=%d ppt=0x%zx widths=0x%zx tile=0x%zx", + npt, (size_t)ppt, (size_t)widths, (size_t)tile); return; } @@ -4940,7 +4940,7 @@ void TASImage::CropSpans(UInt_t npt, TPoint *ppt, UInt_t *widths) } if (!npt || !ppt || !widths) { - Warning("CropSpans", "No points specified npt=%d ppt=0x%lx widths=0x%lx", npt, (Long_t)ppt, (Long_t)widths); + Warning("CropSpans", "No points specified npt=%d ppt=0x%zx widths=0x%zx", npt, (size_t)ppt, (size_t)widths); return; } @@ -5245,7 +5245,7 @@ Bool_t TASImage::GetPolygonSpans(UInt_t npt, TPoint *ppt, UInt_t *nspans, } if ((npt < 3) || !ppt) { - Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%lx", npt, (Long_t)ppt); + Warning("GetPolygonSpans", "No points specified npt=%d ppt=0x%zx", npt, (size_t)ppt); return kFALSE; } @@ -5447,7 +5447,7 @@ void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, const char *col, } if ((count < 3) || !ptsIn) { - Warning("DrawFillArea", "No points specified npt=%d ppt=0x%lx", count, (Long_t)ptsIn); + Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn); return; } @@ -5563,7 +5563,7 @@ void TASImage::DrawFillArea(UInt_t count, TPoint *ptsIn, TImage *tile) } if ((count < 3) || !ptsIn) { - Warning("DrawFillArea", "No points specified npt=%d ppt=0x%lx", count, (Long_t)ptsIn); + Warning("DrawFillArea", "No points specified npt=%d ppt=0x%zx", count, (size_t)ptsIn); return; } diff --git a/graf2d/asimage/src/TASPaletteEditor.cxx b/graf2d/asimage/src/TASPaletteEditor.cxx index 9d1bdb0172d1c..edece4af9cc52 100644 --- a/graf2d/asimage/src/TASPaletteEditor.cxx +++ b/graf2d/asimage/src/TASPaletteEditor.cxx @@ -291,7 +291,7 @@ void TASPaletteEditor::CloseWindow() //////////////////////////////////////////////////////////////////////////////// /// Process all editor mouse events -Bool_t TASPaletteEditor::ProcessMessage(Long_t msg, Long_t param1, Long_t param2) +Bool_t TASPaletteEditor::ProcessMessage(Longptr_t msg, Longptr_t param1, Longptr_t param2) { switch (GET_MSG(msg)) { @@ -451,7 +451,7 @@ void TASPaletteEditor::Save() else strlcpy(fn, fi.fFilename,512); - gROOT->ProcessLine(Form("gROOT->SaveObjectAs((TASPaletteEditor*)0x%lx,\"%s\",\"%s\");",(ULong_t)this,fn,"q")); + gROOT->ProcessLine(Form("gROOT->SaveObjectAs((TASPaletteEditor*)0x%zx,\"%s\",\"%s\");",(size_t)this,fn,"q")); } } diff --git a/graf2d/asimage/src/libAfterImage/asim_afterbase.h b/graf2d/asimage/src/libAfterImage/asim_afterbase.h index a07343c31eca3..2b3cdbf1bfcec 100644 --- a/graf2d/asimage/src/libAfterImage/asim_afterbase.h +++ b/graf2d/asimage/src/libAfterImage/asim_afterbase.h @@ -31,6 +31,7 @@ /* from libAfterBase/astypes.h : */ #include +#include #ifdef __cplusplus extern "C" { @@ -303,7 +304,7 @@ typedef union ASHashableValue } ASHashableValue; #else -typedef unsigned long ASHashableValue; +typedef uintptr_t ASHashableValue; #endif typedef union ASHashData @@ -323,7 +324,7 @@ typedef union ASHashData CARD8 c8 ; }ASHashData; -#define AS_HASHABLE(v) ((ASHashableValue)((unsigned long)(v))) +#define AS_HASHABLE(v) ((ASHashableValue)((uintptr_t)(v))) typedef struct ASHashItem { diff --git a/graf2d/asimage/src/libAfterImage/asvisual.c b/graf2d/asimage/src/libAfterImage/asvisual.c index 27fe0bf659a88..7c060feaf1849 100644 --- a/graf2d/asimage/src/libAfterImage/asvisual.c +++ b/graf2d/asimage/src/libAfterImage/asvisual.c @@ -642,7 +642,7 @@ make_reverse_colorhash( unsigned long *cmap, size_t size, int depth, unsigned sh if( hash ) { for( i = 0 ; i < size ; i++ ) - add_hash_item( hash, (ASHashableValue)cmap[i], (void*)((long)MAKE_ARGB32( 0xFF, (i>>(shift<<1))& mask, (i>>(shift))&mask, i&mask)) ); + add_hash_item( hash, (ASHashableValue)cmap[i], (void*)((intptr_t)MAKE_ARGB32( 0xFF, (i>>(shift<<1))& mask, (i>>(shift))&mask, i&mask)) ); } return hash; } diff --git a/graf2d/asimage/src/libAfterImage/scanline.c b/graf2d/asimage/src/libAfterImage/scanline.c index 08699a5a4e32f..b8cbd1dde8260 100644 --- a/graf2d/asimage/src/libAfterImage/scanline.c +++ b/graf2d/asimage/src/libAfterImage/scanline.c @@ -69,7 +69,7 @@ prepare_scanline( unsigned int width, unsigned int shift, ASScanline *reusable_m return NULL; } - sl->xc1 = sl->red = (CARD32*)((((long)ptr+7)>>3)*8); + sl->xc1 = sl->red = (CARD32*)((((intptr_t)ptr+7)>>3)*8); sl->xc2 = sl->green = sl->red + aligned_width; sl->xc3 = sl->blue = sl->green + aligned_width; sl->alpha = sl->blue + aligned_width; diff --git a/graf2d/asimage/src/libAfterImage/xpm.c b/graf2d/asimage/src/libAfterImage/xpm.c index 787f27f025efc..006e8e1d29053 100644 --- a/graf2d/asimage/src/libAfterImage/xpm.c +++ b/graf2d/asimage/src/libAfterImage/xpm.c @@ -822,7 +822,7 @@ build_xpm_colormap( ASXpmFile *xpm_file ) { xpm_color_names = create_ashash( 0, casestring_hash_value, casestring_compare, NULL ); for( i = 0 ; XpmRGB_Colors[i].name != NULL ; i++ ) - add_hash_item( xpm_color_names, (ASHashableValue)XpmRGB_Colors[i].name, (void*)((long)XpmRGB_Colors[i].argb) ); + add_hash_item( xpm_color_names, (ASHashableValue)XpmRGB_Colors[i].name, (void*)((intptr_t)XpmRGB_Colors[i].argb) ); } for( i = 0 ; i < xpm_file->cmap_size ; ++i ) @@ -865,7 +865,7 @@ LOCAL_DEBUG_OUT( "\t\tcolor = 0x%8.8lX\n", color ); { char *name = mystrndup(xpm_file->str_buf, xpm_file->bpp); LOCAL_DEBUG_OUT( "\t\tname = \"%s\"\n", name ); - add_hash_item( xpm_file->cmap_name_xref, (ASHashableValue)name, (void*)((long)color) ); + add_hash_item( xpm_file->cmap_name_xref, (ASHashableValue)name, (void*)((intptr_t)color) ); } #endif } From 9ade39ebd146ed99733c9a63023616b1c5eb026a Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Mon, 14 Jun 2021 14:20:22 +0200 Subject: [PATCH 192/309] [graf] Port to Win64 (replace Long_t by Longptr_t + pointer formatting) (#8381) --- graf2d/graf/src/TLink.cxx | 2 +- graf2d/graf/src/TPaveText.cxx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/graf2d/graf/src/TLink.cxx b/graf2d/graf/src/TLink.cxx index 4853f9e739512..5d95a21de86d1 100644 --- a/graf2d/graf/src/TLink.cxx +++ b/graf2d/graf/src/TLink.cxx @@ -46,7 +46,7 @@ TLink::TLink(Double_t x, Double_t y, void *pointer) { fLink = pointer; static char line[16]; - snprintf(line,16,"->%lx ", (Long_t)pointer); + snprintf(line,16,"->%zx ", (size_t)pointer); SetTitle(line); } diff --git a/graf2d/graf/src/TPaveText.cxx b/graf2d/graf/src/TPaveText.cxx index 89200fdb74279..1a097a66e1a7a 100644 --- a/graf2d/graf/src/TPaveText.cxx +++ b/graf2d/graf/src/TPaveText.cxx @@ -262,10 +262,10 @@ void TPaveText::EditText() if (!obj->InheritsFrom(TText::Class())) return; TText *text = (TText*)obj; gROOT->SetSelectedPrimitive(text); - gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->SetSelected((TObject*)0x%lx)", - (ULong_t)gPad->GetCanvas(), (ULong_t)text)); - gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->Selected((TVirtualPad*)0x%lx,(TObject*)0x%lx,1)", - (ULong_t)gPad->GetCanvas(), (ULong_t)gPad, (ULong_t)text)); + gROOT->ProcessLine(Form("((TCanvas*)0x%zx)->SetSelected((TObject*)0x%zx)", + (size_t)gPad->GetCanvas(), (size_t)text)); + gROOT->ProcessLine(Form("((TCanvas*)0x%zx)->Selected((TVirtualPad*)0x%zx,(TObject*)0x%zx,1)", + (size_t)gPad->GetCanvas(), (size_t)gPad, (size_t)text)); text->SetTextAttributes(); } From 526096a9d279ab4a09fe0249deba198934e9fd40 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Mon, 14 Jun 2021 14:20:33 +0200 Subject: [PATCH 193/309] [gpad] Port to Win64 (replace Long_t by Longptr_t + pointer formatting) (#8380) --- graf2d/gpad/src/TCanvas.cxx | 24 ++++++++++++------------ graf2d/gpad/src/TInspectCanvas.cxx | 2 +- graf2d/gpad/src/TPad.cxx | 16 ++++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/graf2d/gpad/src/TCanvas.cxx b/graf2d/gpad/src/TCanvas.cxx index 393b878d75fcc..faaddf2a5ae92 100644 --- a/graf2d/gpad/src/TCanvas.cxx +++ b/graf2d/gpad/src/TCanvas.cxx @@ -757,7 +757,7 @@ void TCanvas::Clear(Option_t *option) void TCanvas::Cleared(TVirtualPad *pad) { - Emit("Cleared(TVirtualPad*)", (Long_t)pad); + Emit("Cleared(TVirtualPad*)", (Longptr_t)pad); } //////////////////////////////////////////////////////////////////////////////// @@ -1592,10 +1592,10 @@ TPad *TCanvas::Pick(Int_t px, Int_t py, TObject *prevSelObj) void TCanvas::Picked(TPad *pad, TObject *obj, Int_t event) { - Long_t args[3]; + Longptr_t args[3]; - args[0] = (Long_t) pad; - args[1] = (Long_t) obj; + args[0] = (Longptr_t) pad; + args[1] = (Longptr_t) obj; args[2] = event; Emit("Picked(TPad*,TObject*,Int_t)", args); @@ -1611,10 +1611,10 @@ void TCanvas::Picked(TPad *pad, TObject *obj, Int_t event) void TCanvas::Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y) { - Long_t args[4]; + Longptr_t args[4]; - args[0] = (Long_t) pad; - args[1] = (Long_t) obj; + args[0] = (Longptr_t) pad; + args[1] = (Longptr_t) obj; args[2] = x; args[3] = y; @@ -1638,10 +1638,10 @@ void TCanvas::HighlightConnect(const char *slot) void TCanvas::Selected(TVirtualPad *pad, TObject *obj, Int_t event) { - Long_t args[3]; + Longptr_t args[3]; - args[0] = (Long_t) pad; - args[1] = (Long_t) obj; + args[0] = (Longptr_t) pad; + args[1] = (Longptr_t) obj; args[2] = event; Emit("Selected(TVirtualPad*,TObject*,Int_t)", args); @@ -1652,12 +1652,12 @@ void TCanvas::Selected(TVirtualPad *pad, TObject *obj, Int_t event) void TCanvas::ProcessedEvent(Int_t event, Int_t x, Int_t y, TObject *obj) { - Long_t args[4]; + Longptr_t args[4]; args[0] = event; args[1] = x; args[2] = y; - args[3] = (Long_t) obj; + args[3] = (Longptr_t) obj; Emit("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", args); } diff --git a/graf2d/gpad/src/TInspectCanvas.cxx b/graf2d/gpad/src/TInspectCanvas.cxx index a738badd4021c..5a0802e82d6ba 100644 --- a/graf2d/gpad/src/TInspectCanvas.cxx +++ b/graf2d/gpad/src/TInspectCanvas.cxx @@ -307,7 +307,7 @@ void TInspectCanvas::InspectObject(TObject *obj) strlcpy(&line[kvalue], membertype->AsString(pointer),kline-kvalue); } else - snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)pointer); + snprintf(&line[kvalue],kline-kvalue,"->%zx ", (size_t)pointer); // Encode data member title Int_t ltit = 0; diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index 4c5799f21bab7..a1942496f9e88 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -6934,8 +6934,8 @@ TObject *TPad::WaitPrimitive(const char *pname, const char *emode) TObject *TPad::CreateToolTip(const TBox *box, const char *text, Long_t delayms) { if (gPad->IsBatch()) return 0; - return (TObject*)gROOT->ProcessLineFast(Form("new TGToolTip((TBox*)0x%lx,\"%s\",%d)", - (Long_t)box,text,(Int_t)delayms)); + return (TObject*)gROOT->ProcessLineFast(Form("new TGToolTip((TBox*)0x%zx,\"%s\",%d)", + (size_t)box,text,(Int_t)delayms)); } //////////////////////////////////////////////////////////////////////////////// @@ -6945,7 +6945,7 @@ void TPad::DeleteToolTip(TObject *tip) { // delete tip; if (!tip) return; - gROOT->ProcessLineFast(Form("delete (TGToolTip*)0x%lx", (Long_t)tip)); + gROOT->ProcessLineFast(Form("delete (TGToolTip*)0x%zx", (size_t)tip)); } //////////////////////////////////////////////////////////////////////////////// @@ -6956,8 +6956,8 @@ void TPad::ResetToolTip(TObject *tip) { if (!tip) return; // tip->Reset(this); - gROOT->ProcessLineFast(Form("((TGToolTip*)0x%lx)->Reset((TPad*)0x%lx)", - (Long_t)tip,(Long_t)this)); + gROOT->ProcessLineFast(Form("((TGToolTip*)0x%zx)->Reset((TPad*)0x%zx)", + (size_t)tip,(size_t)this)); } //////////////////////////////////////////////////////////////////////////////// @@ -6967,7 +6967,7 @@ void TPad::CloseToolTip(TObject *tip) { if (!tip) return; // tip->Hide(); - gROOT->ProcessLineFast(Form("((TGToolTip*)0x%lx)->Hide()",(Long_t)tip)); + gROOT->ProcessLineFast(Form("((TGToolTip*)0x%zx)->Hide()",(size_t)tip)); } //////////////////////////////////////////////////////////////////////////////// @@ -7089,7 +7089,7 @@ Int_t TPad::GetGLDevice() void TPad::RecordPave(const TObject *obj) { - Emit("RecordPave(const TObject*)", (Long_t)obj); + Emit("RecordPave(const TObject*)", (Longptr_t)obj); } //////////////////////////////////////////////////////////////////////////////// @@ -7097,7 +7097,7 @@ void TPad::RecordPave(const TObject *obj) void TPad::RecordLatex(const TObject *obj) { - Emit("RecordLatex(const TObject*)", (Long_t)obj); + Emit("RecordLatex(const TObject*)", (Longptr_t)obj); } //////////////////////////////////////////////////////////////////////////////// From 87acb38fcf21614a9619ccfce2edc4469c3e4b85 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Mon, 14 Jun 2021 14:21:02 +0200 Subject: [PATCH 194/309] [graf3d] Port to Win64 (replace Long_t by Longptr_t + pointer formatting) (#8409) --- graf3d/eve/inc/TEveMacro.h | 2 +- graf3d/eve/src/TEveBrowser.cxx | 4 +- graf3d/eve/src/TEveDigitSet.cxx | 10 ++--- graf3d/eve/src/TEveElement.cxx | 8 ++-- graf3d/eve/src/TEveMacro.cxx | 4 +- graf3d/eve/src/TEveSelection.cxx | 6 +-- graf3d/eve/src/TEveTrack.cxx | 2 +- graf3d/eve/src/TEveWindowManager.cxx | 8 ++-- graf3d/eve7/src/REveElement.cxx | 2 +- graf3d/g3d/src/TPointSet3D.cxx | 4 +- graf3d/gl/inc/TGLSAFrame.h | 2 +- graf3d/gl/src/TGL5DPainter.cxx | 2 +- graf3d/gl/src/TGLBoxPainter.cxx | 2 +- graf3d/gl/src/TGLContext.cxx | 10 ++--- graf3d/gl/src/TGLCylinder.cxx | 4 +- graf3d/gl/src/TGLFaceSet.cxx | 2 +- graf3d/gl/src/TGLLegoPainter.cxx | 2 +- graf3d/gl/src/TGLLogicalShape.cxx | 2 +- graf3d/gl/src/TGLOverlayButton.cxx | 2 +- graf3d/gl/src/TGLPShapeObjEditor.cxx | 2 +- graf3d/gl/src/TGLPadPainter.cxx | 2 +- graf3d/gl/src/TGLParametric.cxx | 2 +- graf3d/gl/src/TGLPhysicalShape.cxx | 8 ++-- graf3d/gl/src/TGLPolyLine.cxx | 2 +- graf3d/gl/src/TGLPolyMarker.cxx | 2 +- graf3d/gl/src/TGLSAFrame.cxx | 2 +- graf3d/gl/src/TGLScene.cxx | 4 +- graf3d/gl/src/TGLSphere.cxx | 2 +- graf3d/gl/src/TGLSurfacePainter.cxx | 2 +- graf3d/gl/src/TGLTF3Painter.cxx | 4 +- graf3d/gl/src/TGLTH3Composition.cxx | 2 +- graf3d/gl/src/TGLViewer.cxx | 56 +++++++++++++------------- graf3d/gl/src/TGLVoxelPainter.cxx | 2 +- graf3d/gl/src/TGLWidget.cxx | 22 +++++----- graf3d/gviz3d/src/TStructViewer.cxx | 8 ++-- graf3d/gviz3d/src/TStructViewerGUI.cxx | 8 ++-- graf3d/x3d/inc/TX3DFrame.h | 2 +- graf3d/x3d/src/TX3DFrame.cxx | 2 +- 38 files changed, 106 insertions(+), 106 deletions(-) diff --git a/graf3d/eve/inc/TEveMacro.h b/graf3d/eve/inc/TEveMacro.h index 4683b8e5ad625..d0d893aae758a 100644 --- a/graf3d/eve/inc/TEveMacro.h +++ b/graf3d/eve/inc/TEveMacro.h @@ -26,7 +26,7 @@ class TEveMacro : public TMacro TEveMacro(const char* name); virtual ~TEveMacro() {} - virtual Long_t Exec(const char* params = "0", Int_t* error = 0); + virtual Longptr_t Exec(const char* params = "0", Int_t* error = 0); void ResetRoot(); diff --git a/graf3d/eve/src/TEveBrowser.cxx b/graf3d/eve/src/TEveBrowser.cxx index dd01401f39a44..cd1b09cdc6936 100644 --- a/graf3d/eve/src/TEveBrowser.cxx +++ b/graf3d/eve/src/TEveBrowser.cxx @@ -626,7 +626,7 @@ void TEveBrowser::EveMenu(Int_t id) } case kNewTextEditor: { StartEmbedding(1); - gROOT->ProcessLineFast(Form("new TGTextEditor((const char *)0, (const TGWindow *)0x%lx)", (ULong_t)gClient->GetRoot())); + gROOT->ProcessLineFast(Form("new TGTextEditor((const char *)0, (const TGWindow *)0x%zx)", (size_t)gClient->GetRoot())); StopEmbedding(); SetTabTitle("Editor", 1); break; @@ -637,7 +637,7 @@ void TEveBrowser::EveMenu(Int_t id) { StartEmbedding(1); gROOT->ProcessLine(Form("new TGHtmlBrowser(\"http://root.cern.ch/root/html/ClassIndex.html\", \ - (const TGWindow *)0x%lx)", (ULong_t)gClient->GetRoot())); + (const TGWindow *)0x%zx)", (size_t)gClient->GetRoot())); StopEmbedding(); SetTabTitle("HTML", 1); } diff --git a/graf3d/eve/src/TEveDigitSet.cxx b/graf3d/eve/src/TEveDigitSet.cxx index 4de6bc35f4f2c..7bef1f1bdfc6b 100644 --- a/graf3d/eve/src/TEveDigitSet.cxx +++ b/graf3d/eve/src/TEveDigitSet.cxx @@ -397,8 +397,8 @@ void TEveDigitSet::DigitSelected(Int_t idx) if (fEmitSignals) { SecSelected(this, idx); } else { - printf("TEveDigitSet::DigitSelected idx=%d, value=%d, obj=0x%lx\n", - idx, qb->fValue, (ULong_t)obj); + printf("TEveDigitSet::DigitSelected idx=%d, value=%d, obj=0x%zx\n", + idx, qb->fValue, (size_t)obj); if (obj) obj->Print(); } @@ -410,9 +410,9 @@ void TEveDigitSet::DigitSelected(Int_t idx) void TEveDigitSet::SecSelected(TEveDigitSet* qs, Int_t idx) { - Long_t args[2]; - args[0] = (Long_t) qs; - args[1] = (Long_t) idx; + Longptr_t args[2]; + args[0] = (Longptr_t) qs; + args[1] = (Longptr_t) idx; Emit("SecSelected(TEveDigitSet*, Int_t)", args); } diff --git a/graf3d/eve/src/TEveElement.cxx b/graf3d/eve/src/TEveElement.cxx index dcf7bb108e997..186ca54797b57 100644 --- a/graf3d/eve/src/TEveElement.cxx +++ b/graf3d/eve/src/TEveElement.cxx @@ -957,7 +957,7 @@ void TEveElement::SpawnEditor() void TEveElement::ExportToCINT(char* var_name) { const char* cname = IsA()->GetName(); - gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%lx;", cname, var_name, cname, (ULong_t)this)); + gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%zx;", cname, var_name, cname, (size_t)this)); } //////////////////////////////////////////////////////////////////////////////// @@ -1003,7 +1003,7 @@ void TEveElement::ExportSourceObjectToCINT(char* var_name) const throw eh + "source-object not set."; const char* cname = so->IsA()->GetName(); - gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%lx;", cname, var_name, cname, (ULong_t)so)); + gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%zx;", cname, var_name, cname, (size_t)so)); } //////////////////////////////////////////////////////////////////////////////// @@ -1702,8 +1702,8 @@ void TEveElement::Destroy() static const TEveException eh("TEveElement::Destroy "); if (fDenyDestroy > 0) - throw eh + TString::Format("element '%s' (%s*) 0x%lx is protected against destruction.", - GetElementName(), IsA()->GetName(), (ULong_t)this); + throw eh + TString::Format("element '%s' (%s*) 0x%zx is protected against destruction.", + GetElementName(), IsA()->GetName(), (size_t)this); PreDeleteElement(); delete this; diff --git a/graf3d/eve/src/TEveMacro.cxx b/graf3d/eve/src/TEveMacro.cxx index c8baedd504847..d0b5240228338 100644 --- a/graf3d/eve/src/TEveMacro.cxx +++ b/graf3d/eve/src/TEveMacro.cxx @@ -59,9 +59,9 @@ TEveMacro::TEveMacro(const char* name) : //////////////////////////////////////////////////////////////////////////////// /// Execute the macro. -Long_t TEveMacro::Exec(const char* params, Int_t* error) +Longptr_t TEveMacro::Exec(const char* params, Int_t* error) { - Long_t retval = -1; + Longptr_t retval = -1; if (gROOT->GetGlobalFunction(fName, 0, kTRUE) != 0) { diff --git a/graf3d/eve/src/TEveSelection.cxx b/graf3d/eve/src/TEveSelection.cxx index 92b65350aa34b..b82dec8e54d64 100644 --- a/graf3d/eve/src/TEveSelection.cxx +++ b/graf3d/eve/src/TEveSelection.cxx @@ -228,7 +228,7 @@ void TEveSelection::RecheckImpliedSetForElement(TEveElement* el) void TEveSelection::SelectionAdded(TEveElement* el) { - Emit("SelectionAdded(TEveElement*)", (Long_t)el); + Emit("SelectionAdded(TEveElement*)", (Longptr_t)el); } //////////////////////////////////////////////////////////////////////////////// @@ -236,7 +236,7 @@ void TEveSelection::SelectionAdded(TEveElement* el) void TEveSelection::SelectionRemoved(TEveElement* el) { - Emit("SelectionRemoved(TEveElement*)", (Long_t)el); + Emit("SelectionRemoved(TEveElement*)", (Longptr_t)el); } //////////////////////////////////////////////////////////////////////////////// @@ -252,7 +252,7 @@ void TEveSelection::SelectionCleared() void TEveSelection::SelectionRepeated(TEveElement* el) { - Emit("SelectionRepeated(TEveElement*)", (Long_t)el); + Emit("SelectionRepeated(TEveElement*)", (Longptr_t)el); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf3d/eve/src/TEveTrack.cxx b/graf3d/eve/src/TEveTrack.cxx index 41d2aca3a5fc0..b97b6d86b5e6f 100644 --- a/graf3d/eve/src/TEveTrack.cxx +++ b/graf3d/eve/src/TEveTrack.cxx @@ -545,7 +545,7 @@ void TEveTrack::PrintPathMarks() void TEveTrack::SecSelected(TEveTrack* track) { - Emit("SecSelected(TEveTrack*)", (Long_t)track); + Emit("SecSelected(TEveTrack*)", (Longptr_t)track); } /** \class TEveTrackList diff --git a/graf3d/eve/src/TEveWindowManager.cxx b/graf3d/eve/src/TEveWindowManager.cxx index b71ae788949d5..976946b3127a1 100644 --- a/graf3d/eve/src/TEveWindowManager.cxx +++ b/graf3d/eve/src/TEveWindowManager.cxx @@ -94,7 +94,7 @@ void TEveWindowManager::DeleteWindow(TEveWindow* window) void TEveWindowManager::WindowDocked(TEveWindow* window) { - Emit("WindowDocked(TEveWindow*)", (Long_t)window); + Emit("WindowDocked(TEveWindow*)", (Longptr_t)window); } //////////////////////////////////////////////////////////////////////////////// @@ -102,7 +102,7 @@ void TEveWindowManager::WindowDocked(TEveWindow* window) void TEveWindowManager::WindowUndocked(TEveWindow* window) { - Emit("WindowUndocked(TEveWindow*)", (Long_t)window); + Emit("WindowUndocked(TEveWindow*)", (Longptr_t)window); } //////////////////////////////////////////////////////////////////////////////// @@ -110,7 +110,7 @@ void TEveWindowManager::WindowUndocked(TEveWindow* window) void TEveWindowManager::WindowSelected(TEveWindow* window) { - Emit("WindowSelected(TEveWindow*)", (Long_t)window); + Emit("WindowSelected(TEveWindow*)", (Longptr_t)window); } //////////////////////////////////////////////////////////////////////////////// @@ -118,7 +118,7 @@ void TEveWindowManager::WindowSelected(TEveWindow* window) void TEveWindowManager::WindowDeleted(TEveWindow* window) { - Emit("WindowDeleted(TEveWindow*)", (Long_t)window); + Emit("WindowDeleted(TEveWindow*)", (Longptr_t)window); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf3d/eve7/src/REveElement.cxx b/graf3d/eve7/src/REveElement.cxx index 5857fbc3ed3e3..8c1237d3d9b4c 100644 --- a/graf3d/eve7/src/REveElement.cxx +++ b/graf3d/eve7/src/REveElement.cxx @@ -561,7 +561,7 @@ TClass *REveElement::IsA() const void REveElement::ExportToCINT(const char *var_name) { const char* cname = IsA()->GetName(); - gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%lx;", cname, var_name, cname, (ULong_t)this)); + gROOT->ProcessLine(TString::Format("%s* %s = (%s*)0x%zx;", cname, var_name, cname, (size_t)this)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf3d/g3d/src/TPointSet3D.cxx b/graf3d/g3d/src/TPointSet3D.cxx index d8ddb7fb99115..3926438b0e7bc 100644 --- a/graf3d/g3d/src/TPointSet3D.cxx +++ b/graf3d/g3d/src/TPointSet3D.cxx @@ -145,8 +145,8 @@ void TPointSet3D::ClearIds() void TPointSet3D::PointSelected(Int_t n) { TObject* id = GetPointId(n); - printf("TPointSet3D::PointSelected n=%d, id=(%s*)0x%lx\n", - n, id ? id->IsA()->GetName() : "void", (ULong_t)id); + printf("TPointSet3D::PointSelected n=%d, id=(%s*)0x%zx\n", + n, id ? id->IsA()->GetName() : "void", (size_t)id); if (id) id->Print(); } diff --git a/graf3d/gl/inc/TGLSAFrame.h b/graf3d/gl/inc/TGLSAFrame.h index b634f87796c57..070f793ccf8d9 100644 --- a/graf3d/gl/inc/TGLSAFrame.h +++ b/graf3d/gl/inc/TGLSAFrame.h @@ -39,7 +39,7 @@ class TGLSAFrame : public TGMainFrame TGLSAFrame(const TGWindow *parent, TGLSAViewer &viewer); virtual ~TGLSAFrame(); - Bool_t ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2); + Bool_t ProcessMessage(Longptr_t msg, Longptr_t parm1, Longptr_t parm2); void CloseWindow(); ClassDef(TGLSAFrame, 0) // GUI frame for standalone viewer diff --git a/graf3d/gl/src/TGL5DPainter.cxx b/graf3d/gl/src/TGL5DPainter.cxx index cffd9e949e57f..fe9663dc45884 100644 --- a/graf3d/gl/src/TGL5DPainter.cxx +++ b/graf3d/gl/src/TGL5DPainter.cxx @@ -259,7 +259,7 @@ void TGL5DPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (fBoxCut.IsActive()) fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } diff --git a/graf3d/gl/src/TGLBoxPainter.cxx b/graf3d/gl/src/TGLBoxPainter.cxx index 2c69ac5405e0f..e7562b3869b81 100644 --- a/graf3d/gl/src/TGLBoxPainter.cxx +++ b/graf3d/gl/src/TGLBoxPainter.cxx @@ -226,7 +226,7 @@ void TGLBoxPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (fBoxCut.IsActive()) fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { diff --git a/graf3d/gl/src/TGLContext.cxx b/graf3d/gl/src/TGLContext.cxx index 8b48b775617e5..333493846aed2 100644 --- a/graf3d/gl/src/TGLContext.cxx +++ b/graf3d/gl/src/TGLContext.cxx @@ -59,8 +59,8 @@ TGLContext::TGLContext(TGLWidget *wid, Bool_t shareDefault, shareList = TGLContextIdentity::GetDefaultContextAny(); if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SetContext((TGLWidget *)0x%lx, (TGLContext *)0x%lx)", - (ULong_t)this, (ULong_t)wid, (ULong_t)shareList)); + gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->SetContext((TGLWidget *)0x%zx, (TGLContext *)0x%zx)", + (size_t)this, (size_t)wid, (size_t)shareList)); } else { R__LOCKGUARD(gROOTMutex); @@ -173,7 +173,7 @@ Bool_t TGLContext::MakeCurrent() } if (!gVirtualX->IsCmdThread()) - return Bool_t(gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->MakeCurrent()", this))); + return Bool_t(gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->MakeCurrent()", (size_t)this))); else { R__LOCKGUARD(gROOTMutex); @@ -208,7 +208,7 @@ void TGLContext::SwapBuffers() } if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SwapBuffers()", this)); + gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->SwapBuffers()", (size_t)this)); else { R__LOCKGUARD(gROOTMutex); @@ -227,7 +227,7 @@ void TGLContext::SwapBuffers() void TGLContext::Release() { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->Release()", this)); + gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->Release()", (size_t)this)); return; } diff --git a/graf3d/gl/src/TGLCylinder.cxx b/graf3d/gl/src/TGLCylinder.cxx index 607db82fb6fce..ab9df67607de7 100644 --- a/graf3d/gl/src/TGLCylinder.cxx +++ b/graf3d/gl/src/TGLCylinder.cxx @@ -627,8 +627,8 @@ Short_t TGLCylinder::QuantizeShapeLOD(Short_t shapeLOD, Short_t combiLOD) const void TGLCylinder::DirectDraw(TGLRnrCtx & rnrCtx) const { if (gDebug > 4) { - Info("TGLCylinder::DirectDraw", "this %ld (class %s) LOD %d", - (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLCylinder::DirectDraw", "this %zd (class %s) LOD %d", + (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } // As we are now support display list caching we can create, draw and diff --git a/graf3d/gl/src/TGLFaceSet.cxx b/graf3d/gl/src/TGLFaceSet.cxx index fdcbcfefed5c2..01180d849eb15 100644 --- a/graf3d/gl/src/TGLFaceSet.cxx +++ b/graf3d/gl/src/TGLFaceSet.cxx @@ -312,7 +312,7 @@ void TGLFaceSet::EnforceTriangles() void TGLFaceSet::DirectDraw(TGLRnrCtx & rnrCtx) const { if (gDebug > 4) { - Info("TGLFaceSet::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLFaceSet::DirectDraw", "this %zd (class %s) LOD %d", (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } if (fNbPols == 0) return; diff --git a/graf3d/gl/src/TGLLegoPainter.cxx b/graf3d/gl/src/TGLLegoPainter.cxx index 69402c702024f..73248c2e86527 100644 --- a/graf3d/gl/src/TGLLegoPainter.cxx +++ b/graf3d/gl/src/TGLLegoPainter.cxx @@ -1078,7 +1078,7 @@ void TGLLegoPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) fBoxCut.TurnOnOff(); //gGLManager->PaintSingleObject(this); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { diff --git a/graf3d/gl/src/TGLLogicalShape.cxx b/graf3d/gl/src/TGLLogicalShape.cxx index 86ecedb0e4a78..09abc15e2707a 100644 --- a/graf3d/gl/src/TGLLogicalShape.cxx +++ b/graf3d/gl/src/TGLLogicalShape.cxx @@ -375,7 +375,7 @@ void TGLLogicalShape::Draw(TGLRnrCtx& rnrCtx) const { // Debug tracing if (gDebug > 4) { - Info("TGLLogicalShape::Draw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLLogicalShape::Draw", "this %zd (class %s) LOD %d", (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } entry_point: diff --git a/graf3d/gl/src/TGLOverlayButton.cxx b/graf3d/gl/src/TGLOverlayButton.cxx index ef6507c36c056..9794303215a1f 100644 --- a/graf3d/gl/src/TGLOverlayButton.cxx +++ b/graf3d/gl/src/TGLOverlayButton.cxx @@ -141,7 +141,7 @@ void TGLOverlayButton::Render(TGLRnrCtx& rnrCtx) void TGLOverlayButton::Clicked(TGLViewerBase *viewer) { - Emit("Clicked(TGLViewerBase*)", (Long_t)viewer); + Emit("Clicked(TGLViewerBase*)", (Longptr_t)viewer); } /******************************************************************************/ diff --git a/graf3d/gl/src/TGLPShapeObjEditor.cxx b/graf3d/gl/src/TGLPShapeObjEditor.cxx index 61e32a18ea9bb..55681d4196743 100644 --- a/graf3d/gl/src/TGLPShapeObjEditor.cxx +++ b/graf3d/gl/src/TGLPShapeObjEditor.cxx @@ -514,7 +514,7 @@ namespace { void TGLPShapeObjEditor::DrawSphere()const { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLPShapeObjEditor *)0x%lx)->DrawSphere()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPShapeObjEditor *)0x%zx)->DrawSphere()", (size_t)this)); return; } diff --git a/graf3d/gl/src/TGLPadPainter.cxx b/graf3d/gl/src/TGLPadPainter.cxx index 159a11a0e7840..0fbeccbfcbc36 100644 --- a/graf3d/gl/src/TGLPadPainter.cxx +++ b/graf3d/gl/src/TGLPadPainter.cxx @@ -978,7 +978,7 @@ void TGLPadPainter::SaveImage(TVirtualPad *pad, const char *fileName, Int_t type if (!canvas) return; - gROOT->ProcessLine(Form("((TCanvas *)0x%lx)->Flush();", (ULong_t)canvas)); + gROOT->ProcessLine(Form("((TCanvas *)0x%zx)->Flush();", (size_t)canvas)); std::vector buff(canvas->GetWw() * canvas->GetWh()); glPixelStorei(GL_PACK_ALIGNMENT, 1); diff --git a/graf3d/gl/src/TGLParametric.cxx b/graf3d/gl/src/TGLParametric.cxx index 7468b8a71109d..09e5a7ad4ece3 100644 --- a/graf3d/gl/src/TGLParametric.cxx +++ b/graf3d/gl/src/TGLParametric.cxx @@ -473,7 +473,7 @@ void TGLParametricPlot::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (event == kButton1Double && fBoxCut.IsActive()) { fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress) { diff --git a/graf3d/gl/src/TGLPhysicalShape.cxx b/graf3d/gl/src/TGLPhysicalShape.cxx index 95f48afed2747..62e48fe5a32e0 100644 --- a/graf3d/gl/src/TGLPhysicalShape.cxx +++ b/graf3d/gl/src/TGLPhysicalShape.cxx @@ -339,8 +339,8 @@ void TGLPhysicalShape::Draw(TGLRnrCtx & rnrCtx) const { // Debug tracing if (gDebug > 4) { - Info("TGLPhysicalShape::Draw", "this %ld (class %s) LOD %d", - (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLPhysicalShape::Draw", "this %zd (class %s) LOD %d", + (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } // If LOD is pixel or less can draw pixel(point) directly, skipping @@ -358,8 +358,8 @@ void TGLPhysicalShape::Draw(TGLRnrCtx & rnrCtx) const } if (gDebug > 4) { - Info("TGLPhysicalShape::Draw", "this %ld (class %s) LOD %d", - (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLPhysicalShape::Draw", "this %zd (class %s) LOD %d", + (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } glPushMatrix(); diff --git a/graf3d/gl/src/TGLPolyLine.cxx b/graf3d/gl/src/TGLPolyLine.cxx index 460b8070f1255..5227d422e995f 100644 --- a/graf3d/gl/src/TGLPolyLine.cxx +++ b/graf3d/gl/src/TGLPolyLine.cxx @@ -50,7 +50,7 @@ TGLPolyLine::TGLPolyLine(const TBuffer3D & buffer) : void TGLPolyLine::DirectDraw(TGLRnrCtx & rnrCtx) const { if (gDebug > 4) { - Info("TGLPolyLine::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLPolyLine::DirectDraw", "this %zd (class %s) LOD %d", (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } if (rnrCtx.DrawPass() == TGLRnrCtx::kPassOutlineLine) diff --git a/graf3d/gl/src/TGLPolyMarker.cxx b/graf3d/gl/src/TGLPolyMarker.cxx index da9c786669e60..c4b72ff6cb9f2 100644 --- a/graf3d/gl/src/TGLPolyMarker.cxx +++ b/graf3d/gl/src/TGLPolyMarker.cxx @@ -55,7 +55,7 @@ TGLPolyMarker::TGLPolyMarker(const TBuffer3D & buffer) : void TGLPolyMarker::DirectDraw(TGLRnrCtx & rnrCtx) const { if (gDebug > 4) { - Info("TGLPolyMarker::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLPolyMarker::DirectDraw", "this %zd (class %s) LOD %d", (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } if (rnrCtx.DrawPass() == TGLRnrCtx::kPassOutlineLine) diff --git a/graf3d/gl/src/TGLSAFrame.cxx b/graf3d/gl/src/TGLSAFrame.cxx index 0f168a33bb1d7..9dd54bbddccce 100644 --- a/graf3d/gl/src/TGLSAFrame.cxx +++ b/graf3d/gl/src/TGLSAFrame.cxx @@ -48,7 +48,7 @@ TGLSAFrame::~TGLSAFrame() //////////////////////////////////////////////////////////////////////////////// /// Process GUI message - deferred back up to TGLSAViewer::ProcessFrameMessage() -Bool_t TGLSAFrame::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2) +Bool_t TGLSAFrame::ProcessMessage(Longptr_t msg, Longptr_t parm1, Longptr_t parm2) { return fViewer.ProcessFrameMessage(msg, parm1, parm2); } diff --git a/graf3d/gl/src/TGLScene.cxx b/graf3d/gl/src/TGLScene.cxx index fb0ecbc67f5ff..17273f550bc7e 100644 --- a/graf3d/gl/src/TGLScene.cxx +++ b/graf3d/gl/src/TGLScene.cxx @@ -570,8 +570,8 @@ void TGLScene::PreDraw(TGLRnrCtx& rnrCtx) TSceneInfo* sinfo = dynamic_cast(rnrCtx.GetSceneInfo()); if (sinfo == 0 || sinfo->GetScene() != this) { TGLSceneInfo* si = rnrCtx.GetSceneInfo(); - Error("TGLScene::PreDraw", "%s", Form("SceneInfo mismatch (0x%lx, '%s').", - (ULong_t)si, si ? si->IsA()->GetName() : "<>")); + Error("TGLScene::PreDraw", "%s", Form("SceneInfo mismatch (0x%zx, '%s').", + (size_t)si, si ? si->IsA()->GetName() : "<>")); return; } diff --git a/graf3d/gl/src/TGLSphere.cxx b/graf3d/gl/src/TGLSphere.cxx index 943eb44aa4a0d..b6f715db82cac 100644 --- a/graf3d/gl/src/TGLSphere.cxx +++ b/graf3d/gl/src/TGLSphere.cxx @@ -92,7 +92,7 @@ Short_t TGLSphere::QuantizeShapeLOD(Short_t shapeLOD, Short_t combiLOD) const void TGLSphere::DirectDraw(TGLRnrCtx & rnrCtx) const { if (gDebug > 4) { - Info("TGLSphere::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); + Info("TGLSphere::DirectDraw", "this %zd (class %s) LOD %d", (size_t)this, IsA()->GetName(), rnrCtx.ShapeLOD()); } // 4 stack/slice min for gluSphere to work diff --git a/graf3d/gl/src/TGLSurfacePainter.cxx b/graf3d/gl/src/TGLSurfacePainter.cxx index 9a906f6c415d8..1bde95da9e221 100644 --- a/graf3d/gl/src/TGLSurfacePainter.cxx +++ b/graf3d/gl/src/TGLSurfacePainter.cxx @@ -215,7 +215,7 @@ void TGLSurfacePainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (fBoxCut.IsActive()) fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { diff --git a/graf3d/gl/src/TGLTF3Painter.cxx b/graf3d/gl/src/TGLTF3Painter.cxx index 48ff71cac4c31..a235ed08b7fe4 100644 --- a/graf3d/gl/src/TGLTF3Painter.cxx +++ b/graf3d/gl/src/TGLTF3Painter.cxx @@ -180,7 +180,7 @@ void TGLTF3Painter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) fXOYSectionPos = frame[0].Z(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } @@ -584,7 +584,7 @@ void TGLIsoPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) fXOYSectionPos = frame[0].Z(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } diff --git a/graf3d/gl/src/TGLTH3Composition.cxx b/graf3d/gl/src/TGLTH3Composition.cxx index 60d6a86eaeb96..c7472ed96f63a 100644 --- a/graf3d/gl/src/TGLTH3Composition.cxx +++ b/graf3d/gl/src/TGLTH3Composition.cxx @@ -240,7 +240,7 @@ void TGLTH3CompositionPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (event == kButton1Double && fBoxCut.IsActive()) { fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { diff --git a/graf3d/gl/src/TGLViewer.cxx b/graf3d/gl/src/TGLViewer.cxx index 2c2459fe7af68..4138d439f1409 100644 --- a/graf3d/gl/src/TGLViewer.cxx +++ b/graf3d/gl/src/TGLViewer.cxx @@ -456,7 +456,7 @@ void TGLViewer::RequestDraw(Short_t LODInput) fLOD = LODInput; if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw()", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoDraw()", (size_t)this)); else DoDraw(); } @@ -852,7 +852,7 @@ Bool_t TGLViewer::SavePictureUsingBB(const TString &fileName) fRnrCtx->SetGrabImage(kTRUE); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoDraw(kFALSE)", (size_t)this)); else DoDraw(kFALSE); @@ -942,7 +942,7 @@ Bool_t TGLViewer::SavePictureUsingFBO(const TString &fileName, Int_t w, Int_t h, fRnrCtx->SetGrabImage(kTRUE); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoDraw(kFALSE)", (size_t)this)); else DoDraw(kFALSE); @@ -996,7 +996,7 @@ TImage* TGLViewer::GetPictureUsingBB() fRnrCtx->SetGrabImage(kTRUE); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoDraw(kFALSE)", (size_t)this)); else DoDraw(kFALSE); @@ -1075,7 +1075,7 @@ TImage* TGLViewer::GetPictureUsingFBO(Int_t w, Int_t h,Float_t pixel_object_scal fRnrCtx->SetGrabImage(kTRUE); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this)); + gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoDraw(kFALSE)", (size_t)this)); else DoDraw(kFALSE); @@ -1312,7 +1312,7 @@ Bool_t TGLViewer::RequestSelect(Int_t x, Int_t y) } if (!gVirtualX->IsCmdThread()) - return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSelect(%d, %d)", (ULong_t)this, x, y))); + return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoSelect(%d, %d)", (size_t)this, x, y))); else return DoSelect(x, y); } @@ -1385,7 +1385,7 @@ Bool_t TGLViewer::RequestSecondarySelect(Int_t x, Int_t y) } if (!gVirtualX->IsCmdThread()) - return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSecondarySelect(%d, %d)", (ULong_t)this, x, y))); + return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoSecondarySelect(%d, %d)", (size_t)this, x, y))); else return DoSecondarySelect(x, y); } @@ -1411,8 +1411,8 @@ Bool_t TGLViewer::DoSecondarySelect(Int_t x, Int_t y) { if (gDebug > 0) Info("TGLViewer::SecondarySelect", "Skipping secondary selection " - "(sinfo=0x%lx, pshape=0x%lx).\n", - (Long_t)fSelRec.GetSceneInfo(), (Long_t)fSelRec.GetPhysShape()); + "(sinfo=0x%zx, pshape=0x%zx).\n", + (size_t)fSelRec.GetSceneInfo(), (size_t)fSelRec.GetPhysShape()); fSecSelRec.Reset(); return kFALSE; } @@ -1495,7 +1495,7 @@ Bool_t TGLViewer::RequestOverlaySelect(Int_t x, Int_t y) } if (!gVirtualX->IsCmdThread()) - return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoOverlaySelect(%d, %d)", (ULong_t)this, x, y))); + return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%zx)->DoOverlaySelect(%d, %d)", (size_t)this, x, y))); else return DoOverlaySelect(x, y); } @@ -2093,7 +2093,7 @@ const TGLPhysicalShape * TGLViewer::GetSelected() const void TGLViewer::MouseOver(TGLPhysicalShape *shape) { - Emit("MouseOver(TGLPhysicalShape*)", (Long_t)shape); + Emit("MouseOver(TGLPhysicalShape*)", (Longptr_t)shape); } //////////////////////////////////////////////////////////////////////////////// @@ -2101,8 +2101,8 @@ void TGLViewer::MouseOver(TGLPhysicalShape *shape) void TGLViewer::MouseOver(TGLPhysicalShape *shape, UInt_t state) { - Long_t args[2]; - args[0] = (Long_t)shape; + Longptr_t args[2]; + args[0] = (Longptr_t)shape; args[1] = state; Emit("MouseOver(TGLPhysicalShape*,UInt_t)", args); } @@ -2112,8 +2112,8 @@ void TGLViewer::MouseOver(TGLPhysicalShape *shape, UInt_t state) void TGLViewer::MouseOver(TObject *obj, UInt_t state) { - Long_t args[2]; - args[0] = (Long_t)obj; + Longptr_t args[2]; + args[0] = (Longptr_t)obj; args[1] = state; Emit("MouseOver(TObject*,UInt_t)", args); } @@ -2123,8 +2123,8 @@ void TGLViewer::MouseOver(TObject *obj, UInt_t state) void TGLViewer::ReMouseOver(TObject *obj, UInt_t state) { - Long_t args[2]; - args[0] = (Long_t)obj; + Longptr_t args[2]; + args[0] = (Longptr_t)obj; args[1] = state; Emit("ReMouseOver(TObject*,UInt_t)", args); } @@ -2135,8 +2135,8 @@ void TGLViewer::ReMouseOver(TObject *obj, UInt_t state) void TGLViewer::UnMouseOver(TObject *obj, UInt_t state) { - Long_t args[2]; - args[0] = (Long_t)obj; + Longptr_t args[2]; + args[0] = (Longptr_t)obj; args[1] = state; Emit("UnMouseOver(TObject*,UInt_t)", args); } @@ -2146,7 +2146,7 @@ void TGLViewer::UnMouseOver(TObject *obj, UInt_t state) void TGLViewer::Clicked(TObject *obj) { - Emit("Clicked(TObject*)", (Long_t)obj); + Emit("Clicked(TObject*)", (Longptr_t)obj); } //////////////////////////////////////////////////////////////////////////////// @@ -2154,8 +2154,8 @@ void TGLViewer::Clicked(TObject *obj) void TGLViewer::Clicked(TObject *obj, UInt_t button, UInt_t state) { - Long_t args[3]; - args[0] = (Long_t)obj; + Longptr_t args[3]; + args[0] = (Longptr_t)obj; args[1] = button; args[2] = state; Emit("Clicked(TObject*,UInt_t,UInt_t)", args); @@ -2167,8 +2167,8 @@ void TGLViewer::Clicked(TObject *obj, UInt_t button, UInt_t state) void TGLViewer::ReClicked(TObject *obj, UInt_t button, UInt_t state) { - Long_t args[3]; - args[0] = (Long_t)obj; + Longptr_t args[3]; + args[0] = (Longptr_t)obj; args[1] = button; args[2] = state; Emit("ReClicked(TObject*,UInt_t,UInt_t)", args); @@ -2179,8 +2179,8 @@ void TGLViewer::ReClicked(TObject *obj, UInt_t button, UInt_t state) void TGLViewer::UnClicked(TObject *obj, UInt_t button, UInt_t state) { - Long_t args[3]; - args[0] = (Long_t)obj; + Longptr_t args[3]; + args[0] = (Longptr_t)obj; args[1] = button; args[2] = state; Emit("UnClicked(TObject*,UInt_t,UInt_t)", args); @@ -2191,11 +2191,11 @@ void TGLViewer::UnClicked(TObject *obj, UInt_t button, UInt_t state) void TGLViewer::MouseIdle(TGLPhysicalShape *shape, UInt_t posx, UInt_t posy) { - Long_t args[3]; + Longptr_t args[3]; static UInt_t oldx = 0, oldy = 0; if (oldx != posx || oldy != posy) { - args[0] = (Long_t)shape; + args[0] = (Longptr_t)shape; args[1] = posx; args[2] = posy; Emit("MouseIdle(TGLPhysicalShape*,UInt_t,UInt_t)", args); diff --git a/graf3d/gl/src/TGLVoxelPainter.cxx b/graf3d/gl/src/TGLVoxelPainter.cxx index 1ac539947cba5..ffdbf8f00a93b 100644 --- a/graf3d/gl/src/TGLVoxelPainter.cxx +++ b/graf3d/gl/src/TGLVoxelPainter.cxx @@ -181,7 +181,7 @@ void TGLVoxelPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) if (fBoxCut.IsActive()) fBoxCut.TurnOnOff(); if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", ULong_t(this))); + gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%zx)->Paint()", (size_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { diff --git a/graf3d/gl/src/TGLWidget.cxx b/graf3d/gl/src/TGLWidget.cxx index 051eaeb534442..07f9e085fde66 100644 --- a/graf3d/gl/src/TGLWidget.cxx +++ b/graf3d/gl/src/TGLWidget.cxx @@ -108,7 +108,7 @@ TGLWidget* TGLWidget::Create(const TGLFormat &format, TGLWidget* glw = new TGLWidget(wid, parent, selectInput); #ifdef WIN32 - glw->fWindowIndex = (Int_t) innerData.second; + glw->fWindowIndex = (Int_t)(Longptr_t)innerData.second; #elif defined(R__HAS_COCOA) glw->fWindowIndex = wid; #else @@ -347,8 +347,8 @@ Window_t TGLWidget::CreateWindow(const TGWindow* parent, const TGLFormat& /*form UInt_t width, UInt_t height, std::pair& innerData) { - Int_t widx = gVirtualX->InitWindow((ULong_t)parent->GetId()); - innerData.second = (void*) widx; + Int_t widx = gVirtualX->InitWindow((ULongptr_t)parent->GetId()); + innerData.second = (void*)(Longptr_t)widx; Window_t win = gVirtualX->GetWindowID(widx); gVirtualX->ResizeWindow(win, width, height); return win; @@ -365,7 +365,7 @@ void TGLWidget::SetFormat() return; } if (!gVirtualX->IsCmdThread()) - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->SetFormat()", this)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->SetFormat()", (size_t)this)); R__LOCKGUARD(gROOTMutex); @@ -566,7 +566,7 @@ void TGLWidget::SetEventHandler(TGEventHandler *eh) Bool_t TGLWidget::HandleCrossing(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleCrossing((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleCrossing((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -587,7 +587,7 @@ Bool_t TGLWidget::HandleCrossing(Event_t *ev) Bool_t TGLWidget::HandleButton(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleButton((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleButton((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -603,7 +603,7 @@ Bool_t TGLWidget::HandleButton(Event_t *ev) Bool_t TGLWidget::HandleDoubleClick(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleDoubleClick((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleDoubleClick((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -619,7 +619,7 @@ Bool_t TGLWidget::HandleDoubleClick(Event_t *ev) Bool_t TGLWidget::HandleConfigureNotify(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleConfigureNotify((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleConfigureNotify((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -638,7 +638,7 @@ Bool_t TGLWidget::HandleConfigureNotify(Event_t *ev) Bool_t TGLWidget::HandleFocusChange(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleFocusChange((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleFocusChange((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -654,7 +654,7 @@ Bool_t TGLWidget::HandleFocusChange(Event_t *ev) Bool_t TGLWidget::HandleKey(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleKey((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleKey((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); @@ -670,7 +670,7 @@ Bool_t TGLWidget::HandleKey(Event_t *ev) Bool_t TGLWidget::HandleMotion(Event_t *ev) { if (!gVirtualX->IsCmdThread()) { - gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleMotion((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev)); + gROOT->ProcessLineFast(Form("((TGLWidget *)0x%zx)->HandleMotion((Event_t *)0x%zx)", (size_t)this, (size_t)ev)); return kTRUE; } R__LOCKGUARD(gROOTMutex); diff --git a/graf3d/gviz3d/src/TStructViewer.cxx b/graf3d/gviz3d/src/TStructViewer.cxx index e3fc0717d4a3b..a034eceda046d 100644 --- a/graf3d/gviz3d/src/TStructViewer.cxx +++ b/graf3d/gviz3d/src/TStructViewer.cxx @@ -154,17 +154,17 @@ void TStructViewer::CountMembers(TClass* cl, TStructNode* parent, void* pointer) continue; } - void** pptr = (void**)((ULong_t)pointer + dm->GetOffset()); + void** pptr = (void**)((ULongptr_t)pointer + dm->GetOffset()); ptr = *pptr; if (!ptr) { continue; } - if(fPointers.GetValue((ULong_t)ptr)) { + if(fPointers.GetValue((ULongptr_t)ptr)) { continue; } else { - fPointers.Add((ULong_t)ptr, (ULong_t)ptr); + fPointers.Add((ULongptr_t)ptr, (ULongptr_t)ptr); } ULong_t size = 0; @@ -194,7 +194,7 @@ void TStructViewer::CountMembers(TClass* cl, TStructNode* parent, void* pointer) // all members of node = all nodes of parent + nodes of daughter - 1 because node is added twice parent->SetAllMembersCount(parent->GetAllMembersCount() + node->GetAllMembersCount() - 1); } else { - ptr = (void*)((ULong_t)pointer + dm->GetOffset()); + ptr = (void*)((ULongptr_t)pointer + dm->GetOffset()); if (!ptr) { continue; diff --git a/graf3d/gviz3d/src/TStructViewerGUI.cxx b/graf3d/gviz3d/src/TStructViewerGUI.cxx index 87630c524a172..3fd2cf8271726 100644 --- a/graf3d/gviz3d/src/TStructViewerGUI.cxx +++ b/graf3d/gviz3d/src/TStructViewerGUI.cxx @@ -509,7 +509,7 @@ void TStructViewerGUI::DrawNode(TStructNode* node) for (Float_t i = -(slices-1)/2; i < slices/2; i++) { TGeoVolume* sub = gGeoManager->MakeBox(Form("%s_%d", node->GetName(), fgCounter++), fgMedium,0.45*node->GetWidth() * 0.7 / slices, 0.45*node->GetHeight(), fBoxHeightEntry->GetNumber()); sub->SetLineColor(GetColor(node)); - fVolumes.Add((Long_t)sub, (Long_t)node); + fVolumes.Add((Longptr_t)sub, (Longptr_t)node); TGeoTranslation* subtrans = new TGeoTranslation("subtranslation", i * node->GetWidth() / slices, 0, 0); vol->AddNodeOverlap(sub, 1, subtrans); } @@ -521,7 +521,7 @@ void TStructViewerGUI::DrawNode(TStructNode* node) vol->SetLineWidth(1); TGeoTranslation* trans = new TGeoTranslation("translation", node->GetCenter(), node->GetMiddle(), -(node->GetLevel() * fLevelDistanceEntry->GetNumber())); - fVolumes.Add((Long_t)vol, (Long_t)node); + fVolumes.Add((Longptr_t)vol, (Longptr_t)node); fTopVolume->AddNode(vol,1, trans); } @@ -673,8 +673,8 @@ void TStructViewerGUI::MouseOverSlot(TGLPhysicalShape* shape) fSelectedObject = NULL; return; } - Long_t shapeID = (Long_t)(shape->GetLogical()->ID()); - Long_t volValue = (Long_t)fVolumes.GetValue(shapeID); + Longptr_t shapeID = (Longptr_t)(shape->GetLogical()->ID()); + Longptr_t volValue = (Longptr_t)fVolumes.GetValue(shapeID); fSelectedObject = (TStructNode*)volValue; fToolTip->SetText(TString(fSelectedObject->GetName()) + "\n" + fSelectedObject->GetTypeName()); diff --git a/graf3d/x3d/inc/TX3DFrame.h b/graf3d/x3d/inc/TX3DFrame.h index 272ea122bd077..e3419065495fa 100644 --- a/graf3d/x3d/inc/TX3DFrame.h +++ b/graf3d/x3d/inc/TX3DFrame.h @@ -28,7 +28,7 @@ class TX3DFrame : public TGMainFrame private: TViewerX3D & fViewer; - Bool_t ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2); + Bool_t ProcessMessage(Longptr_t msg, Longptr_t parm1, Longptr_t parm2); void CloseWindow(); public: diff --git a/graf3d/x3d/src/TX3DFrame.cxx b/graf3d/x3d/src/TX3DFrame.cxx index 4e08512da1724..14fe133692bba 100644 --- a/graf3d/x3d/src/TX3DFrame.cxx +++ b/graf3d/x3d/src/TX3DFrame.cxx @@ -38,7 +38,7 @@ TX3DFrame::~TX3DFrame() //////////////////////////////////////////////////////////////////////////////// /// Process Message -Bool_t TX3DFrame::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2) +Bool_t TX3DFrame::ProcessMessage(Longptr_t msg, Longptr_t parm1, Longptr_t parm2) { return fViewer.ProcessFrameMessage(msg, parm1, parm2); } From acb9383e3a470645921767c96d961ac83739a8cc Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 10:28:19 +0200 Subject: [PATCH 195/309] [webgui] use less chrome processes when running headless Do not allow to start sandbox or zygote processes, disable extensions. Reduce from 9 to 4 number of required processes with chromium 90 --- gui/webdisplay/src/RWebDisplayHandle.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/webdisplay/src/RWebDisplayHandle.cxx b/gui/webdisplay/src/RWebDisplayHandle.cxx index 2b824f8bddb56..71715db1ef02c 100644 --- a/gui/webdisplay/src/RWebDisplayHandle.cxx +++ b/gui/webdisplay/src/RWebDisplayHandle.cxx @@ -380,8 +380,8 @@ RWebDisplayHandle::ChromeCreator::ChromeCreator() : BrowserCreator(true) fHeadlessExec = gEnv->GetValue("WebGui.ChromeHeadless", "$prog --headless --disable-gpu $geometry $url &"); fExec = gEnv->GetValue("WebGui.ChromeInteractive", "$prog $geometry --no-first-run --app=$url &"); // & in windows mean usage of spawn #else - fBatchExec = gEnv->GetValue("WebGui.ChromeBatch", "$prog --headless --incognito $geometry $url"); - fHeadlessExec = gEnv->GetValue("WebGui.ChromeHeadless", "fork: --headless --incognito $geometry $url"); + fBatchExec = gEnv->GetValue("WebGui.ChromeBatch", "$prog --headless --incognito --no-sandbox --no-zygote --disable-extensions $geometry $url"); + fHeadlessExec = gEnv->GetValue("WebGui.ChromeHeadless", "fork: --headless --incognito --no-sandbox --no-zygote --disable-extensions $geometry $url"); fExec = gEnv->GetValue("WebGui.ChromeInteractive", "$prog $geometry --no-first-run --incognito --app=\'$url\' &"); #endif } From 32df6e1afbda279293d006187461ac56f52dd4b2 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 12:20:00 +0200 Subject: [PATCH 196/309] [webgui] add RUN_SERIAL to ping.cxx test It requires several threads and may conflict with other tests consuming CPU. --- gui/webdisplay/test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/webdisplay/test/CMakeLists.txt b/gui/webdisplay/test/CMakeLists.txt index d3c6900d37bae..c035b91252be5 100644 --- a/gui/webdisplay/test/CMakeLists.txt +++ b/gui/webdisplay/test/CMakeLists.txt @@ -12,6 +12,7 @@ # test only can be run if Firefox or Chrome are detected on the system if (CHROME_EXECUTABLE OR FIREFOX_EXECUTABLE) ROOT_ADD_TEST(test-webgui-ping + RUN_SERIAL COPY_TO_BUILDDIR ${CMAKE_SOURCE_DIR}/tutorials/webgui/ping/ping.cxx ${CMAKE_SOURCE_DIR}/tutorials/webgui/ping/ping.html COMMAND root.exe -b -q -l ping.cxx PASSREGEX "PING-PONG TEST COMPLETED") From 69d7d5bd87a64bc9869cb1649f8baa368b7c5374 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 12:20:23 +0200 Subject: [PATCH 197/309] [webgui] add more debug output for ping.cxx test running in batch --- tutorials/webgui/ping/ping.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tutorials/webgui/ping/ping.cxx b/tutorials/webgui/ping/ping.cxx index c94b1ba7ea3d4..e7bda1e34bc17 100644 --- a/tutorials/webgui/ping/ping.cxx +++ b/tutorials/webgui/ping/ping.cxx @@ -11,6 +11,7 @@ #include #include +#include std::shared_ptr window; @@ -143,10 +144,16 @@ void ping(int nclients = 1, int test_mode = 0) if (batch_mode) { const int run_limit = 200; const double run_time = 50.; + auto t1 = std::chrono::high_resolution_clock::now(); window->WaitFor([=](double tm) { return (current_counter >= run_limit) || (tm > run_time) ? 1 : 0; }); + auto t2 = std::chrono::high_resolution_clock::now(); + auto ms_int = std::chrono::duration_cast(t2 - t1); + if (current_counter >= run_limit) - std::cout << "PING-PONG TEST COMPLETED" << std::endl; + std::cout << "PING-PONG TEST COMPLETED"; else - std::cout << "PING-PONG TEST FAIL" << std::endl; + std::cout << "PING-PONG TEST FAIL cnt:" << current_counter; + + std::cout << " runs:" << ms_int.count() << "ms" << std::endl; } } From aab106253ce01196581111d457ee0a277c836286 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Fri, 11 Jun 2021 16:57:56 +0200 Subject: [PATCH 198/309] [mathcore] Fix list init of vector. --- math/mathcore/inc/Fit/FitUtil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/mathcore/inc/Fit/FitUtil.h b/math/mathcore/inc/Fit/FitUtil.h index a84792052ec95..c7ed221568840 100644 --- a/math/mathcore/inc/Fit/FitUtil.h +++ b/math/mathcore/inc/Fit/FitUtil.h @@ -401,7 +401,7 @@ namespace FitUtil { (const_cast &>(func)).SetParameters(p); double maxResValue = std::numeric_limits::max() / n; - std::vector ones{1, 1, 1, 1}; + std::vector ones{1., 1., 1., 1.}; auto vecSize = vecCore::VectorSize(); auto mapFunction = [&](unsigned int i) { From a00c905307ca20da8da428401b0cbda5247d2f52 Mon Sep 17 00:00:00 2001 From: Advait Dhingra <62119114+AdvaitDhingra@users.noreply.github.com> Date: Mon, 14 Jun 2021 17:52:06 +0200 Subject: [PATCH 199/309] Added a PR template file (#8423) * Added a PR template I have seen other repos with this and it is usually quite handy. * Spelling --- .github/pull_request_template.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000000..6bc0399d6f933 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,12 @@ +# This Pull request: + +## Changes or fixes: + + +## Checklist: + +- [] tested changes locally +- [] updated the docs (if necessary) + +This PR fixes # + From b9ae6c35f48be53a309375f5872862f988f38739 Mon Sep 17 00:00:00 2001 From: Bertrand Bellenot Date: Tue, 15 Jun 2021 09:18:18 +0200 Subject: [PATCH 200/309] [math] Port to Win64 (replace Long_t by Longptr_t + pointer formatting (#8410) * [math] Port to Win64 (replace Long_t by Longptr_t + pointer formatting * Add missing #include (for uintptr_t) --- math/foam/src/TFoam.cxx | 6 +- math/mathcore/src/triangle.c | 143 +++++++++++++------------ math/matrix/src/TMatrixTBase.cxx | 4 +- math/matrix/src/TVectorT.cxx | 4 +- math/minuit/src/TMinuit.cxx | 12 +-- math/mlp/src/TMLPAnalyzer.cxx | 4 +- math/mlp/src/TMultiLayerPerceptron.cxx | 26 ++--- math/mlp/src/TNeuron.cxx | 4 +- 8 files changed, 102 insertions(+), 101 deletions(-) diff --git a/math/foam/src/TFoam.cxx b/math/foam/src/TFoam.cxx index 46a73f500f980..f04a8c4ae03ae 100644 --- a/math/foam/src/TFoam.cxx +++ b/math/foam/src/TFoam.cxx @@ -1068,9 +1068,9 @@ Double_t TFoam::Eval(Double_t *xRand) Double_t result; if(!fRho) { //interactive mode - Long_t paramArr[3]; - paramArr[0]=(Long_t)fDim; - paramArr[1]=(Long_t)xRand; + Longptr_t paramArr[3]; + paramArr[0]=(Longptr_t)fDim; + paramArr[1]=(Longptr_t)xRand; fMethodCall->SetParamPtrs(paramArr); fMethodCall->Execute(result); } else { //compiled mode diff --git a/math/mathcore/src/triangle.c b/math/mathcore/src/triangle.c index 57991ff8c80c2..e1990a9484b7d 100644 --- a/math/mathcore/src/triangle.c +++ b/math/mathcore/src/triangle.c @@ -316,6 +316,7 @@ #include #include #include +#include #ifndef NO_TIMER #include #endif /* not NO_TIMER */ @@ -622,7 +623,7 @@ REAL o3derrboundA, o3derrboundB, o3derrboundC; /* Random number seed is not constant, but I've made it global anyway. */ -unsigned long randomseed; /* Current random number seed. */ +uintptr_t randomseed; /* Current random number seed. */ /* Mesh data structure. Triangle operates on only one mesh, but the mesh */ @@ -799,7 +800,7 @@ struct behavior { /* extracting an orientation (in the range 0 to 2) and a pointer to the */ /* beginning of a triangle. The encode() routine compresses a pointer to a */ /* triangle and an orientation into a single pointer. My assumptions that */ -/* triangles are four-byte-aligned and that the `unsigned long' type is */ +/* triangles are four-byte-aligned and that the `uintptr_t' type is */ /* long enough to hold a pointer are two of the few kludges in this program.*/ /* */ /* Subsegments are manipulated similarly. A pointer to a subsegment */ @@ -910,16 +911,16 @@ int minus1mod3[3] = {2, 0, 1}; /* extracted from the two least significant bits of the pointer. */ #define decode(ptr, otri) \ - (otri).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ + (otri).orient = (int) ((uintptr_t) (ptr) & (uintptr_t) 3l); \ (otri).tri = (triangle *) \ - ((unsigned long) (ptr) ^ (unsigned long) (otri).orient) + ((uintptr_t) (ptr) ^ (uintptr_t) (otri).orient) /* encode() compresses an oriented triangle into a single pointer. It */ /* relies on the assumption that all triangles are aligned to four-byte */ /* boundaries, so the two least significant bits of (otri).tri are zero. */ #define encode(otri) \ - (triangle) ((unsigned long) (otri).tri | (unsigned long) (otri).orient) + (triangle) ((uintptr_t) (otri).tri | (uintptr_t) (otri).orient) /* The following handle manipulation primitives are all described by Guibas */ /* and Stolfi. However, Guibas and Stolfi use an edge-based data */ @@ -1083,16 +1084,16 @@ int minus1mod3[3] = {2, 0, 1}; #define infect(otri) \ (otri).tri[6] = (triangle) \ - ((unsigned long) (otri).tri[6] | (unsigned long) 2l) + ((uintptr_t) (otri).tri[6] | (uintptr_t) 2l) #define uninfect(otri) \ (otri).tri[6] = (triangle) \ - ((unsigned long) (otri).tri[6] & ~ (unsigned long) 2l) + ((uintptr_t) (otri).tri[6] & ~ (uintptr_t) 2l) /* Test a triangle for viral infection. */ #define infected(otri) \ - (((unsigned long) (otri).tri[6] & (unsigned long) 2l) != 0l) + (((uintptr_t) (otri).tri[6] & (uintptr_t) 2l) != 0l) /* Check or set a triangle's attributes. */ @@ -1130,16 +1131,16 @@ int minus1mod3[3] = {2, 0, 1}; /* are masked out to produce the real pointer. */ #define sdecode(sptr, osub) \ - (osub).ssorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ + (osub).ssorient = (int) ((uintptr_t) (sptr) & (uintptr_t) 1l); \ (osub).ss = (subseg *) \ - ((unsigned long) (sptr) & ~ (unsigned long) 3l) + ((uintptr_t) (sptr) & ~ (uintptr_t) 3l) /* sencode() compresses an oriented subsegment into a single pointer. It */ /* relies on the assumption that all subsegments are aligned to two-byte */ /* boundaries, so the least significant bit of (osub).ss is zero. */ #define sencode(osub) \ - (subseg) ((unsigned long) (osub).ss | (unsigned long) (osub).ssorient) + (subseg) ((uintptr_t) (osub).ss | (uintptr_t) (osub).ssorient) /* ssym() toggles the orientation of a subsegment. */ @@ -3650,27 +3651,27 @@ struct otri *t; struct osub printsh; vertex printvertex; - printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, + printf("triangle x%zx with orientation %d:\n", (size_t) t->tri, t->orient); decode(t->tri[0], printtri); if (printtri.tri == m->dummytri) { printf(" [0] = Outer space\n"); } else { - printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, + printf(" [0] = x%zx %d\n", (size_t) printtri.tri, printtri.orient); } decode(t->tri[1], printtri); if (printtri.tri == m->dummytri) { printf(" [1] = Outer space\n"); } else { - printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, + printf(" [1] = x%zx %d\n", (size_t) printtri.tri, printtri.orient); } decode(t->tri[2], printtri); if (printtri.tri == m->dummytri) { printf(" [2] = Outer space\n"); } else { - printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, + printf(" [2] = x%zx %d\n", (size_t) printtri.tri, printtri.orient); } @@ -3678,38 +3679,38 @@ struct otri *t; if (printvertex == (vertex) NULL) printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); else - printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", - (t->orient + 1) % 3 + 3, (unsigned long) printvertex, + printf(" Origin[%d] = x%zx (%.12g, %.12g)\n", + (t->orient + 1) % 3 + 3, (size_t) printvertex, printvertex[0], printvertex[1]); dest(*t, printvertex); if (printvertex == (vertex) NULL) printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); else - printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", - (t->orient + 2) % 3 + 3, (unsigned long) printvertex, + printf(" Dest [%d] = x%zx (%.12g, %.12g)\n", + (t->orient + 2) % 3 + 3, (size_t) printvertex, printvertex[0], printvertex[1]); apex(*t, printvertex); if (printvertex == (vertex) NULL) printf(" Apex [%d] = NULL\n", t->orient + 3); else - printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", - t->orient + 3, (unsigned long) printvertex, + printf(" Apex [%d] = x%zx (%.12g, %.12g)\n", + t->orient + 3, (size_t) printvertex, printvertex[0], printvertex[1]); if (b->usesegments) { sdecode(t->tri[6], printsh); if (printsh.ss != m->dummysub) { - printf(" [6] = x%lx %d\n", (unsigned long) printsh.ss, + printf(" [6] = x%zx %d\n", (size_t) printsh.ss, printsh.ssorient); } sdecode(t->tri[7], printsh); if (printsh.ss != m->dummysub) { - printf(" [7] = x%lx %d\n", (unsigned long) printsh.ss, + printf(" [7] = x%zx %d\n", (size_t) printsh.ss, printsh.ssorient); } sdecode(t->tri[8], printsh); if (printsh.ss != m->dummysub) { - printf(" [8] = x%lx %d\n", (unsigned long) printsh.ss, + printf(" [8] = x%zx %d\n", (size_t) printsh.ss, printsh.ssorient); } } @@ -3746,20 +3747,20 @@ struct osub *s; (void)b; /*LM: added to suppress warning */ - printf("subsegment x%lx with orientation %d and mark %d:\n", - (unsigned long) s->ss, s->ssorient, mark(*s)); + printf("subsegment x%zx with orientation %d and mark %d:\n", + (size_t) s->ss, s->ssorient, mark(*s)); sdecode(s->ss[0], printsh); if (printsh.ss == m->dummysub) { printf(" [0] = No subsegment\n"); } else { - printf(" [0] = x%lx %d\n", (unsigned long) printsh.ss, + printf(" [0] = x%zx %d\n", (size_t) printsh.ss, printsh.ssorient); } sdecode(s->ss[1], printsh); if (printsh.ss == m->dummysub) { printf(" [1] = No subsegment\n"); } else { - printf(" [1] = x%lx %d\n", (unsigned long) printsh.ss, + printf(" [1] = x%zx %d\n", (size_t) printsh.ss, printsh.ssorient); } @@ -3767,29 +3768,29 @@ struct osub *s; if (printvertex == (vertex) NULL) printf(" Origin[%d] = NULL\n", 2 + s->ssorient); else - printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", - 2 + s->ssorient, (unsigned long) printvertex, + printf(" Origin[%d] = x%zx (%.12g, %.12g)\n", + 2 + s->ssorient, (size_t) printvertex, printvertex[0], printvertex[1]); sdest(*s, printvertex); if (printvertex == (vertex) NULL) printf(" Dest [%d] = NULL\n", 3 - s->ssorient); else - printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", - 3 - s->ssorient, (unsigned long) printvertex, + printf(" Dest [%d] = x%zx (%.12g, %.12g)\n", + 3 - s->ssorient, (size_t) printvertex, printvertex[0], printvertex[1]); decode(s->ss[6], printtri); if (printtri.tri == m->dummytri) { printf(" [6] = Outer space\n"); } else { - printf(" [6] = x%lx %d\n", (unsigned long) printtri.tri, + printf(" [6] = x%zx %d\n", (size_t) printtri.tri, printtri.orient); } decode(s->ss[7], printtri); if (printtri.tri == m->dummytri) { printf(" [7] = Outer space\n"); } else { - printf(" [7] = x%lx %d\n", (unsigned long) printtri.tri, + printf(" [7] = x%zx %d\n", (size_t) printtri.tri, printtri.orient); } @@ -3797,15 +3798,15 @@ struct osub *s; if (printvertex == (vertex) NULL) printf(" Segment origin[%d] = NULL\n", 4 + s->ssorient); else - printf(" Segment origin[%d] = x%lx (%.12g, %.12g)\n", - 4 + s->ssorient, (unsigned long) printvertex, + printf(" Segment origin[%d] = x%zx (%.12g, %.12g)\n", + 4 + s->ssorient, (size_t) printvertex, printvertex[0], printvertex[1]); segdest(*s, printvertex); if (printvertex == (vertex) NULL) printf(" Segment dest [%d] = NULL\n", 5 - s->ssorient); else - printf(" Segment dest [%d] = x%lx (%.12g, %.12g)\n", - 5 - s->ssorient, (unsigned long) printvertex, + printf(" Segment dest [%d] = x%zx (%.12g, %.12g)\n", + 5 - s->ssorient, (size_t) printvertex, printvertex[0], printvertex[1]); } @@ -3868,7 +3869,7 @@ struct memorypool *pool; #endif /* not ANSI_DECLARATORS */ { - unsigned long alignptr; + uintptr_t alignptr; pool->items = 0; pool->maxitems = 0; @@ -3876,11 +3877,11 @@ struct memorypool *pool; /* Set the currently active block. */ pool->nowblock = pool->firstblock; /* Find the first item in the pool. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->nowblock + 1); + alignptr = (uintptr_t) (pool->nowblock + 1); /* Align the item on an `alignbytes'-byte boundary. */ pool->nextitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); + (alignptr + (uintptr_t) pool->alignbytes - + (alignptr % (uintptr_t) pool->alignbytes)); /* There are lots of unallocated items left in this block. */ pool->unallocateditems = pool->itemsfirstblock; /* The stack of deallocated items is empty. */ @@ -3985,7 +3986,7 @@ struct memorypool *pool; { VOID *newitem; VOID **newblock; - unsigned long alignptr; + uintptr_t alignptr; /* First check the linked list of dead items. If the list is not */ /* empty, allocate an item from the list rather than a fresh one. */ @@ -4010,11 +4011,11 @@ struct memorypool *pool; pool->nowblock = (VOID **) *(pool->nowblock); /* Find the first item in the block. */ /* Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->nowblock + 1); + alignptr = (uintptr_t) (pool->nowblock + 1); /* Align the item on an `alignbytes'-byte boundary. */ pool->nextitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); + (alignptr + (uintptr_t) pool->alignbytes - + (alignptr % (uintptr_t) pool->alignbytes)); /* There are lots of unallocated items left in this block. */ pool->unallocateditems = pool->itemsperblock; } @@ -4069,16 +4070,16 @@ struct memorypool *pool; #endif /* not ANSI_DECLARATORS */ { - unsigned long alignptr; + uintptr_t alignptr; /* Begin the traversal in the first block. */ pool->pathblock = pool->firstblock; /* Find the first item in the block. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->pathblock + 1); + alignptr = (uintptr_t) (pool->pathblock + 1); /* Align with item on an `alignbytes'-byte boundary. */ pool->pathitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); + (alignptr + (uintptr_t) pool->alignbytes - + (alignptr % (uintptr_t) pool->alignbytes)); /* Set the number of items left in the current block. */ pool->pathitemsleft = pool->itemsfirstblock; } @@ -4106,7 +4107,7 @@ struct memorypool *pool; { VOID *newitem; - unsigned long alignptr; + uintptr_t alignptr; /* Stop upon exhausting the list of items. */ if (pool->pathitem == pool->nextitem) { @@ -4118,11 +4119,11 @@ struct memorypool *pool; /* Find the next block. */ pool->pathblock = (VOID **) *(pool->pathblock); /* Find the first item in the block. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->pathblock + 1); + alignptr = (uintptr_t) (pool->pathblock + 1); /* Align with item on an `alignbytes'-byte boundary. */ pool->pathitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); + (alignptr + (uintptr_t) pool->alignbytes - + (alignptr % (uintptr_t) pool->alignbytes)); /* Set the number of items left in the current block. */ pool->pathitemsleft = pool->itemsperblock; } @@ -4174,16 +4175,16 @@ int subsegbytes; #endif /* not ANSI_DECLARATORS */ { - unsigned long alignptr; + uintptr_t alignptr; /* Set up `dummytri', the `triangle' that occupies "outer space." */ m->dummytribase = (triangle *) trimalloc(trianglebytes + m->triangles.alignbytes); /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ - alignptr = (unsigned long) m->dummytribase; + alignptr = (uintptr_t) m->dummytribase; m->dummytri = (triangle *) - (alignptr + (unsigned long) m->triangles.alignbytes - - (alignptr % (unsigned long) m->triangles.alignbytes)); + (alignptr + (uintptr_t) m->triangles.alignbytes - + (alignptr % (uintptr_t) m->triangles.alignbytes)); /* Initialize the three adjoining triangles to be "outer space." These */ /* will eventually be changed by various bonding operations, but their */ /* values don't really matter, as long as they can legally be */ @@ -4203,10 +4204,10 @@ int subsegbytes; m->dummysubbase = (subseg *) trimalloc(subsegbytes + m->subsegs.alignbytes); /* Align `dummysub' on a `subsegs.alignbytes'-byte boundary. */ - alignptr = (unsigned long) m->dummysubbase; + alignptr = (uintptr_t) m->dummysubbase; m->dummysub = (subseg *) - (alignptr + (unsigned long) m->subsegs.alignbytes - - (alignptr % (unsigned long) m->subsegs.alignbytes)); + (alignptr + (uintptr_t) m->subsegs.alignbytes - + (alignptr % (uintptr_t) m->subsegs.alignbytes)); /* Initialize the two adjoining subsegments to be the omnipresent */ /* subsegment. These will eventually be changed by various bonding */ /* operations, but their values don't really matter, as long as they */ @@ -4563,7 +4564,7 @@ int number; { VOID **getblock; char *foundvertex; - unsigned long alignptr; + uintptr_t alignptr; int current; getblock = m->vertices.firstblock; @@ -4580,9 +4581,9 @@ int number; } /* Now find the right vertex. */ - alignptr = (unsigned long) (getblock + 1); - foundvertex = (char *) (alignptr + (unsigned long) m->vertices.alignbytes - - (alignptr % (unsigned long) m->vertices.alignbytes)); + alignptr = (uintptr_t) (getblock + 1); + foundvertex = (char *) (alignptr + (uintptr_t) m->vertices.alignbytes - + (alignptr % (uintptr_t) m->vertices.alignbytes)); return (vertex) (foundvertex + m->vertices.itembytes * (number - current)); } @@ -6644,9 +6645,9 @@ struct mesh *m; /*****************************************************************************/ #ifdef ANSI_DECLARATORS -unsigned long randomnation(unsigned int choices) +uintptr_t randomnation(unsigned int choices) #else /* not ANSI_DECLARATORS */ -unsigned long randomnation(choices) +uintptr_t randomnation(choices) unsigned int choices; #endif /* not ANSI_DECLARATORS */ @@ -7626,7 +7627,7 @@ struct otri *searchtri; char *firsttri; struct otri sampletri; vertex torg, tdest; - unsigned long alignptr; + uintptr_t alignptr; REAL searchdist, dist; REAL ahead; long samplesperblock, totalsamplesleft, samplesleft; @@ -7698,11 +7699,11 @@ struct otri *searchtri; population = totalpopulation; } /* Find a pointer to the first triangle in the block. */ - alignptr = (unsigned long) (sampleblock + 1); + alignptr = (uintptr_t) (sampleblock + 1); firsttri = (char *) (alignptr + - (unsigned long) m->triangles.alignbytes - + (uintptr_t) m->triangles.alignbytes - (alignptr % - (unsigned long) m->triangles.alignbytes)); + (uintptr_t) m->triangles.alignbytes)); /* Choose `samplesleft' randomly sampled triangles in this block. */ do { diff --git a/math/matrix/src/TMatrixTBase.cxx b/math/matrix/src/TMatrixTBase.cxx index 99f0cf4ffa593..5fe431459c8f7 100644 --- a/math/matrix/src/TMatrixTBase.cxx +++ b/math/matrix/src/TMatrixTBase.cxx @@ -622,8 +622,8 @@ Element TMatrixTBase::Max() const template void TMatrixTBase::Draw(Option_t *option) { - gROOT->ProcessLine(Form("THistPainter::PaintSpecialObjects((TObject*)0x%lx,\"%s\");", - (ULong_t)this, option)); + gROOT->ProcessLine(Form("THistPainter::PaintSpecialObjects((TObject*)0x%zx,\"%s\");", + (size_t)this, option)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/math/matrix/src/TVectorT.cxx b/math/matrix/src/TVectorT.cxx index 0b0c3a5fa11e5..db2a78b80116d 100644 --- a/math/matrix/src/TVectorT.cxx +++ b/math/matrix/src/TVectorT.cxx @@ -1352,8 +1352,8 @@ TVectorT &TVectorT::Apply(const TElementPosActionT &a template void TVectorT::Draw(Option_t *option) { - gROOT->ProcessLine(Form("THistPainter::PaintSpecialObjects((TObject*)0x%lx,\"%s\");", - (ULong_t)this, option)); + gROOT->ProcessLine(Form("THistPainter::PaintSpecialObjects((TObject*)0x%zx,\"%s\");", + (size_t)this, option)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/math/minuit/src/TMinuit.cxx b/math/minuit/src/TMinuit.cxx index d321f8ca000b3..04d13ca62daec 100644 --- a/math/minuit/src/TMinuit.cxx +++ b/math/minuit/src/TMinuit.cxx @@ -929,12 +929,12 @@ void InteractiveFCNm(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t TMethodCall *m = gMinuit->GetMethodCall(); if (!m) return; - Long_t args[5]; - args[0] = (Long_t)∦ - args[1] = (Long_t)gin; - args[2] = (Long_t)&f; - args[3] = (Long_t)u; - args[4] = (Long_t)flag; + Longptr_t args[5]; + args[0] = (Longptr_t)∦ + args[1] = (Longptr_t)gin; + args[2] = (Longptr_t)&f; + args[3] = (Longptr_t)u; + args[4] = (Longptr_t)flag; m->SetParamPtrs(args); Double_t result; m->Execute(result); diff --git a/math/mlp/src/TMLPAnalyzer.cxx b/math/mlp/src/TMLPAnalyzer.cxx index 67a06b2db9a51..6dfb87c63b06e 100644 --- a/math/mlp/src/TMLPAnalyzer.cxx +++ b/math/mlp/src/TMLPAnalyzer.cxx @@ -187,13 +187,13 @@ void TMLPAnalyzer::GatherInformations() formula = GetNeuronFormula(i); pos = re.Index(formula,&len); if(pos==-1 || len<3) { - formulas[i] = new TTreeFormula(Form("NF%lu",(ULong_t)this),formula,data); + formulas[i] = new TTreeFormula(Form("NF%zu",(size_t)this),formula,data); index[i] = 0; } else { TString newformula(formula,pos); TString val = formula(pos+1,len-2); - formulas[i] = new TTreeFormula(Form("NF%lu",(ULong_t)this),newformula,data); + formulas[i] = new TTreeFormula(Form("NF%zu",(size_t)this),newformula,data); formula = newformula; index[i] = val.Atoi(); } diff --git a/math/mlp/src/TMultiLayerPerceptron.cxx b/math/mlp/src/TMultiLayerPerceptron.cxx index 78e44a5f9dc84..74f32e1113e5d 100644 --- a/math/mlp/src/TMultiLayerPerceptron.cxx +++ b/math/mlp/src/TMultiLayerPerceptron.cxx @@ -458,9 +458,9 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, TTree * data, fData = data; fCurrentTree = -1; fCurrentTreeWeight = 1; - fTraining = new TEventList(Form("fTrainingList_%lu",(ULong_t)this)); + fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); fTrainingOwner = true; - fTest = new TEventList(Form("fTestList_%lu",(ULong_t)this)); + fTest = new TEventList(Form("fTestList_%zu",(size_t)this)); fTestOwner = true; fWeight = "1"; TString testcut = test; @@ -473,8 +473,8 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, TTree * data, fManager = 0; if (data) { BuildNetwork(); - data->Draw(Form(">>fTrainingList_%lu",(ULong_t)this),training,"goff"); - data->Draw(Form(">>fTestList_%lu",(ULong_t)this),(const char *)testcut,"goff"); + data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff"); + data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff"); AttachData(); } else { @@ -531,9 +531,9 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, fData = data; fCurrentTree = -1; fCurrentTreeWeight = 1; - fTraining = new TEventList(Form("fTrainingList_%lu",(ULong_t)this)); + fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); fTrainingOwner = true; - fTest = new TEventList(Form("fTestList_%lu",(ULong_t)this)); + fTest = new TEventList(Form("fTestList_%zu",(size_t)this)); fTestOwner = true; fWeight = weight; TString testcut = test; @@ -546,8 +546,8 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, fManager = 0; if (data) { BuildNetwork(); - data->Draw(Form(">>fTrainingList_%lu",(ULong_t)this),training,"goff"); - data->Draw(Form(">>fTestList_%lu",(ULong_t)this),(const char *)testcut,"goff"); + data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff"); + data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff"); AttachData(); } else { @@ -633,10 +633,10 @@ void TMultiLayerPerceptron::SetTestDataSet(TEventList* test) void TMultiLayerPerceptron::SetTrainingDataSet(const char * train) { if(fTraining && fTrainingOwner) delete fTraining; - fTraining = new TEventList(Form("fTrainingList_%lu",(ULong_t)this)); + fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); fTrainingOwner = true; if (fData) { - fData->Draw(Form(">>fTrainingList_%lu",(ULong_t)this),train,"goff"); + fData->Draw(Form(">>fTrainingList_%zu",(size_t)this),train,"goff"); } else { Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets"); @@ -651,11 +651,11 @@ void TMultiLayerPerceptron::SetTrainingDataSet(const char * train) void TMultiLayerPerceptron::SetTestDataSet(const char * test) { if(fTest && fTestOwner) {delete fTest; fTest=0;} - if(fTest) if(strncmp(fTest->GetName(),Form("fTestList_%lu",(ULong_t)this),10)) delete fTest; - fTest = new TEventList(Form("fTestList_%lu",(ULong_t)this)); + if(fTest) if(strncmp(fTest->GetName(),Form("fTestList_%zu",(size_t)this),10)) delete fTest; + fTest = new TEventList(Form("fTestList_%zu",(size_t)this)); fTestOwner = true; if (fData) { - fData->Draw(Form(">>fTestList_%lu",(ULong_t)this),test,"goff"); + fData->Draw(Form(">>fTestList_%zu",(size_t)this),test,"goff"); } else { Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets"); diff --git a/math/mlp/src/TNeuron.cxx b/math/mlp/src/TNeuron.cxx index 45e0f4e7b96ee..88322a2924e64 100644 --- a/math/mlp/src/TNeuron.cxx +++ b/math/mlp/src/TNeuron.cxx @@ -883,11 +883,11 @@ TTreeFormula* TNeuron::UseBranch(TTree* input, const char* formula) Ssiz_t len = f.Length(); Ssiz_t pos = re.Index(f,&len); if(pos==-1 || len<3) - fFormula = new TTreeFormula(Form("NF%lu",(ULong_t)this),formula,input); + fFormula = new TTreeFormula(Form("NF%zu",(size_t)this),formula,input); else { TString newformula(formula,pos); TString val = f(pos+1,len-2); - fFormula = new TTreeFormula(Form("NF%lu",(ULong_t)this), + fFormula = new TTreeFormula(Form("NF%zu",(size_t)this), (const char*) newformula,input); fIndex = val.Atoi(); f = newformula; From c65f3d96f3f4433bff9d40fa9cf1dec100867a07 Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Tue, 8 Jun 2021 10:12:37 +0200 Subject: [PATCH 201/309] Fix 'this' pointer is null warnings .../roofit/roofitcore/src/RooDataHist.cxx: In member function 'void RooDataHist::_adjustBinning(RooRealVar&, const TAxis&, RooRealVar*, Int_t*)': .../roofit/roofitcore/src/RooDataHist.cxx:595:122: warning: 'this' pointer is null [-Wnonnull] 595 | coutE(InputArguments) << "RooDataHist::adjustBinning(" << GetName() << ") ERROR: dimension " << ourVar->GetName() << " must be real" << endl ; | ^~~~~~~~~~~~~~~ .../roofit/roofitcore/src/RooRealSumFunc.cxx: In constructor 'RooRealSumFunc::RooRealSumFunc(const char*, const char*, const RooArgList&, const RooArgList&)': .../roofit/roofitcore/src/RooRealSumFunc.cxx:156:35: warning: 'this' pointer is null [-Wnonnull] 156 | << " is not of type RooAbsReal, fatal error" << endl; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .../tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx: In member function 'void TMVA::DNN::TDataLoader >::CopyInput(TMatrixT&, TMVA::DNN::IndexIterator_t) [with AData = std::tuple >&, const TMVA::DataSetInfo&>; AReal = float]': .../tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx:131:34: warning: 'this' pointer is null [-Wnonnull] 131 | Int_t n = event->GetNVariables(); | ~~~~~~~~~~~~~~~~~~~~^~ In file included from .../tmva/tmva/inc/TMVA/VariableTransformBase.h:48, from .../tmva/tmva/inc/TMVA/Tools.h:58, from .../tmva/tmva/inc/TMVA/DNN/GeneralLayer.h:36, from .../tmva/tmva/inc/TMVA/DNN/CNN/ConvLayer.h:32, from .../tmva/tmva/inc/TMVA/DNN/Architectures/Reference.h:24, from .../tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx:17: .../tmva/tmva/inc/TMVA/Event.h:88:16: note: in a call to non-static member function 'UInt_t TMVA::Event::GetNVariables() const' 88 | UInt_t GetNVariables() const; | ^~~~~~~~~~~~~ --- roofit/roofitcore/src/RooDataHist.cxx | 2 +- roofit/roofitcore/src/RooRealSumFunc.cxx | 4 ++-- tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/roofit/roofitcore/src/RooDataHist.cxx b/roofit/roofitcore/src/RooDataHist.cxx index 84cf2c0f6897a..8dddb88e2b7ba 100644 --- a/roofit/roofitcore/src/RooDataHist.cxx +++ b/roofit/roofitcore/src/RooDataHist.cxx @@ -591,7 +591,7 @@ void RooDataHist::importDHistSet(const RooArgList& /*vars*/, RooCategory& indexC void RooDataHist::_adjustBinning(RooRealVar &theirVar, const TAxis &axis, RooRealVar *ourVar, Int_t *offset) { - if (!dynamic_cast(ourVar)) { + if (!dynamic_cast(static_cast(ourVar))) { coutE(InputArguments) << "RooDataHist::adjustBinning(" << GetName() << ") ERROR: dimension " << ourVar->GetName() << " must be real" << endl ; assert(0) ; } diff --git a/roofit/roofitcore/src/RooRealSumFunc.cxx b/roofit/roofitcore/src/RooRealSumFunc.cxx index 3f78020acd47f..a1625d7e35290 100644 --- a/roofit/roofitcore/src/RooRealSumFunc.cxx +++ b/roofit/roofitcore/src/RooRealSumFunc.cxx @@ -149,10 +149,10 @@ RooRealSumFunc::RooRealSumFunc(const char *name, const char *title, const RooArg _coefList.add(*coef); } - func = (RooAbsReal *)funcIter->Next(); + func = (RooAbsArg *)funcIter->Next(); if (func) { if (!dynamic_cast(func)) { - coutE(InputArguments) << "RooRealSumFunc::RooRealSumFunc(" << GetName() << ") last func " << coef->GetName() + coutE(InputArguments) << "RooRealSumFunc::RooRealSumFunc(" << GetName() << ") last func " << func->GetName() << " is not of type RooAbsReal, fatal error" << endl; assert(0); } diff --git a/tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx b/tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx index 2465abf3085fa..24a09d1fc01f4 100644 --- a/tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx +++ b/tmva/tmva/src/DNN/Architectures/Reference/DataLoader.cxx @@ -128,7 +128,7 @@ void TDataLoader>::CopyInput(TMatrixT &m Event *event = nullptr; Int_t m = matrix.GetNrows(); - Int_t n = event->GetNVariables(); + Int_t n = matrix.GetNcols(); // Copy input variables. From 714896e36d237cf486f912181cd682642cfde51f Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Tue, 15 Jun 2021 12:07:53 +0200 Subject: [PATCH 202/309] [NFC] Fix display of github PR template when checkboxes are empty --- .github/pull_request_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6bc0399d6f933..ca6fd267aad38 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,8 +5,8 @@ ## Checklist: -- [] tested changes locally -- [] updated the docs (if necessary) +- [ ] tested changes locally +- [ ] updated the docs (if necessary) This PR fixes # From 1f68735eac64584ed5983907efba4e3d72f48185 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Wed, 26 May 2021 15:58:54 +0200 Subject: [PATCH 203/309] [core] Remove long-deprecated memstat, memcheck: These facilities are superseded by valgrind and other memory checkers. memstat has been deprecated since v6.18. Keep objstat. --- cmake/modules/RootBuildOptions.cmake | 15 +- cmake/modules/RootConfiguration.cmake | 6 +- config/Makefile.in | 2 - config/memprobe.in | 309 --------- config/rootrc.in | 26 +- core/base/inc/TApplication.h | 1 - core/base/inc/TEnv.h | 1 - core/base/inc/TObject.h | 2 +- core/base/inc/TROOT.h | 2 - core/base/src/TApplication.cxx | 30 +- core/base/src/TEnv.cxx | 2 +- core/base/src/TROOT.cxx | 18 - core/base/src/TStorage.cxx | 4 +- core/base/src/root-argparse.py | 1 - core/newdelete/CMakeLists.txt | 1 - core/newdelete/inc/MemCheck.h | 181 ----- core/newdelete/src/MemCheck.cxx | 587 ---------------- core/newdelete/src/NewDelete.cxx | 23 - documentation/doxygen/Doxyfile | 1 - documentation/users-guide/GettingStarted.md | 19 - documentation/users-guide/InstallandBuild.md | 14 +- man/man1/memprobe.1 | 120 ---- misc/CMakeLists.txt | 3 - misc/memstat/CMakeLists.txt | 21 - misc/memstat/doc/Makefile | 53 -- .../doc/TMemStat_Technical_Overview.html | 47 -- .../doc/TMemStat_Technical_Overview.xml | 150 ---- misc/memstat/doc/caution.png | Bin 1929 -> 0 bytes misc/memstat/doc/config.xsl | 16 - misc/memstat/doc/docbook.css | 602 ---------------- misc/memstat/doc/important.png | Bin 1397 -> 0 bytes misc/memstat/doc/note.png | Bin 1921 -> 0 bytes misc/memstat/doc/tip.png | Bin 2139 -> 0 bytes misc/memstat/doc/warning.png | Bin 1442 -> 0 bytes misc/memstat/inc/LinkDef.h | 25 - misc/memstat/inc/TMemStat.h | 31 - misc/memstat/inc/TMemStatBacktrace.h | 34 - misc/memstat/inc/TMemStatDef.h | 19 - misc/memstat/inc/TMemStatHelpers.h | 65 -- misc/memstat/inc/TMemStatHook.h | 52 -- misc/memstat/inc/TMemStatMng.h | 150 ---- misc/memstat/src/TMemStat.cxx | 179 ----- misc/memstat/src/TMemStatBacktrace.cxx | 229 ------- misc/memstat/src/TMemStatHelpers.cxx | 58 -- misc/memstat/src/TMemStatHook.cxx | 181 ----- misc/memstat/src/TMemStatMng.cxx | 505 -------------- misc/memstat/test/leak_test.C | 41 -- misc/memstat/test/run.C | 7 - tree/treeviewer/CMakeLists.txt | 2 - tree/treeviewer/inc/LinkDef.h | 1 - tree/treeviewer/inc/TMemStatShow.h | 73 -- tree/treeviewer/src/TMemStatShow.cxx | 647 ------------------ tutorials/CMakeLists.txt | 1 - tutorials/legacy/memstat/index.md | 3 - tutorials/legacy/memstat/memstatExample.C | 366 ---------- 55 files changed, 15 insertions(+), 4911 deletions(-) delete mode 100755 config/memprobe.in delete mode 100644 core/newdelete/inc/MemCheck.h delete mode 100644 core/newdelete/src/MemCheck.cxx delete mode 100644 man/man1/memprobe.1 delete mode 100644 misc/memstat/CMakeLists.txt delete mode 100644 misc/memstat/doc/Makefile delete mode 100644 misc/memstat/doc/TMemStat_Technical_Overview.html delete mode 100644 misc/memstat/doc/TMemStat_Technical_Overview.xml delete mode 100644 misc/memstat/doc/caution.png delete mode 100644 misc/memstat/doc/config.xsl delete mode 100644 misc/memstat/doc/docbook.css delete mode 100644 misc/memstat/doc/important.png delete mode 100644 misc/memstat/doc/note.png delete mode 100644 misc/memstat/doc/tip.png delete mode 100644 misc/memstat/doc/warning.png delete mode 100644 misc/memstat/inc/LinkDef.h delete mode 100644 misc/memstat/inc/TMemStat.h delete mode 100644 misc/memstat/inc/TMemStatBacktrace.h delete mode 100644 misc/memstat/inc/TMemStatDef.h delete mode 100644 misc/memstat/inc/TMemStatHelpers.h delete mode 100644 misc/memstat/inc/TMemStatHook.h delete mode 100644 misc/memstat/inc/TMemStatMng.h delete mode 100644 misc/memstat/src/TMemStat.cxx delete mode 100644 misc/memstat/src/TMemStatBacktrace.cxx delete mode 100644 misc/memstat/src/TMemStatHelpers.cxx delete mode 100644 misc/memstat/src/TMemStatHook.cxx delete mode 100644 misc/memstat/src/TMemStatMng.cxx delete mode 100644 misc/memstat/test/leak_test.C delete mode 100644 misc/memstat/test/run.C delete mode 100644 tree/treeviewer/inc/TMemStatShow.h delete mode 100644 tree/treeviewer/src/TMemStatShow.cxx delete mode 100644 tutorials/legacy/memstat/index.md delete mode 100644 tutorials/legacy/memstat/memstatExample.C diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index 26d21b1ee7fdb..8278b0e96760f 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -141,7 +141,6 @@ ROOT_BUILD_OPTION(libcxx OFF "Build using libc++") ROOT_BUILD_OPTION(macos_native OFF "Disable looking for libraries, includes and binaries in locations other than a native installation (MacOS only)") ROOT_BUILD_OPTION(mathmore ON "Build libMathMore extended math library (requires GSL)") ROOT_BUILD_OPTION(memory_termination OFF "Free internal ROOT memory before process termination (experimental, used for leak checking)") -ROOT_BUILD_OPTION(memstat OFF "Build memory statistics utility (helps to detect memory leaks)") ROOT_BUILD_OPTION(mlp ON "Enable support for TMultilayerPerceptron classes' federation") ROOT_BUILD_OPTION(minuit2 OFF "Build Minuit2 minimization library") ROOT_BUILD_OPTION(monalisa OFF "Enable support for monitoring with Monalisa (requires libapmoncpp)") @@ -237,7 +236,6 @@ if(all) set(fcgi_defvalue ON) set(imt_defvalue ON) set(mathmore_defvalue ON) - set(memstat_defvalue ON) set(minuit2_defvalue ON) set(mlp_defvalue ON) set(monalisa_defvalue ON) @@ -307,7 +305,6 @@ endif() #---Changes in defaults due to platform------------------------------------------------------- if(WIN32) set(davix_defvalue OFF) - set(memstat_defvalue OFF) set(pyroot_legacy_defvalue OFF) set(roottest_defvalue OFF) set(runtime_cxxmodules_defvalue OFF) @@ -404,18 +401,18 @@ endif() #---Removed options------------------------------------------------------------ foreach(opt afdsmgrd afs bonjour castor chirp geocad glite globus hdfs ios - krb5 ldap qt qtgsi rfio ruby sapdb srp table python vmc) + krb5 ldap memstat qt qtgsi rfio ruby sapdb srp table python vmc) if(${opt}) message(FATAL_ERROR ">>> Option '${opt}' is no longer supported in ROOT ${ROOT_VERSION}.") endif() endforeach() #---Deprecated options------------------------------------------------------------------------ -foreach(opt memstat) - if(${opt}) - message(DEPRECATION ">>> Option '${opt}' is deprecated and will be removed in the next release of ROOT. Please contact root-dev@cern.ch should you still need it.") - endif() -endforeach() +# foreach(opt some-deprecated-op) +# if(${opt}) +# message(DEPRECATION ">>> Option '${opt}' is deprecated and will be removed in the next release of ROOT. Please contact root-dev@cern.ch should you still need it.") +# endif() +#endforeach() #---Replaced options-------------------------------------------------------------------------- if(python) diff --git a/cmake/modules/RootConfiguration.cmake b/cmake/modules/RootConfiguration.cmake index df0bef276c9ed..f318536c84c23 100644 --- a/cmake/modules/RootConfiguration.cmake +++ b/cmake/modules/RootConfiguration.cmake @@ -225,8 +225,6 @@ set(gfallibdir ${GFAL_LIBRARY_DIR}) set(gfallib ${GFAL_LIBRARY}) set(gfalincdir ${GFAL_INCLUDE_DIR}) -set(buildmemstat ${value${memstat}}) - set(buildalien ${value${alien}}) set(alienlibdir ${ALIEN_LIBRARY_DIR}) set(alienlib ${ALIEN_LIBRARY}) @@ -832,7 +830,6 @@ endif() set(usercflags ${CMAKE_CXX_FLAGS-CACHED}) file(REMOVE ${CMAKE_BINARY_DIR}/installtree/root-config) configure_file(${CMAKE_SOURCE_DIR}/config/root-config.in ${CMAKE_BINARY_DIR}/installtree/root-config @ONLY NEWLINE_STYLE UNIX) -configure_file(${CMAKE_SOURCE_DIR}/config/memprobe.in ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/memprobe @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.sh @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.csh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.csh @ONLY NEWLINE_STYLE UNIX) configure_file(${CMAKE_SOURCE_DIR}/config/thisroot.fish ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.fish @ONLY NEWLINE_STYLE UNIX) @@ -878,8 +875,7 @@ install(FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/thisroot.sh WORLD_READ DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/memprobe - ${CMAKE_BINARY_DIR}/installtree/root-config +install(FILES ${CMAKE_BINARY_DIR}/installtree/root-config ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/roots ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/proofserv PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ diff --git a/config/Makefile.in b/config/Makefile.in index ffc31251a2425..3862e18dd9fcb 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -204,8 +204,6 @@ GFALINCDIR := $(filter-out /usr/include, @gfalincdir@) SRMIFCEINCDIR := $(filter-out /usr/include, @srmifceincdir@) GLIB2INCDIR := $(filter-out /usr/include, @glib2incdir@) -BUILDMEMSTAT := @buildmemstat@ - BUILDALIEN := @buildalien@ ALIENLIBDIR := @alienlibdir@ ALIENCLILIB := @alienlib@ diff --git a/config/memprobe.in b/config/memprobe.in deleted file mode 100755 index d759a49bb0e2f..0000000000000 --- a/config/memprobe.in +++ /dev/null @@ -1,309 +0,0 @@ -#!@perl@ - -################################################################################ -# -# Authors : D.Bertini and M.Ivanov -# Date: 23/10/2000 -# Updated: 10/05/2001 D.Bertini, v2.0 port to gdb5.0 + glibc2.2 -# -# -# To activate the memory checker you have to set in the .rootrc file -# the resource Root.MemCheck to 1 (e.g.: Root.MemCheck: 1) and you -# have to link with libNew.so (e.g. use root-config --new --libs) or -# use rootn.exe. When all this is the case you will find at the end -# of the program execution a file "memcheck.out" in the directory -# where you started your ROOT program. Alternatively you can set -# the resource Root.MemCheckFile to the name of a file to which -# the leak information will be written. The contents of this -# "memcheck.out" file can be analyzed and transformed into printable -# text via the memprobe program (in $ROOTSYS/bin). -# -################################################################################ - -if ( ( $#ARGV < 0 )) { -Usage(); -} - -use Getopt::Std; - -getopt "h,e,m,d,f"; -#Usage("exec file is mandatory !\n") if ( !($opt_h or $opt_e) ); - -if ( $opt_h ) { Usage();} -if ( $opt_e ) { $ExeFile=$opt_e; - }else { - if (!$opt_h){ Usage("an exec file must be provided !\n");} - } -if ( $opt_m ) { $MemStatFile=$opt_m; - }else{ - $MemStatFile="memcheck.out"; - } -if ( $opt_d ) { $MemDescFile=$opt_d; - }else{ - $MemDescFile="memcheckdesc.out"; - } - -if ( $opt_f ) { $MemFiltFile=$opt_f; - }else{ - $MemFiltFile="analfilter"; - } - - -sub Usage -{ - my ($txt) = @_; - - print "MemProbe v2.0 Usage:\n"; - print "\t $0 -e exec-file [options] [files] \n "; - print "\t-e \t\t\tname of analyzed program\n"; - print "Options: \n"; - print "\t-h \t\t\tthis usage help\n"; - print "\t-m \t\tname of analyzed program output file\n"; - print "\t-d \t\tname of the stat description file\n"; - print "\t-f \t\tname of the filter file\n"; - print "\nWarning: $txt\n" if $txt; - - exit 2; -} - - -# old version -#$ExeFile = shift @ARGV; -#$MemStatFile = $#ARGV >= 0 ? shift @ARGV : "memcheck.out"; - -open (MEMSTAT, $MemStatFile) or die "-E- Could not open leaks data file $MemStatFile: $!"; - -if ($#ARGV >= 0) { - $BreakOn = shift @ARGV; - # Rest in @ARGV are program arguments -} - - -############################################################################## -# Read filter expression -############################################################################## - -open (FILTERFILE, $MemFiltFile); -@FILTER = ; -close (FILTERFILE); -for ($j = 0; $j <= $#FILTER; ++$j){ - chop $FILTER[$j]; - # print $FILTER[$j]; -} - -############################################################################## -# Find leak adresses -############################################################################## - -$n = $u = 0; -$nfull = $ufull = 0; - -while () { - # remove newline - chop $_ ; - - if (/\s*(stack:)\s*/) { - $addrfull = $'; #obtain stack info - $_ = $addrfull; - s/(st)//g; - s/(0x)/:0x/g; - @arr = split(/:/); #obtain different leak points - for ($i = 1; $i < $#arr; ++$i){ - $addr = $arr[$i]; - $u++ if not exists $Size{$addr}; - $Size{$addr} += 0; - $n++; - } - } -} -close (MEMSTAT); - - -############################################################################## -# FIND debug info for addresses - information stored -# in file leak.desc.C -############################################################################## - - -# redirect standard output to the trash -open (STDERR,">/dev/null"); - -# Redirect list of commands to a file -# using unix pipes (needed for RH.7.1 & gdb5.0) - -open (myFile,">commands"); - -# Change set listsize 2 to something else to show more lines -print myFile "set prompt\nset listsize 1\nset height 0\nset verbose off\n"; - - -if (defined($BreakOn)) { - print myFile "break $BreakOn\n"; - print myFile "run ", join(" ", @ARGV), " \n"; -} -else{ - print myFile "break main \n "; - print myFile "run ", join(" ", @ARGV), " \n"; -} - -foreach (sort keys %Size) { - print myFile "l \*$_\n "; -} - -if (defined($BreakOn)) { - print myFile "kill\n"; -} -close (myFile); - -############################################################################## -# Calling now gdb services in batch mode using -# dumped list of commands. -# ==> works with gdb-4.18 gdb-5.0 release versions -############################################################################## - - -open (PIPE, "| gdb -n -q $ExeFile < commands > $MemDescFile") -or die "-E- Cannot start gdb !!!"; -close (PIPE); - - - -############################################################################## -# ASIGN debug info to address -############################################################################## - -open (DBGinfo, $MemDescFile) or die "-E- Could not open desc file $MemDescFile: $!"; -$addr =0; -while (){ - # if (/(0x[0-9a-f]+)\s*/){ - if (/(^0x[0-9a-f]+)/){ - $addr = $1; - #print $addr; - /is in /; - # print $'; - # print "\n"; - $filename{$addr} =$'; - # print "$addr $filename{$addr}\n"; - }else{ - $line{$addr} = $_ if ! /^\s*l/; - } - for ($j = 0; $j <= $#FILTER; ++$j){ - if ( ( $line{$addr} =~ /(${FILTER[$j]})/ ) || - ( $filename{$addr} =~ /(${FILTER[$j]})/ )){ - $line{$addr} = "filtered"; -} -} - -} -close (DBGinfo); - -############################################################################## -# FIND unique leak stack sequences -############################################################################## - -open (MEMSTAT, $MemStatFile) or die "-E- Could not open leaks data file $MemStatFile: $!"; - -while () { - # remove newline - chop $_ ; - if (/\s*(stack:)\s*/) { - $addrfull = $'; #obtain stack info - $info =$`; - $info =~ s/size //; #obtain mem info for given stack sequence - $_ = $addrfull; - s/(st)//g; - s/(0x)/:0x/g; - s/ //g; - @arr = split(/:/); #obtain leak points - $addrfull ="stack"; - $FilterOut=0; - for ($i = 1; ($i <= $#arr)&&($FilterOut==0); ++$i){ - $addr = $arr[$i]; - if ( $line{$addr} =~ /filtered/) - { - $FilterOut=1; - } - if ( $filename{$addr} =~ /\)/) - { - $addrfull .= ":"; - $addrfull .= $addr; - } - } - if ($FilterOut==0){ - $_= $info; - @meminfo = split(/:/); - $ufull++ if not exists $Sizefull{$addrfull}; - $SizeTotal{$addrfull} += $meminfo[1]; - $CountTotal{$addrfull}+= $meminfo[0]; - $SizeLeak{$addrfull} += $meminfo[3]; - $CountLeak{$addrfull}+= $meminfo[2]; - $nfull++; - } - } -} - -print STDERR "total memory corrupted at point==> ($nfull) \n"; -print STDERR "unique allocations ==> ($ufull) \n"; - -close (MEMSTAT); - -############################################################################## -# PRINT output leak information to leak.info.C output file -############################################################################## - - -open (LEAKinfo,">leak.info"); -open (MULTI,">multidelete.info"); -open (MEMSTAT,">memcheck.info"); - -# sort by size of leak -sub bysize { - $SizeLeak{$b} <=> $SizeLeak{$a}; # presuming integers -} - -sub bysizetotal { - $SizeTotal{$b} <=> $SizeTotal{$a}; # presuming integers -} - -foreach (sort bysizetotal keys %SizeTotal) { - print MEMSTAT "Count: $CountTotal{$_}($CountLeak{$_}) Size: $SizeTotal{$_}($SizeLeak{$_}) \n"; - s/stack://g; - @arr = split(/:/); #obtain leak points - for ($i = 0; $i <= $#arr; ++$i){ - $addr = $arr[$i]; - print MEMSTAT "$filename{$addr}$line{$addr}"; - } - print MEMSTAT "\n\n"; -} - - -foreach (sort bysize keys %SizeLeak) { - if ($CountLeak{$_}<0){ - print MULTI "Multiple deallocation :$CountLeak{$_}\n"; - s/stack://g; - @arr = split(/:/); #obtain leak points - for ($i = 0; $i <= $#arr; ++$i){ - $addr = $arr[$i]; - print MULTI "$filename{$addr}$line{$addr}"; - } - print MULTI "\n\n"; - } - if ($SizeLeak{$_}!=0){ - print LEAKinfo "Leaked allocations: $CountLeak{$_} \t Leaked size: $SizeLeak{$_} \n"; - s/stack://g; - @arr = split(/:/); #obtain leak points - for ($i = 0; $i <= $#arr; ++$i){ - $addr = $arr[$i]; - print LEAKinfo "$filename{$addr}$line{$addr}"; - } - print LEAKinfo "\n\n"; - } -} -close(LEAKinfo); -close(MULTI); -close(MEMSTAT); - -$remove = 'rm -rf commands'; -exec $remove; -die " -E- no commands file !"; - diff --git a/config/rootrc.in b/config/rootrc.in index 057ea834ab8f9..43058fb2d37e0 100644 --- a/config/rootrc.in +++ b/config/rootrc.in @@ -44,33 +44,9 @@ Root.CompressionAlgorithm: 0 # Show where item is found in the specified path. Root.ShowPath: false -# Activate malloc/new, free/delete calls via the TMemStat class -# the parameter buffersize is the number of calls to malloc or free that can be stored in one memory buffer. -# when the buffer is full, the calls to malloc/free pointing to the same location -# are eliminated and not written to the final Tree. The default value 100000 -# is such that between 50 and 90% of the calls are eliminated depending on the application. -# the parameter TMemStat.maxcalls is the maximum number of new/delete calls to be monitored -# 5 million calls is a reasonable number. -# if your code has been compiled with -fno-omit-frame-pointer you can specify -# gnubuiltin for Root.TMemStat.system. In this case the backtrace is much faster. -Root.TMemStat: 0 -Root.TMemStat.buffersize: 100000 -Root.TMemStat.maxcalls: 5000000 -#Root.TMemStat.system: gnubuiltin -Root.TMemStat.system: - -# Activate memory statistics (size and cnt is used to trap allocation of -# blocks of a certain size after cnt times). -Root.MemStat: 0 -Root.MemStat.size: -1 -Root.MemStat.cnt: -1 +# Activate TObject statistics. Root.ObjectStat: 0 -# Activate memory leak checker (use in conjunction with $ROOTSYS/bin/memprobe). -# Currently only works on Linux with gcc. -Root.MemCheck: 0 -Root.MemCheckFile: memcheck.out - # Global debug mode. When >0 turns on progressively more details debugging. Root.Debug: 0 Root.ErrorHandlers: 1 diff --git a/core/base/inc/TApplication.h b/core/base/inc/TApplication.h index e6d8fd1af06b3..91a7583a1510e 100644 --- a/core/base/inc/TApplication.h +++ b/core/base/inc/TApplication.h @@ -63,7 +63,6 @@ class TApplication : public TObject, public TQObject { Bool_t fNoLog; //Do not process logon and logoff macros Bool_t fNoLogo; //Do not show splash screen and welcome message Bool_t fQuit; //Exit after having processed input files - Bool_t fUseMemstat; //Run with TMemStat enabled TObjArray *fFiles; //Array of input files or C++ expression (TObjString's) specified via argv TString fWorkDir; //Working directory specified via argv TString fIdleCommand; //Command to execute while application is idle diff --git a/core/base/inc/TEnv.h b/core/base/inc/TEnv.h index 08dd1809aa221..4962628b9a31d 100644 --- a/core/base/inc/TEnv.h +++ b/core/base/inc/TEnv.h @@ -45,7 +45,6 @@ // Unix.Rint.Root.DynamicPath: .:$ROOTSYS/lib:~/lib // // myapp.Root.Debug: FALSE // // TH.Root.Debug: YES // -// *.Root.MemStat: 1 // // // // and or may be the wildcard "*". // // A # in the first column starts comment line. // diff --git a/core/base/inc/TObject.h b/core/base/inc/TObject.h index e96f64ce70fb4..23eaa8af7fba7 100644 --- a/core/base/inc/TObject.h +++ b/core/base/inc/TObject.h @@ -234,7 +234,7 @@ class TObject { /// TObject constructor. It sets the two data words of TObject to their /// initial values. The unique ID is set to 0 and the status word is /// set depending if the object is created on the stack or allocated -/// on the heap. Depending on the ROOT environment variable "Root.MemStat" +/// on the heap. Depending on the ROOT environment variable "Root.ObjStat" /// (see TEnv) the object is added to the global TObjectTable for /// bookkeeping. diff --git a/core/base/inc/TROOT.h b/core/base/inc/TROOT.h index 3b155872bca7d..f3e2a3f358bcb 100644 --- a/core/base/inc/TROOT.h +++ b/core/base/inc/TROOT.h @@ -101,7 +101,6 @@ friend TROOT *ROOT::Internal::GetROOT2(); static Int_t fgDirLevel; //Indentation level for ls() static Bool_t fgRootInit; //Singleton initialization flag - static Bool_t fgMemCheck; //Turn on memory leak checker TROOT(const TROOT&) = delete; TROOT& operator=(const TROOT&) = delete; @@ -344,7 +343,6 @@ friend TROOT *ROOT::Internal::GetROOT2(); static void IndentLevel(); static void Initialize(); static Bool_t Initialized(); - static Bool_t MemCheck(); static void SetDirLevel(Int_t level = 0); static Int_t ConvertVersionCode2Int(Int_t code); static Int_t ConvertVersionInt2Code(Int_t v); diff --git a/core/base/src/TApplication.cxx b/core/base/src/TApplication.cxx index 88ba355cf952a..3637d3acfbfb7 100644 --- a/core/base/src/TApplication.cxx +++ b/core/base/src/TApplication.cxx @@ -96,7 +96,7 @@ static void CallEndOfProcessCleanups() TApplication::TApplication() : fArgc(0), fArgv(nullptr), fAppImp(nullptr), fIsRunning(kFALSE), fReturnFromRun(kFALSE), - fNoLog(kFALSE), fNoLogo(kFALSE), fQuit(kFALSE), fUseMemstat(kFALSE), + fNoLog(kFALSE), fNoLogo(kFALSE), fQuit(kFALSE), fFiles(nullptr), fIdleTimer(nullptr), fSigHandler(nullptr), fExitOnException(kDontExit), fAppRemote(nullptr) { @@ -120,7 +120,7 @@ TApplication::TApplication() : TApplication::TApplication(const char *appClassName, Int_t *argc, char **argv, void * /*options*/, Int_t numOptions) : fArgc(0), fArgv(nullptr), fAppImp(nullptr), fIsRunning(kFALSE), fReturnFromRun(kFALSE), - fNoLog(kFALSE), fNoLogo(kFALSE), fQuit(kFALSE), fUseMemstat(kFALSE), + fNoLog(kFALSE), fNoLogo(kFALSE), fQuit(kFALSE), fFiles(nullptr), fIdleTimer(nullptr), fSigHandler(nullptr), fExitOnException(kDontExit), fAppRemote(nullptr) { @@ -198,17 +198,6 @@ TApplication::TApplication(const char *appClassName, Int_t *argc, char **argv, // to allow user to interact with TCanvas's under WIN32 gROOT->SetLineHasBeenProcessed(); - // activate TMemStat - if (fUseMemstat || gEnv->GetValue("Root.TMemStat", 0)) { - fUseMemstat = kTRUE; - Int_t buffersize = gEnv->GetValue("Root.TMemStat.buffersize", 100000); - Int_t maxcalls = gEnv->GetValue("Root.TMemStat.maxcalls", 5000000); - const char *ssystem = gEnv->GetValue("Root.TMemStat.system","gnubuiltin"); - if (maxcalls > 0) { - gROOT->ProcessLine(Form("new TMemStat(\"%s\",%d,%d);",ssystem,buffersize,maxcalls)); - } - } - //Needs to be done last gApplication = this; gROOT->SetApplication(this); @@ -227,12 +216,6 @@ TApplication::~TApplication() if (fgApplications) fgApplications->Remove(this); - //close TMemStat - if (fUseMemstat) { - ProcessLine("TMemStat::Close()"); - fUseMemstat = kFALSE; - } - // Reduce the risk of the files or sockets being closed after the // end of 'main' (or more exactly before the library start being // unloaded). @@ -385,9 +368,6 @@ void TApplication::GetOptions(Int_t *argc, char **argv) } else if (!strcmp(argv[i], "-config")) { fprintf(stderr, "ROOT ./configure options:\n%s\n", gROOT->GetConfigOptions()); Terminate(0); - } else if (!strcmp(argv[i], "-memstat")) { - fUseMemstat = kTRUE; - argv[i] = null; } else if (!strcmp(argv[i], "-b")) { MakeBatch(); argv[i] = null; @@ -1689,12 +1669,6 @@ void TApplication::Terminate(Int_t status) if (fReturnFromRun) gSystem->ExitLoop(); else { - //close TMemStat - if (fUseMemstat) { - ProcessLine("TMemStat::Close()"); - fUseMemstat = kFALSE; - } - gSystem->Exit(status); } } diff --git a/core/base/src/TEnv.cxx b/core/base/src/TEnv.cxx index c4f49b46eeff3..35c4bff65649f 100644 --- a/core/base/src/TEnv.cxx +++ b/core/base/src/TEnv.cxx @@ -40,7 +40,7 @@ E.g.: Unix.Rint.Root.DynamicPath: .:$(ROOTSYS)/lib:~/lib myapp.Root.Debug: FALSE TH.Root.Debug: YES - *.Root.MemStat: 1 + *.Root.ObjStat: 1 ~~~ `` and `` or `` may be the wildcard "*". A # in the first column starts comment line. diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx index 35ac7838215cd..8322e7e920eed 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -284,7 +284,6 @@ namespace { Int_t TROOT::fgDirLevel = 0; Bool_t TROOT::fgRootInit = kFALSE; -Bool_t TROOT::fgMemCheck = kFALSE; static void at_exit_of_TROOT() { if (ROOT::Internal::gROOTLocal) @@ -1977,15 +1976,6 @@ void TROOT::InitSystem() if (gDebug > 0 && isatty(2)) fprintf(stderr, "Info in : running with gDebug = %d\n", gDebug); - if (gEnv->GetValue("Root.MemStat", 0)) - TStorage::EnableStatistics(); - int msize = gEnv->GetValue("Root.MemStat.size", -1); - int mcnt = gEnv->GetValue("Root.MemStat.cnt", -1); - if (msize != -1 || mcnt != -1) - TStorage::EnableStatistics(msize, mcnt); - - fgMemCheck = gEnv->GetValue("Root.MemCheck", 0); - #if defined(R__HAS_COCOA) // create and delete a dummy TUrl so that TObjectStat table does not contain // objects that are deleted after recording is turned-off (in next line), @@ -2823,14 +2813,6 @@ Bool_t TROOT::Initialized() return fgRootInit; } -//////////////////////////////////////////////////////////////////////////////// -/// Return kTRUE if the memory leak checker is on. - -Bool_t TROOT::MemCheck() -{ - return fgMemCheck; -} - //////////////////////////////////////////////////////////////////////////////// /// Return Indentation level for ls(). diff --git a/core/base/src/TStorage.cxx b/core/base/src/TStorage.cxx index 2a890b2199acc..287fe43c114b6 100644 --- a/core/base/src/TStorage.cxx +++ b/core/base/src/TStorage.cxx @@ -189,7 +189,7 @@ void *TStorage::ReAlloc(void *ovp, size_t size) // Needs to be protected by global mutex R__LOCKGUARD(gGlobalMutex); - if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck()) + if (fgReAllocHook && fgHasCustomNewDelete) return (*fgReAllocHook)(ovp, size); } @@ -225,7 +225,7 @@ void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize) { R__LOCKGUARD(gGlobalMutex); - if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck()) + if (fgReAllocCHook && fgHasCustomNewDelete) return (*fgReAllocCHook)(ovp, size, oldsize); } diff --git a/core/base/src/root-argparse.py b/core/base/src/root-argparse.py index 89fb0d996d671..396df8fabaa44 100644 --- a/core/base/src/root-argparse.py +++ b/core/base/src/root-argparse.py @@ -15,7 +15,6 @@ def get_argparse(): parser.add_argument('-l', help='Do not show the ROOT banner') parser.add_argument('-a', help='Show the ROOT splash screen') parser.add_argument('-config', help='print ./configure options') - parser.add_argument('-memstat', help='run with memory usage monitoring') parser.add_argument('-h','-?', '--help', help='Show summary of options') parser.add_argument('--version', help='Show the ROOT version') parser.add_argument('--notebook', help='Execute ROOT notebook') diff --git a/core/newdelete/CMakeLists.txt b/core/newdelete/CMakeLists.txt index 1d6cccb31da7e..ca0be2252c7ad 100644 --- a/core/newdelete/CMakeLists.txt +++ b/core/newdelete/CMakeLists.txt @@ -9,7 +9,6 @@ ############################################################################ ROOT_LINKER_LIBRARY(New - src/MemCheck.cxx src/NewDelete.cxx DEPENDENCIES Core diff --git a/core/newdelete/inc/MemCheck.h b/core/newdelete/inc/MemCheck.h deleted file mode 100644 index 2fd30e0ac57db..0000000000000 --- a/core/newdelete/inc/MemCheck.h +++ /dev/null @@ -1,181 +0,0 @@ -// @(#)root/new:$Id$ -// Author: D.Bertini and M.Ivanov 10/08/2000 - -/************************************************************************* - * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -//****************************************************************************// -// -// -// MemCheck is used to check the memory in ROOT based applications. -// -// Principe: -// A memory leak often arises whenever memory allocated through -// (new, new[]) is never returned via a corresponding (delete, delete[]). -// Redefining a special version of (operator new, operator delete) will -// allow the bookkeeping of created pointers to chunks of memory and, at -// the same time, pointers to the current function (and all of its callers -// scanning the stack) in order to trace back where the memory is not freed. -// This specific bookkeeping of pointers will be done by a kind of -// "memory info" container class TMemHashTable that will be used via -// the ROOT memory management defined inside the NewDelete.cxx file. -// -// To activate the memory checker you have to set in the .rootrc file -// the resource Root.MemCheck to 1 (e.g.: Root.MemCheck: 1) and you -// have to link with libNew.so (e.g. use root-config --new --libs) or -// use rootn.exe. When all this is the case you will find at the end -// of the program execution a file "memcheck.out" in the directory -// where you started your ROOT program. Alternatively you can set -// the resource Root.MemCheckFile to the name of a file to which -// the leak information will be written. The contents of this -// "memcheck.out" file can be analyzed and transformed into printable -// text via the memprobe program (in $ROOTSYS/bin). -// -// (c) 2000 : Gesellschaft fuer Schwerionenforschung GmbH -// Planckstrasse, 1 -// D-64291 Darmstadt -// Germany -// -// Created 10/08/2000 by: D.Bertini and M.Ivanov. -// Based on ideas from LeakTracer by Erwin Andreasen. -// -// - Updated: -// Date: 12/02/2001 Adapt script to new GDB 5.0, new glibc2.2.x and gcc 2.96. -// Date: 23/10/2000 (hash mechanism speeding up the bookkeeping) -// -// - Documentation: -// -// http://www-hades.gsi.de/~dbertini/mem.html -// -//****************************************************************************// - -#ifndef ROOT_MemCheck -#define ROOT_MemCheck - -#include "TROOT.h" - - -class TStackInfo { -public: - UInt_t fSize; //size of the stack - Int_t fTotalAllocCount; //total number of allocation for stack sequence - Int_t fTotalAllocSize; //total size of allocated memory - Int_t fAllocCount; //current number of allocation-deallocation - Int_t fAllocSize; //current allocated size - TStackInfo *fNextHash; //index-pointer to the next info for given hash value - -public: - void Init(Int_t stacksize, void **stackptrs); //initialization - void Inc(Int_t memSize); //increment counters -when memory allocated - void Dec(Int_t memSize); //decrement counters -when memory deallocated - ULong_t Hash(); - Int_t IsEqual(UInt_t size, void **ptr); - void *StackAt(UInt_t i); - TStackInfo *Next(); //index of the next entries - - static ULong_t HashStack(UInt_t size, void **ptr); -}; - - -class TStackTable { -private: - char *fTable; //pointer to the table - TStackInfo **fHashTable; //pointer to the hash table - Int_t fSize; //current size of the table - Int_t fHashSize; //current size of the hash table - Int_t fCount; //number of entries in table - char *fNext; //pointer to the last stack info - - void Expand(Int_t newsize); - -public: - void Init(); - TStackInfo *AddInfo(Int_t size, void **stackptrs); - TStackInfo *FindInfo(Int_t size, void **stackptrs); - Int_t GetIndex(TStackInfo *info); - TStackInfo *GetInfo(Int_t index); - TStackInfo *First() { return (TStackInfo *)fTable; } -}; - - -class TMemInfo { -public: - void *fAddress; //mem address - size_t fSize; //size of the allocated memory - Int_t fStackIndex; //index of the stack info -}; - -class TMemTable { -public: - Int_t fAllocCount; //number of memory allocation blocks - Int_t fMemSize; //total memory allocated size - Int_t fTableSize; //amount of entries in the below array - Int_t fFirstFreeSpot; //where is the first free spot in the leaks array? - TMemInfo *fLeaks; //leak table -}; - -class TDeleteTable { -public: - Int_t fAllocCount; //how many memory blocks do we have - Int_t fTableSize; //amount of entries in the below array - TMemInfo *fLeaks; //leak table -}; - - -class TMemHashTable { -public: - static Int_t fgSize; //size of hash table - static TMemTable **fgLeak; //pointer to the hash table - static Int_t fgAllocCount; //number of memory allocation blocks - static TStackTable fgStackTable; //table with stack pointers - static TDeleteTable fgMultDeleteTable; //pointer to the table - - ~TMemHashTable() { if (TROOT::MemCheck()) Dump(); } - - static void Init(); - static void RehashLeak(Int_t newSize); //rehash leak pointers - static void *AddPointer(size_t size, void *ptr=0); //add pointer to the table - static void FreePointer(void *p); //free pointer - static void Dump(); //write leaks to the output file -}; - - - -inline void TStackInfo::Inc(Int_t memSize) -{ - fTotalAllocCount += 1; - fTotalAllocSize += memSize; - fAllocCount += 1; - fAllocSize += memSize; -} - -inline void TStackInfo::Dec(int memSize) -{ - fAllocCount -= 1; - fAllocSize -= memSize; -} - -inline ULong_t TStackInfo::Hash() -{ - return HashStack(fSize, (void**)&(this[1])); -} - -inline void *TStackInfo::StackAt(UInt_t i) -{ - //return i -#include -#include -#include -#include "MemCheck.h" -#include "TSystem.h" -#include "TEnv.h" -#include "TError.h" - -#define stack_history_size 20 - - -static TMemHashTable gMemHashTable; - - -//****************************************************************************// -// Storage of Stack information -//****************************************************************************// - -//////////////////////////////////////////////////////////////////////////////// -///Initialize the stack - -void TStackInfo::Init(int stacksize, void **stackptrs) -{ - fSize = stacksize; - memcpy(&(this[1]), stackptrs, stacksize * sizeof(void *)); - fTotalAllocCount = fTotalAllocSize = fAllocCount = fAllocSize = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Hash stack information. - -ULong_t TStackInfo::HashStack(unsigned int size, void **ptr) -{ - ULong_t hash = 0; - for (unsigned int i = 0; i < size; i++) - hash ^= TString::Hash(&ptr[i], sizeof(void*)); - return hash; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Return 0 if stack information not equal otherwise return 1. - -int TStackInfo::IsEqual(unsigned int size, void **ptr) -{ - if (size != fSize) - return 0; - void **stptr = (void **) &(this[1]); - for (unsigned int i = 0; i < size; i++) - if (ptr[i] != stptr[i]) - return 0; - return 1; -} - - -//****************************************************************************// -// Global Stack Table -//****************************************************************************// - -//////////////////////////////////////////////////////////////////////////////// -///Initialize table. - -void TStackTable::Init() -{ - fSize = 65536; - fCount = 0; - fTable = (char *) malloc(fSize); - if (!fTable) - _exit(1); - memset(fTable, 0, fSize); - fNext = fTable; - //initialize hash table - fHashSize = 65536; - fHashTable = (TStackInfo **) malloc(sizeof(TStackInfo *) * fHashSize); - memset(fHashTable, 0, sizeof(TStackInfo *) * fHashSize); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Expand stack buffer to the new size. - -void TStackTable::Expand(int newsize) -{ - char *tableold = fTable; - fTable = (char *) realloc(fTable, newsize); - fSize = newsize; - int nextindex = (char *) fNext - tableold; - memset(&fTable[nextindex], 0, fSize - nextindex); - fNext = (char *) (&fTable[nextindex]); - // - //update list - TStackInfo *info = (TStackInfo *) fTable; - while (((char *) info->Next() - fTable) <= nextindex) { - if (info->fNextHash != 0) - info->fNextHash = (TStackInfo *) - & fTable[(char *) info->fNextHash - tableold]; - info = info->Next(); - } - // - //update hash table - for (int i = 0; i < fHashSize; i++) - if (fHashTable[i] != 0) - fHashTable[i] = - (TStackInfo *) & fTable[((char *) fHashTable[i]) - tableold]; - // printf("new table %p\n",fTable); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Add stack information to table. - -TStackInfo *TStackTable::AddInfo(int size, void **stackptrs) -{ - // add next stack to table - TStackInfo *info = (TStackInfo *) fNext; - if (((char *) info + size * sizeof(void *) - + sizeof(TStackInfo) - fTable) > fSize) { - //need expand - Expand(2 * fSize); - info = (TStackInfo *) fNext; - } - info->Init(size, stackptrs); - info->fNextHash = 0; - fNext = (char *) info->Next(); - - //add info to hash table - int hash = int(info->Hash() % fHashSize); - TStackInfo *info2 = fHashTable[hash]; - if (info2 == 0) { - fHashTable[hash] = info; - } else { - while (info2->fNextHash) - info2 = info2->fNextHash; - info2->fNextHash = info; - } - fCount++; - return info; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Try to find stack info in hash table if doesn't find it will add it. - -TStackInfo *TStackTable::FindInfo(int size, void **stackptrs) -{ - int hash = int(TStackInfo::HashStack(size, (void **) stackptrs) % fHashSize); - TStackInfo *info = fHashTable[hash]; - if (info == 0) { - info = AddInfo(size, stackptrs); - //printf("f0 %p - %d\n",info,(char*)info-fTable); - return info; - } - while (info->IsEqual(size, stackptrs) == 0) { - if (info->fNextHash == 0) { - info = AddInfo(size, stackptrs); - // printf("f1 %p - %d\n",info,(char*)info-fTable); - return info; - } else - info = info->fNextHash; - } - //printf("f2 %p - %d\n",info,(char*)info-fTable); - return info; -}; - -//////////////////////////////////////////////////////////////////////////////// -///return index of info - -int TStackTable::GetIndex(TStackInfo * info) -{ - return (char *) info - fTable; -} - -//////////////////////////////////////////////////////////////////////////////// -///return TStackInfo class corresponding to index - -TStackInfo *TStackTable::GetInfo(int index) -{ - return (TStackInfo *) & fTable[index]; -} - - -Int_t TMemHashTable::fgSize = 0; -Int_t TMemHashTable::fgAllocCount = 0; -TMemTable **TMemHashTable::fgLeak = 0; -TDeleteTable TMemHashTable::fgMultDeleteTable; -TStackTable TMemHashTable::fgStackTable; - - -static void *get_stack_pointer(int level); - -//////////////////////////////////////////////////////////////////////////////// -///Initialize the hash table - -void TMemHashTable::Init() -{ - fgStackTable.Init(); - fgSize = 65536; - fgAllocCount = 0; - fgLeak = (TMemTable **) malloc(sizeof(void *) * fgSize); - fgMultDeleteTable.fLeaks = 0; - fgMultDeleteTable.fAllocCount = 0; - fgMultDeleteTable.fTableSize = 0; - - for (int i = 0; i < fgSize; i++) { - fgLeak[i] = (TMemTable *) malloc(sizeof(TMemTable)); - fgLeak[i]->fAllocCount = 0; - fgLeak[i]->fMemSize = 0; - fgLeak[i]->fFirstFreeSpot = 0; - fgLeak[i]->fTableSize = 0; - fgLeak[i]->fLeaks = 0; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Rehash leak pointers. - -void TMemHashTable::RehashLeak(int newSize) -{ - if (newSize <= fgSize) - return; - TMemTable **newLeak = (TMemTable **) malloc(sizeof(void *) * newSize); - for (int i = 0; i < newSize; i++) { - //build new branches - newLeak[i] = (TMemTable *) malloc(sizeof(TMemTable)); - newLeak[i]->fAllocCount = 0; - newLeak[i]->fMemSize = 0; - newLeak[i]->fFirstFreeSpot = 0; - newLeak[i]->fTableSize = 0; - newLeak[i]->fLeaks = 0; - } - for (int ib = 0; ib < fgSize; ib++) { - TMemTable *branch = fgLeak[ib]; - for (int i = 0; i < branch->fTableSize; i++) - if (branch->fLeaks[i].fAddress != 0) { - int hash = int(TString::Hash(&branch->fLeaks[i].fAddress, sizeof(void*)) % newSize); - TMemTable *newbranch = newLeak[hash]; - if (newbranch->fAllocCount >= newbranch->fTableSize) { - int newTableSize = - newbranch->fTableSize == - 0 ? 16 : newbranch->fTableSize * 2; - newbranch->fLeaks = - (TMemInfo *) realloc(newbranch->fLeaks, - sizeof(TMemInfo) * newTableSize); - if (!newbranch->fLeaks) { - Error("TMemHashTable::AddPointer", "realloc failure"); - _exit(1); - } - memset(newbranch->fLeaks + newbranch->fTableSize, 0, - sizeof(TMemInfo) * (newTableSize - - newbranch->fTableSize)); - newbranch->fTableSize = newTableSize; - } - memcpy(&newbranch->fLeaks[newbranch->fAllocCount], - &branch->fLeaks[i], sizeof(TMemInfo)); - newbranch->fAllocCount++; - newbranch->fMemSize += branch->fLeaks[i].fSize; - } - free(branch->fLeaks); - free(branch); - } //loop over all old branches and rehash information - free(fgLeak); - fgLeak = newLeak; - fgSize = newSize; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Add pointer to table. - -void *TMemHashTable::AddPointer(size_t size, void *ptr) -{ - void *p = 0; - - if (ptr == 0) { - p = malloc(size); - if (!p) { - Error("TMemHashTable::AddPointer", "malloc failure"); - _exit(1); - } - } else { - p = realloc((char *) ptr, size); - if (!p) { - Error("TMemHashTable::AddPointer", "realloc failure"); - _exit(1); - } - return p; - } - - if (!fgSize) - Init(); - fgAllocCount++; - if ((fgAllocCount / fgSize) > 128) - RehashLeak(fgSize * 2); - int hash = int(TString::Hash(&p, sizeof(void*)) % fgSize); - TMemTable *branch = fgLeak[hash]; - branch->fAllocCount++; - branch->fMemSize += size; - for (;;) { - for (int i = branch->fFirstFreeSpot; i < branch->fTableSize; i++) - if (branch->fLeaks[i].fAddress == 0) { - branch->fLeaks[i].fAddress = p; - branch->fLeaks[i].fSize = size; - void *sp = 0; - int j = 0; - void *stptr[stack_history_size + 1]; - for (j = 0; (j < stack_history_size); j++) { - sp = get_stack_pointer(j + 1); - if (sp == 0) - break; - stptr[j] = sp; - } - TStackInfo *info = fgStackTable.FindInfo(j, stptr); - info->Inc(size); - branch->fLeaks[i].fStackIndex = fgStackTable.GetIndex(info); - branch->fFirstFreeSpot = i + 1; - return p; - } - - int newTableSize = - branch->fTableSize == 0 ? 16 : branch->fTableSize * 2; - branch->fLeaks = - (TMemInfo *) realloc(branch->fLeaks, - sizeof(TMemInfo) * newTableSize); - if (!branch->fLeaks) { - Error("TMemHashTable::AddPointer", "realloc failure (2)"); - _exit(1); - } - memset(branch->fLeaks + branch->fTableSize, 0, sizeof(TMemInfo) * - (newTableSize - branch->fTableSize)); - branch->fTableSize = newTableSize; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Free pointer. - -void TMemHashTable::FreePointer(void *p) -{ - if (p == 0) - return; - int hash = int(TString::Hash(&p, sizeof(void*)) % fgSize); - fgAllocCount--; - TMemTable *branch = fgLeak[hash]; - for (int i = 0; i < branch->fTableSize; i++) { - if (branch->fLeaks[i].fAddress == p) { - branch->fLeaks[i].fAddress = 0; - branch->fMemSize -= branch->fLeaks[i].fSize; - if (i < branch->fFirstFreeSpot) - branch->fFirstFreeSpot = i; - free(p); - TStackInfo *info = - fgStackTable.GetInfo(branch->fLeaks[i].fStackIndex); - info->Dec(branch->fLeaks[i].fSize); - branch->fAllocCount--; - return; - } - } - // - //if try to delete non existing pointer - //printf("***TMemHashTable::FreePointer: Multiple deletion %8p ** ? \n",p); - // printf("-+-+%8p \n",p); - //free(p); - if (fgMultDeleteTable.fTableSize + 1 > fgMultDeleteTable.fAllocCount) { - int newTableSize = - fgMultDeleteTable.fTableSize == - 0 ? 16 : fgMultDeleteTable.fTableSize * 2; - fgMultDeleteTable.fLeaks = - (TMemInfo *) realloc(fgMultDeleteTable.fLeaks, - sizeof(TMemInfo) * newTableSize); - fgMultDeleteTable.fAllocCount = newTableSize; - } - - fgMultDeleteTable.fLeaks[fgMultDeleteTable.fTableSize].fAddress = 0; - void *sp = 0; - void *stptr[stack_history_size + 1]; - int j; - for (j = 0; (j < stack_history_size); j++) { - sp = get_stack_pointer(j + 1); - if (sp == 0) - break; - stptr[j] = sp; - } - TStackInfo *info = fgStackTable.FindInfo(j, stptr); - info->Dec(0); - fgMultDeleteTable.fLeaks[fgMultDeleteTable.fTableSize].fStackIndex = - fgStackTable.GetIndex(info); - fgMultDeleteTable.fTableSize++; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Print memory check information. - -void TMemHashTable::Dump() -{ - const char *filename; - if (gEnv) - filename = gEnv->GetValue("Root.MemCheckFile", "memcheck.out"); - else - filename = "memcheck.out"; - - char *fn = 0; - if (gSystem) - fn = gSystem->ExpandPathName(filename); - - FILE *fp; - if (!(fp = fn ? fopen(fn, "w") : fopen(filename, "w"))) - Error("TMenHashTable::Dump", "could not open %s", filename); - else { - /* - for (int i = 0; i < fgMultDeleteTable.fTableSize; i++){ - fprintf(fp, "size %9ld ",(long)0); - fprintf(fp, "stack:"); - TStackInfo *info = fgStackTable.GetInfo(fgMultDeleteTable.fLeaks[i].fStackIndex); - for (int j=0; info->StackAt(j);j++) - fprintf(fp, "%8p ", info->StackAt(j)); - fprintf(fp, "\n"); - } - */ - TStackInfo *info = fgStackTable.First(); - while (info->fSize) { - fprintf(fp, "size %d:%d:%d:%d ", - info->fTotalAllocCount, info->fTotalAllocSize, - info->fAllocCount, info->fAllocSize); - fprintf(fp, "stack:"); - for (int j = 0; info->StackAt(j); j++) - fprintf(fp, "%8p ", info->StackAt(j)); - fprintf(fp, "\n"); - info = info->Next(); - } - fclose(fp); - } - delete [] fn; -} - -//////////////////////////////////////////////////////////////////////////////// -/// These special __builtin calls are supported by gcc "only". -/// For other compiler one will need to implement this again ! - -static void *get_stack_pointer(int level) -{ - void *p = 0; -#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) -#if __GNUC__ > 5 -#pragma GCC diagnostic ignored "-Wframe-address" -#endif - switch (level) { - case 0: - if (__builtin_frame_address(1)) - p = __builtin_return_address(1); - break; - case 1: - if (__builtin_frame_address(2)) - p = __builtin_return_address(2); - break; - case 2: - if (__builtin_frame_address(3)) - p = __builtin_return_address(3); - break; - case 3: - if (__builtin_frame_address(4)) - p = __builtin_return_address(4); - break; - case 4: - if (__builtin_frame_address(5)) - p = __builtin_return_address(5); - break; - case 5: - if (__builtin_frame_address(6)) - p = __builtin_return_address(6); - break; - case 6: - if (__builtin_frame_address(7)) - p = __builtin_return_address(7); - break; - case 7: - if (__builtin_frame_address(8)) - p = __builtin_return_address(8); - break; - case 8: - if (__builtin_frame_address(9)) - p = __builtin_return_address(9); - break; - case 9: - if (__builtin_frame_address(10)) - p = __builtin_return_address(10); - break; - case 10: - if (__builtin_frame_address(11)) - p = __builtin_return_address(11); - break; - case 11: - if (__builtin_frame_address(12)) - p = __builtin_return_address(12); - break; - case 12: - if (__builtin_frame_address(13)) - p = __builtin_return_address(13); - break; - case 13: - if (__builtin_frame_address(14)) - p = __builtin_return_address(14); - break; - case 14: - if (__builtin_frame_address(15)) - p = __builtin_return_address(15); - break; - case 15: - if (__builtin_frame_address(16)) - p = __builtin_return_address(16); - break; - case 16: - if (__builtin_frame_address(17)) - p = __builtin_return_address(17); - break; - case 17: - if (__builtin_frame_address(18)) - p = __builtin_return_address(18); - break; - case 18: - if (__builtin_frame_address(19)) - p = __builtin_return_address(19); - break; - case 19: - if (__builtin_frame_address(20)) - p = __builtin_return_address(20); - break; - - default: - p = 0; - } -#else - if (level) { } -#endif - return p; -} diff --git a/core/newdelete/src/NewDelete.cxx b/core/newdelete/src/NewDelete.cxx index 67b3259be8d07..3d76489fc0fe8 100644 --- a/core/newdelete/src/NewDelete.cxx +++ b/core/newdelete/src/NewDelete.cxx @@ -60,7 +60,6 @@ #include #include -#include "MemCheck.h" #include "TObjectTable.h" #include "TError.h" #include "TStorage.h" // for ROOT::Internal::gFreeIfTMapFile @@ -182,10 +181,6 @@ static int gNewInit = 0; void *operator new(size_t size) { - // use memory checker - if (TROOT::MemCheck()) - return TMemHashTable::AddPointer(size); - static const char *where = "operator new"; if (!gNewInit) { @@ -239,10 +234,6 @@ void *operator new(size_t size, void *vp) } if (vp == 0) { - // use memory checker - if (TROOT::MemCheck()) - return TMemHashTable::AddPointer(size); - void *vp; if (ROOT::Internal::gMmallocDesc) vp = ::mcalloc(ROOT::Internal::gMmallocDesc, RealSize(size), sizeof(char)); @@ -262,12 +253,6 @@ void *operator new(size_t size, void *vp) void operator delete(void *ptr) noexcept { - // use memory checker - if (TROOT::MemCheck()) { - TMemHashTable::FreePointer(ptr); - return; - } - static const char *where = "operator delete"; if (!gNewInit) @@ -397,10 +382,6 @@ void operator delete[](void * /* ptr */, std::size_t, std::align_val_t /* al */) void *CustomReAlloc1(void *ovp, size_t size) { - // use memory checker - if (TROOT::MemCheck()) - return TMemHashTable::AddPointer(size, ovp); - static const char *where = "CustomReAlloc1"; if (ovp == 0) @@ -433,10 +414,6 @@ void *CustomReAlloc1(void *ovp, size_t size) void *CustomReAlloc2(void *ovp, size_t size, size_t oldsize) { - // use memory checker - if (TROOT::MemCheck()) - return TMemHashTable::AddPointer(size, ovp); - static const char *where = "CustomReAlloc2"; if (ovp == 0) diff --git a/documentation/doxygen/Doxyfile b/documentation/doxygen/Doxyfile index 2a32f4cfd9b73..c25f3f5d0caed 100644 --- a/documentation/doxygen/Doxyfile +++ b/documentation/doxygen/Doxyfile @@ -893,7 +893,6 @@ INPUT = . \ ../../io/xmlparser/ \ ../../main/src/hadd.cxx \ ../../math/ \ - ../../misc/memstat/ \ ../../montecarlo/ \ ../../net/alien/ \ ../../net/auth/ \ diff --git a/documentation/users-guide/GettingStarted.md b/documentation/users-guide/GettingStarted.md index 569dcc33d4691..22a83111cbb93 100644 --- a/documentation/users-guide/GettingStarted.md +++ b/documentation/users-guide/GettingStarted.md @@ -119,7 +119,6 @@ Options: -h : print usage --help : print usage -config : print ./configure options - -memstat : run with memory usage monitoring ``` - -b ROOT session runs in batch mode, without graphics display. This @@ -1162,7 +1161,6 @@ Unix.*.Root.UseTTFonts: true Unix.*.Root.TTFontPath: ... # Activate memory statistics -Rint.Root.MemStat: 1 Rint.Load: rootalias.C Rint.Logon: rootlogon.C Rint.Logoff: rootlogoff.C @@ -1239,7 +1237,6 @@ use this facility, edit the file `$ROOTSYS/etc/system.rootrc` or `.rootrc` if you have this file and add the two following lines: ``` -Root.MemStat: 1 Root.ObjectStat: 1 ``` @@ -1255,22 +1252,6 @@ see objects that you forgot to delete. Note that this method cannot show leaks coming from the allocation of non-objects or classes unknown to ROOT. -### Memory Checker - - -A memory checking system was developed by D.Bertini and M.Ivanov and -added in ROOT version 3.02.07. To activate the memory checker you can -set the resource `Root.MemCheck` to 1 (e.g.: `Root.MemCheck: 1` in the -`.rootrc` file). You also have to link with `libNew.so` (e.g. use -`root-config --new --libs`) or to use `rootn.exe`. When these settings -are in place, you will find a file "`memcheck.out`" in the directory -where you started your ROOT program after the completion of the -program execution. You can also set the resource `Root.MemCheckFile` -to the name of a file. The memory information will be written to that -file. The contents of this `memcheck.out` can be analyzed and -transformed into printable text via the `memprobe` program -(in `$ROOTSYS/bin`). - ## Converting from PAW to ROOT diff --git a/documentation/users-guide/InstallandBuild.md b/documentation/users-guide/InstallandBuild.md index e51c659a3dfc1..bca4dc16799ea 100644 --- a/documentation/users-guide/InstallandBuild.md +++ b/documentation/users-guide/InstallandBuild.md @@ -162,24 +162,12 @@ Show where item is found in the specified path: Root.ShowPath: false ``` -Activate memory statistics (`size` and `cnt` are used to trap allocation -of blocks of a certain `size` after `cnt` attempts). +Activate memory statistics. ``` {.cpp} -Root.MemStat: 0 -Root.MemStat.size: -1 -Root.MemStat.cnt: -1 Root.ObjectStat: 0 ``` -Activate memory leak checker (use in conjunction with -`$ROOTSYS/bin/memprobe`). Currently only works on Linux with gcc. - -``` {.cpp} -Root.MemCheck: 0 -Root.MemCheckFile: memcheck.out -``` - Global debug mode. When `>0` turns on progressively more details debugging. diff --git a/man/man1/memprobe.1 b/man/man1/memprobe.1 deleted file mode 100644 index f1957080635f8..0000000000000 --- a/man/man1/memprobe.1 +++ /dev/null @@ -1,120 +0,0 @@ -.\" -.\" $Id: memprobe.1,v 1.2 2005/03/21 21:42:21 rdm Exp $ -.\" -.TH MEMPROBE 1 "Version 3" "ROOT" -.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection -.\" other parms are allowed: see man(7), man(1) -.SH NAME -memprobe \- ROOT utility to examine memory usage -.SH SYNOPSIS -.B memprobe -.I "[options]" -.SH "DESCRIPTION" -To activate the memory checker you have to set in the \fB.rootrc\fR -file the resource \fBRoot.MemCheck\fR to 1 (e.g.: \fBRoot.MemCheck: -1\fR) and you have to link with \fBlibNew.so\fR (e.g. use -\fBroot-config \-\-new \-\-libs\fR) or use \fBrootn.exe\fR. -.PP -When all this is the case you will find at the end of the program -execution a file \fBmemcheck.out\fR in the directory where you started -your ROOT program. Alternatively you can set the resource -\fBRoot.MemCheckFile\fR to the name of a file to which the leak -information will be written. The contents of this \fBmemcheck.out\fR -file can be analyzed and transformed into printable text via the -\fBmemprobe\fR program (in \fB/usr/bin\fR). -.SH "SEE ALSO" -\fIroot\fR(1) -.PP -See also the \fBROOT\fR webpages: -.UR http://root.cern.ch -\fIhttp://root.cern.ch\fR -.UE -.SH "ORIGINAL AUTHORS" -The ROOT team (see web page above): -.RS -\fBRene Brun\fR and \fBFons Rademakers\fR -.RE -.SH "COPYRIGHT" -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2.1 of the -License, or (at your option) any later version. -.P -This library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. -.P -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -.SH AUTHOR -This manual page was written by Christian Holm Christensen -, for the Debian GNU/Linux system (but may be used by -others). -.\" -.\" $Log: memprobe.1,v $ -.\" Revision 1.2 2005/03/21 21:42:21 rdm -.\" From Christian Holm Christensen: -.\" * New Debian and RedHat rpm packaging scripts. -.\" * Added a description to `build/package/debian/README.Debian' on -.\" how to add a new package. It's not that complicated so it -.\" should be a simple thing to add a new package, even for some -.\" with little or no experience with RPMs or DEBs. -.\" * When searching for the Oracle client libraries, I added the -.\" directories `/usr/lib/oracle/*/client/lib' and -.\" `/usr/include/oracle/*/client' - as these are the paths that the -.\" RPMs install into. -.\" * I added the packages `root-plugin-krb5' and -.\" `root-plugin-oracle'. -.\" * The library `libXMLIO' is in `libroot'. -.\" * The package `root-plugin-xml' contains the XML parser. -.\" * I fixed an cosmetic error in `build/misc/root.m4'. The -.\" definition of `ROOT_PATH' should be quoted, otherwise aclocal -.\" will complain. -.\" * In the top-level `Makefile' I pass an additional argument to -.\" `makecintdlls' - namely `$(ROOTCLINGSTAGE2)'. In `makecintdlls' I -.\" use that argument to make the various dictionaries for -.\" `lib...Dict.so'. Originally, the script used plain `rootcint'. -.\" However, as `rootcint' may not be in the path yet, or the one in -.\" the path may be old, this failed. Hence, I use what we know is -.\" there - namely the newly build `rootcint_tmp'. BTW, what are -.\" these shared libraries, and where do they belong? I guess they -.\" are specific to ROOT, and not used by plain `CINT'. For now, I -.\" put them in `libroot'. -.\" * Made the two `virtual' packages `root-db-client' - provided the -.\" DB plugins, and `root-fitter' provided by `root-plugin-minuit' -.\" and `root-plugin-fumili'. Note, the virtual package -.\" `root-file-server' provided by `root-rootd' and `root-xrootd' -.\" already existed in the previous patch. -.\" * Note, I added the directory `build/package/debian/po' which is -.\" for translations of DebConf templates. DebConf is Debians very -.\" advanced package configuration interface. It presents the user -.\" with a set of questions in some sort of `GUI' based on how much -.\" the user would like to change. These `dialogs' can be -.\" translated quite easily. As an example, I translated the -.\" questions used by the `ttf-root-installer' package into Danish. -.\" I'm sure someone can translate them into German, French, -.\" Italien, Spanish, and so on. -.\" -.\" Revision 1.1 2002/01/20 14:23:52 rdm -.\" Mega patch by Christian Holm concerning the configure, build and -.\" Debian and RedHat packaging scripts. The configure script has been -.\" rationalized (introduction of two shell functions to find package -.\" headers and libraries). Extensive update of the INSTALL writeup, -.\" including description of all new packages (PgSql, etc.). -.\" More options to the root-config script. Man page for memprobe. -.\" Big overhaul of the Debian and RedHat packaging scripts, supporting -.\" the new libraries. -.\" -.\" Revision 1.1 2001/08/15 13:30:48 rdm -.\" move man files to new subdir man1. This makes it possible to add -.\" $ROOTSYS/man to MANPATH and have "man root" work. -.\" -.\" Revision 1.2 2001/04/23 09:10:12 rdm -.\" updates by Christian Holm for making debian and RedHat packages. -.\" -.\" Revision 1.1 2000/12/08 17:41:01 rdm -.\" man pages of all ROOT executables provided by Christian Holm. -.\" -.\" diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index 66776093b9ff2..db085e5a501a0 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -7,6 +7,3 @@ if(CMAKE_Fortran_COMPILER) add_subdirectory(minicern) endif() -if(memstat) - add_subdirectory(memstat) -endif() diff --git a/misc/memstat/CMakeLists.txt b/misc/memstat/CMakeLists.txt deleted file mode 100644 index edd3b43e04fed..0000000000000 --- a/misc/memstat/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. -# All rights reserved. -# -# For the licensing terms see $ROOTSYS/LICENSE. -# For the list of contributors see $ROOTSYS/README/CREDITS. - -############################################################################ -# CMakeLists.txt file for building ROOT misc/memstat package -# @author Pere Mato, CERN -############################################################################ - -ROOT_ADD_CXX_FLAG(CMAKE_CXX_FLAGS -Wno-deprecated-declarations) - -set(sources TMemStat.cxx TMemStatMng.cxx TMemStatBacktrace.cxx TMemStatHelpers.cxx TMemStatHook.cxx) -set(headers TMemStatHelpers.h TMemStat.h TMemStatBacktrace.h TMemStatDef.h TMemStatMng.h TMemStatHook.h ) - -ROOT_STANDARD_LIBRARY_PACKAGE(MemStat - HEADERS ${headers} - SOURCES ${sources} - LIBRARIES ${CMAKE_DL_LIBS} - DEPENDENCIES Tree Gpad Graf) diff --git a/misc/memstat/doc/Makefile b/misc/memstat/doc/Makefile deleted file mode 100644 index 72b6decdfe497..0000000000000 --- a/misc/memstat/doc/Makefile +++ /dev/null @@ -1,53 +0,0 @@ - -SRC= \ - TMemStat_Technical_Overview.xml - -DOCBOOK=TMemStat_Technical_Overview.xml - -HTML_OUT_DIR=./ - -#IMGS= \ - important.png\ - tip.png\ - warning.png\ - note.png -#IMG_DIR = img - -HTML_OUT= \ - TMemStat_Technical_Overview.html - -CSS_FILES=docbook.css - -XMLTO=xmlto - -#XMLTO_PARAM=-vv -o $(HTML_OUT_DIR) xhtml -m config.xsl -#XMLTO_PARAM_NOCHUNKS=-o $(HTML_OUT_DIR) xhtml-nochunks -m config.xsl -XMLTO_PARAM=-o $(HTML_OUT_DIR) xhtml-nochunks -m config.xsl - -all: gen_html - -$(HTML_OUT_DIR): - @echo "Creating output directory for html doc [$(HTML_OUT_DIR)]..." - @mkdir $(HTML_OUT_DIR) - -$(HTML_OUT_DIR)/%.css: - @echo "Using custom CSS..." - @cp $(CSS_FILES) $(HTML_OUT_DIR)/ - -$(HTML_OUT_DIR)/%.html: $(SRC) - @echo "Generating html doc..." - $(XMLTO) $(XMLTO_PARAM) $(DOCBOOK) - -#$(HTML_OUT_DIR)/%.png: -# @echo "Copying images..." -# @cp ${addprefix $(IMG_DIR)/, $(IMGS)} $(HTML_OUT_DIR)/ - -html_files: ${addprefix $(HTML_OUT_DIR)/, $(HTML_OUT)} -css_files: ${addprefix $(HTML_OUT_DIR)/, $(CSS_FILES)} -#img_files: ${addprefix $(HTML_OUT_DIR)/, $(IMGS)} - -#gen_html: $(HTML_OUT_DIR) css_files img_files html_files -gen_html: $(HTML_OUT_DIR) css_files html_files - -clean: - @-rm -f index.html diff --git a/misc/memstat/doc/TMemStat_Technical_Overview.html b/misc/memstat/doc/TMemStat_Technical_Overview.html deleted file mode 100644 index 2deb67a339ed8..0000000000000 --- a/misc/memstat/doc/TMemStat_Technical_Overview.html +++ /dev/null @@ -1,47 +0,0 @@ - - -New TMemStat: Technical Overview

New TMemStat: Technical Overview

Anar Manafov

2010


Obtaining a backtrace

-In the current implementation of TMemStat we have implemented 2 algorithms to unwind the stack after a malloc/free hook is called: -

  1. - backtrace - a function of the GNU C Library, -

  2. - __builtin_frame_address - a built-in function of gcc. -

- -User can switch between algorithms by providing an option to TMemStat constructor. When user sets “gnubuiltin” as an option, than gcc builtin will be used, if user provides anything else or an empty string, than C Library backtrace will be used. -

-Each algorithm has its own advantages and disadvantages. Up to now we know, that C Library backtrace is very slow, but woks in most of the cases. Gcc builtin doesn't always work when application is compiled in optimized mode and frame pointers are omitted. Actually both algorithms could have problems if frame pointers are omitted (compiler optimization option). -

Algorithms Comparison

General check

-The following systems were used for tests. -

-


-Linux 64bit:
-Linux  2.6.18-164.11.1.el5 #1 SMP Wed Jan 20 12:36:24 CET 2010 x86_64 x86_64 x86_64 GNU/Linux
-gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)
-

-

-


-Linux 32bit:
-

-

-


-MacOSX 10.5:
-

-

-


-MacOSX 10.6:
-Darwin 10.2.0 Darwin Kernel Version 10.2.0: Tue Nov  3 10:37:10 PST 2009; root:xnu-1486.2.11~1/RELEASE_I386 i386
-gcc version 4.2.1 (Apple Inc. build 5646) (dot 1)
-

-

Table 1. General comparison

algorithm / OSLinix 64b (opt.[a])Linux 64b (debug[b])Linux 32b (opt.[a])Linux 32b (debug [b])MacOSX 10.5 (opt[a])MacOSX 10.5 (debug[b])MacOSX 10.6 (opt.[a])MacOSX 10.6 (debug[b])
backtraceOk.Ok.----Ok. [c] -Ok.
builtinXOk.----Ok. [c]Ok.

[a] opt. means that TMemStat compiled with the default ROOT optimization flags and the same valid for a test script. -

[b] debug means that TMemStat library is compiled with “make ROOTBUILD=debug” and a test script compiled by ACLIC with C++g option. -

[c] -Works, but if the malloc/free is called in a loop, than we get two unique backtraces for each loop. Probably there is a partial optimization, and compiler unrolls the first iteration outside of the loop. This is why we actually get two calls for malloc/free, one before the loop and another is in the loop. I checked, that it doesn’t matter how many iteration we do, 10 or 100000. We always get two different back traces. -Sometimes we even can get full loop unroll, which means we get as many return address as iterations in the loop. -Both algorithms beehives the same in this case. -What else we could expect, if the code was really optimized and compiler unrolled the loop... -


Speed check

-

Usage tips

-Starting from gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) imply by the default the -fomit-frame-pointer flag. This flagprevents our “gcc builtin” algorithm to work properly. It you want memstat to use this algorithm and your application is comoled with optimization flags, we recommend to also use build your application with -fno-omit-frame-pointer option. -

diff --git a/misc/memstat/doc/TMemStat_Technical_Overview.xml b/misc/memstat/doc/TMemStat_Technical_Overview.xml deleted file mode 100644 index 11e4ba0308abf..0000000000000 --- a/misc/memstat/doc/TMemStat_Technical_Overview.xml +++ /dev/null @@ -1,150 +0,0 @@ - - -
- - AnarManafov - am - - 2010 - New TMemStat: Technical Overview - - - - -Obtaining a backtrace - -In the current implementation of TMemStat we have implemented 2 algorithms to unwind the stack after a malloc/free hook is called: - - - - - backtrace - a function of the GNU C Library, - - - - - __builtin_frame_address - a built-in function of gcc. - - - - -User can switch between algorithms by providing an option to TMemStat constructor. When user sets “gnubuiltin” as an option, than gcc builtin will be used, if user provides anything else or an empty string, than C Library backtrace will be used. - - -Each algorithm has its own advantages and disadvantages. Up to now we know, that C Library backtrace is very slow, but woks in most of the cases. Gcc builtin doesn't always work when application is compiled in optimized mode and frame pointers are omitted. Actually both algorithms could have problems if frame pointers are omitted (compiler optimization option). - - - -Algorithms Comparison -General check - -The following systems were used for tests. - - - -Linux 64bit: -Linux 2.6.18-164.11.1.el5 #1 SMP Wed Jan 20 12:36:24 CET 2010 x86_64 x86_64 x86_64 GNU/Linux -gcc version 4.1.2 20080704 (Red Hat 4.1.2-46) - - - - - -Linux 32bit: - - - - - -MacOSX 10.5: - - - - - -MacOSX 10.6: -Darwin 10.2.0 Darwin Kernel Version 10.2.0: Tue Nov 3 10:37:10 PST 2009; root:xnu-1486.2.11~1/RELEASE_I386 i386 -gcc version 4.2.1 (Apple Inc. build 5646) (dot 1) - - - - General comparison - - - - algorithm / OS - Linix 64b (opt.opt. means that TMemStat compiled with the default ROOT optimization flags and the same valid for a test script. -) - Linux 64b (debugdebug means that TMemStat library is compiled with “make ROOTBUILD=debug” and a test script compiled by ACLIC with C++g option. -) - Linux 32b (opt.) - Linux 32b (debug ) - MacOSX 10.5 (opt) - MacOSX 10.5 (debug) - MacOSX 10.6 (opt.) - MacOSX 10.6 (debug) - - - - - backtrace - Ok. - Ok. - - - - - - - - - Ok. - -Works, but if the malloc/free is called in a loop, than we get two unique backtraces for each loop. Probably there is a partial optimization, and compiler unrolls the first iteration outside of the loop. This is why we actually get two calls for malloc/free, one before the loop and another is in the loop. I checked, that it doesn’t matter how many iteration we do, 10 or 100000. We always get two different back traces. -Sometimes we even can get full loop unroll, which means we get as many return address as iterations in the loop. -Both algorithms beehives the same in this case. -What else we could expect, if the code was really optimized and compiler unrolled the loop... - - - - Ok. - - - builtin - X - Ok. - - - - - - - - - Ok. - Ok. - - - -
- -
- -Speed check - - - - -
- -Usage tips - -Starting from gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) imply by the default the -fomit-frame-pointer flag. This flagprevents our “gcc builtin” algorithm to work properly. It you want memstat to use this algorithm and your application is comoled with optimization flags, we recommend to also use build your application with -fno-omit-frame-pointer option. - - - -
- diff --git a/misc/memstat/doc/caution.png b/misc/memstat/doc/caution.png deleted file mode 100644 index 78555f1c6810d24a25acc1bc31e4a21e7ac7e970..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1929 zcmV;42X^?0P)y{D4^00!$xL_t(o z!|j)OOp|vU#(P3rY&qo=XbZHWfcKqj&g}2S&H1NW=Kj$oTe3gYEnBjL;SNnqHU&fu zK`C+wa%dFrp5lE`)Xj6~Se1FUwSw2P=hwc)ZgbQtS+e*hzq~1Vd4Hci-{<>$f0fBz zUH^kCf@_XkCR@a{;7LpNcr6moO8@h6E~W3Lx9D_vi_^@`hMXMKWoMykL?+f)EhtM* z!z!~81*s|cF*ym#5)-gAJ{I#L!=1@$Ri5}?#YM-m{PQ4DsPZ#P+P$+W6yPl&Qa&a>VCGxEn_myc=aLAZE03kN| z`||&N9al|=0(BZC8gy#Z4$)wqHpHE%kPBrD&swH%p#&j30^*>F5PW%+*i2eBKR_S^ zRj48CdW{Mj2+=eo6dMg%YzPm-d|jv~ULntYsxqnN@&RMA98SknLP$!KD`hB_$xtSj zHdZ~p`%6*F=jyd8)DXlbRMCZCb3_>0qYT&>9ZndHGr^~fUKvaYi?19W$JEI{~n6ocpdp-qkvNQAe3H+O060NG;`J553p+bYp98iz;+sUHx1kt8%+ai zJrc~I%FJPlx*bypVf2+lY*@%Tw}1Z~?%ltSOI=-9J@YNB5Tz1+2$lRm02@IHvqqq^ zu@Qau?xAzb7L=M&u{$;j9f`3xI4l7>6XWnO4ZDVBLNU%t>h-npDl#v z&K*2>_z;&*okICLGf_xo>Lfqd_)KBWNOWy%K|dj!PAB$P*-*iEbtJ^%P;vr}rY7MO z+dV&iD5T)~HxT)P(lnFr#s2Q#y@LKI;0yPbl;Ez%oOrgxGf3&H9$xlhb-m=mG zWki{TGAqX9z~0p4Q-To3H*G@kxY5`g7lR`yi8#(L(M5=#3GwUj43s4g3l5Uchw1~& z7--5$;TOJiPf0O6ZZ{r0cmT)QvpC<;f&Tt}Z#j;&G^1qv7_Snd6emn6IGJX|FP1c% zBSa6CTf;9K6yyiWR!{Q>|KvneRZviLX#lJYMhRm;x;Vgn<)S+Bub8nbA|bX@E1_Nw9q zxpfP*AI(QabR?DV`QbEY(OJ%<3z=42q7uIo;^x@VsL4nR4zeUR2J1r=k3&i$@g(&neFAmc?WmmfHd@%C0^%IA=i&$}E@zK`V^lW&7&{7X z8hE`WBRI&nF;U*q1kQ`bFh;dr>zx}#oWB0<5T594Ys0~sYM*DMZnDjO7p*k5faqaM zUm2Z^Yc%gILfoA+0rl3W0Qov9!rL{X6b+2%CT=d~MJ+*AW(VYi@C1!nJZ=oihg;C$ z^^DX_%$cg$v#_0BxH38iH~7r$iR0j$G#+;+PkcI%+(-kOScVM}#3q9dja)^9=oIDf z=LB1{l*Zh~G8|%e)UjOqR+kOHblW?zj>;S+3(=WkJ}A|SRCqRZQwX5LL`VA(pDGj|Ajx33@et?g){ zBDYx*0U_26LM={79z5d3AWBjw@;=e1J$ZbDq=y})GjSTvf!hn`A0l_hgJ ze#(*E%Bi`F18WDvX)VoH&X%oUEAHU%5?yh|>dS{q%m-o0-Z7)l!|rIMGSzR+zpB?!HA0fcosdx&G&I|iMT$^s22HfQOXAg^Fct| zWVxJFODJ%a5I6YQ50OtL(lwggXF9)1hZciTsm%K#(%|0Dp>;yc3zkC63x7WR#(cO! z1+I-1t?7gCdqFHe#0rzqZS^T(P(JVBIaQ^~{VFEPbt26l)jmJ;u#2uz_UrV7$cI1( zr*xOf;gXclzwplqvs#_^O - - - - - - - diff --git a/misc/memstat/doc/docbook.css b/misc/memstat/doc/docbook.css deleted file mode 100644 index fe502de014f68..0000000000000 --- a/misc/memstat/doc/docbook.css +++ /dev/null @@ -1,602 +0,0 @@ -/*============================================================================= - Copyright (c) 2004 Joel de Guzman - http://spirit.sourceforge.net/ - - Distributed under the Boost Software License, Version 1.0. (See accompany- - ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ - -/* Updated by Anar Manafov, - Copyright (c) 2010 GSI, Scientific Computing group. All rights reserved.*/ - -/*============================================================================= - Body defaults -=============================================================================*/ - - body - { - margin: 1em; - font-family: sans-serif; - } - -/*============================================================================= - Paragraphs -=============================================================================*/ - - p - { - text-align: left; - font-size: 10pt; - line-height: 1.15; - } - -/*============================================================================= - Program listings -=============================================================================*/ - - /* Code on paragraphs */ - p tt.computeroutput - { - font-size: 9pt; - } - - pre.synopsis - { - font-size: 90%; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - .programlisting, - .screen - { - font-size: 9pt; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - /* Program listings in tables don't get borders */ - td .programlisting, - td .screen - { - margin: 0pc 0pc 0pc 0pc; - padding: 0pc 0pc 0pc 0pc; - } - -/*============================================================================= - Headings -=============================================================================*/ - - h1, h2, h3, h4, h5, h6 - { - text-align: left; - margin: 1em 0em 0.5em 0em; - font-weight: bold; - } - - h1 { font: 140% } - h2 { font: bold 140% } - h3 { font: bold 130% } - h4 { font: bold 120% } - h5 { font: italic 110% } - h6 { font: italic 100% } - - /* Top page titles */ - title, - h1.title, - h2.title - h3.title, - h4.title, - h5.title, - h6.title, - .refentrytitle - { - font-weight: bold; - margin-bottom: 1pc; - } - - h1.title { font-size: 140% } - h2.title { font-size: 140% } - h3.title { font-size: 130% } - h4.title { font-size: 120% } - h5.title { font-size: 110% } - h6.title { font-size: 100% } - - .section h1 - { - margin: 0em 0em 0.5em 0em; - font-size: 140%; - } - - .section h2 { font-size: 140% } - .section h3 { font-size: 130% } - .section h4 { font-size: 120% } - .section h5 { font-size: 110% } - .section h6 { font-size: 100% } - - /* Code on titles */ - h1 tt.computeroutput { font-size: 140% } - h2 tt.computeroutput { font-size: 140% } - h3 tt.computeroutput { font-size: 130% } - h4 tt.computeroutput { font-size: 130% } - h5 tt.computeroutput { font-size: 130% } - h6 tt.computeroutput { font-size: 130% } - - -/*============================================================================= - Author -=============================================================================*/ - - h3.author - { - font-size: 100% - } - -/*============================================================================= - Lists -=============================================================================*/ - - li - { - font-size: 10pt; - line-height: 1.3; - } - - /* Unordered lists */ - ul - { - text-align: left; - } - - /* Ordered lists */ - ol - { - text-align: left; - } - -/*============================================================================= - Links -=============================================================================*/ - - a - { - text-decoration: none; /* no underline */ - } - - a:hover - { - text-decoration: underline; - } - -/*============================================================================= - Spirit style navigation -=============================================================================*/ - - .spirit-nav - { - text-align: right; - } - - .spirit-nav a - { - color: white; - padding-left: 0.5em; - } - - .spirit-nav img - { - border-width: 0px; - } - -/*============================================================================= - Copyright footer -=============================================================================*/ - .copyright-footer - { - text-align: right; - font-size: 70%; - } - - .copyright-footer p - { - text-align: right; - font-size: 80%; - } - -/*============================================================================= - Table of contents -=============================================================================*/ - - .toc - { - margin: 1pc 4% 0pc 4%; - padding: 0.1pc 1pc 0.1pc 1pc; - font-size: 80%; - line-height: 1.15; - } - - .boost-toc - { - float: right; - padding: 0.5pc; - } - - /* Code on toc */ - .toc .computeroutput { font-size: 120% } - -/*============================================================================= - Tables -=============================================================================*/ - - .table-title, - div.table p.title - { - margin-left: 4%; - padding-right: 0.5em; - padding-left: 0.5em; - } - - .informaltable table, - .table table - { - width: 92%; - margin-left: 4%; - margin-right: 4%; - } - - div.informaltable table, - div.table table - { - padding: 4px; - border: none; - } - - /* Table Cells */ - div.informaltable table tr td, - div.table table tr td - { - padding: 0.5em; - text-align: left; - font-size: 9pt; - } - - div.informaltable table tr th, - div.table table tr th - { - padding: 0.5em 0.5em 0.5em 0.5em; - border: 1pt solid white; - font-size: 80%; - } - - table.simplelist - { - width: auto !important; - margin: 0em !important; - padding: 0em !important; - border: none !important; - } - table.simplelist td - { - margin: 0em !important; - padding: 0em !important; - text-align: left !important; - font-size: 9pt !important; - border: none !important; - } - -/*============================================================================= - Blurbs -=============================================================================*/ - - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - font-size: 9pt; /* A little bit smaller than the main text */ - line-height: 1.2; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - p.blurb img - { - padding: 1pt; - } - -/*============================================================================= - Variable Lists -=============================================================================*/ - - div.variablelist - { - margin: 1em 0; - } - - /* Make the terms in definition lists bold */ - div.variablelist dl dt, - span.term - { - font-weight: bold; - font-size: 10pt; - } - - div.variablelist table tbody tr td - { - text-align: left; - vertical-align: top; - padding: 0em 2em 0em 0em; - font-size: 10pt; - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - - div.variablelist dl dt - { - margin-bottom: 0.2em; - } - - div.variablelist dl dd - { - margin: 0em 0em 0.5em 2em; - font-size: 10pt; - } - - div.variablelist table tbody tr td p, - div.variablelist dl dd p - { - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - -/*============================================================================= - Misc -=============================================================================*/ - - /* Title of books and articles in bibliographies */ - span.title - { - font-style: italic; - } - - span.underline - { - text-decoration: underline; - } - - span.strikethrough - { - text-decoration: line-through; - } - - /* Copyright, Legal Notice */ - div div.legalnotice p - { - text-align: left - } - -/*============================================================================= - Colors -=============================================================================*/ - - @media screen - { - body { - background-color: #FFFFFF; - color: #000000; - } - - /* Links */ - a - { - color: #005a9c; - } - - a:visited - { - color: #9c5a9c; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, - h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, - h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited - { - text-decoration: none; /* no underline */ - color: #000000; - } - - /* Syntax Highlighting */ - .keyword { color: #0000AA; } - .identifier { color: #000000; } - .special { color: #707070; } - .preprocessor { color: #402080; } - .char { color: teal; } - .comment { color: #800000; } - .string { color: teal; } - .number { color: teal; } - .white_bkd { background-color: #FFFFFF; } - .dk_grey_bkd { background-color: #999999; } - - /* Copyright, Legal Notice */ - .copyright - { - color: #666666; - font-size: small; - } - - div div.legalnotice p - { - color: #666666; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid #DCDCDC; - } - - .programlisting, - .screen - { - border: 1px solid #DCDCDC; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Blurbs */ - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - border: 1px solid #DCDCDC; - } - - /* Table of contents */ - .toc - { - border: 1px solid #DCDCDC; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - } - - div.informaltable table tr th, - div.table table tr th - { - background-color: #F0F0F0; - border: 1px solid #DCDCDC; - } - - .copyright-footer - { - color: #8F8F8F; - } - - /* Misc */ - span.highlight - { - color: #00A000; - } - } - - @media print - { - /* Links */ - a - { - color: black; - } - - a:visited - { - color: black; - } - - .spirit-nav - { - display: none; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid gray; - } - - .programlisting, - .screen - { - border: 1px solid gray; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Table of contents */ - .toc - { - border: 1px solid gray; - } - - .informaltable table, - .table table - { - border: 1px solid gray; - border-collapse: collapse; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid gray; - } - - div.informaltable table tr th, - div.table table tr th - { - border: 1px solid gray; - } - - table.simplelist tr td - { - border: none !important; - } - - /* Misc */ - span.highlight - { - font-weight: bold; - } - } - -/*============================================================================= - Images -=============================================================================*/ - - span.inlinemediaobject img - { - vertical-align: middle; - } - -/*============================================================================== - Super and Subscript: style so that line spacing isn't effected, see - http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 -==============================================================================*/ - -sup, -sub { - height: 0; - line-height: 1; - vertical-align: baseline; - _vertical-align: bottom; - position: relative; - -} - -sup { - bottom: 1ex; -} - -sub { - top: .5ex; -} - diff --git a/misc/memstat/doc/important.png b/misc/memstat/doc/important.png deleted file mode 100644 index 84a52a1f7ba894def3412103ff282458a1410aae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1397 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 Hu0mjfsi>tn diff --git a/misc/memstat/doc/tip.png b/misc/memstat/doc/tip.png deleted file mode 100644 index fce91aa42cc1f6f0c8635caec77cfc412834b807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2139 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 diff --git a/misc/memstat/inc/LinkDef.h b/misc/memstat/inc/LinkDef.h deleted file mode 100644 index dec8981239b58..0000000000000 --- a/misc/memstat/inc/LinkDef.h +++ /dev/null @@ -1,25 +0,0 @@ -// @(#)root/memstat:$Name$:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-04-28 - -/************************************************************************* - * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifdef __CINT__ -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ namespace Memstat; - -#pragma link C++ class TMemStat; -#pragma link C++ class Memstat::TMemStatMng; - - -//#pragma link C++ function Memstat::dig2bytes(Long64_t); - -#endif diff --git a/misc/memstat/inc/TMemStat.h b/misc/memstat/inc/TMemStat.h deleted file mode 100644 index 524d934b69d2c..0000000000000 --- a/misc/memstat/inc/TMemStat.h +++ /dev/null @@ -1,31 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -#ifndef ROOT_TMemStat -#define ROOT_TMemStat - -#include "TObject.h" - -class TMemStat: public TObject { -private: - Bool_t fIsActive; // is object attached to MemStat - -public: - TMemStat(Option_t* option = "read", Int_t buffersize=10000, Int_t maxcalls=5000000); - virtual ~TMemStat(); - static void Close(); - virtual void Disable(); - virtual void Enable(); - static void Show(Double_t update=0.1, Int_t nbigleaks=20, const char* fname="*"); - - ClassDef(TMemStat, 0) // a user interface class of MemStat -}; - -#endif diff --git a/misc/memstat/inc/TMemStatBacktrace.h b/misc/memstat/inc/TMemStatBacktrace.h deleted file mode 100644 index 5f5f99bf72698..0000000000000 --- a/misc/memstat/inc/TMemStatBacktrace.h +++ /dev/null @@ -1,34 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2010-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -#ifndef ROOT_TMemStatBacktrace -#define ROOT_TMemStatBacktrace - -#define _INIT_TOP_STACK extern void *g_global_stack_end; -#define _GET_CALLER_FRAME_ADDR g_global_stack_end = __builtin_frame_address(1); - -// ROOT -#include "Rtypes.h" - -class TString; - -namespace Memstat { - // - // Backtrace functions - // - size_t getBacktrace(void **_trace, size_t _size, Bool_t _bUseGNUBuiltinBacktrace = kFALSE); - int getSymbols(void *_pAddr, - TString &_strInfo, TString &_strLib, TString &_strSymbol); - void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _seporator = " | "); - void demangle(char *_codeInfo, TString &_str); -} - - -#endif diff --git a/misc/memstat/inc/TMemStatDef.h b/misc/memstat/inc/TMemStatDef.h deleted file mode 100644 index c294675f72d75..0000000000000 --- a/misc/memstat/inc/TMemStatDef.h +++ /dev/null @@ -1,19 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2010-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -#ifndef ROOT_TMemStatDef -#define ROOT_TMemStatDef - -#include - -namespace Memstat { - const size_t g_BTStackLevel = 50; -} -#endif diff --git a/misc/memstat/inc/TMemStatHelpers.h b/misc/memstat/inc/TMemStatHelpers.h deleted file mode 100644 index 10c59621ef468..0000000000000 --- a/misc/memstat/inc/TMemStatHelpers.h +++ /dev/null @@ -1,65 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -#ifndef ROOT_TMemStatHelpers -#define ROOT_TMemStatHelpers - -// ROOT -#include "TString.h" -#include "TObjString.h" -#include "TCollection.h" -// STD -#include -#include -#include -#include - - -class TObject; - -namespace Memstat { - std::string dig2bytes(Long64_t bytes); - -//______________________________________________________________________________ - struct SFind_t : std::binary_function { - bool operator()(TObject *_Obj, const TString &_ToFind) const { - TObjString *str(dynamic_cast(_Obj)); - if(!str) - return false; - return !str->String().CompareTo(_ToFind); - } - }; - -//______________________________________________________________________________ - template - Int_t find_string(const T &_Container, const TString &_ToFind) - { - // This function retuns an index in _Container of found element. - // Returns -1 if there was no element found. - - typedef TIterCategory iterator_t; - - iterator_t iter(&_Container); - iterator_t found( - std::find_if(iter.Begin(), iterator_t::End(), std::bind(SFind_t(), std::placeholders::_1, _ToFind)) - ); - return ((!(*found)) ? -1 : std::distance(iter.Begin(), found)); - } - -//______________________________________________________________________________ -// HACK: because of the bug in gcc 3.3 we need to use this nasty ToLower and ToUpper instead of direct calls of tolower (tolower.. is inline in this version of std lib)... - struct ToLower_t { - char operator()(char c) const { - return std::tolower(c); - } - }; - -} -#endif diff --git a/misc/memstat/inc/TMemStatHook.h b/misc/memstat/inc/TMemStatHook.h deleted file mode 100644 index 2b0975607d702..0000000000000 --- a/misc/memstat/inc/TMemStatHook.h +++ /dev/null @@ -1,52 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -// -// TYamsMemHook -// Non standard C/C++ functions -// Needed for memory statistic - -#ifndef ROOT_TMemStatHook -#define ROOT_TMemStatHook - -#include - -#if defined(__APPLE__) -#ifndef __CINT__ -#include -#endif -typedef void (*zoneMallocHookFunc_t)(void *ptr, size_t size); -typedef void (*zoneFreeHookFunc_t)(void *ptr); -#endif - -class TMemStatHook { -public: -#if !defined(__APPLE__) - // - // Memory management HOOK functions - // - typedef void*(*MallocHookFunc_t)(size_t size, const void *caller); - typedef void (*FreeHookFunc_t)(void *ptr, const void *caller); - - static MallocHookFunc_t GetMallocHook(); // malloc function getter - static FreeHookFunc_t GetFreeHook(); // free function getter - static void SetMallocHook(MallocHookFunc_t p); // malloc function setter - static void SetFreeHook(FreeHookFunc_t p); // free function setter -#else - // - // Public methods for Mac OS X - // - static void trackZoneMalloc(zoneMallocHookFunc_t pm, zoneFreeHookFunc_t pf); - static void untrackZoneMalloc(); -#endif -}; - -#endif - diff --git a/misc/memstat/inc/TMemStatMng.h b/misc/memstat/inc/TMemStatMng.h deleted file mode 100644 index 8acd1cb4acb9a..0000000000000 --- a/misc/memstat/inc/TMemStatMng.h +++ /dev/null @@ -1,150 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -#ifndef ROOT_TMemStatMng -#define ROOT_TMemStatMng - -// STD -#include -#include -// ROOT -#include "TObject.h" -#include "TTimeStamp.h" -// Memstat -#include "TMemStatHook.h" -#include "TMemStatDef.h" - -class TTree; -class TFile; -class TH1I; -class TObjArray; - -namespace Memstat { - - class TMemStatFAddrContainer { - typedef std::map Container_t; - typedef Container_t::iterator pos_type; - typedef Container_t::value_type value_type; - - public: - bool add(ULong_t addr, Int_t idx) { - std::pair ret = fContainer.insert(value_type(addr, idx)); - return (ret.second); - } - - Int_t find(ULong_t addr) { - pos_type iter = fContainer.find(addr); - if(fContainer.end() == iter) - return -1; - - return iter->second; - } - - private: - Container_t fContainer; - }; - - const UShort_t g_digestSize = 16; - struct SCustomDigest { - SCustomDigest() { - memset(fValue, 0, g_digestSize); - } - SCustomDigest(UChar_t _val[g_digestSize]) { - memcpy(fValue, _val, g_digestSize); - } - - UChar_t fValue[g_digestSize]; - }; - inline bool operator< (const SCustomDigest &a, const SCustomDigest &b) - { - for(int i = 0; i < g_digestSize; ++i) { - if(a.fValue[i] != b.fValue[i]) - return (a.fValue[i] < b.fValue[i]); - } - return false; - } - - - class TMemStatMng: public TObject { - typedef std::map CRCSet_t; - - private: - TMemStatMng(); - virtual ~TMemStatMng(); - - public: - void Enable(); //enable memory statistic - void Disable(); //Disable memory statistic - static TMemStatMng* GetInstance(); //get instance of class - ONLY ONE INSTANCE - static void Close(); //close MemStatManager - void SetBufferSize(Int_t buffersize); - void SetMaxCalls(Int_t maxcalls); - - public: - //stack data members - void SetUseGNUBuiltinBacktrace(Bool_t newVal) { - fUseGNUBuiltinBacktrace = newVal; - } - - protected: -#if !defined(__APPLE__) - TMemStatHook::MallocHookFunc_t fPreviousMallocHook; //!old malloc function - TMemStatHook::FreeHookFunc_t fPreviousFreeHook; //!old free function -#endif - void Init(); - void AddPointer(void *ptr, Int_t size); //add pointer to the table - void FillTree(); - static void *AllocHook(size_t size, const void* /*caller*/); - static void FreeHook(void* ptr, const void* /*caller*/); - static void MacAllocHook(void *ptr, size_t size); - static void MacFreeHook(void *ptr); - Int_t generateBTID(UChar_t *CRCdigest, Int_t stackEntries, - void **stackPointers); - - - // memory information - TFile* fDumpFile; //!file to dump current information - TTree *fDumpTree; //!tree to dump information - static TMemStatMng *fgInstance; // pointer to instance - static void *fgStackTop; // stack top pointer - - Bool_t fUseGNUBuiltinBacktrace; - TTimeStamp fTimeStamp; - Double_t fBeginTime; //time when monitoring starts - ULong64_t fPos; //position in memory where alloc/free happens - Int_t fTimems; //10000*(current time - begin time) - Int_t fNBytes; //number of bytes allocated/freed - Int_t fBtID; //back trace identifier - Int_t fMaxCalls; //max number of malloc/frees to register in the output Tree - Int_t fBufferSize; //max number of malloc/free to keep in the buffer - Int_t fBufN; //current number of alloc or free in the buffer - ULong64_t *fBufPos; //position in memory where alloc/free happens - Int_t *fBufTimems; //10000*(current time - begin time) - Int_t *fBufNBytes; //number of bytes allocated/freed - Int_t *fBufBtID; //back trace identifier - Int_t *fIndex; //array to sort fBufPos - Bool_t *fMustWrite; //flag to write or not the entry - - private: - TMemStatFAddrContainer fFAddrs; - TObjArray *fFAddrsList; - TH1I *fHbtids; - CRCSet_t fBTChecksums; - Int_t fBTCount; - // for Debug. A counter of all (de)allacations. - UInt_t fBTIDCount; - TNamed *fSysInfo; - - ClassDef(TMemStatMng, 0) // a manager of memstat sessions. - }; - -} - -#endif diff --git a/misc/memstat/src/TMemStat.cxx b/misc/memstat/src/TMemStat.cxx deleted file mode 100644 index ecbc476817dad..0000000000000 --- a/misc/memstat/src/TMemStat.cxx +++ /dev/null @@ -1,179 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) and Rene Brun 23/09/2010 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ - -//___________________________________________________________________________ -// TMemStat records all the calls to malloc and free and write a TTree -// with the position where the memory is allocated/freed , as well as -// the number of bytes. -// -// To use the class TMemStat, add the following statement at the beginning -// of your script or program -// TMemStat mm("gnubuiltin"); -// or in an interactive session do something like: -// root > TMemStat mm("gnubuiltin"); -// root > .x somescript.C -// root > .q -// -// another (may be more practical way) is to modify $ROOTSYS/etc/system.rootrc -// and activate the variable -// Root.TMemStat: 1 -// -// The file collected by TMemStat is named memstat_ProcessID and can be analyzed and results shown -// by executing the static function Show. -// When TMemStat is active it recors every call to malloc/free in a ROOT Tree. -// You must be careful when running jobs with many millions (or more) of calls -// to malloc/free because the generated Tree may become very large. -// The TMemStat constructor TMemStat(const char* system, Int_t buffersize, Int_t maxcalls) -// has its 3 arguments optional: -// -system refers to the internal algorithm to compute the back traces. -// the recommended value is "gnubuiltin" -// -buffersize is the number of calls to malloc or free that can be stored in one memory buffer. -// when the buffer is full, the calls to malloc/free pointing to the same location -// are eliminated and not written to the final Tree. The default value 100000 -// is such that between 50 and 90% of the calls are eliminated depending on the application. -// You can set buffersize <=1 to keep every single call to malloc/free. -// -maxcalls can set a limit for the maximum number of calls to be registered in the Tree. -// The default value is 5000000. -// The 3 arguments can be set in $ROOTSYS/etc/system.rootrc -// Root.TMemStat.system gnubuiltin -// Root.TMemStat.buffersize 100000 -// Root.TMemStat.maxcalls 5000000 -// -// TMemStat::Show creates 3 canvases. -// -In canvas1 it displays a dynamic histogram showing for pages (10 kbytes by default) -// the percentage of the page used. -// A summary pave shows the total memory still in use when the TMemStat object -// goes out of scope and the average occupancy of the pages. -// The average occupancy gives a good indication of the memory fragmentation. -// -// -In canvas2 it displays the histogram of memory leaks in decreasing order. -// when moving the mouse on this canvas, a tooltip shows the backtrace for the leak -// in the bin below the mouse. -// -// -In canvas3 it displays the histogram of the nbigleaks largest leaks (default is 20) -// for each leak, the number of allocs and average alloc size is shown. -// -// -// Simply do: -// root > TMemStat::Show() -// or specifying arguments -// root > TMemStat::Show(0.1,20,"mydir/mymemstat.root"); -// -// The first argument to Show is the percentage of the time of the original job -// that produced the file after which the display is updated. By default update=0.1, -// ie 10 time intervals will be shown. -// The second argument is nbigleaks. -// The third argument is the imput file name (result of TMemStat). -// If this argument is omitted, Show will take the most recent file -// generated by TMemStat. -// -// You can restrict the address range to be analyzed via TMemStatShow::SetAddressRange -// You can restrict the entry range to be analyzed via TMemStatShow::SetEntryRange -// -//___________________________________________________________________________ - -#include "TROOT.h" -#include "TDirectory.h" -#include "TMemStat.h" -#include "TMemStatBacktrace.h" -#include "TMemStatMng.h" -#include "TMemStatHelpers.h" - -#if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ > 5 -#pragma GCC diagnostic ignored "-Wframe-address" -#endif -#endif - -ClassImp(TMemStat); - -using namespace std; -using namespace Memstat; - -_INIT_TOP_STACK; - -//////////////////////////////////////////////////////////////////////////////// -/// Supported options: -/// "gnubuiltin" - if declared, then MemStat will use gcc build-in function, -/// otherwise glibc backtrace will be used -/// -/// Note: Currently MemStat uses a hard-coded output file name (for writing) = "memstat.root"; - -TMemStat::TMemStat(Option_t* option, Int_t buffersize, Int_t maxcalls): fIsActive(kFALSE) -{ - // It marks the highest used stack address. - _GET_CALLER_FRAME_ADDR; - - //preserve context. When exiting will restore the current directory - TDirectory::TContext context; - - Bool_t useBuiltin = kTRUE; - // Define string in a scope, so that the deletion of it will be not recorded by YAMS - { - string opt(option); - transform(opt.begin(), opt.end(), opt.begin(), - Memstat::ToLower_t()); - - useBuiltin = (opt.find("gnubuiltin") != string::npos) ? kTRUE : kFALSE; - } - - TMemStatMng::GetInstance()->SetUseGNUBuiltinBacktrace(useBuiltin); - TMemStatMng::GetInstance()->SetBufferSize(buffersize); - TMemStatMng::GetInstance()->SetMaxCalls(maxcalls); - TMemStatMng::GetInstance()->Enable(); - // set this variable only if "NEW" mode is active - fIsActive = kTRUE; - -} - -//////////////////////////////////////////////////////////////////////////////// -///destructor - -TMemStat::~TMemStat() -{ - if (fIsActive) { - TMemStatMng::GetInstance()->Disable(); - TMemStatMng::GetInstance()->Close(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -///close the TMemStat manager - -void TMemStat::Close() -{ - TMemStatMng::Close(); -} - -//////////////////////////////////////////////////////////////////////////////// -///Disable memory statistics - -void TMemStat::Disable() -{ - TMemStatMng::GetInstance()->Disable(); -} - -//////////////////////////////////////////////////////////////////////////////// -///Enable memory statistics - -void TMemStat::Enable() -{ - TMemStatMng::GetInstance()->Enable(); -} - -//////////////////////////////////////////////////////////////////////////////// -///Show results - -void TMemStat::Show(Double_t update, Int_t nbigleaks, const char* fname) -{ - TString action = TString::Format("TMemStatShow::Show(%g,%d,\"%s\");",update,nbigleaks,fname); - gROOT->ProcessLine(action); -} diff --git a/misc/memstat/src/TMemStatBacktrace.cxx b/misc/memstat/src/TMemStatBacktrace.cxx deleted file mode 100644 index c649839d26147..0000000000000 --- a/misc/memstat/src/TMemStatBacktrace.cxx +++ /dev/null @@ -1,229 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2010-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, 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 "TMemStatBacktrace.h" - -// STD -#include - -#ifndef __CINT__ -#if !defined(__APPLE__) || defined(MAC_OS_X_VERSION_10_5) -#include -#endif -#include -#endif - -#include -// ROOT -#include "TString.h" - -#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD) || (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_5))) -#define SUPPORTS_MEMSTAT -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#if __GNUC__ > 5 -#pragma GCC diagnostic ignored "-Wframe-address" -#endif -#endif - -// This is a global variable set at MSManager init time. -// It marks the highest used stack address. -void *g_global_stack_end = NULL; - -#if defined(SUPPORTS_MEMSTAT) -// Comment from Anar: -// HACK: there is an ugly bug in gcc (Bug#8743): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8743 -// "receiving result from __builtin_return_address() beyond stack top causes segfault" -// NOTE that __builtin_return_address should only be used with a non-zero argument for -// debugging purposes. So we use it on our risk. -// A workaround: -// This means the address is out of range. Note that for the -// toplevel we see a frame pointer with value NULL which clearly is out of range. -// NOTE 2: With gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) have started to imply -fomit-frame-pointer. -// One should use GCC builtin function with -fno-omit-frame-pointer option. -#define G__builtin_return_address(N) \ - ((__builtin_frame_address(N) == NULL) || \ - (__builtin_frame_address(N) >= g_global_stack_end) || \ - (__builtin_frame_address(N) < __builtin_frame_address(0))) ? \ - NULL : __builtin_return_address(N) -// __builtin_return_address(0) yields the address to which the current -// function will return. __builtin_return_address(1) yields the address to -// which the caller will return, and so on up the stack. -#define _RET_ADDR(x) case x: return G__builtin_return_address(x); - -#endif - -namespace Memstat { - - -//////////////////////////////////////////////////////////////////////////////// -/// we have a limit on the depth = 35 - - static void *return_address(int _frame) - { -#if defined(SUPPORTS_MEMSTAT) - switch(_frame) { - _RET_ADDR(0); - _RET_ADDR(1); - _RET_ADDR(2); - _RET_ADDR(3); - _RET_ADDR(4); - _RET_ADDR(5); - _RET_ADDR(6); - _RET_ADDR(7); - _RET_ADDR(8); - _RET_ADDR(9); - _RET_ADDR(10); - _RET_ADDR(11); - _RET_ADDR(12); - _RET_ADDR(13); - _RET_ADDR(14); - _RET_ADDR(15); - _RET_ADDR(16); - _RET_ADDR(17); - _RET_ADDR(18); - _RET_ADDR(19); - _RET_ADDR(20); - _RET_ADDR(21); - _RET_ADDR(22); - _RET_ADDR(23); - _RET_ADDR(24); - _RET_ADDR(25); - _RET_ADDR(26); - _RET_ADDR(27); - _RET_ADDR(28); - _RET_ADDR(29); - _RET_ADDR(30); - _RET_ADDR(31); - _RET_ADDR(32); - _RET_ADDR(33); - _RET_ADDR(34); - _RET_ADDR(35); - default: - return 0; - } -#else - if(_frame) { } - return 0; -#endif - } - -//////////////////////////////////////////////////////////////////////////////// - - size_t builtin_return_address(void **_container, size_t _limit) - { - size_t i(0); - void *addr; - for(i = 0; (i < _limit) && (addr = return_address(i)); ++i) - _container[i] = addr; - - return i; - } -//////////////////////////////////////////////////////////////////////////////// -/// Get the backtrace -/// _trace - array of pointers -/// _size - maximal deepness of stack information -/// _bUseGNUBuiltinBacktrace - whether to use gcc builtin backtrace or C library one. -/// The builtin version is much faster, but very sensitive and in some conditions could fail to return a proper result. -/// return value = min(stack deepness, dsize) - - size_t getBacktrace(void **_trace, size_t _size, Bool_t _bUseGNUBuiltinBacktrace) - { -#if defined(SUPPORTS_MEMSTAT) - if(_bUseGNUBuiltinBacktrace) { - // Initialize the stack end variable. - return builtin_return_address(_trace, _size); - } - return backtrace(_trace, _size); -#else - if(_trace || _size || _bUseGNUBuiltinBacktrace) { } - return 0; -#endif - } - -//////////////////////////////////////////////////////////////////////////////// -/// get the name of the function and library - - int getSymbols(void *_pAddr, - TString &/*_strInfo*/, TString &_strLib, TString &_strSymbol) - { -#if defined(SUPPORTS_MEMSTAT) - Dl_info info; - if(0 == dladdr(_pAddr, &info)) { - return -1; - } - if(NULL != info.dli_sname) { - int status(0); - char *ch = abi::__cxa_demangle(info.dli_sname, 0, 0, &status); - - _strSymbol = (0 == status) ? ch : info.dli_sname; - - // it's our responsibility to free that pointer - free(ch); - } - if(NULL != info.dli_fname) - _strLib = info.dli_fname; -#else - if(!_pAddr) { - _strLib = ""; - _strSymbol = ""; - } -#endif - return 0; - } - -//////////////////////////////////////////////////////////////////////////////// - - void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _separator) - { - if(!_retInfo) - return; - -#if defined(SUPPORTS_MEMSTAT) - TString strInfo; - TString strLib; - TString strFun; - int res = getSymbols(_pAddr, strInfo, strLib, strFun); - if(0 != res) - return; - - *_retInfo += strInfo; - *_retInfo += _separator; - *_retInfo += strLib; - *_retInfo += _separator; - *_retInfo += strFun; -#else - if(_pAddr || _separator) { } -#endif - } - -//////////////////////////////////////////////////////////////////////////////// -/// demangle symbols - - void demangle(char *_codeInfo, TString &_str) - { -#if defined(SUPPORTS_MEMSTAT) - int status = 0; - char *ch = abi::__cxa_demangle(_codeInfo, 0, 0, &status); - if(ch) { - _str = ch; - free(ch); - } else { - _str = "unknown"; - } -#else - if(!_codeInfo) { - _str = ""; - } -#endif - } - -} diff --git a/misc/memstat/src/TMemStatHelpers.cxx b/misc/memstat/src/TMemStatHelpers.cxx deleted file mode 100644 index c01546c8fc6b8..0000000000000 --- a/misc/memstat/src/TMemStatHelpers.cxx +++ /dev/null @@ -1,58 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -// STD -#include -#include -// ROOT -#include "Rtypes.h" -// Memstat -#include "TMemStatHelpers.h" - -using namespace std; - -//////////////////////////////////////////////////////////////////////////////// -/// This function creates a string representation of the number of bytes, -/// represented as a number in B, kB, MB or GB depending on the value. -/// The result is rounded to a sensible number of digits - -string Memstat::dig2bytes(Long64_t bytes) -{ - ostringstream ss; - ss << fixed; - - if(bytes < 0) { - ss << '-'; - bytes = -bytes; - } - - static const long kB = 1024L; - static const long lMB = kB * kB; - static const long lGB = lMB * kB; - - if(bytes < kB) - ss << bytes << " B"; - else if(bytes < (10L * kB)) - ss << setprecision(2) << ((double)bytes / (float)kB) << " kB"; - else if(bytes < (100L * kB)) - ss << setprecision(1) << ((double)bytes / (float)kB) << " kB"; - else if(bytes < lMB) - ss << setprecision(0) << ((double)bytes / (float)kB) << " kB"; - else if(bytes < (10L * lMB)) - ss << setprecision(2) << ((double)bytes / (float)lMB) << " MB"; - else if(bytes < (100L * lMB)) - ss << setprecision(1) << ((double)bytes / (float)lMB) << " MB"; - else if(bytes < lGB) - ss << setprecision(0) << ((double)bytes / (float)lMB) << " MB"; - else - ss << setprecision(2) << ((double)bytes / (float)lGB) << " GB"; - - return ss.str(); -} diff --git a/misc/memstat/src/TMemStatHook.cxx b/misc/memstat/src/TMemStatHook.cxx deleted file mode 100644 index e17d8347e6e9a..0000000000000 --- a/misc/memstat/src/TMemStatHook.cxx +++ /dev/null @@ -1,181 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -//STD -#include -// MemStat -#include "TMemStatHook.h" -#include - -// TODO: move it to a separate file -#if defined(__APPLE__) -static malloc_zone_t original_zone; -#ifndef __CINT__ -static void* profile_malloc(malloc_zone_t *zone, size_t size); -static void* profile_calloc(malloc_zone_t *zone, size_t num_items, size_t size); -static void* profile_valloc(malloc_zone_t *zone, size_t size); -static void profile_free(malloc_zone_t *zone, void *ptr); -#if defined(MAC_OS_X_VERSION_10_6) -static void profile_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size); -#endif -#endif - -static zoneMallocHookFunc_t m_pm; -static zoneFreeHookFunc_t m_pf; -#else -#include -#endif - -#if defined(R__GNU) && (defined(R__LINUX) || defined(__APPLE__)) -#define SUPPORTS_MEMSTAT -#endif - - -using namespace std; - -#if !defined(__APPLE__) -//////////////////////////////////////////////////////////////////////////////// -/// GetMallocHook - a static function -/// malloc function getter - -TMemStatHook::MallocHookFunc_t TMemStatHook::GetMallocHook() -{ -#if defined(SUPPORTS_MEMSTAT) - return __malloc_hook; -#else - return 0; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// GetFreeHook - a static function -/// free function getter - -TMemStatHook::FreeHookFunc_t TMemStatHook::GetFreeHook() -{ -#if defined(SUPPORTS_MEMSTAT) - return __free_hook; -#else - return 0; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// SetMallocHook - a static function -/// Set pointer to function replacing alloc function - -void TMemStatHook::SetMallocHook(MallocHookFunc_t p) -{ -#if defined(SUPPORTS_MEMSTAT) - __malloc_hook = p; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// SetFreeHook - a static function -/// Set pointer to function replacing free function - -void TMemStatHook::SetFreeHook(FreeHookFunc_t p) -{ -#if defined(SUPPORTS_MEMSTAT) - __free_hook = p; -#endif -} -#endif // !defined(__APPLE__) - -//////////////////////////////////////////////////////////////////////////////// -/// tracZoneMalloc - a static function -/// override the default Mac OS X memory zone - -#if defined (__APPLE__) -void TMemStatHook::trackZoneMalloc(zoneMallocHookFunc_t pm, - zoneFreeHookFunc_t pf) -{ - malloc_zone_t* zone = malloc_default_zone(); - if (!zone) { - cerr << "Error: Can't get malloc_default_zone" << endl; - return; - } - m_pm = pm; - m_pf = pf; - - original_zone = *zone; - zone->malloc = &profile_malloc; - zone->calloc = &profile_calloc; - zone->valloc = &profile_valloc; - zone->free = &profile_free; -#if defined(MAC_OS_X_VERSION_10_6) - if (zone->version >= 6 && zone->free_definite_size) - zone->free_definite_size = &profile_free_definite_size; -#endif -} -//////////////////////////////////////////////////////////////////////////////// -/// untrackZoneMalloc - a static function -/// set the default Mac OS X memory zone to original - -void TMemStatHook::untrackZoneMalloc() -{ - malloc_zone_t* zone = malloc_default_zone(); - if (!zone) { - cerr << "Error: Can't get malloc_default_zone" << endl; - return; - } - *zone = original_zone; -} -//////////////////////////////////////////////////////////////////////////////// -/// Mac OS X profiler of malloc calls - -void* profile_malloc(malloc_zone_t *zone, size_t size) -{ - void* ptr = (*original_zone.malloc)(zone, size); - m_pm(ptr, size); - return ptr; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Mac OS X profiler of calloc calls - -void* profile_calloc(malloc_zone_t *zone, size_t num_items, size_t size) -{ - void* ptr = (*original_zone.calloc)(zone, num_items, size); - m_pm(ptr, size); - return ptr; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Mac OS X profiler of valloc calls - -void* profile_valloc(malloc_zone_t *zone, size_t size) -{ - void* ptr = (*original_zone.valloc)(zone, size); - m_pm(ptr, size); - return ptr; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Mac OS X profiler of free calls - -void profile_free(malloc_zone_t *zone, void *ptr) -{ - (*original_zone.free)(zone, ptr); - m_pf(ptr); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Mac OS X profiler of free_definite_size calls - -#if defined(MAC_OS_X_VERSION_10_6) -void profile_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) -{ - (*original_zone.free_definite_size)(zone, ptr, size); - m_pf(ptr); -} -#endif // defined(MAC_OS_X_VERSION_10_6) -#endif // defined(__APPLE__) diff --git a/misc/memstat/src/TMemStatMng.cxx b/misc/memstat/src/TMemStatMng.cxx deleted file mode 100644 index 92a9e9e13ba30..0000000000000 --- a/misc/memstat/src/TMemStatMng.cxx +++ /dev/null @@ -1,505 +0,0 @@ -// @(#)root/memstat:$Id$ -// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02 - -/************************************************************************* -* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * -* All rights reserved. * -* * -* For the licensing terms see $ROOTSYS/LICENSE. * -* For the list of contributors see $ROOTSYS/README/CREDITS. * -*************************************************************************/ -// STD -#include -// ROOT -#include "TSystem.h" -#include "TError.h" -#include "Riostream.h" -#include "TObject.h" -#include "TFile.h" -#include "TTree.h" -#include "TArrayL64.h" -#include "TH1.h" -#include "TMD5.h" -#include "TMath.h" -// Memstat -#include "TMemStatBacktrace.h" -#include "TMemStatMng.h" - -using namespace Memstat; - -ClassImp(TMemStatMng); - -TMemStatMng* TMemStatMng::fgInstance = NULL; - -//****************************************************************************// -// -//****************************************************************************// - -TMemStatMng::TMemStatMng(): - TObject(), -#if !defined(__APPLE__) - fPreviousMallocHook(TMemStatHook::GetMallocHook()), - fPreviousFreeHook(TMemStatHook::GetFreeHook()), -#endif - fDumpFile(NULL), - fDumpTree(NULL), - fUseGNUBuiltinBacktrace(kFALSE), - fBeginTime(0), - fPos(0), - fTimems(0), - fNBytes(0), - fBtID(0), - fMaxCalls(5000000), - fBufferSize(10000), - fBufN(0), - fBufPos(0), - fBufTimems(0), - fBufNBytes(0), - fBufBtID(0), - fIndex(0), - fMustWrite(0), - fFAddrsList(0), - fHbtids(0), - fBTCount(0), - fBTIDCount(0), - fSysInfo(0) -{ - // Default constructor -} - -//////////////////////////////////////////////////////////////////////////////// -///Initialize MemStat manager - used only by instance method - -void TMemStatMng::Init() -{ - fBeginTime = fTimeStamp.AsDouble(); - - fDumpFile = new TFile(Form("memstat_%d.root", gSystem->GetPid()), "recreate"); - Int_t opt = 200000; - if(!fDumpTree) { - fDumpTree = new TTree("T", "Memory Statistics"); - fDumpTree->Branch("pos", &fPos, "pos/l", opt); - fDumpTree->Branch("time", &fTimems, "time/I", opt); - fDumpTree->Branch("nbytes", &fNBytes, "nbytes/I", opt); - fDumpTree->Branch("btid", &fBtID, "btid/I", opt); - } - - fBTCount = 0; - - fBTIDCount = 0; - - fFAddrsList = new TObjArray(); - fFAddrsList->SetOwner(kTRUE); - fFAddrsList->SetName("FAddrsList"); - - fHbtids = new TH1I("btids", "table of btids", 10000, 0, 1); //where fHbtids is a member of the manager class - fHbtids->SetDirectory(0); - // save the histogram and the TObjArray to the tree header - fDumpTree->GetUserInfo()->Add(fHbtids); - fDumpTree->GetUserInfo()->Add(fFAddrsList); - // save the system info to a tree header - std::string sSysInfo(gSystem->GetBuildNode()); - sSysInfo += " | "; - sSysInfo += gSystem->GetBuildCompilerVersion(); - sSysInfo += " | "; - sSysInfo += gSystem->GetFlagsDebug(); - sSysInfo += " "; - sSysInfo += gSystem->GetFlagsOpt(); - fSysInfo = new TNamed("SysInfo", sSysInfo.c_str()); - - fDumpTree->GetUserInfo()->Add(fSysInfo); - fDumpTree->SetAutoSave(10000000); -} - -//////////////////////////////////////////////////////////////////////////////// -/// GetInstance - a static function -/// Initialize a singleton of MemStat manager - -TMemStatMng* TMemStatMng::GetInstance() -{ - if(!fgInstance) { - fgInstance = new TMemStatMng; - fgInstance->Init(); - } - return fgInstance; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Close - a static function -/// This method stops the manager, -/// flashes all the buffered data and closes the output tree. - -void TMemStatMng::Close() -{ - // TODO: This is a temporary solution until we find a properalgorithm for SaveData - //fgInstance->fDumpFile->WriteObject(fgInstance->fFAddrsList, "FAddrsList"); - -/* std::ofstream f("mem_stat_debug.txt"); - int *btids = fgInstance->fHbtids->GetArray(); - if( !btids ) - return; - int btid(1); - int count(0); - bool bStop(false); - int count_empty(0); - for (int i = 0; i < fgInstance->fBTChecksums.size(); ++i) - { - if (bStop) - break; - count = btids[btid-1]; - f << "++++++++++++++++++++++++\n"; - f << "BTID: " << btid << "\n"; - if ( count <= 0 ) - ++count_empty; - for (int j = btid+1; j <= (btid+count); ++j ) - { - TNamed *nm = (TNamed*)fgInstance->fFAddrsList->At(btids[j]); - if( !nm ) - { - f << "Bad ID" << std::endl; - bStop = true; - } - f << "-------> " << nm->GetTitle() << "\n"; - } - btid = btid + count + 1; - } - f.close(); - ::Info("TMemStatMng::Close", "btids without a stack %d\n", count_empty); -*/ - - // to be documented - fgInstance->FillTree(); - fgInstance->Disable(); - fgInstance->fDumpTree->AutoSave(); - fgInstance->fDumpTree->GetUserInfo()->Delete(); - - ::Info("TMemStatMng::Close", "Tree saved to file %s\n", fgInstance->fDumpFile->GetName()); - ::Info("TMemStatMng::Close", "Tree entries = %d, file size = %g MBytes\n", (Int_t)fgInstance->fDumpTree->GetEntries(),1e-6*Double_t(fgInstance->fDumpFile->GetEND())); - - delete fgInstance->fDumpFile; - //fgInstance->fDumpFile->Close(); - //delete fgInstance->fFAddrsList; - //delete fgInstance->fSysInfo; - - delete fgInstance; - fgInstance = NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -/// if an instance is destructed - the hooks are reseted to old hooks - -TMemStatMng::~TMemStatMng() -{ - if(this != TMemStatMng::GetInstance()) - return; - - Info("~TMemStatMng", ">>> All free/malloc calls count: %d", fBTIDCount); - Info("~TMemStatMng", ">>> Unique BTIDs count: %zu", fBTChecksums.size()); - - Disable(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set the maximum number of alloc/free calls to be buffered. -///if the alloc and free are in the buffer, the corresponding entries -///are not saved tio the Tree, reducing considerably the Tree output size - -void TMemStatMng::SetBufferSize(Int_t buffersize) -{ - fBufferSize = buffersize; - if (fBufferSize < 1) fBufferSize = 1; - fBufN = 0; - fBufPos = new ULong64_t[fBufferSize]; - fBufTimems = new Int_t[fBufferSize]; - fBufNBytes = new Int_t[fBufferSize]; - fBufBtID = new Int_t[fBufferSize]; - fIndex = new Int_t[fBufferSize]; - fMustWrite = new Bool_t[fBufferSize]; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set the maximum number of new/delete registered in the output Tree. - -void TMemStatMng::SetMaxCalls(Int_t maxcalls) -{ - fMaxCalls = maxcalls; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Enable memory hooks - -void TMemStatMng::Enable() -{ - if(this != GetInstance()) - return; -#if defined(__APPLE__) - TMemStatHook::trackZoneMalloc(MacAllocHook, MacFreeHook); -#else - // set hook to our functions - TMemStatHook::SetMallocHook(AllocHook); - TMemStatHook::SetFreeHook(FreeHook); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// Disble memory hooks - -void TMemStatMng::Disable() -{ - //FillTree(); - if(this != GetInstance()) - return; -#if defined(__APPLE__) - TMemStatHook::untrackZoneMalloc(); -#else - // set hook to our functions - TMemStatHook::SetMallocHook(fPreviousMallocHook); - TMemStatHook::SetFreeHook(fPreviousFreeHook); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// AllocHook - a static function -/// a special memory hook for Mac OS X memory zones. -/// Triggered when memory is allocated. - -void TMemStatMng::MacAllocHook(void *ptr, size_t size) -{ - TMemStatMng* instance = TMemStatMng::GetInstance(); - // Restore all old hooks - instance->Disable(); - - // Call our routine - instance->AddPointer(ptr, Int_t(size)); - - // Restore our own hooks - instance->Enable(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// AllocHook - a static function -/// a special memory hook for Mac OS X memory zones. -/// Triggered when memory is deallocated. - -void TMemStatMng::MacFreeHook(void *ptr) -{ - TMemStatMng* instance = TMemStatMng::GetInstance(); - // Restore all old hooks - instance->Disable(); - - // Call our routine - instance->AddPointer(ptr, -1); - - // Restore our own hooks - instance->Enable(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// AllocHook - a static function -/// A glibc memory allocation hook. - -void *TMemStatMng::AllocHook(size_t size, const void* /*caller*/) -{ - TMemStatMng* instance = TMemStatMng::GetInstance(); - // Restore all old hooks - instance->Disable(); - - // Call recursively - void *result = malloc(size); - // Call our routine - instance->AddPointer(result, Int_t(size)); - // TTimer::SingleShot(0, "TYamsMemMng", instance, "SaveData()"); - - // Restore our own hooks - instance->Enable(); - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -/// FreeHook - a static function -/// A glibc memory deallocation hook. - -void TMemStatMng::FreeHook(void* ptr, const void* /*caller*/) -{ - TMemStatMng* instance = TMemStatMng::GetInstance(); - // Restore all old hooks - instance->Disable(); - - // Call recursively - free(ptr); - - // Call our routine - instance->AddPointer(ptr, -1); - - // Restore our own hooks - instance->Enable(); -} - -//////////////////////////////////////////////////////////////////////////////// -/// An internal function, which returns a bitid for a corresponding CRC digest -/// cache variables - -Int_t TMemStatMng::generateBTID(UChar_t *CRCdigest, Int_t stackEntries, - void **stackPointers) -{ - static Int_t old_btid = -1; - static SCustomDigest old_digest; - - Int_t ret_val = -1; - bool startCheck(false); - if(old_btid >= 0) { - for(int i = 0; i < g_digestSize; ++i) { - if(old_digest.fValue[i] != CRCdigest[i]) { - startCheck = true; - break; - } - } - ret_val = old_btid; - } else { - startCheck = true; - } - - // return cached value - if(!startCheck) - return ret_val; - - old_digest = SCustomDigest(CRCdigest); - CRCSet_t::const_iterator found = fBTChecksums.find(CRCdigest); - - if(fBTChecksums.end() == found) { - // check the size of the BT array container - const int nbins = fHbtids->GetNbinsX(); - //check that the current allocation in fHbtids is enough, otherwise expend it with - if(fBTCount + stackEntries + 1 >= nbins) { - fHbtids->SetBins(nbins * 2, 0, 1); - } - - int *btids = fHbtids->GetArray(); - // the first value is a number of entries in a given stack - btids[fBTCount++] = stackEntries; - ret_val = fBTCount; - if(stackEntries <= 0) { - Warning("AddPointer", - "A number of stack entries is equal or less than zero. For btid %d", ret_val); - } - - // add new BT's CRC value - std::pair res = fBTChecksums.insert(CRCSet_t::value_type(CRCdigest, ret_val)); - if(!res.second) - Error("AddPointer", "Can't added a new BTID to the container."); - - // save all symbols of this BT - for(int i = 0; i < stackEntries; ++i) { - ULong_t func_addr = (ULong_t)(stackPointers[i]); - Int_t idx = fFAddrs.find(func_addr); - // check, whether it's a new symbol - if(idx < 0) { - TString strFuncAddr; - strFuncAddr += func_addr; - TString strSymbolInfo; - getSymbolFullInfo(stackPointers[i], &strSymbolInfo); - - TNamed *nm = new TNamed(strFuncAddr, strSymbolInfo); - fFAddrsList->Add(nm); - idx = fFAddrsList->GetEntriesFast() - 1; - // TODO: more detailed error message... - if(!fFAddrs.add(func_addr, idx)) - Error("AddPointer", "Can't add a function return address to the container"); - } - - // even if we have -1 as an index we add it to the container - btids[fBTCount++] = idx; - } - - } else { - // reuse an existing BT - ret_val = found->second; - } - - old_btid = ret_val; - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Add pointer to table. -/// This method is called every time when any of the hooks are triggered. -/// The memory de-/allocation information will is recorded. - -void TMemStatMng::AddPointer(void *ptr, Int_t size) -{ - void *stptr[g_BTStackLevel + 1]; - const int stackentries = getBacktrace(stptr, g_BTStackLevel, fUseGNUBuiltinBacktrace); - - // save only unique BTs - TMD5 md5; - md5.Update(reinterpret_cast(stptr), sizeof(void*) * stackentries); - UChar_t digest[g_digestSize]; - md5.Final(digest); - - // for Debug. A counter of all (de)allacations. - ++fBTIDCount; - - Int_t btid(generateBTID(digest, stackentries, stptr)); - - if(btid <= 0) - Error("AddPointer", "bad BT id"); - - fTimeStamp.Set(); - Double_t CurTime = fTimeStamp.AsDouble(); - fBufTimems[fBufN] = Int_t(10000.*(CurTime - fBeginTime)); - ULong_t ul = (ULong_t)(ptr); - fBufPos[fBufN] = (ULong64_t)(ul); - fBufNBytes[fBufN] = size; - fBufBtID[fBufN] = btid; - fBufN++; - if (fBufN >= fBufferSize) { - FillTree(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -///loop on all entries in the buffer and fill the output Tree -///entries with alloc and free in the buffer are eliminated - -void TMemStatMng::FillTree() -{ - - //eliminate alloc/free pointing to the same location in the current buffer - TMath::Sort(fBufN,fBufPos,fIndex,kFALSE); - memset(fMustWrite,0,fBufN*sizeof(Bool_t)); - Int_t i=0,j; - while (i indj) indmin = indj; - if (indmax < indj) indmax = indj; - j++; - } - if (indmin == indmax) fMustWrite[indmin] = kTRUE; - if (fBufNBytes[indmin] == -1) fMustWrite[indmin] = kTRUE; - if (fBufNBytes[indmax] > 0) fMustWrite[indmax] = kTRUE; - i = j; - } - - // now fill the Tree with the remaining allocs/frees - for (i=0;iFill(); - } - - fBufN = 0; - if (fDumpTree->GetEntries() >= fMaxCalls) TMemStatMng::GetInstance()->Disable(); -} diff --git a/misc/memstat/test/leak_test.C b/misc/memstat/test/leak_test.C deleted file mode 100644 index 4377f8f16ab1f..0000000000000 --- a/misc/memstat/test/leak_test.C +++ /dev/null @@ -1,41 +0,0 @@ -// @(#)root/memstat:$Name$:$Id$ -// Author: M.Ivanov -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 - -/************************************************************************* - * Copyright (C) 1995-2008, 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 "TH1.h" -// MemStat -#include "TMemStat.h" - -const int g_count = 2; - -void test1() -{ - double* x[g_count]; - for(int i = 0; i < g_count; ++i) { - x[i] = new double[i+1]; - } - for(int i = 0; i < g_count; ++i) { - delete x[i]; - } -} -void test2() -{ - TH1F* h[100]; - for(int i = 0; i < 100; ++i) { - h[i] = new TH1F(Form("h%d", i), "test", 10 + i, 0, 10); - h[i]->Sumw2(); - } -} -void leak_test() -{ - TMemStat m("gnubuiltin"); - test1(); - test2(); -} diff --git a/misc/memstat/test/run.C b/misc/memstat/test/run.C deleted file mode 100644 index 959f31e791f9e..0000000000000 --- a/misc/memstat/test/run.C +++ /dev/null @@ -1,7 +0,0 @@ -void run(bool only_compile = false) -{ - gSystem->Load("libMemStat"); - // calling a "leaker" - if(!only_compile) - gROOT->ProcessLine(".x leak_test.C++g"); -} diff --git a/tree/treeviewer/CMakeLists.txt b/tree/treeviewer/CMakeLists.txt index 702ac934761d0..46cd87d9f1aaf 100644 --- a/tree/treeviewer/CMakeLists.txt +++ b/tree/treeviewer/CMakeLists.txt @@ -13,7 +13,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(TreeViewer HEADERS HelpTextTV.h TGTreeTable.h - TMemStatShow.h TParallelCoordEditor.h TParallelCoord.h TParallelCoordRange.h @@ -26,7 +25,6 @@ ROOT_STANDARD_LIBRARY_PACKAGE(TreeViewer SOURCES src/HelpTextTV.cxx src/TGTreeTable.cxx - src/TMemStatShow.cxx src/TParallelCoord.cxx src/TParallelCoordEditor.cxx src/TParallelCoordRange.cxx diff --git a/tree/treeviewer/inc/LinkDef.h b/tree/treeviewer/inc/LinkDef.h index e7a0d1a8a9f8a..7af9bf125ae85 100644 --- a/tree/treeviewer/inc/LinkDef.h +++ b/tree/treeviewer/inc/LinkDef.h @@ -29,5 +29,4 @@ #pragma link C++ class TParallelCoordSelect+; #pragma link C++ class TParallelCoordEditor; #pragma link C++ class TGTreeTable; -#pragma link C++ class TMemStatShow; #endif diff --git a/tree/treeviewer/inc/TMemStatShow.h b/tree/treeviewer/inc/TMemStatShow.h deleted file mode 100644 index 76a6434f76997..0000000000000 --- a/tree/treeviewer/inc/TMemStatShow.h +++ /dev/null @@ -1,73 +0,0 @@ -// @(#)root/treeviewer:$Id$ -// Author: Rene Brun 21/09/2010 - -/************************************************************************* - * Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -#ifndef ROOT_TMemStatShow -#define ROOT_TMemStatShow - -////////////////////////////////////////////////////////////////////////// -// // -// TMemStatShow // -// // -// class to visualize the results of TMemStat // -// // -////////////////////////////////////////////////////////////////////////// - -#include "TObject.h" - -class TTree; -class TH1D; -class TH1I; -class TGToolTip; -class TObjArray; -class TCanvas; - -class TMemStatShow : public TObject { - -protected: - static TTree *fgT; ///< TMemStat Tree - static TH1D *fgHalloc; ///< histogram with allocations - static TH1D *fgHfree; ///< histogram with frees - static TH1D *fgH; ///< histogram with allocations - frees - static TH1I *fgHleaks; ///< histogram with leaks - static TH1I *fgHentry; ///< histogram with entry numbers in the TObjArray - static TH1I *fgHdiff; ///< histogram with diff of entry number between alloc/free - - static TGToolTip *fgTip1; ///< pointer to tool tip for canvas 1 - static TGToolTip *fgTip2; ///< pointer to tool tip for canvas 2 - static TObjArray *fgBtidlist; ///< list of back trace ids - static Double_t *fgV1; ///< pointer to V1 array of TTree::Draw (pos) - static Double_t *fgV2; ///< pointer to V2 array of TTree::Draw (nbytes) - static Double_t *fgV3; ///< pointer to V3 array of TTree::Draw (time) - static Double_t *fgV4; ///< pointer to V4 array of TTree::Draw (btid) - static TCanvas *fgC1; ///< pointer to canvas showing allocs/deallocs vs time - static TCanvas *fgC2; ///< pointer to canvas with leaks in decreasing order - static TCanvas *fgC3; ///< pointer to canvas showing the main leaks - - static Long64_t fgAddressFirst; ///< first address to process - static Long64_t fgAddressN; ///< number of addresses in bytes to process - static Long64_t fgEntryFirst; ///< first entry to process - static Long64_t fgEntryN; ///< number of entries to process - -public: - TMemStatShow() {;} - virtual ~TMemStatShow() {;} - static void EventInfo1(Int_t event, Int_t px, Int_t py, TObject *selected); - static void EventInfo2(Int_t event, Int_t px, Int_t py, TObject *selected); - static void FillBTString(Int_t bin, Int_t mode, TString &btstring); - - static void SetAddressRange(Long64_t nbytes=0, Long64_t first=0); - static void SetEntryRange(Long64_t nentries=0, Long64_t first=0); - static void Show(Double_t update=0.1, Int_t nbigleaks=20, const char* fname="*"); - - ClassDef(TMemStatShow,0) //class to visualize the results of TMemStat -}; - -#endif diff --git a/tree/treeviewer/src/TMemStatShow.cxx b/tree/treeviewer/src/TMemStatShow.cxx deleted file mode 100644 index e5d9740dc5e47..0000000000000 --- a/tree/treeviewer/src/TMemStatShow.cxx +++ /dev/null @@ -1,647 +0,0 @@ -// @(#)root/treeviewer:$Id$ -// Author: Rene Brun 21/09/2010 - -/************************************************************************* - * Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. * - * All rights reserved. * - * * - * For the licensing terms see $ROOTSYS/LICENSE. * - * For the list of contributors see $ROOTSYS/README/CREDITS. * - *************************************************************************/ - -/** \class TMemStatShow -Utility class post-processing the file generated by TMemStat (default memstat.root) - -TMemStat records all the calls to malloc and free and write a TTree -with the position where the memory is allocated/freed , as well as -the number of bytes. - -To use the class TMemStat, add the following statement at the beginning -of your script or program -~~~ {.cpp} - TMemStat mm("gnubuiltin"); -~~~ -or in an interactive session do something like: -~~~ {.cpp} - root > TMemStat mm("gnubuiltin"); - root > .x somescript.C - root > .q -~~~ - -another (may be more practical way) is to modify `$ROOTSYS/etc/system.rootrc` -and activate the variable -~~~ {.cpp} - Root.TMemStat: 1 -~~~ -The file collected by TMemStat is named memstat_ProcessID and can be analyzed and results shown -by executing the static function Show. -When TMemStat is active it recors every call to malloc/free in a ROOT Tree. -You must be careful when running jobs with many millions (or more) of calls -to malloc/free because the generated Tree may become very large. -The TMemStat constructor TMemStat(const char* system, Int_t buffersize, Int_t maxcalls) -has its 3 arguments optional: - - system refers to the internal algorithm to compute the back traces. - the recommended value is "gnubuiltin" - - buffersize is the number of calls to malloc or free that can be stored in one memory buffer. - when the buffer is full, the calls to malloc/free pointing to the same location - are eliminated and not written to the final Tree. The default value 100000 - is such that between 50 and 90% of the calls are eliminated depending on the application. - You can set buffersize <=1 to keep every single call to malloc/free. - - maxcalls can set a limit for the maximum number of calls to be registered in the Tree. - The default value is 5000000. -The 3 arguments can be set in `$ROOTSYS/etc/system.rootrc` -~~~ {.cpp} - Root.TMemStat.system gnubuiltin - Root.TMemStat.buffersize 100000 - Root.TMemStat.maxcalls 5000000 -~~~ -TMemStat::Show creates 3 canvases. - - In canvas1 it displays a dynamic histogram showing for pages (10 kbytes by default) - the percentage of the page used. - A summary pave shows the total memory still in use when the TMemStat object - goes out of scope and the average occupancy of the pages. - The average occupancy gives a good indication of the memory fragmentation. - When moving the mouse on this canvas, a tooltip shows the backtrace for the allocations - at the address at the mouse position. - - In canvas2 it displays the histogram of memory leaks in decreasing order. - when moving the mouse on this canvas, a tooltip shows the backtrace for the leak - in the bin below the mouse. - - In canvas3 it displays the histogram of the nbigleaks largest leaks (default is 20) - for each leak, the number of allocs and average alloc size is shown. - -Simply do: -~~~ {.cpp} - root > TMemStat::Show() -~~~ -or specifying arguments -~~~ {.cpp} - root > TMemStat::Show(0.1,20,"mydir/mymemstat.root"); -~~~ -The first argument to Show is the percentage of the time of the original job -that produced the file after which the display is updated. By default update=0.1, -ie 10 time intervals will be shown. -The second argument is nbigleaks. if <=0 canvas2 and canvas3 are not shown -The third argument is the input file name (result of TMemStat). -If this argument is omitted, Show will take the most recent file -generated by TMemStat. - -You can restrict the address range to be analyzed via TMemStatShow::SetAddressRange -You can restrict the entry range to be analyzed via TMemStatShow::SetEntryRange -*/ - -#include "TMemStatShow.h" -#include "TMath.h" -#include "TFile.h" -#include "TTree.h" -#include "TCanvas.h" -#include "TStyle.h" -#include "TH1.h" -#include "TPaveText.h" -#include "TPaveLabel.h" -#include "TSystem.h" -#include "TGClient.h" -#include "TGToolTip.h" -#include "TRootCanvas.h" - - TTree *TMemStatShow::fgT = 0; //TMemStat Tree - TH1D *TMemStatShow::fgHalloc = 0; //histogram with allocations - TH1D *TMemStatShow::fgHfree = 0; //histogram with frees - TH1D *TMemStatShow::fgH = 0; //histogram with allocations - frees - TH1I *TMemStatShow::fgHleaks = 0; //histogram with leaks - TH1I *TMemStatShow::fgHentry = 0; //histogram with entry numbers in the TObjArray - TH1I *TMemStatShow::fgHdiff = 0; //histogram with diff of entry number between alloc/free - - TGToolTip *TMemStatShow::fgTip1 = 0; //pointer to tool tip for canvas 1 - TGToolTip *TMemStatShow::fgTip2 = 0; //pointer to tool tip for canvas 2 - TObjArray *TMemStatShow::fgBtidlist = 0; //list of back trace ids - Double_t *TMemStatShow::fgV1 = 0; //pointer to V1 array of TTree::Draw (pos) - Double_t *TMemStatShow::fgV2 = 0; //pointer to V2 array of TTree::Draw (nbytes) - Double_t *TMemStatShow::fgV3 = 0; //pointer to V3 array of TTree::Draw (time) - Double_t *TMemStatShow::fgV4 = 0; //pointer to V4 array of TTree::Draw (btid) - TCanvas *TMemStatShow::fgC1 = 0; //pointer to canvas showing allocs/deallocs vs time - TCanvas *TMemStatShow::fgC2 = 0; //pointer to canvas with leaks in decreasing order - TCanvas *TMemStatShow::fgC3 = 0; //pointer to canvas showing the main leaks - - Long64_t TMemStatShow::fgEntryFirst = 0; //first address to process - Long64_t TMemStatShow::fgEntryN = 0; //number of addresses in bytes to process - Long64_t TMemStatShow::fgAddressFirst = 0; //first entry to process - Long64_t TMemStatShow::fgAddressN = 0; //number of entries to process - -//////////////////////////////////////////////////////////////////////////////// -/// Specify a memory address range to process (static function). -/// This function can be used to restrict the range of memory addresses -/// to be analyzed. For example when TmemStat is run on a 64 bits machine and -/// the results visualized on a 32 bits machine, it might be necessary to -/// restrict the analysis range to the addresses below 2 Gigabytes, eg -/// TMemStatShow::SetMemoryRange(500000000,0); //analyse only the first 500 MBytes -/// - first : first address to process (default is 0) -/// - nbytes : number of addresses in bytes to process starting at first -/// if 0 (default), then all addresses are processed - -void TMemStatShow::SetAddressRange(Long64_t nbytes, Long64_t first) -{ - fgAddressFirst = first; - fgAddressN = nbytes; -} - -//////////////////////////////////////////////////////////////////////////////// -///Specify a range of entries to process (static function) -/// - first : first entry to process (default is 0) -/// - nentries : number of entries to process starting at first -/// if 0 (default), then all entries are processed -/// call this function when the amount of data collected in the Tree is large -/// and therefore making the analysis slow. - -void TMemStatShow::SetEntryRange(Long64_t nentries, Long64_t first) -{ - fgEntryFirst = first; - fgEntryN = nentries; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Function called by TMemStat::Show -/// Open the memstat data file, then call TTree::Draw to precompute -/// the arrays of positions and nbytes per entry. -/// update is the time interval in the data file in seconds after which -/// the display is updated. For example is the job producing the memstat.root file -/// took 100s to execute, an update of 0.1s will generate 1000 time views of -/// the memory use. -/// the histogram hbigleaks will contain the nbigleaks largest leaks -/// if fname=="*" (default), the most recent file memstat*.root will be taken. - -void TMemStatShow::Show(double update, int nbigleaks, const char* fname) -{ - - TString s; - if (!fname || strlen(fname) <5 || strstr(fname,"*")) { - //take the most recent file memstat*.root - s = gSystem->GetFromPipe("ls -lrt memstat*.root"); - Int_t ns = s.Length(); - fname = strstr(s.Data()+ns-25,"memstat"); - } - printf("Analyzing file: %s\n",fname); - TFile *f = TFile::Open(fname); - if (!f) { - printf("Cannot open file %s\n",fname); - return; - } - fgT = (TTree*)f->Get("T"); - if (!fgT) { - printf("cannot find the TMemStat TTree named T in file %s\n",fname); - return; - } - if (update <= 0) { - printf("Illegal update value %g, changed to 0.01\n",update); - update = 0.01; - } - if (update < 0.001) printf("Warning update parameter is very small, processing may be slow\n"); - - //autorestrict the amount of data to analyze - MemInfo_t minfo; - gSystem->GetMemInfo(&minfo); - Int_t nfree = minfo.fMemTotal - minfo.fMemUsed; //in Mbytes - printf("TMemStat::Show info: you are running on a machine with %d free MBytes of memory\n",nfree); - Long64_t nfreebytes = 200000*Long64_t(nfree); //use only 20% of the memory available - if (fgAddressN <=0) fgAddressN = nfreebytes; - Long64_t nentries = fgT->GetEntries(); - if (fgEntryN > 0 && nentries > fgEntryN) nentries = fgEntryN; - if (2*8*nentries > 4*nfreebytes) { - nentries = 4*nfreebytes/16; - printf("not enough memory, restricting analysis to %lld entries\n",nentries); - } - fgT->SetEstimate(nentries); - Long64_t nsel = fgT->Draw("pos","pos>0","goff",nentries); - fgV1 = fgT->GetV1(); - Long64_t ivmin = (Long64_t)TMath::MinElement(nsel,fgV1); - Long64_t ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1); - if (ivmax-ivmin > fgAddressN) ivmax = ivmin+fgAddressN; - printf("TMemStatShow::Show will analyze only %lld bytes in its first pass\n",ivmax); - - - //initialize statics - fgTip1 = 0; - fgTip2 = 0; - fgBtidlist = 0; - - Long64_t ne = nfreebytes/32LL; - if (ne < nentries) nentries = ne; - fgT->SetEstimate(nentries+10); - printf("sel: ivmin=%lld, ivmax=%lld, nentries=%lld\n",ivmin,ivmax,nentries); - nsel = fgT->Draw("pos:nbytes:time:btid", - TString::Format("pos>%g && pos<%g",Double_t(ivmin),Double_t(ivmax)), - "goff",nentries,fgEntryFirst); - - //now we compute the best binning for the histogram - Int_t nbytes; - Double_t pos; - fgV1 = fgT->GetV1(); - fgV2 = fgT->GetV2(); - fgV3 = fgT->GetV3(); - fgV4 = fgT->GetV4(); - ivmin = (Long64_t)TMath::MinElement(nsel,fgV1); - ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1); - Long64_t bw = 1000; - Double_t dvv = (Double_t(ivmax) - Double_t(ivmin))/Double_t(bw); - Long64_t nbins = Long64_t(dvv); - ivmin = ivmin -ivmin%bw; - ivmax = ivmin+bw*nbins; - Long64_t nvm = Long64_t(ivmax-ivmin+1); - printf("==>The data Tree contains %lld entries with addresses in range[%lld,%lld]\n",nsel,ivmin,ivmax); - //ne = (1000000*nfree-nvm*12)/32; - ne = 1000000LL*nfree/32LL; - if (ne < 0) return; - if (ne < nentries) { - //we take only the first side of the allocations - //we are mostly interested by the small allocations, so we select - //only values in the first gigabyte - nsel = fgT->Draw("pos:nbytes:time:btid", - TString::Format("pos>=%g && pos<%g",Double_t(ivmin),Double_t(ivmax)),"goff",ne,fgEntryFirst); - fgV1 = fgT->GetV1(); - fgV2 = fgT->GetV2(); - fgV3 = fgT->GetV3(); - fgV4 = fgT->GetV4(); - ivmin = (Long64_t)TMath::MinElement(nsel,fgV1); - ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1); - bw = 10000; - dvv = (Double_t(ivmax) - Double_t(ivmin))/Double_t(bw); - nbins = Long64_t(dvv+0.5); - ivmin = ivmin -ivmin%bw; - ivmax = ivmin+bw*nbins; - printf("==>Address range or/and Entry range is too large\n"); - printf("==>restricting the analysis range to [%lld,%lld] and %lld entries\n",ivmin,ivmax,ne); - printf("==>you can restrict the address range with TMemStatShow::SetAddressRange\n"); - printf("==>you can restrict the entries range with TMemStatShow::SetEntryRange\n"); - } - update *= 0.0001*fgV3[nsel-1]; //convert time per cent in seconds - nvm = Long64_t(ivmax-ivmin); - Long64_t *nbold = new Long64_t[nvm]; - Int_t *ientry = new Int_t[nvm]; - if (!nbold || !ientry) { - printf("you do not have enough memory to run, %lld bytes needed\n",12*nvm); - return; - } - memset(nbold,0,nvm*8); - memset(ientry,0,nvm*4); - Double_t dv = (ivmax-ivmin)/nbins; - TH1D *h = new TH1D("h",Form("%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax); - fgH = h; - TAxis *axis = h->GetXaxis(); - gStyle->SetOptStat("ie"); - h->SetFillColor(kRed); - h->SetMinimum(0); - h->SetMaximum(100); - fgHalloc = new TH1D("fgHalloc",Form("%s;pos;number of mallocs",fname),nbins,ivmin,ivmax); - fgHfree = new TH1D("fgHfree", Form("%s;pos;number of frees",fname),nbins,ivmin,ivmax); - fgHdiff = new TH1I("fgHdiff","",1000,0,1e5); - //open a canvas and draw the empty histogram - fgC1 = new TCanvas("fgC1","c1",1200,600); - fgC1->SetFrameFillColor(kYellow-3); - fgC1->SetGridx(); - fgC1->SetGridy(); - h->Draw(); - //create a TPaveText to show the summary results - TPaveText *pvt = new TPaveText(.5,.9,.75,.99,"brNDC"); - pvt->Draw(); - //create a TPaveLabel to show the time - TPaveLabel *ptime = new TPaveLabel(.905,.7,.995,.76,"time","brNDC"); - ptime->SetFillColor(kYellow-3); - ptime->Draw(); - //draw producer identifier - TNamed *named = (TNamed*)fgT->GetUserInfo()->FindObject("SysInfo"); - TText tmachine; - tmachine.SetTextSize(0.02); - tmachine.SetNDC(); - if (named) tmachine.DrawText(0.01,0.01,named->GetTitle()); - - //start loop on selected rows - Int_t bin,nb=0,j; - Long64_t ipos; - Double_t dbin,rest,time; - Double_t updateLast = 0; - Int_t nleaks = 0; - Int_t i; - for (i=0;iFindBin(pos); - if (bin<1 || bin>nbins) continue; - dbin = axis->GetBinUpEdge(bin)-pos; - if (nbytes > 0) { - ientry[ipos] = i; - fgHalloc->Fill(pos); - if (dbin > nbytes) dbin = nbytes; - //fill bytes in the first page - h->AddBinContent(bin,100*dbin/dv); - //fill bytes in full following pages - nb = Int_t((nbytes-dbin)/dv); - if (bin+nb >nbins) nb = nbins-bin; - for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100); - //fill the bytes remaining in last page - rest = nbytes-nb*dv-dbin; - if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv); - //we save nbytes at pos. This info will be used when we free this slot - //if (nbold[ipos] > 0) printf("reallocating %d bytes (was %lld) at %lld, entry=%d\n",nbytes,nbold[ipos],ipos,i); - if (nbold[ipos] == 0) { - nleaks++; - //save the Tree entry number where we made this allocation - ientry[ipos] = i; - } - nbold[ipos] = nbytes; - } else { - fgHfree->Fill(pos); - nbytes = nbold[ipos]; - if (bin+nb >nbins) nb = nbins-bin; - nbold[ipos] = 0; nleaks--; - fgHdiff->Fill(i-ientry[ipos]); - if (nbytes <= 0) continue; - //fill bytes free in the first page - if (dbin > nbytes) dbin = nbytes; - h->AddBinContent(bin,-100*dbin/dv); - //fill bytes free in full following pages - nb = Int_t((nbytes-dbin)/dv); - if (bin+nb >nbins) nb = nbins-bin; - for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100); - //fill the bytes free in in last page - rest = nbytes-nb*dv-dbin; - if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv); - - } - if (time -updateLast > update) { - //update canvas at regular intervals - updateLast = time; - h->SetEntries(i); - fgC1->Modified(); - pvt->GetListOfLines()->Delete(); - Double_t mbytes = 0; - Int_t nonEmpty = 0; - Double_t w; - for (Int_t k=1;kGetBinContent(k); - if (w > 0) { - nonEmpty++; - mbytes += 0.01*w*dv; - } - } - Double_t occupancy = mbytes/(nonEmpty*0.01*dv); - pvt->AddText(Form("memory used = %g Mbytes",mbytes*1e-6)); - pvt->AddText(Form("page occupancy = %f per cent",occupancy)); - pvt->AddText("(for non empty pages only)"); - ptime->SetLabel(Form("%g sec",time)); - - fgC1->Update(); - gSystem->ProcessEvents(); - } - } - h->SetEntries(nsel); - if (nleaks < 0) nleaks=0; - Int_t nlmax = nleaks; - nleaks += 1000; - Int_t *lindex = new Int_t[nleaks]; - Int_t *entry = new Int_t[nleaks]; - Int_t *ileaks = new Int_t[nleaks]; - - nleaks =0; - for (Int_t ii=0;ii 0) { - ileaks[nleaks] = (Int_t)nbold[ii]; - entry[nleaks] = ientry[ii]; - nleaks++; - if (nleaks > nlmax) break; - } - } - TMath::Sort(nleaks,ileaks,lindex); - fgHentry = new TH1I("fgHentry","leak entry index",nleaks,0,nleaks); - fgHleaks = new TH1I("fgHleaks","leaks;leak number;nbytes in leak",nleaks,0,nleaks); - for (Int_t k=0;kSetBinContent(k+1,i); - fgHleaks->SetBinContent(k+1,ileaks[kk]); - } - delete [] ileaks; - delete [] entry; - delete [] lindex; - delete [] nbold; - delete [] ientry; - fgHentry->SetEntries(nleaks); - fgHleaks->SetEntries(nleaks); - - - //construct the first tooltip - fgC1->Modified(); - fgC1->Update(); - TRootCanvas *rc1 = (TRootCanvas *)fgC1->GetCanvasImp(); - TGMainFrame *frm1 = dynamic_cast(rc1); - // create the tooltip with a timeout of 250 ms - if (!fgTip1) fgTip1 = new TGToolTip(gClient->GetDefaultRoot(), frm1, "", 250); - fgC1->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", - "TMemStatShow", 0, "EventInfo1(Int_t, Int_t, Int_t, TObject*)"); - if (nbigleaks <= 0) return; - - //--------------------------------------------------------------------------- - //open a second canvas and draw the histogram with leaks in decreasing order - fgC2 = new TCanvas("fgC2","c2",1200,600); - fgC2->SetFrameFillColor(kCyan-6); - fgC2->SetGridx(); - fgC2->SetGridy(); - fgC2->SetLogy(); - fgHleaks->SetFillColor(kRed-3); - if (nleaks > 1000) fgHleaks->GetXaxis()->SetRange(1,1000); - fgHleaks->Draw(); - //draw producer identifier - if (named) tmachine.DrawText(0.01,0.01,named->GetTitle()); - - //construct the second tooltip - TRootCanvas *rc2 = (TRootCanvas *)fgC2->GetCanvasImp(); - TGMainFrame *frm2 = dynamic_cast(rc2); - // create the tooltip with a timeout of 250 ms - if (!fgTip2) fgTip2 = new TGToolTip(gClient->GetDefaultRoot(), frm2, "", 250); - fgC2->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", - "TMemStatShow", 0, "EventInfo2(Int_t, Int_t, Int_t, TObject*)"); - - //--------------------------------------------------------------------------- - //open a third canvas and draw the histogram with the nbigleaks largest leaks - fgC3 = new TCanvas("fgC3","c3",1200,600); - fgC3->SetFrameFillColor(kCyan-6); - fgC3->SetGridx(); - fgC3->SetGridy(); - fgC3->SetLogx(); - fgC3->SetLeftMargin(0.05); - fgC3->SetRightMargin(0.7); - - //fill histogram htotleaks accumulating in the same bin all leaks - //from btids having identical nchar first characters - TH1I *htotleaks = new TH1I("htotleaks","main leaks sorted by btids",100,0,0); - Int_t l; - for (l=1;l<=nleaks;l++) { - TString btstring = ""; - TMemStatShow::FillBTString(l,1,btstring); - htotleaks->Fill(btstring.Data()+2,fgHleaks->GetBinContent(l)); - } - Double_t tsize = 0.03; - if (nbigleaks > 30) tsize = 0.02; - htotleaks->LabelsOption(">"); - htotleaks->GetXaxis()->SetRange(1,nbigleaks); - htotleaks->GetXaxis()->SetLabelSize(tsize); - htotleaks->GetYaxis()->SetLabelSize(tsize); - htotleaks->SetFillColor(kBlue-3); - htotleaks->Draw("hbar2 y+"); - - //now loop on all the sorted bins and count the number of leaks - Double_t xr = 0.96*fgC3->GetLeftMargin(); - Double_t xr2 = 1.04*fgC3->GetLeftMargin(); - Double_t ytop = 1-fgC3->GetTopMargin(); - Double_t ylow = fgC3->GetBottomMargin(); - Double_t dy = (ytop-ylow)/nbigleaks; - TString btstring; - TText tnl; - tnl.SetNDC(); - tnl.SetTextSize(tsize); - tnl.SetTextAlign(32); - TText tnl2; - tnl2.SetNDC(); - tnl2.SetTextSize(tsize); - tnl2.SetTextAlign(12); - tnl2.SetTextColor(kYellow); - for (Int_t lb=1;lb<=nbigleaks;lb++) { - if (htotleaks->GetBinContent(lb) <= 0) continue; - const char *label = htotleaks->GetXaxis()->GetBinLabel(lb); - Int_t nchlabel = strlen(label); - if (nchlabel == 0) htotleaks->GetXaxis()->SetBinLabel(lb,"???"); - Int_t nl =0; - for (l=1;l<=nleaks;l++) { - btstring = ""; - TMemStatShow::FillBTString(l,1,btstring); - if (nchlabel > 0) { - if (!strncmp(btstring.Data()+2,label,nchlabel)) nl++; - } else { - if (btstring.Length() == 0) nl++; - } - } - Double_t yr = ylow +(lb-0.5)*dy; - tnl.DrawText(xr,yr,Form("%d",nl)); - Int_t nbmean = Int_t(htotleaks->GetBinContent(lb)/nl); - if (lb == 1) tnl2.DrawText(xr2,yr,Form("%d bytes/alloc",nbmean)); - else tnl2.DrawText(xr2,yr,Form("%d",nbmean)); - } - tnl.DrawText(xr,ytop+0.015,"nallocs"); - tnl.DrawText(1-fgC3->GetRightMargin(),0.5*ylow,"nbytes"); - //draw producer identifier - if (named) tmachine.DrawText(0.01,0.01,named->GetTitle()); - -} - -//////////////////////////////////////////////////////////////////////////////// -/// Static: draw the tooltip showing the backtrace for the allocations histogram - -void TMemStatShow::EventInfo1(Int_t event, Int_t px, Int_t , TObject *selected) -{ - if (!fgTip1) return; - fgTip1->Hide(); - if (event == kMouseLeave) - return; - Double_t xpx = fgC1->AbsPixeltoX(px); - Double_t xpx1 = fgC1->AbsPixeltoX(px+1); - Int_t bin = fgH->GetXaxis()->FindBin(xpx); - Int_t bin1 = fgH->GetXaxis()->FindBin(xpx1); - //to take into account consecutive bins on the same pixel - while (bin <= bin1) { - if (fgH->GetBinContent(bin) > 0) break; - bin++; - } - if (fgH->GetBinContent(bin) <= 0) return; - if (bin <=0 || bin > fgH->GetXaxis()->GetNbins()) return; - Double_t posmin = fgH->GetXaxis()->GetBinLowEdge(bin); - Double_t posmax = fgH->GetXaxis()->GetBinUpEdge(bin); - Int_t nsel = (Int_t)fgT->GetSelectedRows(); - Int_t entry = 0; - Int_t nhits = 0; - Int_t nbytes = 0; - //search for all allocations in this bin and select last one only - for (Int_t i=0;iposmin) { - entry = i; - nbytes = (Int_t)fgV2[i]; - nhits++; - } - } - if (!nhits) return; - - Double_t time = 0.0001*fgV3[entry]; - TString ttip; - TMemStatShow::FillBTString(entry,0,ttip); - - if (selected) { - TString form1 = TString::Format(" Alloc(%d) at %lld of %d bytes, time=%gseconds\n\n",nhits,Long64_t(fgV1[entry]),nbytes,time); - fgTip1->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() )); - fgTip1->SetPosition(px+15, 100); - fgTip1->Reset(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Static: draw the tooltip showing the backtrace for the histogram of leaks - -void TMemStatShow::EventInfo2(Int_t event, Int_t px, Int_t , TObject *selected) -{ - if (!fgTip2) return; - fgTip2->Hide(); - if (event == kMouseLeave) - return; - Double_t xpx = fgC2->AbsPixeltoX(px); - Int_t bin = fgHleaks->GetXaxis()->FindBin(xpx); - if (bin <=0 || bin > fgHleaks->GetXaxis()->GetNbins()) return; - Int_t nbytes = (Int_t)fgHleaks->GetBinContent(bin); - Int_t entry = (Int_t)fgHentry->GetBinContent(bin); - Double_t time = 0.0001*fgV3[entry]; - TString ttip; - TMemStatShow::FillBTString(entry,0,ttip); - - if (selected) { - TString form1 = TString::Format(" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time); - fgTip2->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() )); - fgTip2->SetPosition(px+15, 100); - fgTip2->Reset(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// Static: fill btstring with the traceback corresponding to entry in T -/// btstring must be initialized in calling function - -void TMemStatShow::FillBTString(Int_t entry,Int_t mode,TString &btstring) -{ - Int_t btid = (Int_t)fgV4[entry]; - TH1I *hbtids = (TH1I*)fgT->GetUserInfo()->FindObject("btids"); - if (!hbtids) return; - if (!fgBtidlist) fgBtidlist = (TObjArray*)fgT->GetUserInfo()->FindObject("FAddrsList"); - if (!fgBtidlist) fgBtidlist = (TObjArray*)gFile->Get("FAddrsList"); //old memstat files - if (!fgBtidlist) return; - Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1); - for (Int_t i=0;iGetBinContent(btid+i); - TNamed *nm = (TNamed*)fgBtidlist->At(j); - if (nm==0) break; - char *title = (char*)nm->GetTitle(); - Int_t nch = strlen(title); - if (nch < 10) continue; - if (strstr(title,"malloc")) continue; - if (strstr(title,"memstat")) continue; - if (strstr(title,"TMemStatHook")) continue; - char *bar = strchr(title+5,'|'); - if (!bar) bar = title; - - if (strstr(bar,"operator new")) continue; - if (strstr(bar,"libMemStat")) continue; - if (strstr(bar,"G__Exception")) continue; - if (mode) { - btstring += TString::Format("%s ",bar); - if (btstring.Length() > 80) return; - } else { - btstring += TString::Format("%2d %s\n",i,bar+1); - } - } -} diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index dd198a798cfaf..857b433ca0afc 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -306,7 +306,6 @@ set(extra_veto rootlogon.C # Helper macro rootlogoff.C # Helper macro legacy/rootmarks.C # Instrumentation. Not a standalone tutorial - legacy/memstat/memstatExample.C # Instrumentation. Not a standalone tutorial multicore/mp_H1_lambdas.C # not a tutorial; used by mp104_processH1.C et al. html/*.C net/*.C diff --git a/tutorials/legacy/memstat/index.md b/tutorials/legacy/memstat/index.md deleted file mode 100644 index 8fe5c38172702..0000000000000 --- a/tutorials/legacy/memstat/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_memstat TMemStat tutorials -\ingroup tutorial_legacy -\brief Examples showing the TMemStat class. \ No newline at end of file diff --git a/tutorials/legacy/memstat/memstatExample.C b/tutorials/legacy/memstat/memstatExample.C deleted file mode 100644 index 6a2e6f5e77998..0000000000000 --- a/tutorials/legacy/memstat/memstatExample.C +++ /dev/null @@ -1,366 +0,0 @@ -/// \file -/// \ingroup tutorial_heritage -/// Script post-processing the file generated by TMemStat (default memstat.root) -/// -/// To use the class TMemStat, add the following statement at the beginning -/// of your script or program -/// -/// ~~~ {.cpp} -/// TMemStat mm("gnubuiltin"); -/// ~~~ -/// -/// or in an interactive session do something like: -/// -/// ~~~ {.cpp} -/// root > TMemStat mm("gnubuiltin"); -/// root > .x somescript.C -/// root > .q -/// ~~~ -/// -/// TMemStat records all the calls to malloc and free and write a TTree -/// with the position where the memory is allocated/freed , as well as -/// the number of bytes. -/// -/// This script creates 2 canvases. -/// -/// - In canvas1 it displays a dynamic histogram showing for pages (10 kbytes by default) -/// the percentage of the page used. -/// A summary pave shows the total memory still in use when the TMemStat object -/// goes out of scope and the average occupancy of the pages. -/// The average occupancy gives a good indication of the memory fragmentation. -/// -/// - In canvas2 it displays the histogram of memory leaks in decreasing order. -/// when moving the mouse on this canvas, a tooltip shows the backtrace for the leak -/// in the bin below the mouse. -/// -/// The script can be executed simply as -/// -/// ~~~ {.cpp} -/// root > .x memstat.C (or via ACLIC .x memstat.C+ ) -/// ~~~ -/// -/// or specifying arguments -/// -/// ~~~ {.cpp} -/// root > .x memstat.C+(0.01,"mydir/mymemstat.root"); -/// ~~~ -/// -/// The first argument to the script is the percentage of the time of the original job -/// that produced the file after which the display is updated. By default update=0.01, -/// ie 100 time intervals will be shown. -/// The second argument is the input file name (result of TMemStat). -/// If this argument is omitted, the script will take the most recent file -/// generated by TMemStat. -/// -/// \macro_image -/// \macro_output -/// \macro_code -/// -/// \author Rene Brun 7 July 2010 - -#include "TMath.h" -#include "TFile.h" -#include "TTree.h" -#include "TCanvas.h" -#include "TStyle.h" -#include "TH1.h" -#include "TPaveText.h" -#include "TPaveLabel.h" -#include "TSystem.h" -#include "TGClient.h" -#include "TGToolTip.h" -#include "TRootCanvas.h" - -TFile *f; -TTree *T; -TH1D *h; -TH1D *halloc, *hfree; -TH1I *hleaks, *hentry; -TGToolTip *gTip = 0; -TObjArray *btidlist=0; -Double_t *V1, *V2, *V3, *V4; - -void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected); - -void memstatExample(double update=0.01, const char* fname="*") { - // Open the memstat data file, then call TTree::Draw to precompute - // the arrays of positions and nbytes per entry. - // update is the time interval in the data file in seconds after which - // the display is updated. For example is the job producing the memstat.root file - // took 100s to execute, an update of 0.1s will generate 1000 time views of - // the memory use. - // if fname=="*" (default), the most recent file memstat*.root will be taken. - - TString s; - if (!fname || strlen(fname) <5 || strstr(fname,"*")) { - //take the most recent file memstat*.root - s = gSystem->GetFromPipe("ls -lrt memstat*.root"); - Int_t ns = s.Length(); - fname = strstr(s.Data()+ns-25,"memstat"); - } - printf("Analyzing file: %s\n",fname); - f = TFile::Open(fname); - if (!f) { - printf("Cannot open file %s\n",fname); - return; - } - T = (TTree*)f->Get("T"); - if (!T) { - printf("cannot find the TMemStat TTree named T in file %s\n",fname); - return; - } - if (update <= 0) { - printf("Illegal update value %g, changed to 0.01\n",update); - update = 0.01; - } - if (update < 0.001) printf("Warning update parameter is very small, processing may be slow\n"); - - - Long64_t nentries = T->GetEntries(); - T->SetEstimate(nentries+10); - Long64_t nsel = T->Draw("pos:nbytes:time:btid","","goff"); - - //now we compute the best binning for the histogram - Int_t nbytes; - Double_t pos; - V1 = T->GetV1(); - V2 = T->GetV2(); - V3 = T->GetV3(); - V4 = T->GetV4(); - Long64_t imean = (Long64_t)TMath::Mean(nsel,V1); - Long64_t irms = (Long64_t)TMath::RMS(nsel,V1); - //Long64_t bw = 10000; - Long64_t bw = 1000; - imean = imean - imean%bw; - irms = irms -irms%bw; - Int_t nbins = Int_t(4*irms/bw); - Long64_t ivmin = imean -bw*nbins/2; - Long64_t ivmax = ivmin+bw*nbins; - if (ivmax > 2000000000 && ivmin <2000000000) { - //the data set has been likely generated on a 32 bits machine - //we are mostly interested by the small allocations, so we select - //only values below 2 GBytes - printf("memory locations above 2GBytes will be ignored\n"); - nsel = T->Draw("pos:nbytes:time:btid","pos <2e9","goff"); - V1 = T->GetV1(); - V2 = T->GetV2(); - V3 = T->GetV3(); - V4 = T->GetV4(); - imean = (Long64_t)TMath::Mean(nsel,V1); - irms = (Long64_t)TMath::RMS(nsel,V1); - bw = 10000; - imean = imean - imean%bw; - irms = irms -irms%bw; - nbins = Int_t(4*irms/bw); - ivmin = imean -bw*nbins/2; - ivmax = ivmin+bw*nbins; - } - update *= 0.0001*V3[nsel-1]; //convert time per cent in seconds - Long64_t nvm = Long64_t(ivmax-ivmin+1); - Long64_t *nbold = new Long64_t[nvm]; - Int_t *ientry = new Int_t[nvm]; - memset(nbold,0,nvm*8); - Double_t dv = (ivmax-ivmin)/nbins; - h = new TH1D("h",Form("%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax); - TAxis *axis = h->GetXaxis(); - gStyle->SetOptStat("ie"); - h->SetFillColor(kRed); - h->SetMinimum(0); - h->SetMaximum(100); - halloc = new TH1D("halloc",Form("%s;pos;number of mallocs",fname),nbins,ivmin,ivmax); - hfree = new TH1D("hfree", Form("%s;pos;number of frees",fname),nbins,ivmin,ivmax); - //open a canvas and draw the empty histogram - TCanvas *c1 = new TCanvas("c1","c1",1200,600); - c1->SetFrameFillColor(kYellow-3); - c1->SetGridx(); - c1->SetGridy(); - h->Draw(); - //create a TPaveText to show the summary results - TPaveText *pvt = new TPaveText(.5,.9,.75,.99,"brNDC"); - pvt->Draw(); - //create a TPaveLabel to show the time - TPaveLabel *ptime = new TPaveLabel(.905,.7,.995,.76,"time","brNDC"); - ptime->SetFillColor(kYellow-3); - ptime->Draw(); - //draw producer identifier - TNamed *named = (TNamed*)T->GetUserInfo()->FindObject("SysInfo"); - TText tmachine; - tmachine.SetTextSize(0.02); - tmachine.SetNDC(); - if (named) tmachine.DrawText(0.01,0.01,named->GetTitle()); - - //start loop on selected rows - Int_t bin,nb=0,j; - Long64_t ipos; - Double_t dbin,rest,time; - Double_t updateLast = 0; - Int_t nleaks = 0; - Int_t i; - for (i=0;iFindBin(pos); - if (bin<1 || bin>nbins) continue; - dbin = axis->GetBinUpEdge(bin)-pos; - if (nbytes > 0) { - halloc->Fill(pos); - if (dbin > nbytes) dbin = nbytes; - //fill bytes in the first page - h->AddBinContent(bin,100*dbin/dv); - //fill bytes in full following pages - nb = Int_t((nbytes-dbin)/dv); - if (bin+nb >nbins) nb = nbins-bin; - for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100); - //fill the bytes remaining in last page - rest = nbytes-nb*dv-dbin; - if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv); - //we save nbytes at pos. This info will be used when we free this slot - if (nbold[ipos] > 0) printf("reallocating %d bytes (was %lld) at %lld, entry=%d\n",nbytes,nbold[ipos],ipos,i); - if (nbold[ipos] == 0) { - nleaks++; - //save the Tree entry number where we made this allocation - ientry[ipos] = i; - } - nbold[ipos] = nbytes; - } else { - hfree->Fill(pos); - nbytes = nbold[ipos]; - if (bin+nb >nbins) nb = nbins-bin; - nbold[ipos] = 0; nleaks--; - if (nbytes <= 0) continue; - //fill bytes free in the first page - if (dbin > nbytes) dbin = nbytes; - h->AddBinContent(bin,-100*dbin/dv); - //fill bytes free in full following pages - nb = Int_t((nbytes-dbin)/dv); - if (bin+nb >nbins) nb = nbins-bin; - for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100); - //fill the bytes free in in last page - rest = nbytes-nb*dv-dbin; - if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv); - - } - if (time -updateLast > update) { - //update canvas at regular intervals - updateLast = time; - h->SetEntries(i); - c1->Modified(); - pvt->GetListOfLines()->Delete(); - Double_t mbytes = 0; - Int_t nonEmpty = 0; - Double_t w; - for (Int_t k=1;kGetBinContent(k); - if (w > 0) { - nonEmpty++; - mbytes += 0.01*w*dv; - } - } - Double_t occupancy = mbytes/(nonEmpty*0.01*dv); - pvt->AddText(Form("memory used = %g Mbytes",mbytes*1e-6)); - pvt->AddText(Form("page occupancy = %f per cent",occupancy)); - pvt->AddText("(for non empty pages only)"); - ptime->SetLabel(Form("%g sec",time)); - - c1->Update(); - gSystem->ProcessEvents(); - } - } - h->SetEntries(nsel); - Int_t nlmax = nleaks; - nleaks += 1000; - Int_t *lindex = new Int_t[nleaks]; - Int_t *entry = new Int_t[nleaks]; - Int_t *ileaks = new Int_t[nleaks]; - - nleaks =0; - for (Int_t ii=0;ii 0) { - ileaks[nleaks] = (Int_t)nbold[ii]; - entry[nleaks] = ientry[ii]; - nleaks++; - if (nleaks > nlmax) break; - } - } - - TMath::Sort(nleaks,ileaks,lindex); - hentry = new TH1I("hentry","leak entry index",nleaks,0,nleaks); - hleaks = new TH1I("hleaks","leaks;leak number;nbytes in leak",nleaks,0,nleaks); - for (Int_t k=0;kSetBinContent(k+1,i); - hleaks->SetBinContent(k+1,ileaks[kk]); - } - hentry->SetEntries(nleaks); - hleaks->SetEntries(nleaks); - - //open a second canvas and draw the histogram with leaks in decreasing order - TCanvas *c2 = new TCanvas("c2","c2",1200,600); - c2->SetFrameFillColor(kCyan-6); - c2->SetGridx(); - c2->SetGridy(); - c2->SetLogy(); - hleaks->SetFillColor(kRed-3); - if (nleaks > 1000) hleaks->GetXaxis()->SetRange(1,1000); - hleaks->Draw(); - //draw producer identifier - if (named) tmachine.DrawText(0.01,0.01,named->GetTitle()); - - //construct the tooltip - TRootCanvas *rc = (TRootCanvas *)c2->GetCanvasImp(); - TGMainFrame *frm = dynamic_cast(rc); - // create the tooltip with a timeout of 250 ms - if (!gTip) gTip = new TGToolTip(gClient->GetDefaultRoot(), frm, "", 250); - c2->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)", - 0, 0, "EventInfo(Int_t, Int_t, Int_t, TObject*)"); - -} - -//______________________________________________________________________ -void EventInfo(Int_t event, Int_t px, Int_t , TObject *selected) -{ - //draw the tooltip showing the backtrace for the bin at px - if (!gTip) return; - gTip->Hide(); - if (event == kMouseLeave) - return; - Double_t xpx = gPad->AbsPixeltoX(px); - Int_t bin = hleaks->GetXaxis()->FindBin(xpx); - if (bin <=0 || bin > hleaks->GetXaxis()->GetNbins()) return; - Int_t nbytes = (Int_t)hleaks->GetBinContent(bin); - Int_t entry = (Int_t)hentry->GetBinContent(bin); - Int_t btid = (Int_t)V4[entry]; - Double_t time = 0.0001*V3[entry]; - TH1I *hbtids = (TH1I*)T->GetUserInfo()->FindObject("btids"); - if (!hbtids) return; - if (!btidlist) btidlist = (TObjArray*)T->GetUserInfo()->FindObject("FAddrsList"); - if (!btidlist) btidlist = (TObjArray*)f->Get("FAddrsList"); //old memstat files - if (!btidlist) return; - Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1); - TString ttip; - for (Int_t i=0;iGetBinContent(btid+i); - TNamed *nm = (TNamed*)btidlist->At(j); - if (nm==0) break; - char *title = (char*)nm->GetTitle(); - Int_t nch = strlen(title); - if (nch < 20) continue; - if (nch > 100) title[100] =0; - const char *bar = strstr(title,"| "); - if (!bar) continue; - if (strstr(bar,"operator new")) continue; - if (strstr(bar,"libMemStat")) continue; - if (strstr(bar,"G__Exception")) continue; - ttip += TString::Format("%2d %s\n",i,bar+1); - } - - if (selected) { - TString form1 = TString::Format(" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time); - gTip->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() )); - gTip->SetPosition(px+15, 100); - gTip->Reset(); - } -} From 4116fca6f876c0a68f081d02aa0d7a37e47c3eab Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 15 Jun 2021 18:48:01 +0200 Subject: [PATCH 204/309] [RF] Avoid using RooCmdArg::_nextSharedData directly in header file Calling `RooCmdArg::take` in `RooGlobalFunc.h` header can cause linker errors, because it accesses a static data member. That's unsupported across DLL boundaries on Windows. This should fix the Windows 10 test errors that appeard after #8416. --- roofit/roofitcore/inc/RooCmdArg.h | 5 +++-- roofit/roofitcore/src/RooCmdArg.cxx | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/roofit/roofitcore/inc/RooCmdArg.h b/roofit/roofitcore/inc/RooCmdArg.h index 64b91be1fee2b..1497a191d1f52 100644 --- a/roofit/roofitcore/inc/RooCmdArg.h +++ b/roofit/roofitcore/inc/RooCmdArg.h @@ -100,8 +100,8 @@ class RooCmdArg : public TNamed { template static T const& take(T && obj) { - _nextSharedData.emplace_back(new T{std::move(obj)}); - return static_cast(*_nextSharedData.back()); + getNextSharedData().emplace_back(new T{std::move(obj)}); + return static_cast(*getNextSharedData().back()); } protected: @@ -128,6 +128,7 @@ class RooCmdArg : public TNamed { // the next RooCmdArg created will take ownership of this data static DataCollection _nextSharedData; + static DataCollection &getNextSharedData(); ClassDef(RooCmdArg,2) // Generic named argument container }; diff --git a/roofit/roofitcore/src/RooCmdArg.cxx b/roofit/roofitcore/src/RooCmdArg.cxx index 6e77c1d2c1f36..48243d3a9f15f 100644 --- a/roofit/roofitcore/src/RooCmdArg.cxx +++ b/roofit/roofitcore/src/RooCmdArg.cxx @@ -232,3 +232,5 @@ void RooCmdArg::Print(const char*) const { } RooCmdArg::DataCollection RooCmdArg::_nextSharedData = RooCmdArg::DataCollection{}; + +RooCmdArg::DataCollection &RooCmdArg::getNextSharedData() { return _nextSharedData; } From f3804af4b55f4815569a31f7807aa9c7d0f4530f Mon Sep 17 00:00:00 2001 From: moneta Date: Wed, 26 May 2021 17:14:53 +0200 Subject: [PATCH 205/309] Fix bug in using the pdf derivative in TUnuranContDist This fixes the ROOT issue #8196 --- math/unuran/src/TUnuranContDist.cxx | 41 +++++++++++++---------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/math/unuran/src/TUnuranContDist.cxx b/math/unuran/src/TUnuranContDist.cxx index 474976cc19f5a..f48b34bed6ef2 100644 --- a/math/unuran/src/TUnuranContDist.cxx +++ b/math/unuran/src/TUnuranContDist.cxx @@ -25,7 +25,7 @@ ClassImp(TUnuranContDist); TUnuranContDist::TUnuranContDist (const ROOT::Math::IGenFunction & pdf, const ROOT::Math::IGenFunction * deriv, bool isLogPdf, bool copyFunc ) : fPdf(&pdf), fDPdf(deriv), - fCdf(0), + fCdf(nullptr), fXmin(1.), fXmax(-1.), fMode(0), @@ -40,15 +40,15 @@ TUnuranContDist::TUnuranContDist (const ROOT::Math::IGenFunction & pdf, const RO // manage the functions and clone them if flag copyFunc is true if (fOwnFunc) { fPdf = fPdf->Clone(); - if (fDPdf) fDPdf->Clone(); + if (fDPdf) fDPdf = fDPdf->Clone(); } } TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, bool isLogPdf ) : - fPdf( (pdf) ? new ROOT::Math::WrappedTF1 ( *pdf) : 0 ), - fDPdf( (deriv) ? new ROOT::Math::WrappedTF1 ( *deriv) : 0 ), - fCdf(0), + fPdf( (pdf) ? new ROOT::Math::WrappedTF1 ( *pdf) : nullptr ), + fDPdf( (deriv) ? new ROOT::Math::WrappedTF1 ( *deriv) : nullptr ), + fCdf(nullptr), fXmin(1.), fXmax(-1.), fMode(0), @@ -66,9 +66,9 @@ TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, bool isLogPdf ) : TUnuranContDist::TUnuranContDist(const TUnuranContDist & rhs) : TUnuranBaseDist(), - fPdf(0), - fDPdf(0), - fCdf(0) + fPdf(nullptr), + fDPdf(nullptr), + fCdf(nullptr) { // Implementation of copy constructor operator=(rhs); @@ -96,9 +96,9 @@ TUnuranContDist & TUnuranContDist::operator = (const TUnuranContDist &rhs) if (fPdf) delete fPdf; if (fDPdf) delete fDPdf; if (fCdf) delete fCdf; - fPdf = (rhs.fPdf) ? rhs.fPdf->Clone() : 0; - fDPdf = (rhs.fDPdf) ? rhs.fDPdf->Clone() : 0; - fCdf = (rhs.fCdf) ? rhs.fCdf->Clone() : 0; + fPdf = (rhs.fPdf) ? rhs.fPdf->Clone() : nullptr; + fDPdf = (rhs.fDPdf) ? rhs.fDPdf->Clone() : nullptr; + fCdf = (rhs.fCdf) ? rhs.fCdf->Clone() : nullptr; } return *this; @@ -123,29 +123,25 @@ void TUnuranContDist::SetCdf(TF1 * cdf) { // set cumulative distribution function from a TF1 if (!fOwnFunc) { // need to manage all functions now - assert (fPdf != 0); - fPdf = fPdf->Clone(); + if (fPdf) fPdf = fPdf->Clone(); if (fDPdf) fDPdf->Clone(); } else - if (fOwnFunc && fCdf) delete fCdf; + if (fCdf) delete fCdf; - fCdf = (cdf) ? new ROOT::Math::WrappedTF1 ( *cdf) : 0; + fCdf = (cdf) ? new ROOT::Math::WrappedTF1 ( *cdf) : nullptr; fOwnFunc = true; } double TUnuranContDist::Pdf ( double x) const { - // evaluate the pdf of the distribution - assert(fPdf != 0); - //fX[0] = x; - return (*fPdf)(x); + // evaluate the pdf of the distribution. Return NaN if pdf is not available + return (fPdf) ? (*fPdf)(x) : TMath::QuietNaN(); } double TUnuranContDist::DPdf( double x) const { // evaluate the derivative of the pdf // if derivative function is not given is evaluated numerically - if (fDPdf != 0) { - //fX[0] = x; + if (fDPdf) { return (*fDPdf)(x); } // do numerical derivation using numerical derivation @@ -158,8 +154,7 @@ double TUnuranContDist::DPdf( double x) const { double TUnuranContDist::Cdf(double x) const { // evaluate the integral (cdf) on the domain - if (fCdf != 0) { - // fX[0] = x; + if (fCdf) { return (*fCdf)(x); } // do numerical integration From a3a85037e6775bfbadaee2c5c20e7e3af5363e4f Mon Sep 17 00:00:00 2001 From: moneta Date: Fri, 28 May 2021 09:53:21 +0200 Subject: [PATCH 206/309] add new constructor for TUnuranContDist passing pdf, dpdf, cdf --- math/unuran/inc/TUnuranContDist.h | 16 +++++++++---- math/unuran/src/TUnuranContDist.cxx | 35 ++++++++++++++++------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/math/unuran/inc/TUnuranContDist.h b/math/unuran/inc/TUnuranContDist.h index 1fff870c5cf42..ae1d29c885fa1 100644 --- a/math/unuran/inc/TUnuranContDist.h +++ b/math/unuran/inc/TUnuranContDist.h @@ -58,16 +58,24 @@ class TUnuranContDist : public TUnuranBaseDist { cdf explicity defined. UnuRan, if needed, can compute some of this quantities, but the user if they know them can set them in order to speed up the algorithm. For example in case of the Cdf, if the user has not set it, a numerical integration algorithm is used to estimate the Cdf from the Pdf. - In case an algorithm requires only the Cdf (no Pdf), an empty distribution can be constructed and then the user must - set afterwards the Cdf. */ explicit TUnuranContDist (TF1 * pdf = 0, TF1 * deriv = 0, bool isLogPdf = false ); - + /** + Constructor as above but with the possibility to pass also the Cdf. + In case an algorithm requiring only the Cdf (no Pdf), one can use this contructor passing nullptr for Pdf and derivative of + the Pdf + */ + TUnuranContDist (TF1 * pdf, TF1 * deriv, TF1 * cdf, bool isLogPdf = false ); /** Constructor as before but from a generic function object interface for one-dim functions */ explicit TUnuranContDist (const ROOT::Math::IGenFunction & pdf, const ROOT::Math::IGenFunction * dpdf = 0, bool isLogPdf = false, bool copyFunc = false); - + /** + Constructor as before from pointers to generic function object interface for one-dim functions + which can be use for all algorithms including those requiring only the Cdf + */ + TUnuranContDist (const ROOT::Math::IGenFunction * pdf, const ROOT::Math::IGenFunction * dpdf, + const ROOT::Math::IGenFunction * cdf, bool isLogPdf = false, bool copyFunc = false ); /** Destructor diff --git a/math/unuran/src/TUnuranContDist.cxx b/math/unuran/src/TUnuranContDist.cxx index f48b34bed6ef2..3b734d18e4f7c 100644 --- a/math/unuran/src/TUnuranContDist.cxx +++ b/math/unuran/src/TUnuranContDist.cxx @@ -22,33 +22,30 @@ ClassImp(TUnuranContDist); -TUnuranContDist::TUnuranContDist (const ROOT::Math::IGenFunction & pdf, const ROOT::Math::IGenFunction * deriv, bool isLogPdf, bool copyFunc ) : - fPdf(&pdf), - fDPdf(deriv), - fCdf(nullptr), - fXmin(1.), - fXmax(-1.), - fMode(0), - fArea(0), - fIsLogPdf(isLogPdf), - fHasDomain(0), - fHasMode(0), - fHasArea(0), - fOwnFunc(copyFunc) +TUnuranContDist::TUnuranContDist(const ROOT::Math::IGenFunction *pdf, const ROOT::Math::IGenFunction *dpdf, + const ROOT::Math::IGenFunction *cdf, bool isLogPdf, bool copyFunc) + : fPdf(pdf), fDPdf(dpdf), fCdf(cdf), fXmin(1.), fXmax(-1.), fMode(0), fArea(0), fIsLogPdf(isLogPdf), fHasDomain(0), + fHasMode(0), fHasArea(0), fOwnFunc(copyFunc) { // Constructor from generic function interfaces // manage the functions and clone them if flag copyFunc is true if (fOwnFunc) { fPdf = fPdf->Clone(); - if (fDPdf) fDPdf = fDPdf->Clone(); + if (fDPdf) + fDPdf = fDPdf->Clone(); + if (fCdf) + fCdf = fCdf->Clone(); } } +TUnuranContDist::TUnuranContDist (const ROOT::Math::IGenFunction & pdf, const ROOT::Math::IGenFunction * deriv, bool isLogPdf, bool copyFunc ) : + TUnuranContDist(&pdf,deriv, nullptr, isLogPdf, copyFunc) +{} -TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, bool isLogPdf ) : +TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, TF1 * cdf, bool isLogPdf ) : fPdf( (pdf) ? new ROOT::Math::WrappedTF1 ( *pdf) : nullptr ), fDPdf( (deriv) ? new ROOT::Math::WrappedTF1 ( *deriv) : nullptr ), - fCdf(nullptr), + fCdf( (cdf) ? new ROOT::Math::WrappedTF1 ( *cdf) : nullptr), fXmin(1.), fXmax(-1.), fMode(0), @@ -63,6 +60,9 @@ TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, bool isLogPdf ) : // function pointers are managed by class } +TUnuranContDist::TUnuranContDist (TF1 * pdf, TF1 * deriv, bool isLogPdf ) : + TUnuranContDist(pdf,deriv, nullptr, isLogPdf) + {} TUnuranContDist::TUnuranContDist(const TUnuranContDist & rhs) : TUnuranBaseDist(), @@ -141,9 +141,11 @@ double TUnuranContDist::Pdf ( double x) const { double TUnuranContDist::DPdf( double x) const { // evaluate the derivative of the pdf // if derivative function is not given is evaluated numerically + // in case a pdf is available, otherwise a NaN is returned if (fDPdf) { return (*fDPdf)(x); } + if (!fPdf) return TMath::QuietNaN(); // do numerical derivation using numerical derivation ROOT::Math::RichardsonDerivator rd; static double gEps = 0.001; @@ -158,6 +160,7 @@ double TUnuranContDist::Cdf(double x) const { return (*fCdf)(x); } // do numerical integration + if (!fPdf) return TMath::QuietNaN(); ROOT::Math::Integrator ig; if (fXmin > fXmax) return ig.Integral( *fPdf ); else From 6ddcc0d17cd6d5fe0dc11b5ddca3989fc1fda159 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 16 Jun 2021 08:54:43 +0200 Subject: [PATCH 207/309] Fix drawing in df104 tutorial 1. Disable automatic drawing when fitting 2. Draw data histogram only when all settings are done 3. Use TH1I instead of TF1 for axis drawing in lower pad Created canvas can be stored and read back properly from ROOT file --- .../dataframe/df104_HiggsToTwoPhotons.py | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tutorials/dataframe/df104_HiggsToTwoPhotons.py b/tutorials/dataframe/df104_HiggsToTwoPhotons.py index b836e4a41572b..a8d0e57eabd7a 100644 --- a/tutorials/dataframe/df104_HiggsToTwoPhotons.py +++ b/tutorials/dataframe/df104_HiggsToTwoPhotons.py @@ -113,7 +113,6 @@ lower_pad.Draw() # Fit signal + background model to data -upper_pad.cd() fit = ROOT.TF1("fit", "([0]+[1]*x+[2]*x^2+[3]*x^3)+[4]*exp(-0.5*((x-[5])/[6])^2)", 105, 160) fit.FixParameter(5, 125.0) fit.FixParameter(4, 119.1) @@ -121,30 +120,33 @@ fit.SetLineColor(2) fit.SetLineStyle(1) fit.SetLineWidth(2) -data.Fit("fit", "", "E SAME", 105, 160) -fit.Draw("SAME") - -# Draw background -bkg = ROOT.TF1("bkg", "([0]+[1]*x+[2]*x^2+[3]*x^3)", 105, 160) -for i in range(4): - bkg.SetParameter(i, fit.GetParameter(i)) -bkg.SetLineColor(4) -bkg.SetLineStyle(2) -bkg.SetLineWidth(2) -bkg.Draw("SAME") +data.Fit("fit", "0", "", 105, 160) # Draw data +upper_pad.cd() data.SetMarkerStyle(20) data.SetMarkerSize(1.2) data.SetLineWidth(2) data.SetLineColor(ROOT.kBlack) -data.Draw("E SAME") data.SetMinimum(1e-3) data.SetMaximum(8e3) data.GetYaxis().SetLabelSize(0.045) data.GetYaxis().SetTitleSize(0.05) data.SetStats(0) data.SetTitle("") +data.Draw("E") + +# Draw fit +fit.Draw("SAME") + +# Draw background +bkg = ROOT.TF1("bkg", "([0]+[1]*x+[2]*x^2+[3]*x^3)", 105, 160) +for i in range(4): + bkg.SetParameter(i, fit.GetParameter(i)) +bkg.SetLineColor(4) +bkg.SetLineStyle(2) +bkg.SetLineWidth(2) +bkg.Draw("SAME") # Scale simulated events with luminosity * cross-section / sum of weights # and merge to single Higgs signal @@ -158,7 +160,7 @@ # Draw ratio lower_pad.cd() -ratiobkg = ROOT.TF1("zero", "0", 105, 160) +ratiobkg = ROOT.TH1I("zero", "", 100, 105, 160) ratiobkg.SetLineColor(4) ratiobkg.SetLineStyle(2) ratiobkg.SetLineWidth(2) @@ -175,7 +177,7 @@ ratiobkg.GetYaxis().SetNdivisions(503, False) ratiobkg.GetYaxis().ChangeLabel(-1, -1, 0) ratiobkg.GetXaxis().SetTitle("m_{#gamma#gamma} [GeV]") -ratiobkg.Draw() +ratiobkg.Draw("AXIS") ratiosig = ROOT.TH1F("ratiosig", "ratiosig", 5500, 105, 160) ratiosig.Eval(fit) @@ -187,9 +189,9 @@ ratiodata = data.Clone() ratiodata.Add(bkg, -1) -ratiodata.Draw("E SAME") for i in range(1, data.GetNbinsX()): ratiodata.SetBinError(i, data.GetBinError(i)) +ratiodata.Draw("E SAME") # Add legend upper_pad.cd() @@ -203,7 +205,7 @@ legend.AddEntry(bkg, "Background", "l") legend.AddEntry(fit, "Signal + Bkg.", "l") legend.AddEntry(higgs, "Signal", "l") -legend.Draw("SAME") +legend.Draw() # Add ATLAS label text = ROOT.TLatex() From 1d919775d3d9224f2e4dc16cecc6fd9bf80d9780 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Tue, 15 Jun 2021 17:09:39 +0200 Subject: [PATCH 208/309] [RF] Fix copy-paste error in RooAddModel constructor and modernization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * replace wrong `dynamic_cast` with `dynamic_cast` (presumably a copy-paste error) * use `TIter` and range-based loop instead of `TIterator*` * avoid C-style casts * replace `assert(0)` with `std::runtime_error`, as asserts only work in debug buils * replace one orrurence of `coef->GetName()` with `pdf->GetName()`, which was probably also a copy-paste error This fixes the following warning in gcc11: ``` ../roofit/roofitcore/src/RooAddModel.cxx: In constructor ‘RooAddModel::RooAddModel(const char*, const char*, const RooArgList&, const RooArgList&, Bool_t)’: ../roofit/roofitcore/src/RooAddModel.cxx:125:106: warning: ‘this’ pointer is null [-Wnonnull] 125 | coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() << ") pdf " << pdf->GetName() << " is not of type RooAbsPdf, ignored" << endl ; ``` --- roofit/roofitcore/src/RooAddModel.cxx | 46 ++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/roofit/roofitcore/src/RooAddModel.cxx b/roofit/roofitcore/src/RooAddModel.cxx index 40aee617b813d..375818147ff0a 100644 --- a/roofit/roofitcore/src/RooAddModel.cxx +++ b/roofit/roofitcore/src/RooAddModel.cxx @@ -86,7 +86,7 @@ RooAddModel::RooAddModel() : /// All PDFs must inherit from RooAbsPdf. All coefficients must inherit from RooAbsReal. RooAddModel::RooAddModel(const char *name, const char *title, const RooArgList& inPdfList, const RooArgList& inCoefList, Bool_t ownPdfList) : - RooResolutionModel(name,title,((RooResolutionModel*)inPdfList.at(0))->convVar()), + RooResolutionModel(name,title,(static_cast(inPdfList.at(0)))->convVar()), _refCoefNorm("!refCoefNorm","Reference coefficient normalization set",this,kFALSE,kFALSE), _refCoefRangeName(0), _projectCoefs(kFALSE), @@ -99,29 +99,32 @@ RooAddModel::RooAddModel(const char *name, const char *title, const RooArgList& _allExtendable(kFALSE) { if (inPdfList.getSize()>inCoefList.getSize()+1) { - coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() - << ") number of pdfs and coefficients inconsistent, must have Npdf=Ncoef or Npdf=Ncoef+1" << endl ; - assert(0) ; + std::stringstream msgSs; + msgSs << "RooAddModel::RooAddModel(" << GetName() + << ") number of pdfs and coefficients inconsistent, must have Npdf=Ncoef or Npdf=Ncoef+1"; + const std::string msgStr = msgSs.str(); + coutE(InputArguments) << msgStr << endl; + throw std::runtime_error(msgStr); } // Constructor with N PDFs and N or N-1 coefs - TIterator* pdfIter = inPdfList.createIterator() ; - TIterator* coefIter = inCoefList.createIterator() ; - RooAbsPdf* pdf ; - RooAbsReal* coef ; + auto pdfIter = inPdfList.fwdIterator() ; - while((coef = (RooAbsPdf*)coefIter->Next())) { - pdf = (RooAbsPdf*) pdfIter->Next() ; + for(auto const& coef : inCoefList) { + auto pdf = pdfIter.next() ; if (!pdf) { - coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() - << ") number of pdfs and coefficients inconsistent, must have Npdf=Ncoef or Npdf=Ncoef+1" << endl ; - assert(0) ; + std::stringstream msgSs; + msgSs << "RooAddModel::RooAddModel(" << GetName() + << ") number of pdfs and coefficients inconsistent, must have Npdf=Ncoef or Npdf=Ncoef+1"; + const std::string msgStr = msgSs.str(); + coutE(InputArguments) << msgStr << endl; + throw std::runtime_error(msgStr); } if (!dynamic_cast(coef)) { coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() << ") coefficient " << coef->GetName() << " is not of type RooAbsReal, ignored" << endl ; continue ; } - if (!dynamic_cast(pdf)) { + if (!dynamic_cast(pdf)) { coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() << ") pdf " << pdf->GetName() << " is not of type RooAbsPdf, ignored" << endl ; continue ; } @@ -129,20 +132,19 @@ RooAddModel::RooAddModel(const char *name, const char *title, const RooArgList& _coefList.add(*coef) ; } - pdf = (RooAbsPdf*) pdfIter->Next() ; - if (pdf) { - if (!dynamic_cast(pdf)) { - coutE(InputArguments) << "RooAddModel::RooAddModel(" << GetName() << ") last pdf " << coef->GetName() << " is not of type RooAbsPdf, fatal error" << endl ; - assert(0) ; + if (auto pdf = pdfIter.next()) { + if (!dynamic_cast(pdf)) { + std::stringstream msgSs; + msgSs << "RooAddModel::RooAddModel(" << GetName() << ") last pdf " << pdf->GetName() << " is not of type RooAbsPdf, fatal error"; + const std::string msgStr = msgSs.str(); + coutE(InputArguments) << msgStr << endl; + throw std::runtime_error(msgStr); } _pdfList.add(*pdf) ; } else { _haveLastCoef=kTRUE ; } - delete pdfIter ; - delete coefIter ; - _coefCache = new Double_t[_pdfList.getSize()] ; _coefErrCount = _errorCount ; From 923562b78bf0c9c6b9c820decbda1a14329e5744 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 16 Jun 2021 10:11:28 -0500 Subject: [PATCH 209/309] correct syntax for preloading ACLiC library --- test/dt_wrap.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dt_wrap.C b/test/dt_wrap.C index 2ab49748af0d1..d8f2fc8add975 100644 --- a/test/dt_wrap.C +++ b/test/dt_wrap.C @@ -1,4 +1,4 @@ -R__LOAD_LIBRARY(dt_RunDrawTest.C+) +#include "dt_RunDrawTest.C+" void dt_wrap(const char* from, Int_t mode = 0, Int_t verboseLevel = 0) { // gROOT->ProcessLine(".L dt_RunDrawTest.C+"); From 1b7fd5a4f415b6e00e329b6ad0da9ed86fac4302 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Sat, 12 Jun 2021 17:30:58 +0200 Subject: [PATCH 210/309] [ntuple,daos] libdaos_mock: provide implementation for `daos_oclass_{name2id,id2name}` Provides mocks for the oclass name to id conversion functions. --- tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h | 3 +++ .../v7/src/libdaos_mock/libdaos_mock.cxx | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h b/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h index 8d645547a42ef..6a85dae96ba6f 100644 --- a/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h +++ b/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h @@ -345,6 +345,9 @@ enum { typedef uint16_t daos_oclass_id_t; typedef uint16_t daos_ofeat_t; +int daos_oclass_name2id(const char *name); +int daos_oclass_id2name(daos_oclass_id_t oc_id, char *name); + //////////////////////////////////////////////////////////////////////////////// daos_obj.h diff --git a/tree/ntuple/v7/src/libdaos_mock/libdaos_mock.cxx b/tree/ntuple/v7/src/libdaos_mock/libdaos_mock.cxx index 52eb6b7e862d5..381f192cde2af 100644 --- a/tree/ntuple/v7/src/libdaos_mock/libdaos_mock.cxx +++ b/tree/ntuple/v7/src/libdaos_mock/libdaos_mock.cxx @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -242,6 +243,26 @@ const char *d_errstr(int rc) return rc ? "DER_INVAL" : "Success"; } +int daos_oclass_name2id(const char *name) +{ + if (strcmp(name, "SX") == 0) return OC_SX; + if (strcmp(name, "RP_XSF") == 0) return OC_RP_XSF; + return OC_UNKNOWN; +} + +int daos_oclass_id2name(daos_oclass_id_t oc_id, char *name) +{ + switch (oc_id) { + case OC_SX: + strcpy(name, "SX"); // NOLINT + return 0; + case OC_RP_XSF: + strcpy(name, "RP_XSF"); // NOLINT + return 0; + } + return -1; +} + //////////////////////////////////////////////////////////////////////////////// From 38a4c5d57cf3cd2b9894950313f110c493624809 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Sat, 12 Jun 2021 17:30:58 +0200 Subject: [PATCH 211/309] [ntuple] Remove unused `OC_xxx` constants from libdaos_mock/daos.h libdaos_mock/daos.h shall be kept minimal, i.e. it should only contain the declarations required by the unit tests. --- tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h | 212 -------------------- 1 file changed, 212 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h b/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h index 6a85dae96ba6f..f4216a98ad6f1 100644 --- a/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h +++ b/tree/ntuple/v7/inc/ROOT/libdaos_mock/daos.h @@ -105,33 +105,10 @@ int daos_event_fini(daos_event_t *ev); /** Predefined object classes */ enum { OC_UNKNOWN = 0, - OC_BACK_COMPAT = 50, - OC_TINY, - OC_SMALL, - OC_LARGE, - OC_MAX, - - /** object classes protected by replication */ - OC_RP_TINY = 60, - OC_RP_SMALL, - OC_RP_LARGE, - OC_RP_MAX, - - /** Object classes protected by replication which supports Scalable Fetch (SF) */ - OC_RP_SF_TINY = 70, - OC_RP_SF_SMALL, - OC_RP_SF_LARGE, - OC_RP_SF_MAX, /** Replicated object class which is extremely scalable for fetch. */ OC_RP_XSF = 80, - /** Object classes protected by erasure code */ - OC_EC_TINY = 100, - OC_EC_SMALL, - OC_EC_LARGE, - OC_EC_MAX, - /** Object classes with explicit layout */ OC_S1 = 200, OC_S2, @@ -149,195 +126,6 @@ enum { OC_S8K, OC_SX, - /** Replicated object with explicit layout */ - /** 2-way replicated object classes */ - OC_RP_2G1 = 220, - OC_RP_2G2, - OC_RP_2G4, - OC_RP_2G8, - OC_RP_2G16, - OC_RP_2G32, - OC_RP_2G64, - OC_RP_2G128, - OC_RP_2G256, - OC_RP_2G512, - OC_RP_2G1K, - OC_RP_2G2K, - OC_RP_2G4K, - OC_RP_2G8K, - OC_RP_2GX, - - /** 3-way replicated object classes */ - OC_RP_3G1 = 240, - OC_RP_3G2, - OC_RP_3G4, - OC_RP_3G8, - OC_RP_3G16, - OC_RP_3G32, - OC_RP_3G64, - OC_RP_3G128, - OC_RP_3G256, - OC_RP_3G512, - OC_RP_3G1K, - OC_RP_3G2K, - OC_RP_3G4K, - OC_RP_3G8K, - OC_RP_3GX, - - /** 8-way replicated object classes */ - OC_RP_8G1 = 260, - OC_RP_8G2, - OC_RP_8G4, - OC_RP_8G8, - OC_RP_8G16, - OC_RP_8G32, - OC_RP_8G64, - OC_RP_8G128, - OC_RP_8G256, - OC_RP_8G512, - OC_RP_8G1K, - OC_RP_8G2K, - OC_RP_8G4K, - OC_RP_8G8K, - OC_RP_8GX, - - /** Erasure coded object with explicit layout */ - /** EC 2+1 object classes */ - OC_EC_2P1G1 = 280, - OC_EC_2P1G2, - OC_EC_2P1G4, - OC_EC_2P1G8, - OC_EC_2P1G16, - OC_EC_2P1G32, - OC_EC_2P1G64, - OC_EC_2P1G128, - OC_EC_2P1G256, - OC_EC_2P1G512, - OC_EC_2P1G1K, - OC_EC_2P1G2K, - OC_EC_2P1G4K, - OC_EC_2P1G8K, - OC_EC_2P1GX, - - /** EC 2+2 object classes */ - OC_EC_2P2G1 = 300, - OC_EC_2P2G2, - OC_EC_2P2G4, - OC_EC_2P2G8, - OC_EC_2P2G16, - OC_EC_2P2G32, - OC_EC_2P2G64, - OC_EC_2P2G128, - OC_EC_2P2G256, - OC_EC_2P2G512, - OC_EC_2P2G1K, - OC_EC_2P2G2K, - OC_EC_2P2G4K, - OC_EC_2P2G8K, - OC_EC_2P2GX, - - /** EC 4+1 object classes */ - OC_EC_4P1G1 = 320, - OC_EC_4P1G2, - OC_EC_4P1G4, - OC_EC_4P1G8, - OC_EC_4P1G16, - OC_EC_4P1G32, - OC_EC_4P1G64, - OC_EC_4P1G128, - OC_EC_4P1G256, - OC_EC_4P1G512, - OC_EC_4P1G1K, - OC_EC_4P1G2K, - OC_EC_4P1G4K, - OC_EC_4P1G8K, - OC_EC_4P1GX, - - /** EC 4+2 object classes */ - OC_EC_4P2G1 = 340, - OC_EC_4P2G2, - OC_EC_4P2G4, - OC_EC_4P2G8, - OC_EC_4P2G16, - OC_EC_4P2G32, - OC_EC_4P2G64, - OC_EC_4P2G128, - OC_EC_4P2G256, - OC_EC_4P2G512, - OC_EC_4P2G1K, - OC_EC_4P2G2K, - OC_EC_4P2G4K, - OC_EC_4P2G8K, - OC_EC_4P2GX, - - /** EC 8+1 object classes */ - OC_EC_8P1G1 = 360, - OC_EC_8P1G2, - OC_EC_8P1G4, - OC_EC_8P1G8, - OC_EC_8P1G16, - OC_EC_8P1G32, - OC_EC_8P1G64, - OC_EC_8P1G128, - OC_EC_8P1G256, - OC_EC_8P1G512, - OC_EC_8P1G1K, - OC_EC_8P1G2K, - OC_EC_8P1G4K, - OC_EC_8P1G8K, - OC_EC_8P1GX, - - /** EC 8+2 object classes */ - OC_EC_8P2G1 = 380, - OC_EC_8P2G2, - OC_EC_8P2G4, - OC_EC_8P2G8, - OC_EC_8P2G16, - OC_EC_8P2G32, - OC_EC_8P2G64, - OC_EC_8P2G128, - OC_EC_8P2G256, - OC_EC_8P2G512, - OC_EC_8P2G1K, - OC_EC_8P2G2K, - OC_EC_8P2G4K, - OC_EC_8P2G8K, - OC_EC_8P2GX, - - /** EC 16+1 object classes */ - OC_EC_16P1G1 = 400, - OC_EC_16P1G2, - OC_EC_16P1G4, - OC_EC_16P1G8, - OC_EC_16P1G16, - OC_EC_16P1G32, - OC_EC_16P1G64, - OC_EC_16P1G128, - OC_EC_16P1G256, - OC_EC_16P1G512, - OC_EC_16P1G1K, - OC_EC_16P1G2K, - OC_EC_16P1G4K, - OC_EC_16P1G8K, - OC_EC_16P1GX, - - /** EC 16+2 object classes */ - OC_EC_16P2G1 = 420, - OC_EC_16P2G2, - OC_EC_16P2G4, - OC_EC_16P2G8, - OC_EC_16P2G16, - OC_EC_16P2G32, - OC_EC_16P2G64, - OC_EC_16P2G128, - OC_EC_16P2G256, - OC_EC_16P2G512, - OC_EC_16P2G1K, - OC_EC_16P2G2K, - OC_EC_16P2G4K, - OC_EC_16P2G8K, - OC_EC_16P2GX, - /** Class ID equal or higher than this is reserved */ OC_RESERVED = (1U << 10), }; From 5f564f19dcb4ce228867a646e3c4237a73f20d81 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Sat, 12 Jun 2021 17:30:58 +0200 Subject: [PATCH 212/309] [ntuple,daos] Minor changes in the RDaosContainer class interface These changes affect the functions to read/write a single attribute key. In particular, DAOS-specific arguments appear last in the function signature. Other arguments, e.g. object class may be added in the future. --- tree/ntuple/v7/inc/ROOT/RDaos.hxx | 31 +++++++------------- tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx | 3 ++ tree/ntuple/v7/src/RDaos.cxx | 18 +++--------- tree/ntuple/v7/src/RPageStorageDaos.cxx | 31 ++++++++++---------- 4 files changed, 32 insertions(+), 51 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RDaos.hxx b/tree/ntuple/v7/inc/ROOT/RDaos.hxx index 23411c0aafedd..54fe854efb99b 100644 --- a/tree/ntuple/v7/inc/ROOT/RDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RDaos.hxx @@ -101,8 +101,8 @@ public: class RDaosContainer { friend class RDaosObject; public: - using DistributionKey_t = std::uint64_t; - using AttributeKey_t = std::uint64_t; + using DistributionKey_t = RDaosObject::DistributionKey_t; + using AttributeKey_t = RDaosObject::AttributeKey_t; /// \brief Describes a read/write operation on multiple objects; see the `ReadV`/`WriteV` functions. struct RWOperation { @@ -132,8 +132,6 @@ private: daos_handle_t fContainerHandle{}; uuid_t fContainerUuid{}; std::shared_ptr fPool; - /// OID that will be used by the next call to `WriteObject(const void *, std::size_t, DistributionKey_t, AttributeKey_t)`. - daos_obj_id_t fSequentialWrOid{}; /** \brief Perform a vector read/write operation on different objects. @@ -165,37 +163,28 @@ public: ~RDaosContainer(); /** - \brief Read data from an object in this container to the given buffer. - \param oid A 128-bit DAOS object identifier. + \brief Read data from a single object attribute key to the given buffer. \param buffer The address of a buffer that has capacity for at least `length` bytes. \param length Length of the buffer. - \param dkey The distribution key used for this operation. - \param akey The attribute key used for this operation. - \return 0 if the operation succeeded; a negative DAOS error number otherwise. - */ - int ReadObject(daos_obj_id_t oid, void *buffer, std::size_t length, DistributionKey_t dkey, AttributeKey_t akey); - - /** - \brief Write the given buffer to an object in this container. \param oid A 128-bit DAOS object identifier. - \param buffer The address of the source buffer. - \param length Length of the buffer. \param dkey The distribution key used for this operation. \param akey The attribute key used for this operation. \return 0 if the operation succeeded; a negative DAOS error number otherwise. */ - int WriteObject(daos_obj_id_t oid, const void *buffer, std::size_t length, DistributionKey_t dkey, AttributeKey_t akey); + int ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey); /** - \brief Write the given buffer to an object in this container and return a generated OID. + \brief Write the given buffer to a single object attribute key. \param buffer The address of the source buffer. \param length Length of the buffer. + \param oid A 128-bit DAOS object identifier. \param dkey The distribution key used for this operation. \param akey The attribute key used for this operation. - \return A `std::tuple<>` that contains the generated OID and a DAOS error number (0 if the operation succeeded). + \return 0 if the operation succeeded; a negative DAOS error number otherwise. */ - std::tuple - WriteObject(const void *buffer, std::size_t length, DistributionKey_t dkey, AttributeKey_t akey); + int WriteSingleAkey(const void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey); /** \brief Perform a vector read operation on (possibly) multiple objects. diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx index a316dc259dcaf..f85087b787135 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,8 @@ private: /// (which calls `daos_cont_close()`; the destructor for the `std::shared_ptr` is invoked /// after (which calls `daos_pool_disconect()`). std::unique_ptr fDaosContainer; + /// OID for the next committed page; it is automatically incremented in `CommitSealedPageImpl()` + std::atomic fOid{0}; /// \brief A URI to a DAOS pool of the form 'daos://pool-uuid:svc_replicas/container-uuid' std::string fURI; diff --git a/tree/ntuple/v7/src/RDaos.cxx b/tree/ntuple/v7/src/RDaos.cxx index 9cb030408a4d7..4dce57f8723d6 100644 --- a/tree/ntuple/v7/src/RDaos.cxx +++ b/tree/ntuple/v7/src/RDaos.cxx @@ -153,8 +153,8 @@ ROOT::Experimental::Detail::RDaosContainer::~RDaosContainer() { daos_cont_close(fContainerHandle, nullptr); } -int ROOT::Experimental::Detail::RDaosContainer::ReadObject(daos_obj_id_t oid, void *buffer, std::size_t length, - DistributionKey_t dkey, AttributeKey_t akey) +int ROOT::Experimental::Detail::RDaosContainer::ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey) { std::vector iovs(1); d_iov_set(&iovs[0], buffer, length); @@ -162,21 +162,11 @@ int ROOT::Experimental::Detail::RDaosContainer::ReadObject(daos_obj_id_t oid, vo return RDaosObject(*this, oid).Fetch(args); } -int ROOT::Experimental::Detail::RDaosContainer::WriteObject(daos_obj_id_t oid, const void *buffer, std::size_t length, - DistributionKey_t dkey, AttributeKey_t akey) +int ROOT::Experimental::Detail::RDaosContainer::WriteSingleAkey(const void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey) { std::vector iovs(1); d_iov_set(&iovs[0], const_cast(buffer), length); RDaosObject::FetchUpdateArgs args(dkey, akey, iovs); return RDaosObject(*this, oid).Update(args); } - -std::tuple -ROOT::Experimental::Detail::RDaosContainer::WriteObject(const void *buffer, std::size_t length, - DistributionKey_t dkey, AttributeKey_t akey) -{ - auto ret = std::make_tuple(fSequentialWrOid, - WriteObject(fSequentialWrOid, buffer, length, dkey, akey)); - fSequentialWrOid.lo++; - return ret; -} diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index 4e1dccc9f38ac..ec3e194d7bdbd 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -158,13 +158,11 @@ ROOT::Experimental::RClusterDescriptor::RLocator ROOT::Experimental::Detail::RPageSinkDaos::CommitSealedPageImpl( DescriptorId_t /*columnId*/, const RPageStorage::RSealedPage &sealedPage) { - std::uint64_t offsetData; + auto offsetData = fOid.fetch_add(1); { RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite); - offsetData = std::get<0>(fDaosContainer->WriteObject(sealedPage.fBuffer, - sealedPage.fSize, - kDistributionKey, - kAttributeKey)).lo; + fDaosContainer->WriteSingleAkey(sealedPage.fBuffer, sealedPage.fSize, + {offsetData, 0}, kDistributionKey, kAttributeKey); } RClusterDescriptor::RLocator result; @@ -204,7 +202,7 @@ void ROOT::Experimental::Detail::RPageSinkDaos::CommitDatasetImpl() void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleHeader( const void *data, size_t nbytes, size_t lenHeader) { - fDaosContainer->WriteObject(kOidHeader, data, nbytes, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(data, nbytes, kOidHeader, kDistributionKey, kAttributeKey); fNTupleAnchor.fLenHeader = lenHeader; fNTupleAnchor.fNBytesHeader = nbytes; } @@ -212,7 +210,7 @@ void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleHeader( void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleFooter( const void *data, size_t nbytes, size_t lenFooter) { - fDaosContainer->WriteObject(kOidFooter, data, nbytes, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(data, nbytes, kOidFooter, kDistributionKey, kAttributeKey); fNTupleAnchor.fLenFooter = lenFooter; fNTupleAnchor.fNBytesFooter = nbytes; } @@ -221,7 +219,7 @@ void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleAnchor() { const auto ntplSize = RDaosNTupleAnchor::GetSize(); auto buffer = std::make_unique(ntplSize); fNTupleAnchor.Serialize(buffer.get()); - fDaosContainer->WriteObject(kOidAnchor, buffer.get(), ntplSize, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, kAttributeKey); } ROOT::Experimental::Detail::RPage @@ -287,18 +285,18 @@ ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceDao RDaosNTupleAnchor ntpl; const auto ntplSize = RDaosNTupleAnchor::GetSize(); auto buffer = std::make_unique(ntplSize); - fDaosContainer->ReadObject(kOidAnchor, buffer.get(), ntplSize, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, kAttributeKey); ntpl.Deserialize(buffer.get()); buffer = std::make_unique(ntpl.fLenHeader); auto zipBuffer = std::make_unique(ntpl.fNBytesHeader); - fDaosContainer->ReadObject(kOidHeader, zipBuffer.get(), ntpl.fNBytesHeader, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesHeader, kOidHeader, kDistributionKey, kAttributeKey); fDecompressor->Unzip(zipBuffer.get(), ntpl.fNBytesHeader, ntpl.fLenHeader, buffer.get()); descBuilder.SetFromHeader(buffer.get()); buffer = std::make_unique(ntpl.fLenFooter); zipBuffer = std::make_unique(ntpl.fNBytesFooter); - fDaosContainer->ReadObject(kOidFooter, zipBuffer.get(), ntpl.fNBytesFooter, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesFooter, kOidFooter, kDistributionKey, kAttributeKey); fDecompressor->Unzip(zipBuffer.get(), ntpl.fNBytesFooter, ntpl.fLenFooter, buffer.get()); descBuilder.AddClustersFromFooter(buffer.get()); @@ -318,9 +316,9 @@ void ROOT::Experimental::Detail::RPageSourceDaos::LoadSealedPage( sealedPage.fSize = bytesOnStorage; sealedPage.fNElements = pageInfo.fNElements; if (sealedPage.fBuffer) { - fDaosContainer->ReadObject({static_cast(pageInfo.fLocator.fPosition), 0}, - const_cast(sealedPage.fBuffer), bytesOnStorage, - kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(const_cast(sealedPage.fBuffer), bytesOnStorage, + {static_cast(pageInfo.fLocator.fPosition), 0}, + kDistributionKey, kAttributeKey); } } @@ -341,8 +339,9 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceDaos::P if (fOptions.GetClusterCache() == RNTupleReadOptions::EClusterCache::kOff) { directReadBuffer = std::make_unique(bytesOnStorage); - fDaosContainer->ReadObject({static_cast(pageInfo.fLocator.fPosition), 0}, - directReadBuffer.get(), bytesOnStorage, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(directReadBuffer.get(), bytesOnStorage, + {static_cast(pageInfo.fLocator.fPosition), 0}, + kDistributionKey, kAttributeKey); fCounters->fNPageLoaded.Inc(); fCounters->fNRead.Inc(); fCounters->fSzReadPayload.Add(bytesOnStorage); From 4bc21b88d215958a506efbc4a9f38cdc902411a2 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Sat, 12 Jun 2021 21:26:56 +0200 Subject: [PATCH 213/309] [ntuple,daos] RDaosContainer: allow specifying an object class Helper functions to read/write data, e.g. {Read,Write}SingleAkey allow for specifying an object class ID. A default oclass may be specified for an RDaosContainer intance via the `SetDefaultObjectClass()` function. --- tree/ntuple/v7/inc/ROOT/RDaos.hxx | 60 +++++++++++++++++++++++++------ tree/ntuple/v7/src/RDaos.cxx | 23 ++++++++---- 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RDaos.hxx b/tree/ntuple/v7/inc/ROOT/RDaos.hxx index 54fe854efb99b..761bcba594123 100644 --- a/tree/ntuple/v7/inc/ROOT/RDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RDaos.hxx @@ -26,6 +26,7 @@ extern "C" void d_rank_list_free(d_rank_list_t *rank_list); #include #include +#include #include #include @@ -63,7 +64,26 @@ private: public: using DistributionKey_t = std::uint64_t; using AttributeKey_t = std::uint64_t; - + + /// \brief Wrap around a `daos_oclass_id_t`. An object class describes the schema of data distribution + /// and protection. + struct ObjClassId { + daos_oclass_id_t fCid; + + ObjClassId(const ObjClassId&) = default; + ObjClassId(daos_oclass_id_t cid) : fCid(cid) {} + ObjClassId(const std::string &name) : fCid(daos_oclass_name2id(name.data())) {} + + bool IsUnknown() const { return fCid == OC_UNKNOWN; } + std::string ToString() const; + + /// This limit is currently not defined in any header and any call to + /// `daos_oclass_id2name()` within DAOS uses a stack-allocated buffer + /// whose length varies from 16 to 50, e.g. `https://github.com/daos-stack/daos/blob/master/src/utils/daos_dfs_hdlr.c#L78`. + /// As discussed with the development team, 64 is a reasonable limit. + static constexpr std::size_t kOCNameMaxLength = 64; + }; + /// \brief Contains required information for a single fetch/update operation. struct FetchUpdateArgs { FetchUpdateArgs() = default; @@ -87,7 +107,9 @@ public: }; RDaosObject() = delete; - RDaosObject(RDaosContainer &container, daos_obj_id_t oid, daos_oclass_id_t cid = OC_RP_XSF); + /// Provides low-level access to an object. If `cid` is OC_UNKNOWN, the user is responsible for + /// calling `daos_obj_generate_id()` to fill the reserved bits in `oid` before calling this constructor. + RDaosObject(RDaosContainer &container, daos_obj_id_t oid, ObjClassId cid = OC_UNKNOWN); ~RDaosObject(); int Fetch(FetchUpdateArgs &args); @@ -103,6 +125,7 @@ class RDaosContainer { public: using DistributionKey_t = RDaosObject::DistributionKey_t; using AttributeKey_t = RDaosObject::AttributeKey_t; + using ObjClassId_t = RDaosObject::ObjClassId; /// \brief Describes a read/write operation on multiple objects; see the `ReadV`/`WriteV` functions. struct RWOperation { @@ -132,22 +155,24 @@ private: daos_handle_t fContainerHandle{}; uuid_t fContainerUuid{}; std::shared_ptr fPool; + ObjClassId_t fDefaultObjectClass{OC_RP_XSF}; /** \brief Perform a vector read/write operation on different objects. \param vec A `std::vector` that describes read/write operations to perform. + \param cid The `daos_oclass_id_t` used to qualify OIDs. \param fn Either `std::mem_fn<&RDaosObject::Fetch>` (read) or `std::mem_fn<&RDaosObject::Update>` (write). \return Number of requests that did not complete; this should be 0 after a successful call. */ template - int VectorReadWrite(std::vector &vec, Fn fn) { + int VectorReadWrite(std::vector &vec, ObjClassId_t cid, Fn fn) { int ret; DaosEventQueue eventQueue(vec.size()); { std::vector, RDaosObject::FetchUpdateArgs>> requests{}; requests.reserve(vec.size()); for (size_t i = 0; i < vec.size(); ++i) { - requests.push_back(std::make_tuple(std::unique_ptr(new RDaosObject(*this, vec[i].fOid)), + requests.push_back(std::make_tuple(std::unique_ptr(new RDaosObject(*this, vec[i].fOid, cid.fCid)), RDaosObject::FetchUpdateArgs{ vec[i].fDistributionKey, vec[i].fAttributeKey, vec[i].fIovs, &eventQueue.fEvs[i]})); @@ -162,6 +187,9 @@ public: RDaosContainer(std::shared_ptr pool, std::string_view containerUuid, bool create = false); ~RDaosContainer(); + ObjClassId_t GetDefaultObjectClass() const { return fDefaultObjectClass; } + void SetDefaultObjectClass(const ObjClassId_t cid) { fDefaultObjectClass = cid; } + /** \brief Read data from a single object attribute key to the given buffer. \param buffer The address of a buffer that has capacity for at least `length` bytes. @@ -169,10 +197,14 @@ public: \param oid A 128-bit DAOS object identifier. \param dkey The distribution key used for this operation. \param akey The attribute key used for this operation. + \param cid An object class ID. \return 0 if the operation succeeded; a negative DAOS error number otherwise. */ int ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, - DistributionKey_t dkey, AttributeKey_t akey); + DistributionKey_t dkey, AttributeKey_t akey, ObjClassId_t cid); + int ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey) + { return ReadSingleAkey(buffer, length, oid, dkey, akey, fDefaultObjectClass); } /** \brief Write the given buffer to a single object attribute key. @@ -181,26 +213,34 @@ public: \param oid A 128-bit DAOS object identifier. \param dkey The distribution key used for this operation. \param akey The attribute key used for this operation. + \param cid An object class ID. \return 0 if the operation succeeded; a negative DAOS error number otherwise. */ int WriteSingleAkey(const void *buffer, std::size_t length, daos_obj_id_t oid, - DistributionKey_t dkey, AttributeKey_t akey); + DistributionKey_t dkey, AttributeKey_t akey, ObjClassId_t cid); + int WriteSingleAkey(const void *buffer, std::size_t length, daos_obj_id_t oid, + DistributionKey_t dkey, AttributeKey_t akey) + { return WriteSingleAkey(buffer, length, oid, dkey, akey, fDefaultObjectClass); } /** \brief Perform a vector read operation on (possibly) multiple objects. \param vec A `std::vector` that describes read operations to perform. + \param cid An object class ID. \return Number of operations that could not complete. */ - int ReadV(std::vector &vec) - { return VectorReadWrite(vec, std::mem_fn(&RDaosObject::Fetch)); } + int ReadV(std::vector &vec, ObjClassId_t cid) + { return VectorReadWrite(vec, cid, std::mem_fn(&RDaosObject::Fetch)); } + int ReadV(std::vector &vec) { return ReadV(vec, fDefaultObjectClass); } /** \brief Perform a vector write operation on (possibly) multiple objects. \param vec A `std::vector` that describes write operations to perform. + \param cid An object class ID. \return Number of operations that could not complete. */ - int WriteV(std::vector &vec) - { return VectorReadWrite(vec, std::mem_fn(&RDaosObject::Update)); } + int WriteV(std::vector &vec, ObjClassId_t cid) + { return VectorReadWrite(vec, cid, std::mem_fn(&RDaosObject::Update)); } + int WriteV(std::vector &vec) { return WriteV(vec, fDefaultObjectClass); } }; } // namespace Detail diff --git a/tree/ntuple/v7/src/RDaos.cxx b/tree/ntuple/v7/src/RDaos.cxx index 4dce57f8723d6..b0de771b35af3 100644 --- a/tree/ntuple/v7/src/RDaos.cxx +++ b/tree/ntuple/v7/src/RDaos.cxx @@ -47,6 +47,14 @@ ROOT::Experimental::Detail::RDaosPool::~RDaosPool() { //////////////////////////////////////////////////////////////////////////////// +std::string ROOT::Experimental::Detail::RDaosObject::ObjClassId::ToString() const +{ + char name[kOCNameMaxLength + 1] = {}; + daos_oclass_id2name(fCid, name); + return std::string{name}; +} + + ROOT::Experimental::Detail::RDaosObject::FetchUpdateArgs::FetchUpdateArgs(FetchUpdateArgs&& fua) : fDkey(fua.fDkey), fAkey(fua.fAkey), fIods{fua.fIods[0]}, fSgls{fua.fSgls[0]}, fIovs(std::move(fua.fIovs)), fEv(fua.fEv) @@ -74,9 +82,10 @@ ROOT::Experimental::Detail::RDaosObject::FetchUpdateArgs::FetchUpdateArgs } ROOT::Experimental::Detail::RDaosObject::RDaosObject(RDaosContainer &container, daos_obj_id_t oid, - daos_oclass_id_t cid) + ObjClassId cid) { - daos_obj_generate_id(&oid, DAOS_OF_DKEY_UINT64 | DAOS_OF_AKEY_UINT64 /*| DAOS_OF_ARRAY_BYTE*/, cid, 0); + if (!cid.IsUnknown()) + daos_obj_generate_id(&oid, DAOS_OF_DKEY_UINT64 | DAOS_OF_AKEY_UINT64 /*| DAOS_OF_ARRAY_BYTE*/, cid.fCid, 0); if (int err = daos_obj_open(container.fContainerHandle, oid, DAOS_OO_RW, &fObjectHandle, nullptr)) throw RException(R__FAIL("daos_obj_open: error: " + std::string(d_errstr(err)))); } @@ -154,19 +163,21 @@ ROOT::Experimental::Detail::RDaosContainer::~RDaosContainer() { } int ROOT::Experimental::Detail::RDaosContainer::ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, - DistributionKey_t dkey, AttributeKey_t akey) + DistributionKey_t dkey, AttributeKey_t akey, + ObjClassId_t cid) { std::vector iovs(1); d_iov_set(&iovs[0], buffer, length); RDaosObject::FetchUpdateArgs args(dkey, akey, iovs); - return RDaosObject(*this, oid).Fetch(args); + return RDaosObject(*this, oid, cid.fCid).Fetch(args); } int ROOT::Experimental::Detail::RDaosContainer::WriteSingleAkey(const void *buffer, std::size_t length, daos_obj_id_t oid, - DistributionKey_t dkey, AttributeKey_t akey) + DistributionKey_t dkey, AttributeKey_t akey, + ObjClassId_t cid) { std::vector iovs(1); d_iov_set(&iovs[0], const_cast(buffer), length); RDaosObject::FetchUpdateArgs args(dkey, akey, iovs); - return RDaosObject(*this, oid).Update(args); + return RDaosObject(*this, oid, cid.fCid).Update(args); } From ab70f6cd8ea54f72bcc512eda709f1fd927a4228 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 11:54:33 +0200 Subject: [PATCH 214/309] [rcanvas] Provide return type to RPadBase::Draw method PyROOT not able to deduce "auto" type for such templated methods --- graf2d/gpadv7/inc/ROOT/RPadBase.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx index e17f460796cc8..b48bc7f30097c 100644 --- a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx @@ -83,7 +83,7 @@ public: /// Create drawable of specified class T template - auto Draw(ARGS... args) + std::shared_ptr Draw(ARGS... args) { auto drawable = std::make_shared(args...); @@ -95,7 +95,7 @@ public: } /// Add existing drawable instance to canvas - auto Draw(std::shared_ptr &&drawable) + std::shared_ptr Draw(std::shared_ptr &&drawable) { TestIfFrameRequired(drawable.get()); From f1419eb629f8a7c64427a22a5d5794b2cb37d8d2 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 12:21:09 +0200 Subject: [PATCH 215/309] [rdrawable] provide new signatures for TObjectDrawable constructor Let create drawable just with existing TObject instance taking ownership over the object --- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 21 ++++++++++++++++++--- graf2d/gpadv7/src/TObjectDrawable.cxx | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index f3bb967be7b07..582827506fa58 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -66,7 +66,7 @@ protected: void ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member); - static std::string DetectCssType(const std::shared_ptr &obj); + static std::string DetectCssType(const TObject *obj); public: // special kinds, see TWebSnapshot enums @@ -76,19 +76,34 @@ public: kPalette = 6 ///< list of colors from palette }; - TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj)) + TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj.get())) { fKind = kObject; fObj = obj; } - TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : RDrawable(DetectCssType(obj)) + TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : RDrawable(DetectCssType(obj.get())) { fKind = kObject; fObj = obj; SetOpt(opt); } + /// Constructor takes ownership + TObjectDrawable(TObject *obj) : RDrawable(DetectCssType(obj)) + { + fKind = kObject; + fObj = std::shared_ptr(obj); + } + + /// Constructor takes ownership + TObjectDrawable(TObject *obj, const std::string &opt) : RDrawable(DetectCssType(obj)) + { + fKind = kObject; + fObj = std::shared_ptr(obj); + SetOpt(opt); + } + TObjectDrawable(EKind kind, bool persistent = false) : RDrawable("tobject") { fKind = kind; diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 636c3420ebc2d..f3c4dd26bc4a4 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -26,7 +26,7 @@ using namespace ROOT::Experimental; -std::string TObjectDrawable::DetectCssType(const std::shared_ptr &obj) +std::string TObjectDrawable::DetectCssType(const TObject *obj) { const char *clname = obj ? obj->ClassName() : "TObject"; if (strncmp(clname, "TH1", 3) == 0) return "th1"; From 70db9dfbc1d6e856c23faf568e95ee68c9253b1e Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 15:31:00 +0200 Subject: [PATCH 216/309] [rdrawable] always call TH1::SetDirectory(nullptr) in TObjectDrawable To avoid linking with libHist, use TMethodCall --- graf2d/gpadv7/src/TObjectDrawable.cxx | 12 ++++++++++-- tutorials/v7/draw_v6.cxx | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index f3c4dd26bc4a4..310635548666c 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -18,6 +18,7 @@ #include "TObjString.h" #include "TROOT.h" #include "TStyle.h" +#include "TMethodCall.h" #include #include @@ -28,10 +29,17 @@ using namespace ROOT::Experimental; std::string TObjectDrawable::DetectCssType(const TObject *obj) { + bool ishist = false; + // special handling for TH1 classes without linking to libHist + if (obj && obj->InheritsFrom("TH1")) { + TMethodCall call(obj->IsA(), "SetDirectory", "nullptr"); + call.Execute((void *)(obj)); + ishist = true; + } const char *clname = obj ? obj->ClassName() : "TObject"; - if (strncmp(clname, "TH1", 3) == 0) return "th1"; - if (strncmp(clname, "TH2", 3) == 0) return "th2"; if (strncmp(clname, "TH3", 3) == 0) return "th3"; + if (strncmp(clname, "TH2", 3) == 0) return "th2"; + if ((strncmp(clname, "TH1", 3) == 0) || ishist) return "th1"; if (strncmp(clname, "TGraph", 6) == 0) return "tgraph"; if (strcmp(clname, "TLine") == 0) return "tline"; if (strcmp(clname, "TBox") == 0) return "tbox"; diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index 905f0a147119b..2b5ace4134631 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -37,20 +37,25 @@ auto v6_style = RStyle::Parse("tgraph { line_width: 3; line_color: red; }"); void draw_v6() { static constexpr int npoints = 10; + static constexpr int nth1points = 100; + static constexpr int nth2points = 40; + double x[npoints] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. }; double y[npoints] = { .1, .2, .3, .4, .3, .2, .1, .2, .3, .4 }; - auto gr = std::make_shared(npoints, x, y); + auto gr = new TGraph(npoints, x, y); - static constexpr int nth1points = 100; - auto th1 = std::make_shared("gaus", "Example of TH1", nth1points, -5, 5); - th1->SetDirectory(nullptr); + // create normal object to be able draw it once + auto th1 = new TH1I("gaus", "Example of TH1", nth1points, -5, 5); + // it is recommended to set directory to nullptr, but it is also automatically done in TObjectDrawable + // th1->SetDirectory(nullptr); for (int n=0;nSetBinContent(n+1, (int) (1000*TMath::Gaus(x))); } - static constexpr int nth2points = 40; + // use std::shared_ptr to let draw same histogram twice with different draw options auto th2 = std::make_shared("gaus2", "Example of TH2", nth2points, -5, 5, nth2points, -5, 5); + // is is highly recommended to set directory to nullptr to avoid ownership conflicts th2->SetDirectory(nullptr); for (int n=0;nDivide(2,2); + // draw graph with "AL" option, drawable take over object ownership subpads[0][0]->Draw(gr, "AL"); // one can change basic attributes via v7 classes, value will be replaced on client side @@ -88,7 +94,7 @@ void draw_v6() // show same object again, but with other draw options subpads[1][1]->Draw(th2, "lego2"); - // add style, here used to configure TGraph attrbutes, evaluated only on client side + // add style, here used to configure TGraph attributes, evaluated only on client side canvas->UseStyle(v6_style); // new window in web browser should popup and async update will be triggered From 9bb07b262129f471bf788f2c69684f913000b3da Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 14 Jun 2021 17:06:53 +0200 Subject: [PATCH 217/309] [rdrawable] let extract THStack colors and axes colors from TH1 --- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 14 +++- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 4 +- graf2d/gpadv7/src/TObjectDrawable.cxx | 74 +++++++++++++------ 3 files changed, 67 insertions(+), 25 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx index ef9cbd4cb2da2..bb8f9d054dc0c 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx @@ -14,6 +14,8 @@ #include #include +#include + #include "TObject.h" namespace ROOT { @@ -61,10 +63,16 @@ public: if (fOwner) delete fObject; } - void AddTColor(int color_indx, const std::string &color_value) + void AddColor(int color_indx, const std::string &color_value) { - fColIndex.emplace_back(color_indx); - fColValue.emplace_back(color_value); + auto pos = std::find(fColIndex.begin(), fColIndex.end(), color_indx); + if (pos == fColIndex.end()) { + fColIndex.emplace_back(color_indx); + fColValue.emplace_back(color_value); + } else { + auto indx = pos - fColIndex.begin(); + fColValue[indx] = color_value; + } } }; diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index 582827506fa58..41fe548a082f8 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -64,7 +64,9 @@ protected: void Execute(const std::string &) final; - void ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member); + static void ExtractTColor(std::unique_ptr &item, TObject *obj, const char *class_name, const char *class_member); + + static void ExtractObjectColors(std::unique_ptr &item, TObject *obj); static std::string DetectCssType(const TObject *obj); diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 310635548666c..ef2eb7c9368cc 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -17,6 +17,7 @@ #include "TObjArray.h" #include "TObjString.h" #include "TROOT.h" +#include "TList.h" #include "TStyle.h" #include "TMethodCall.h" @@ -106,19 +107,41 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) /// Check if object has specified color value and store it in display item /// Ensure that color matches on client side too -void TObjectDrawable::ExtractTColor(std::unique_ptr &item, const char *class_name, const char *class_member) +void TObjectDrawable::ExtractObjectColors(std::unique_ptr &item, TObject *obj) { - TClass *cl = fObj->IsA(); - if (!cl->GetBaseClass(class_name)) return; - - auto offset = cl->GetDataMemberOffset(class_member); - if (offset <= 0) return; - - Color_t *icol = (Color_t *)((char *) fObj.get() + offset); - if (*icol < 10) return; - - TColor *col = gROOT->GetColor(*icol); - if (col) item->AddTColor(*icol, col->AsHexString()); + TClass *cl = obj->IsA(); + + auto ExtractColor = [&item, cl, obj](const char *class_name, const char *class_member) { + if (!cl->GetBaseClass(class_name)) return; + + auto offset = cl->GetDataMemberOffset(class_member); + if (offset <= 0) return; + + Color_t *icol = (Color_t *)((char *) obj + offset); + if (*icol < 10) return; + + TColor *col = gROOT->GetColor(*icol); + if (col) item->AddColor(*icol, col->AsHexString()); + }; + + ExtractColor("TAttLine", "fLineColor"); + ExtractColor("TAttFill", "fFillColor"); + ExtractColor("TAttMarker", "fMarkerColor"); + ExtractColor("TAttText", "fTextColor"); + ExtractColor("TAttPad", "fFrameFillColor"); + ExtractColor("TAttPad", "fFrameLineColor"); + ExtractColor("TAttAxis", "fAxisColor"); + ExtractColor("TAttAxis", "fLabelColor"); + ExtractColor("TAttAxis", "fTitleColor"); + + if (cl->InheritsFrom("TH1")) { + auto offx = cl->GetDataMemberOffset("fXaxis"); + if (offx > 0) ExtractObjectColors(item, (TObject *) ((char *) obj + offx)); + auto offy = cl->GetDataMemberOffset("fYaxis"); + if (offy > 0) ExtractObjectColors(item, (TObject *) ((char *) obj + offy)); + auto offz = cl->GetDataMemberOffset("fZaxis"); + if (offz > 0) ExtractObjectColors(item, (TObject *) ((char *) obj + offz)); + } } @@ -131,15 +154,24 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct if ((fKind == kObject) || fObj) { auto item = std::make_unique(*this, fKind, fObj.get()); if ((fKind == kObject) && fObj) { - ExtractTColor(item, "TAttLine", "fLineColor"); - ExtractTColor(item, "TAttFill", "fFillColor"); - ExtractTColor(item, "TAttMarker", "fMarkerColor"); - ExtractTColor(item, "TAttText", "fTextColor"); - ExtractTColor(item, "TAttPad", "fFrameFillColor"); - ExtractTColor(item, "TAttPad", "fFrameLineColor"); - ExtractTColor(item, "TAttAxis", "fAxisColor"); - ExtractTColor(item, "TAttAxis", "fLabelColor"); - ExtractTColor(item, "TAttAxis", "fTitleColor"); + ExtractObjectColors(item, fObj.get()); + + // special handling of THStack to support any custom colors inside + if (strcmp(fObj->ClassName(), "THStack") == 0) { + TClass *cl = gROOT->GetClass("THStack"); + // do not call stack->GetHistogram() to avoid it auto-creation + auto off1 = cl->GetDataMemberOffset("fHistogram"); + if (off1 > 0) ExtractObjectColors(item, *((TObject **) ((char *) fObj.get() + off1))); + // here make identic to gHistogram, one also can use TMethodCall + auto off2 = cl->GetDataMemberOffset("fHists"); + if (off2 > 0) { + TIter iter(*(TList **) (((char *) fObj.get() + off1))); + TObject *hist = nullptr; + while ((hist = iter()) != nullptr) + ExtractObjectColors(item, hist); + } + + } } return item; From a6bebcd3d1948b842266ab0be2153e940cbe0c51 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 09:56:38 +0200 Subject: [PATCH 218/309] [rcanvas] simplify RPad constructor Set parent pointer only when adding pad object to primitives --- graf2d/gpadv7/inc/ROOT/RCanvas.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RPad.hxx | 16 +++++++--- graf2d/gpadv7/inc/ROOT/RPadBase.hxx | 42 +++++++++++++------------ graf2d/gpadv7/src/RPadBase.cxx | 48 ++++++++++++++++++----------- 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RCanvas.hxx b/graf2d/gpadv7/inc/ROOT/RCanvas.hxx index 2ac3abd365205..2252850b0cb22 100644 --- a/graf2d/gpadv7/inc/ROOT/RCanvas.hxx +++ b/graf2d/gpadv7/inc/ROOT/RCanvas.hxx @@ -76,7 +76,7 @@ public: static std::shared_ptr Create(const std::string &title); /// Create a temporary RCanvas; for long-lived ones please use Create(). - RCanvas() = default; + RCanvas() : RPadBase("canvas") {} ~RCanvas() = default; diff --git a/graf2d/gpadv7/inc/ROOT/RPad.hxx b/graf2d/gpadv7/inc/ROOT/RPad.hxx index e54342ed47572..3f61c4c0e5f42 100644 --- a/graf2d/gpadv7/inc/ROOT/RPad.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPad.hxx @@ -24,6 +24,8 @@ namespace Experimental { class RPad: public RPadBase { + friend class RPadBase; ///< required to set parent + /// Pad containing this pad as a sub-pad. RPadBase *fParent{nullptr}; ///< The parent pad, if this pad has one. @@ -32,16 +34,22 @@ class RPad: public RPadBase { RAttrLine fAttrLine{this, "border"}; /// Display(const RDisplayContext &) final; public: /// Create a topmost, non-paintable pad. - RPad() = default; - - /// Create a child pad. - RPad(RPadBase *parent, const RPadPos &pos, const RPadExtent &size): fParent(parent) { fPos = pos; fSize = size; } + RPad() : RPadBase("pad") {} + + /// Create a pad. + RPad(const RPadPos &pos, const RPadExtent &size) : RPad() + { + fPos = pos; + fSize = size; + } /// Destructor to have a vtable. virtual ~RPad(); diff --git a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx index b48bc7f30097c..cb63d1c8f468e 100644 --- a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx @@ -58,7 +58,7 @@ private: protected: /// Allow derived classes to default construct a RPadBase. - RPadBase() : RDrawable("pad") {} + explicit RPadBase(const std::string &csstype) : RDrawable(csstype) {} void CollectShared(Internal::RIOSharedVector_t &) override; @@ -66,6 +66,8 @@ protected: void SetDrawableVersion(Version_t vers) override; + void AddPrimitive(std::shared_ptr drawable); + public: using Primitives_t = std::vector>; @@ -81,6 +83,22 @@ public: /// \returns vector of vector (ret[x][y]) of created pads. std::vector>> Divide(int nHoriz, int nVert, const RPadExtent &padding = {}); + /// Add object to be painted. + /// Correspondent drawable will be created via GetDrawable() function which should be defined and be accessed at calling time. + /// If required, extra arguments for GetDrawable() function can be provided. + template + auto Draw(const std::shared_ptr &what, ARGS... args) + { + // Requires GetDrawable(what) to be known! + auto drawable = GetDrawable(what, args...); + + TestIfFrameRequired(drawable.get()); + + AddPrimitive(drawable); + + return drawable; + } + /// Create drawable of specified class T template std::shared_ptr Draw(ARGS... args) @@ -89,7 +107,7 @@ public: TestIfFrameRequired(drawable.get()); - fPrimitives.emplace_back(drawable); + AddPrimitive(drawable); return drawable; } @@ -99,25 +117,11 @@ public: { TestIfFrameRequired(drawable.get()); - fPrimitives.emplace_back(std::move(drawable)); + auto dr = std::move(drawable); - return fPrimitives.back().get_shared(); - } + AddPrimitive(dr); - /// Add object to be painted. - /// Correspondent drawable will be created via GetDrawable() function which should be defined and be accessed at calling time. - /// If required, extra arguments for GetDrawable() function can be provided. - template - auto Draw(const std::shared_ptr &what, ARGS... args) - { - // Requires GetDrawable(what) to be known! - auto drawable = GetDrawable(what, args...); - - TestIfFrameRequired(drawable.get()); - - fPrimitives.emplace_back(drawable); - - return drawable; + return dr; } /// returns number of primitives in the pad diff --git a/graf2d/gpadv7/src/RPadBase.cxx b/graf2d/gpadv7/src/RPadBase.cxx index 989d2ba6453a7..d436c811755de 100644 --- a/graf2d/gpadv7/src/RPadBase.cxx +++ b/graf2d/gpadv7/src/RPadBase.cxx @@ -20,22 +20,37 @@ using namespace std::string_literals; -ROOT::Experimental::RPadBase::~RPadBase() = default; +using namespace ROOT::Experimental; + +RPadBase::~RPadBase() = default; /////////////////////////////////////////////////////////////////////////// /// Use provided style for pad and all primitives inside -void ROOT::Experimental::RPadBase::UseStyle(const std::shared_ptr &style) +void RPadBase::UseStyle(const std::shared_ptr &style) { RDrawable::UseStyle(style); for (auto &drawable : fPrimitives) drawable->UseStyle(style); } +/////////////////////////////////////////////////////////////////////////// +/// Add primitive + +void RPadBase::AddPrimitive(std::shared_ptr drawable) +{ + if (drawable->GetCssType() == "pad") { + auto pad = dynamic_cast(drawable.get()); + if (pad) pad->SetParent(this); + } + + fPrimitives.emplace_back(drawable); +} + /////////////////////////////////////////////////////////////////////////// /// Find primitive with specified id -std::shared_ptr ROOT::Experimental::RPadBase::FindPrimitive(const std::string &id) const +std::shared_ptr RPadBase::FindPrimitive(const std::string &id) const { for (auto &drawable : fPrimitives) { @@ -59,7 +74,7 @@ std::shared_ptr ROOT::Experimental::RPadBase::Fin /// Find primitive with unique id, produce for RDisplayItem /// Such id used for client-server identification of objects -std::shared_ptr ROOT::Experimental::RPadBase::FindPrimitiveByDisplayId(const std::string &id) const +std::shared_ptr RPadBase::FindPrimitiveByDisplayId(const std::string &id) const { auto p = id.find("_"); if (p == std::string::npos) @@ -82,7 +97,7 @@ std::shared_ptr ROOT::Experimental::RPadBase::Fin /////////////////////////////////////////////////////////////////////////// /// Find subpad which contains primitive with given display id -const ROOT::Experimental::RPadBase *ROOT::Experimental::RPadBase::FindPadForPrimitiveWithDisplayId(const std::string &id) const +const RPadBase *RPadBase::FindPadForPrimitiveWithDisplayId(const std::string &id) const { auto p = id.find("_"); if (p == std::string::npos) @@ -107,7 +122,7 @@ const ROOT::Experimental::RPadBase *ROOT::Experimental::RPadBase::FindPadForPrim /// Each display item gets its special id, which used later for client-server communication /// Second parameter is version id which already delivered to the client -void ROOT::Experimental::RPadBase::DisplayPrimitives(RPadBaseDisplayItem &paditem, RDisplayContext &ctxt) +void RPadBase::DisplayPrimitives(RPadBaseDisplayItem &paditem, RDisplayContext &ctxt) { paditem.SetAttributes(&GetAttrMap()); paditem.SetPadStyle(fStyle.lock()); @@ -134,8 +149,8 @@ void ROOT::Experimental::RPadBase::DisplayPrimitives(RPadBaseDisplayItem &padite /// Divide pad on nHoriz X nVert subpads /// Return array of array of pads -std::vector>> -ROOT::Experimental::RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding) +std::vector>> +RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding) { std::vector>> ret; if (!nHoriz) @@ -158,10 +173,9 @@ ROOT::Experimental::RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &pa RPadPos subPos = offset; subPos *= {1. * iHoriz, 1. * iVert}; - auto subpad = Draw(this, subPos, size); + auto subpad = Draw(subPos, size); ret.back().emplace_back(subpad); - // printf("Create subpad pos %5.2f %5.2f\n", subPos.fHoriz.fNormal.fVal, subPos.fVert.fNormal.fVal); } } return ret; @@ -171,22 +185,20 @@ ROOT::Experimental::RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &pa /// Get a frame object for the pad. /// If frame not exists - creates and add to the end of primitives list - -std::shared_ptr ROOT::Experimental::RPadBase::GetOrCreateFrame() +std::shared_ptr RPadBase::GetOrCreateFrame() { auto frame = GetFrame(); if (!frame) { - frame.reset(new RFrame()); + frame.reset(new RFrame); fPrimitives.emplace_back(frame); } - return frame; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a frame object if exists -const std::shared_ptr ROOT::Experimental::RPadBase::GetFrame() const +const std::shared_ptr RPadBase::GetFrame() const { for (auto &drawable : fPrimitives) { if (drawable->GetCssType() == "frame") { @@ -200,7 +212,7 @@ const std::shared_ptr ROOT::Experimental::RPadBase:: ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a frame object if exists -std::shared_ptr ROOT::Experimental::RPadBase::GetFrame() +std::shared_ptr RPadBase::GetFrame() { for (auto &drawable : fPrimitives) { if (drawable->GetCssType() == "frame") { @@ -214,7 +226,7 @@ std::shared_ptr ROOT::Experimental::RPadBase::GetFra ///////////////////////////////////////////////////////////////////////////////////////////////// /// Collect all shared items to resolve shared_ptr after IO -void ROOT::Experimental::RPadBase::CollectShared(Internal::RIOSharedVector_t &vect) +void RPadBase::CollectShared(Internal::RIOSharedVector_t &vect) { for (auto &handle : fPrimitives) { vect.emplace_back(&handle); @@ -226,7 +238,7 @@ void ROOT::Experimental::RPadBase::CollectShared(Internal::RIOSharedVector_t &ve ///////////////////////////////////////////////////////////////////////////////////////////////// /// Assign drawable version - for pad itself and all primitives -void ROOT::Experimental::RPadBase::SetDrawableVersion(Version_t vers) +void RPadBase::SetDrawableVersion(Version_t vers) { RDrawable::SetDrawableVersion(vers); From 055a5cd5b93fc964fbce1d32c9433c225379f873 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 11:44:35 +0200 Subject: [PATCH 219/309] [rdrawable] Provide more signatures for TObjectDrawable constr Let provide TObject & as argument - will Clone() object Can be used together with PyROOT --- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 47 ++------- graf2d/gpadv7/src/TObjectDrawable.cxx | 108 ++++++++++++++++++--- tutorials/v7/draw_v6.cxx | 5 +- 3 files changed, 107 insertions(+), 53 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index 41fe548a082f8..16a42b510f950 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -68,6 +68,8 @@ protected: static void ExtractObjectColors(std::unique_ptr &item, TObject *obj); + static void CheckOwnership(TObject *obj); + static std::string DetectCssType(const TObject *obj); public: @@ -78,43 +80,14 @@ public: kPalette = 6 ///< list of colors from palette }; - TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj.get())) - { - fKind = kObject; - fObj = obj; - } - - TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : RDrawable(DetectCssType(obj.get())) - { - fKind = kObject; - fObj = obj; - SetOpt(opt); - } - - /// Constructor takes ownership - TObjectDrawable(TObject *obj) : RDrawable(DetectCssType(obj)) - { - fKind = kObject; - fObj = std::shared_ptr(obj); - } - - /// Constructor takes ownership - TObjectDrawable(TObject *obj, const std::string &opt) : RDrawable(DetectCssType(obj)) - { - fKind = kObject; - fObj = std::shared_ptr(obj); - SetOpt(opt); - } - - TObjectDrawable(EKind kind, bool persistent = false) : RDrawable("tobject") - { - fKind = kind; - - if (persistent) - fObj = CreateSpecials(kind); - } - - virtual ~TObjectDrawable() = default; + TObjectDrawable(TObject &obj); + TObjectDrawable(TObject &obj, const std::string &opt); + TObjectDrawable(TObject *obj); + TObjectDrawable(TObject *obj, const std::string &opt); + TObjectDrawable(const std::shared_ptr &obj); + TObjectDrawable(const std::shared_ptr &obj, const std::string &opt); + TObjectDrawable(EKind kind, bool persistent = false); + virtual ~TObjectDrawable(); std::shared_ptr GetObject() const { return fObj.get_shared(); } diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index ef2eb7c9368cc..1a8992a9d9d25 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -28,38 +29,121 @@ using namespace ROOT::Experimental; -std::string TObjectDrawable::DetectCssType(const TObject *obj) +//////////////////////////////////////////////////////////////////// +/// Checks object ownership - used for TH1 directory handling + +void TObjectDrawable::CheckOwnership(TObject *obj) { - bool ishist = false; - // special handling for TH1 classes without linking to libHist if (obj && obj->InheritsFrom("TH1")) { TMethodCall call(obj->IsA(), "SetDirectory", "nullptr"); call.Execute((void *)(obj)); - ishist = true; } - const char *clname = obj ? obj->ClassName() : "TObject"; +} + +//////////////////////////////////////////////////////////////////// +/// Provide css type + +std::string TObjectDrawable::DetectCssType(const TObject *obj) +{ + if (!obj) return "tobject"; + + const char *clname = obj->ClassName(); if (strncmp(clname, "TH3", 3) == 0) return "th3"; if (strncmp(clname, "TH2", 3) == 0) return "th2"; - if ((strncmp(clname, "TH1", 3) == 0) || ishist) return "th1"; + if ((strncmp(clname, "TH1", 3) == 0) || obj->InheritsFrom("TH1")) return "th1"; if (strncmp(clname, "TGraph", 6) == 0) return "tgraph"; if (strcmp(clname, "TLine") == 0) return "tline"; if (strcmp(clname, "TBox") == 0) return "tbox"; return "tobject"; } +//////////////////////////////////////////////////////////////////// +/// Constructor, clones TObject instance + +TObjectDrawable::TObjectDrawable(TObject &obj) : RDrawable(DetectCssType(&obj)) +{ + fKind = kObject; + auto clone = obj.Clone(); + CheckOwnership(clone); + fObj = std::shared_ptr(clone); +} + +//////////////////////////////////////////////////////////////////// +/// Constructor, clones TObject instance + +TObjectDrawable::TObjectDrawable(TObject &obj, const std::string &opt) : TObjectDrawable(obj) +{ + SetOpt(opt); +} + +//////////////////////////////////////////////////////////////////// +/// Constructor, takes ownership over the object + +TObjectDrawable::TObjectDrawable(TObject *obj) : RDrawable(DetectCssType(obj)) +{ + fKind = kObject; + CheckOwnership(obj); + fObj = std::shared_ptr(obj); +} + +//////////////////////////////////////////////////////////////////// +/// Constructor, takes ownership over the object + +TObjectDrawable::TObjectDrawable(TObject *obj, const std::string &opt) : TObjectDrawable(obj) +{ + SetOpt(opt); +} + +//////////////////////////////////////////////////////////////////// +/// Constructor + +TObjectDrawable::TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj.get())) +{ + fKind = kObject; + CheckOwnership(fObj.get()); + fObj = obj; +} + + +//////////////////////////////////////////////////////////////////// +/// Constructor + +TObjectDrawable::TObjectDrawable(const std::shared_ptr &obj, const std::string &opt) : TObjectDrawable(obj) +{ + SetOpt(opt); +} + +//////////////////////////////////////////////////////////////////// +/// Creates special kind for for palette or list of colors +/// One can create persistent, which does not updated to actual values + +TObjectDrawable::TObjectDrawable(EKind kind, bool persistent) : RDrawable("tobject") +{ + fKind = kind; + + if (persistent) + fObj = CreateSpecials(kind); +} + +//////////////////////////////////////////////////////////////////// +/// Destructor + +TObjectDrawable::~TObjectDrawable() = default; + //////////////////////////////////////////////////////////////////// /// Convert TColor to RGB string for using with SVG const char *TObjectDrawable::GetColorCode(TColor *col) { - static TString code; + static std::string code; + + RColor rcol((uint8_t) (255*col->GetRed()), (uint8_t) (255*col->GetGreen()), (uint8_t) (255*col->GetBlue())); + if (col->GetAlpha() != 1) + rcol.SetAlphaFloat(col->GetAlpha()); - if (col->GetAlpha() == 1) - code.Form("rgb(%d,%d,%d)", (int) (255*col->GetRed()), (int) (255*col->GetGreen()), (int) (255*col->GetBlue())); - else - code.Form("rgba(%d,%d,%d,%5.3f)", (int) (255*col->GetRed()), (int) (255*col->GetGreen()), (int) (255*col->GetBlue()), col->GetAlpha()); + code = rcol.AsSVG(); - return code.Data(); + return code.c_str(); } //////////////////////////////////////////////////////////////////// diff --git a/tutorials/v7/draw_v6.cxx b/tutorials/v7/draw_v6.cxx index 2b5ace4134631..f4ae87b11e986 100644 --- a/tutorials/v7/draw_v6.cxx +++ b/tutorials/v7/draw_v6.cxx @@ -48,10 +48,7 @@ void draw_v6() auto th1 = new TH1I("gaus", "Example of TH1", nth1points, -5, 5); // it is recommended to set directory to nullptr, but it is also automatically done in TObjectDrawable // th1->SetDirectory(nullptr); - for (int n=0;nSetBinContent(n+1, (int) (1000*TMath::Gaus(x))); - } + th1->FillRandom("gaus", 5000); // use std::shared_ptr to let draw same histogram twice with different draw options auto th2 = std::make_shared("gaus2", "Example of TH2", nth2points, -5, 5, nth2points, -5, 5); From c0d6e4a2672f194444dc77e503cd8ae6a2aaea1d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 13:12:02 +0200 Subject: [PATCH 220/309] [raxis] adjust methods to naming conventions, add nolabels --- graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx | 18 ++++++++++-------- graf2d/gpadv7/inc/ROOT/RFrame.hxx | 4 ++-- tutorials/v7/draw_axes.cxx | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx index 726668ecbba94..9200fa6e0adb7 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx @@ -46,10 +46,11 @@ class RAttrAxis : public RAttrBase { RAttrValue fTicksSize{this, "ticks_size", 0.02_normal}; /// fTicksColor{this, "ticks_color", RColor::kBlack}; /// fTicksWidth{this, "ticks_width", 1}; /// fNoLabels{this, "nolabels", false}; /// fLabelsOffset{this, "labels_offset", {}}; /// fLabelsCenter{this, "labels_center", false}; /// fTitle{this, "title", ""}; /// fTitlePos{this, "title_position", "right"}; /// fTitleOffset{this, "title_offset", {}}; /// fGridY{this, "gridy", false}; /// fSwapX{this, "swapx", false}; /// fSwapY{this, "swapy", false}; /// fTicksX{this, "ticksx", 1}; /// fTicksY{this, "ticksy", 1}; /// fTicksX{this, "ticksx", 1}; /// fTicksY{this, "ticksy", 1}; /// fClientRanges; ///Draw(RPadPos(x1, 0.3_normal), false, w1); draw4->SetMinMax(TDatime(2020,11,12,9,0,0).Convert(), TDatime(2020,11,12,12,0,0).Convert()) - .AttrAxis().SetTimeDisplay("%d/%m/%y %H:%M").SetTitle("time display").LabelsAttr().SetSize(0.01).SetColor(RColor::kRed); + .AttrAxis().SetTimeDisplay("%d/%m/%y %H:%M").SetTitle("time display").AttrLabels().SetSize(0.01).SetColor(RColor::kRed); std::vector labels = {"first", "second", "third", "forth", "fifth"}; auto draw5 = canvas->Draw(RPadPos(x1, 0.1_normal), false, w1); @@ -56,7 +56,7 @@ void draw_axes() draw6->SetMinMax(0, 10).AttrAxis().SetTitle("vertical negative length").SetEndingArrow(); auto draw7 = canvas->Draw(RPadPos(x2, 0.9_normal), false, w2); - draw7->SetMinMax(1, 100).AttrAxis().SetLog(10).SetTitle("log10 scale").SetTitleCenter().TitleAttr().SetFont(12).SetColor(RColor::kGreen); + draw7->SetMinMax(1, 100).AttrAxis().SetLog(10).SetTitle("log10 scale").SetTitleCenter().AttrTitle().SetFont(12).SetColor(RColor::kGreen); auto draw8 = canvas->Draw(RPadPos(x2, 0.7_normal), false, w2); draw8->SetMinMax(0.125, 128).AttrAxis().SetLog(2).SetTitle("log2 scale").SetTitleCenter(); From 822bcdcdb29b728d4589f0f8220978ffbc87664d Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 15:47:01 +0200 Subject: [PATCH 221/309] [rprimitives] adjust primitives methods Return *this from all setter methods --- graf2d/primitivesv7/inc/ROOT/RBox.hxx | 17 ++++------------- graf2d/primitivesv7/inc/ROOT/RLine.hxx | 17 ++++------------- graf2d/primitivesv7/inc/ROOT/RMarker.hxx | 10 +++------- graf2d/primitivesv7/inc/ROOT/RText.hxx | 16 ++++------------ 4 files changed, 15 insertions(+), 45 deletions(-) diff --git a/graf2d/primitivesv7/inc/ROOT/RBox.hxx b/graf2d/primitivesv7/inc/ROOT/RBox.hxx index eb9838fdde3be..a1edb636c30c9 100644 --- a/graf2d/primitivesv7/inc/ROOT/RBox.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RBox.hxx @@ -49,17 +49,8 @@ public: fP2 = p2; } - RBox &SetP1(const RPadPos &p1) - { - fP1 = p1; - return *this; - } - - RBox &SetP2(const RPadPos &p2) - { - fP2 = p2; - return *this; - } + RBox &SetP1(const RPadPos &p1) { fP1 = p1; return *this; } + RBox &SetP2(const RPadPos &p2) { fP2 = p2; return *this; } const RPadPos &GetP1() const { return fP1; } const RPadPos &GetP2() const { return fP2; } @@ -70,10 +61,10 @@ public: const RAttrFill &AttrFill() const { return fAttrFill; } RAttrFill &AttrFill() { return fAttrFill; } - void SetOnFrame(bool on = true) { fOnFrame = on; } + RBox &SetOnFrame(bool on = true) { fOnFrame = on; return *this; } bool GetOnFrame() const { return fOnFrame; } - void SetClipping(bool on = true) { fClipping = on; } + RBox &SetClipping(bool on = true) { fClipping = on; return *this; } bool GetClipping() const { return fClipping; } }; diff --git a/graf2d/primitivesv7/inc/ROOT/RLine.hxx b/graf2d/primitivesv7/inc/ROOT/RLine.hxx index 7c378beb09baa..6e1d6f5cae031 100644 --- a/graf2d/primitivesv7/inc/ROOT/RLine.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RLine.hxx @@ -40,17 +40,8 @@ public: fP2 = p2; } - RLine &SetP1(const RPadPos &p1) - { - fP1 = p1; - return *this; - } - - RLine &SetP2(const RPadPos &p2) - { - fP2 = p2; - return *this; - } + RLine &SetP1(const RPadPos &p1) { fP1 = p1; return *this; } + RLine &SetP2(const RPadPos &p2) { fP2 = p2; return *this; } const RPadPos &GetP1() const { return fP1; } const RPadPos &GetP2() const { return fP2; } @@ -58,10 +49,10 @@ public: const RAttrLine &AttrLine() const { return fAttrLine; } RAttrLine &AttrLine() { return fAttrLine; } - void SetOnFrame(bool on = true) { fOnFrame = on; } + RLine &SetOnFrame(bool on = true) { fOnFrame = on; return *this; } bool GetOnFrame() const { return fOnFrame; } - void SetClipping(bool on = true) { fClipping = on; } + RLine &SetClipping(bool on = true) { fClipping = on; return *this; } bool GetClipping() const { return fClipping; } }; diff --git a/graf2d/primitivesv7/inc/ROOT/RMarker.hxx b/graf2d/primitivesv7/inc/ROOT/RMarker.hxx index b4031dbec6fb4..da09aaf0219af 100644 --- a/graf2d/primitivesv7/inc/ROOT/RMarker.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RMarker.hxx @@ -38,20 +38,16 @@ public: RMarker(const RPadPos &p) : RMarker() { fP = p; } - RMarker &SetP(const RPadPos &p) - { - fP = p; - return *this; - } + RMarker &SetP(const RPadPos &p) { fP = p; return *this; } const RPadPos &GetP() const { return fP; } const RAttrMarker &AttrMarker() const { return fAttrMarker; } RAttrMarker &AttrMarker() { return fAttrMarker; } - void SetOnFrame(bool on = true) { fOnFrame = on; } + RMarker &SetOnFrame(bool on = true) { fOnFrame = on; return *this; } bool GetOnFrame() const { return fOnFrame; } - void SetClipping(bool on = true) { fClipping = on; } + RMarker &SetClipping(bool on = true) { fClipping = on; return *this; } bool GetClipping() const { return fClipping; } }; diff --git a/graf2d/primitivesv7/inc/ROOT/RText.hxx b/graf2d/primitivesv7/inc/ROOT/RText.hxx index 36ca8e3ddfba2..fe02702282e50 100644 --- a/graf2d/primitivesv7/inc/ROOT/RText.hxx +++ b/graf2d/primitivesv7/inc/ROOT/RText.hxx @@ -46,27 +46,19 @@ public: fPos = p; } - RText &SetText(const std::string &t) - { - fText = t; - return *this; - } + RText &SetText(const std::string &t) { fText = t; return *this; } const std::string &GetText() const { return fText; } - RText &SetPos(const RPadPos &p) - { - fPos = p; - return *this; - } + RText &SetPos(const RPadPos &p) { fPos = p; return *this; } const RPadPos &GetPos() const { return fPos; } const RAttrText &AttrText() const { return fAttrText; } RAttrText &AttrText() { return fAttrText; } - void SetOnFrame(bool on = true) { fOnFrame = on; } + RText &SetOnFrame(bool on = true) { fOnFrame = on; return *this; } bool GetOnFrame() const { return fOnFrame; } - void SetClipping(bool on = true) { fClipping = on; } + RText &SetClipping(bool on = true) { fClipping = on; return *this; } bool GetClipping() const { return fClipping; } }; From 49c57e10eb532e1b08c90a08962a3c6fe8c10d48 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 18:28:28 +0200 Subject: [PATCH 222/309] [rdrawables] improve RPave, let draw errors in RLegend Also fix error in RAttrText handling --- graf2d/gpadv7/inc/ROOT/RAttrText.hxx | 4 +-- graf2d/gpadv7/inc/ROOT/RPave.hxx | 7 +++- graf2d/primitivesv7/inc/ROOT/RLegend.hxx | 42 ++++++++++-------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx index af203229f9c1c..4a82bada4261a 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx @@ -74,8 +74,8 @@ class RAttrText : public RAttrBase { } SetFontFamily(family); - SetFontWeight(style); - SetFontStyle(weight); + SetFontWeight(weight); + SetFontStyle(style); return *this; } diff --git a/graf2d/gpadv7/inc/ROOT/RPave.hxx b/graf2d/gpadv7/inc/ROOT/RPave.hxx index 1ba5d11e61195..d35c610517f29 100644 --- a/graf2d/gpadv7/inc/ROOT/RPave.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPave.hxx @@ -15,6 +15,7 @@ #include #include #include +#include namespace ROOT { namespace Experimental { @@ -38,9 +39,13 @@ class RPave : public RDrawable { RAttrValue fWidth{this, "width", 0.4}; /// fHeight{this, "height", 0.2}; /// fDrawable; ///< reference to RDrawable @@ -84,18 +84,10 @@ public: fLabel = lbl; } - REntry &SetLabel(const std::string &lbl) - { - fLabel = lbl; - return *this; - } + REntry &SetLabel(const std::string &lbl) { fLabel = lbl; return *this; } const std::string &GetLabel() const { return fLabel; } - REntry &SetLine(bool on = true) - { - fLine = on; - return *this; - } + REntry &SetLine(bool on = true) { fLine = on; return *this; } bool GetLine() const { return fLine; } REntry &SetAttrLine(const RAttrLine &attr) @@ -114,11 +106,7 @@ public: return {}; } - REntry &SetFill(bool on = true) - { - fFill = on; - return *this; - } + REntry &SetFill(bool on = true) { fFill = on; return *this; } bool GetFill() const { return fFill; } REntry &SetAttrFill(const RAttrFill &attr) @@ -137,11 +125,7 @@ public: return {}; } - REntry &SetMarker(bool on = true) - { - fMarker = on; - return *this; - } + REntry &SetMarker(bool on = true) { fMarker = on; return *this; } bool GetMarker() const { return fMarker; } REntry &SetAttrMarker(const RAttrMarker &attr) @@ -159,6 +143,9 @@ public: return RAttrMarker(const_cast(fDrawable.get())); return {}; } + + REntry &SetError(bool on = true) { fError = on; return *this; } + bool GetError() const { return fError; } }; private: @@ -206,11 +193,15 @@ public: RLegend(const std::string &title) : RLegend() { SetTitle(title); } - RLegend &SetTitle(const std::string &title) + RLegend(const RPadPos &corner, const RPadExtent &size) : RLegend() { - fTitle = title; - return *this; + SetCornerX(corner.Horiz()); + SetCornerY(corner.Vert()); + SetWidth(size.Horiz()); + SetHeight(size.Vert()); } + + RLegend &SetTitle(const std::string &title) { fTitle = title; return *this; } const std::string &GetTitle() const { return fTitle; } REntry &AddEntry(const std::string &lbl) @@ -219,12 +210,13 @@ public: return fEntries.back(); } - REntry &AddEntry(std::shared_ptr drawable, const std::string &lbl) + REntry &AddEntry(const std::shared_ptr &drawable, const std::string &lbl) { fEntries.emplace_back(drawable, lbl); return fEntries.back(); } + auto NumEntries() const { return fEntries.size(); } auto &GetEntry(int n) { return fEntries[n]; } From a017040538dfbac65de5accbc4caeab9446db0b0 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 18:33:29 +0200 Subject: [PATCH 223/309] [jsroot] dev 15/06/2021 with new v7 features Support new TObjectDrawable functionality Support drawing TH1 inside RFrame New features of RLegend --- js/changes.md | 2 + js/scripts/JSRoot.core.js | 2 +- js/scripts/JSRoot.gpad.js | 8 +- js/scripts/JSRoot.v7gpad.js | 217 +++++++++++++++++++++++++++--------- js/scripts/JSRoot.v7more.js | 20 +++- 5 files changed, 186 insertions(+), 63 deletions(-) diff --git a/js/changes.md b/js/changes.md index 33deb085a5d0a..b008a10d1bbcb 100644 --- a/js/changes.md +++ b/js/changes.md @@ -6,6 +6,8 @@ 3. Remove deprecated JSRootCore.js script, one have to use JSRoot.core.js 4. Upgrade three.js to r127 5. Upgrade d3.js to 6.7.0 +6. Implement "nozoomx" and "nozoomy" draw options for TPad +7. Implement "frame" draw option for TGaxis - fix position of axis relative to the frame ## Changes in 6.1.0 diff --git a/js/scripts/JSRoot.core.js b/js/scripts/JSRoot.core.js index 952cb60158f7d..c5c94e53aca9b 100644 --- a/js/scripts/JSRoot.core.js +++ b/js/scripts/JSRoot.core.js @@ -104,7 +104,7 @@ /** @summary JSROOT version date * @desc Release date in format day/month/year like "14/01/2021"*/ - JSROOT.version_date = "10/06/2021"; + JSROOT.version_date = "15/06/2021"; /** @summary JSROOT version id and date * @desc Produced by concatenation of {@link JSROOT.version_id} and {@link JSROOT.version_date} diff --git a/js/scripts/JSRoot.gpad.js b/js/scripts/JSRoot.gpad.js index dec08e905eba0..d0d9081019451 100644 --- a/js/scripts/JSRoot.gpad.js +++ b/js/scripts/JSRoot.gpad.js @@ -515,7 +515,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if ((res.length > 0) && real_draw) axis_g.append("svg:path").attr("d", res).call(this.lineatt.func); - if ((secondShift!==0) && (res2.length>0) && real_draw) + if ((secondShift !== 0) && (res2.length > 0) && real_draw) axis_g.append("svg:path").attr("d", res2).call(this.lineatt.func); } @@ -666,7 +666,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (is_gaxis) { this.createAttLine({ attr: axis }); - draw_lines = axis.fLineColor != 0; + draw_lines = (axis.fLineColor != 0); chOpt = axis.fChopt; tickSize = axis.fTickSize; scaling_size = vertical ? 1.7*h : 0.6*w; @@ -705,7 +705,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { // optionY = (chOpt.indexOf("Y")>=0), // optionUp = (chOpt.indexOf("0")>=0), // optionDown = (chOpt.indexOf("O")>=0), - optionUnlab = (chOpt.indexOf("U")>=0), // no labels + optionUnlab = (chOpt.indexOf("U")>=0) || this.optionUnlab, // no labels optionNoopt = (chOpt.indexOf("N")>=0), // no ticks position optimization optionInt = (chOpt.indexOf("I")>=0), // integer labels optionNoexp = axis.TestBit(JSROOT.EAxisBits.kNoExponent); @@ -726,7 +726,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { let handle = this.createTicks(false, optionNoexp, optionNoopt, optionInt); - this.drawTicks(axis_g, handle, side, tickSize, ticksPlusMinus, secondShift, draw_lines && !disable_axis_drawing); + this.drawTicks(axis_g, handle, side, tickSize, ticksPlusMinus, secondShift, draw_lines && !disable_axis_drawing && !this.disable_ticks); let labelSize0 = Math.round( (axis.fLabelSize < 1) ? axis.fLabelSize * text_scaling_size : axis.fLabelSize), labeloffset = Math.round(Math.abs(axis.fLabelOffset)*text_scaling_size); diff --git a/js/scripts/JSRoot.v7gpad.js b/js/scripts/JSRoot.v7gpad.js index 9ab7db69fbeab..ad5778826f615 100644 --- a/js/scripts/JSRoot.v7gpad.js +++ b/js/scripts/JSRoot.v7gpad.js @@ -171,13 +171,13 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (!dflts) dflts = {}; else if (typeof dflts == "number") dflts = { size: dflts }; - let text_size = this.v7EvalAttr( name + "_size", dflts.size || 12), - text_angle = this.v7EvalAttr( name + "_angle", 0), - text_align = this.v7EvalAttr( name + "_align", dflts.align || "none"), - text_color = this.v7EvalColor( name + "_color", dflts.color || "none"), - font_family = this.v7EvalAttr( name + "_font_family", "Arial"), - font_style = this.v7EvalAttr( name + "_font_style", ""), - font_weight = this.v7EvalAttr( name + "_font_weight", ""); + let text_size = this.v7EvalAttr(name + "_size", dflts.size || 12), + text_angle = this.v7EvalAttr(name + "_angle", 0), + text_align = this.v7EvalAttr(name + "_align", dflts.align || "none"), + text_color = this.v7EvalColor(name + "_color", dflts.color || "none"), + font_family = this.v7EvalAttr(name + "_font_family", "Arial"), + font_style = this.v7EvalAttr(name + "_font_style", ""), + font_weight = this.v7EvalAttr(name + "_font_weight", ""); if (typeof text_size == "string") text_size = parseFloat(text_size); if (!Number.isFinite(text_size) || (text_size <= 0)) text_size = 12; @@ -1133,6 +1133,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.ticksColor = this.v7EvalColor("ticks_color", ""); this.ticksWidth = this.v7EvalAttr("ticks_width", 1); this.labelsOffset = this.v7EvalLength("labels_offset", this.scaling_size, 0); + this.optionUnlab = this.v7EvalAttr("nolabels", false); this.fTitle = this.v7EvalAttr("title", ""); @@ -1166,8 +1167,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (this.standalone) this.drawMainLine(axis_g); - let optionUnlab = false, // no labels - optionNoopt = false, // no ticks position optimization + let optionNoopt = false, // no ticks position optimization optionInt = false, // integer labels optionNoexp = false; // do not create exp @@ -1176,10 +1176,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { // first draw ticks let tgaps = this.drawTicks(axis_g, side, true); - this.optionUnlab = optionUnlab; - // draw labels - let labelsPromise = optionUnlab ? Promise.resolve(tgaps) : this.drawLabels(axis_g, side, tgaps); + let labelsPromise = this.optionUnlab ? Promise.resolve(tgaps) : this.drawLabels(axis_g, side, tgaps); return labelsPromise.then(lgaps => { // when drawing axis on frame, zoom rect should be always outside @@ -1705,6 +1703,86 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { } } + /** @summary Create x,y objects which maps user coordinates into pixels + * @desc Must be used only for v6 objects, see TFramePainter for more details + * @private */ + RFramePainter.prototype.createXY = function(opts) { + + this.cleanXY(); // remove all previous configurations + + if (!opts) opts = {}; + + this.v6axes = true; + this.swap_xy = opts.swap_xy || false; + this.reverse_x = opts.reverse_x || false; + this.reverse_y = opts.reverse_y || false; + + this.logx = this.v7EvalAttr("x_log", 0); + this.logy = this.v7EvalAttr("y_log", 0); + + let w = this.getFrameWidth(), h = this.getFrameHeight(); + + this.scale_xmin = this.xmin; + this.scale_xmax = this.xmax; + + this.scale_ymin = this.ymin; + this.scale_ymax = this.ymax; + + if (opts.extra_y_space) { + let log_scale = this.swap_xy ? this.logx : this.logy; + if (log_scale && (this.scale_ymax > 0)) + this.scale_ymax = Math.exp(Math.log(this.scale_ymax)*1.1); + else + this.scale_ymax += (this.scale_ymax - this.scale_ymin)*0.1; + } + + if (opts.check_pad_range) { + // take zooming out of pad or axis attributes - skip! + } + + if ((this.zoom_ymin == this.zoom_ymax) && (opts.zoom_ymin != opts.zoom_ymax) && !this.zoomChangedInteractive("y")) { + this.zoom_ymin = opts.zoom_ymin; + this.zoom_ymax = opts.zoom_ymax; + } + + if (this.zoom_xmin != this.zoom_xmax) { + this.scale_xmin = this.zoom_xmin; + this.scale_xmax = this.zoom_xmax; + } + + if (this.zoom_ymin != this.zoom_ymax) { + this.scale_ymin = this.zoom_ymin; + this.scale_ymax = this.zoom_ymax; + } + + this.x_handle = new JSROOT.TAxisPainter(this.getDom(), this.xaxis, true); + this.x_handle.setPadName(this.getPadName()); + this.x_handle.optionUnlab = this.v7EvalAttr("x_nolabels", false); + + this.x_handle.configureAxis("xaxis", this.xmin, this.xmax, this.scale_xmin, this.scale_xmax, this.swap_xy, this.swap_xy ? [0,h] : [0,w], + { reverse: this.reverse_x, + log: this.swap_xy ? this.logy : this.logx, + symlog: this.swap_xy ? opts.symlog_y : opts.symlog_x, + logcheckmin: this.swap_xy, + logminfactor: 0.0001 }); + + this.x_handle.assignFrameMembers(this,"x"); + + this.y_handle = new JSROOT.TAxisPainter(this.getDom(), this.yaxis, true); + this.y_handle.setPadName(this.getPadName()); + this.y_handle.optionUnlab = this.v7EvalAttr("y_nolabels", false); + + this.y_handle.configureAxis("yaxis", this.ymin, this.ymax, this.scale_ymin, this.scale_ymax, !this.swap_xy, this.swap_xy ? [0,w] : [0,h], + { reverse: this.reverse_y, + log: this.swap_xy ? this.logx : this.logy, + symlog: this.swap_xy ? opts.symlog_x : opts.symlog_y, + logcheckmin: (opts.ndim < 2) || this.swap_xy, + log_min_nz: opts.ymin_nz && (opts.ymin_nz < 0.01*this.ymax) ? 0.3 * opts.ymin_nz : 0, + logminfactor: 3e-4 }); + + this.y_handle.assignFrameMembers(this,"y"); + } + /** @summary Identify if requested axes are drawn * @desc Checks if x/y axes are drawn. Also if second side is already there */ RFramePainter.prototype.hasDrawnAxes = function(second_x, second_y) { @@ -1715,12 +1793,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { * @desc axes can be drawn only for main histogram */ RFramePainter.prototype.drawAxes = function() { - if (this.axes_drawn || (this.xmin==this.xmax) || (this.ymin==this.ymax)) + if (this.axes_drawn || (this.xmin == this.xmax) || (this.ymin == this.ymax)) return Promise.resolve(this.axes_drawn); - this.cleanupAxes(); - - this.swap_xy = false; let ticksx = this.v7EvalAttr("ticksx", 1), ticksy = this.v7EvalAttr("ticksy", 1), sidex = 1, sidey = 1; @@ -1730,48 +1805,56 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { let w = this.getFrameWidth(), h = this.getFrameHeight(); - if (this.zoom_xmin != this.zoom_xmax) { - this.scale_xmin = this.zoom_xmin; - this.scale_xmax = this.zoom_xmax; - } else { - this.scale_xmin = this.xmin; - this.scale_xmax = this.xmax; - } + if (!this.v6axes) { + // this is partially same as v6 createXY method - if (this.zoom_ymin != this.zoom_ymax) { - this.scale_ymin = this.zoom_ymin; - this.scale_ymax = this.zoom_ymax; - } else { - this.scale_ymin = this.ymin; - this.scale_ymax = this.ymax; - } + this.cleanupAxes(); - this.recalculateRange(0); + this.swap_xy = false; - this.x_handle = new RAxisPainter(this.getDom(), this, this.xaxis, "x_"); - this.x_handle.setPadName(this.getPadName()); - this.x_handle.snapid = this.snapid; - this.x_handle.draw_swapside = (sidex < 0); - this.x_handle.draw_ticks = ticksx; + if (this.zoom_xmin != this.zoom_xmax) { + this.scale_xmin = this.zoom_xmin; + this.scale_xmax = this.zoom_xmax; + } else { + this.scale_xmin = this.xmin; + this.scale_xmax = this.xmax; + } - this.y_handle = new RAxisPainter(this.getDom(), this, this.yaxis, "y_"); - this.y_handle.setPadName(this.getPadName()); - this.y_handle.snapid = this.snapid; - this.y_handle.draw_swapside = (sidey < 0); - this.y_handle.draw_ticks = ticksy; + if (this.zoom_ymin != this.zoom_ymax) { + this.scale_ymin = this.zoom_ymin; + this.scale_ymax = this.zoom_ymax; + } else { + this.scale_ymin = this.ymin; + this.scale_ymax = this.ymax; + } - this.z_handle = new RAxisPainter(this.getDom(), this, this.zaxis, "z_"); - this.z_handle.setPadName(this.getPadName()); - this.z_handle.snapid = this.snapid; + this.recalculateRange(0); - this.x_handle.configureAxis("xaxis", this.xmin, this.xmax, this.scale_xmin, this.scale_xmax, false, [0,w], w, { reverse: false }); - this.x_handle.assignFrameMembers(this,"x"); + this.x_handle = new RAxisPainter(this.getDom(), this, this.xaxis, "x_"); + this.x_handle.setPadName(this.getPadName()); + this.x_handle.snapid = this.snapid; + this.x_handle.draw_swapside = (sidex < 0); + this.x_handle.draw_ticks = ticksx; - this.y_handle.configureAxis("yaxis", this.ymin, this.ymax, this.scale_ymin, this.scale_ymax, true, [h,0], -h, { reverse: false }); - this.y_handle.assignFrameMembers(this,"y"); + this.y_handle = new RAxisPainter(this.getDom(), this, this.yaxis, "y_"); + this.y_handle.setPadName(this.getPadName()); + this.y_handle.snapid = this.snapid; + this.y_handle.draw_swapside = (sidey < 0); + this.y_handle.draw_ticks = ticksy; + + this.z_handle = new RAxisPainter(this.getDom(), this, this.zaxis, "z_"); + this.z_handle.setPadName(this.getPadName()); + this.z_handle.snapid = this.snapid; + + this.x_handle.configureAxis("xaxis", this.xmin, this.xmax, this.scale_xmin, this.scale_xmax, false, [0,w], w, { reverse: false }); + this.x_handle.assignFrameMembers(this,"x"); + + this.y_handle.configureAxis("yaxis", this.ymin, this.ymax, this.scale_ymin, this.scale_ymax, true, [h,0], -h, { reverse: false }); + this.y_handle.assignFrameMembers(this,"y"); - // only get basic properties like log scale - this.z_handle.configureZAxis("zaxis", this); + // only get basic properties like log scale + this.z_handle.configureZAxis("zaxis", this); + } let layer = this.getFrameSvg().select(".axis_layer"); @@ -1783,6 +1866,27 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { if (pp && pp._fast_drawing) { draw_promise = Promise.resolve(true) + } else if (this.v6axes) { + + // in v7 ticksx/y values shifted by 1 relative to v6 + // In v7 ticksx==0 means no ticks, ticksx==1 equivalent to ==0 in v6 + + let can_adjust_frame = false, disable_x_draw = false, disable_y_draw = false; + + draw_horiz.disable_ticks = (ticksx <= 0); + draw_vertical.disable_ticks = (ticksy <= 0); + + let promise1 = draw_horiz.drawAxis(layer, w, h, + draw_horiz.invert_side ? undefined : `translate(0,${h})`, + (ticksx > 1) ? -h : 0, disable_x_draw, + undefined, false); + + let promise2 = draw_vertical.drawAxis(layer, w, h, + draw_vertical.invert_side ? `translate(${w},0)` : undefined, + (ticksy > 1) ? w : 0, disable_y_draw, + draw_vertical.invert_side ? 0 : this._frame_x, can_adjust_frame); + draw_promise = Promise.all([promise1, promise2]).then(() => this.drawGrids()); + } else { let promise1 = (ticksx > 0) ? draw_horiz.drawAxis(layer, (sidex > 0) ? `translate(0,${h})` : "", sidex) : true; @@ -1904,8 +2008,9 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.redrawPad(); } - /** @summary Remove all axes drawings */ - RFramePainter.prototype.cleanupAxes = function() { + /** @summary Remove all x/y functions + * @private */ + RFramePainter.prototype.cleanXY = function() { // remove all axes drawings let clean = (name,grname) => { if (this[name]) { @@ -1921,6 +2026,14 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { clean("x2_handle", "grx2"); clean("y2_handle", "gry2"); + delete this.v6axes; // marker that v6 axes are used + } + + /** @summary Remove all axes drawings + * @private */ + RFramePainter.prototype.cleanupAxes = function() { + this.cleanXY(); + if (this.draw_g) { this.draw_g.select(".grid_layer").selectAll("*").remove(); this.draw_g.select(".axis_layer").selectAll("*").remove(); diff --git a/js/scripts/JSRoot.v7more.js b/js/scripts/JSRoot.v7more.js index 73d8e7d442309..ef46dcb1e2786 100644 --- a/js/scripts/JSRoot.v7more.js +++ b/js/scripts/JSRoot.v7more.js @@ -112,7 +112,7 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { function drawLegendContent() { let legend = this.getObject(), - textFont = this.v7EvalFont("legend_text", { size: 12, color: "black", align: 22 }), + textFont = this.v7EvalFont("text", { size: 12, color: "black", align: 22 }), width = this.pave_width, height = this.pave_height, nlines = legend.fEntries.length, @@ -128,12 +128,11 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { this.startTextDrawing(textFont, 'font' ); if (legend.fTitle) { - this.drawText({ align: 22, latex: 1, - width: width - 2*margin_x, height: stepy, x: margin_x, y: posy, text: legend.fTitle }); + this.drawText({ latex: 1, width: width - 2*margin_x, height: stepy, x: margin_x, y: posy, text: legend.fTitle }); posy += stepy; } - for (let i=0; i { .attr("y2", Math.round(posy + stepy/2)) .call(objp.lineatt.func); + if (objp && entry.fError && objp.lineatt) + this.draw_g + .append("svg:line") + .attr("x1", Math.round(margin_x + width/8)) + .attr("y1", Math.round(posy + stepy*0.2)) + .attr("x2", Math.round(margin_x + width/8)) + .attr("y2", Math.round(posy + stepy*0.8)) + .call(objp.lineatt.func); + if (objp && entry.fMarker && objp.markeratt) this.draw_g.append("svg:path") .attr("d", objp.markeratt.create(margin_x + width/8, posy + stepy/2)) @@ -188,7 +196,7 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { function drawPaveTextContent() { let pavetext = this.getObject(), - textFont = this.v7EvalFont("pavetext_text", { size: 12, color: "black", align: 22 }), + textFont = this.v7EvalFont("text", { size: 12, color: "black", align: 22 }), width = this.pave_width, height = this.pave_height, nlines = pavetext.fText.length; @@ -201,7 +209,7 @@ JSROOT.define(['painter', 'v7gpad'], (jsrp) => { this.startTextDrawing(textFont, 'font'); - for (let i=0; i < pavetext.fText.length; ++i) { + for (let i = 0; i < pavetext.fText.length; ++i) { let line = pavetext.fText[i]; this.drawText({ latex: 1, width: width - 2*margin_x, height: stepy, x: margin_x, y: posy, text: line }); From 124b82898bcb6803138c117caf2366666ab193d3 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 15 Jun 2021 18:40:46 +0200 Subject: [PATCH 224/309] [tutorials] add first PyROOT tutorials for ROOT7 graphics box.py is replica of box.cxx with PyROOT interface df104.py if replica of dataframe/df104_HiggsToTwoPhotons.py --- tutorials/CMakeLists.txt | 3 +- tutorials/launcher.py | 1 + tutorials/v7/box.cxx | 11 +- tutorials/v7/box.py | 41 +++++++ tutorials/v7/df104.py | 226 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 274 insertions(+), 8 deletions(-) create mode 100644 tutorials/v7/box.py create mode 100644 tutorials/v7/df104.py diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index 857b433ca0afc..d6835d0b00ba6 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -279,6 +279,7 @@ if(root7) v7/filedialog.cxx v7/fitpanel.cxx v7/fitpanel6.cxx + v7/df104.py ) if(NOT davix) list(APPEND root7_veto v7/ntuple/ntpl003_lhcbOpenData.C) @@ -290,7 +291,7 @@ if(root7) list(APPEND root7_veto v7/ntuple/ntpl004_dimuon.C) endif() else() - file(GLOB v7_veto_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ v7/*.cxx v7/*/*.cxx v7/*.C v7/*/*.C) + file(GLOB v7_veto_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ v7/*.py v7/*.cxx v7/*/*.cxx v7/*.C v7/*/*.C) list(APPEND root7_veto ${v7_veto_files}) endif() diff --git a/tutorials/launcher.py b/tutorials/launcher.py index fb61ff29ed461..18456250e03bd 100644 --- a/tutorials/launcher.py +++ b/tutorials/launcher.py @@ -20,6 +20,7 @@ # Ensure batch mode (some tutorials use graphics) import ROOT ROOT.gROOT.SetBatch(True) + ROOT.gROOT.SetWebDisplay("batch") # Prevent import from generating .pyc files in source directory sys.dont_write_bytecode = True diff --git a/tutorials/v7/box.cxx b/tutorials/v7/box.cxx index 786a6978faff7..202b9eb68e44a 100644 --- a/tutorials/v7/box.cxx +++ b/tutorials/v7/box.cxx @@ -26,15 +26,12 @@ void box() auto canvas = RCanvas::Create("RBox drawing"); auto box1 = canvas->Draw(RPadPos(0.1_normal, 0.3_normal), RPadPos(0.3_normal,0.6_normal)); - RColor Color1(0, 255, 0, 0.5); // 50% opaque - RColor Color2(0, 0, 255, 0.7); // 70% opaque - - box1->AttrBorder().SetColor(Color1).SetWidth(5); - box1->AttrFill().SetColor(RColor::kRed); + box1->AttrBorder().SetColor(RColor::kBlue).SetWidth(5); + box1->AttrFill().SetColor(RColor(0, 255, 0, 127)); // 50% opaque auto box2 = canvas->Draw(RPadPos(0.4_normal, 0.2_normal), RPadPos(0.6_normal,0.7_normal)); - box2->AttrBorder().SetColor(Color2).SetStyle(2).SetWidth(10); - box2->AttrFill().SetColor(RColor::kGreen); + box2->AttrBorder().SetColor(RColor::kRed).SetStyle(2).SetWidth(10); + box2->AttrFill().SetColor(RColor(0, 0, 255, 179)); // 70% opaque auto box3 = canvas->Draw(RPadPos(0.7_normal, 0.4_normal), RPadPos(0.9_normal,0.6_normal)); box3->AttrBorder().SetWidth(3); diff --git a/tutorials/v7/box.py b/tutorials/v7/box.py new file mode 100644 index 0000000000000..c1d29829f94b3 --- /dev/null +++ b/tutorials/v7/box.py @@ -0,0 +1,41 @@ +## \file +## \ingroup tutorial_v7 +## +## This ROOT 7 example demonstrates how to create a ROOT 7 canvas (RCanvas) and +## draw ROOT 7 boxes in it (RBox). It generates a set of boxes using the +## "normal" coordinates' system. +## Run macro with python3 -i box.py command to get interactive canvas +## +## \macro_image (rcanvas_js) +## \macro_code +## +## \date 2021-06-15 +## \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback +## is welcome! +## \author Sergey Linev + +import ROOT +from ROOT.Experimental import RCanvas, RBox, RPadPos, RColor + +# Create a canvas to be displayed. +canvas = RCanvas.Create("RBox drawing") + +box1 = canvas.Draw[RBox](RPadPos(0.1, 0.1), RPadPos(0.3, 0.6)) +box1.AttrBorder().SetColor(RColor.kBlue).SetWidth(5) +box1.AttrFill().SetColor(RColor(0, 255, 0, 127)) # 50% opaque + +box2 = canvas.Draw[RBox](RPadPos(0.4, 0.2), RPadPos(0.6, 0.7)) +box2.AttrBorder().SetColor(RColor.kRed).SetStyle(2).SetWidth(10) +box2.AttrFill().SetColor(RColor(0, 0, 255, 179)) # 70% opaque + +box3 = canvas.Draw[RBox](RPadPos(0.7, 0.4), RPadPos(0.9, 0.6)) +box3.AttrBorder().SetWidth(3) +box3.AttrFill().SetColor(RColor.kBlue) + +box4 = canvas.Draw[RBox](RPadPos(0.7, 0.7), RPadPos(0.9, 0.9)) +box4.AttrBorder().SetWidth(4) + +box5 = canvas.Draw[RBox](RPadPos(0.7, 0.1), RPadPos(0.9, 0.3)) +box5.AttrBorder().SetRx(10).SetRy(10).SetWidth(2) + +canvas.Show() diff --git a/tutorials/v7/df104.py b/tutorials/v7/df104.py new file mode 100644 index 0000000000000..31c38139940e5 --- /dev/null +++ b/tutorials/v7/df104.py @@ -0,0 +1,226 @@ +## \file +## \ingroup tutorial_v7 +## The Higgs to two photons analysis from the ATLAS Open Data 2020 release, with RDataFrame. +## +## This tutorial is the Higgs to two photons analysis from the ATLAS Open Data release in 2020 +## (http://opendata.atlas.cern/release/2020/documentation/). The data was taken with the ATLAS detector +## during 2016 at a center-of-mass energy of 13 TeV. Although the Higgs to two photons decay is very rare, +## the contribution of the Higgs can be seen as a narrow peak around 125 GeV because of the excellent +## reconstruction and identification efficiency of photons at the ATLAS experiment. +## +## The analysis is translated to a RDataFrame workflow processing 1.7 GB of simulated events and data. +## +## This macro is replica of tutorials/dataframe/df104_HiggsToTwoPhotons.py, but with usage of ROOT7 graphics +## Run macro with python3 -i df104.py command to get interactive canvas +## +## \macro_image (rcanvas_js) +## \macro_code +## +## \date 2021-06-15 +## \authors Stefan Wunsch (KIT, CERN) Sergey Linev (GSI) + +import ROOT +import os +from ROOT.Experimental import RCanvas, RPad, RText, RLegend, RPadPos, RPadExtent, TObjectDrawable + +# Enable multi-threading +ROOT.ROOT.EnableImplicitMT() + +# Create a ROOT dataframe for each dataset +path = "root://eospublic.cern.ch//eos/opendata/atlas/OutreachDatasets/2020-01-22" +df = {} +df["data"] = ROOT.RDataFrame("mini", (os.path.join(path, "GamGam/Data/data_{}.GamGam.root".format(x)) for x in ("A", "B", "C", "D"))) +df["ggH"] = ROOT.RDataFrame("mini", os.path.join(path, "GamGam/MC/mc_343981.ggH125_gamgam.GamGam.root")) +df["VBF"] = ROOT.RDataFrame("mini", os.path.join(path, "GamGam/MC/mc_345041.VBFH125_gamgam.GamGam.root")) +processes = list(df.keys()) + +# Apply scale factors and MC weight for simulated events and a weight of 1 for the data +for p in ["ggH", "VBF"]: + df[p] = df[p].Define("weight", + "scaleFactor_PHOTON * scaleFactor_PhotonTRIGGER * scaleFactor_PILEUP * mcWeight"); +df["data"] = df["data"].Define("weight", "1.0") + +# Select the events for the analysis +for p in processes: + # Apply preselection cut on photon trigger + df[p] = df[p].Filter("trigP") + + # Find two good muons with tight ID, pt > 25 GeV and not in the transition region between barrel and encap + df[p] = df[p].Define("goodphotons", "photon_isTightID && (photon_pt > 25000) && (abs(photon_eta) < 2.37) && ((abs(photon_eta) < 1.37) || (abs(photon_eta) > 1.52))")\ + .Filter("Sum(goodphotons) == 2") + + # Take only isolated photons + df[p] = df[p].Filter("Sum(photon_ptcone30[goodphotons] / photon_pt[goodphotons] < 0.065) == 2")\ + .Filter("Sum(photon_etcone20[goodphotons] / photon_pt[goodphotons] < 0.065) == 2") + +# Compile a function to compute the invariant mass of the diphoton system +ROOT.gInterpreter.Declare( +""" +using Vec_t = const ROOT::VecOps::RVec; +float ComputeInvariantMass(Vec_t& pt, Vec_t& eta, Vec_t& phi, Vec_t& e) { + ROOT::Math::PtEtaPhiEVector p1(pt[0], eta[0], phi[0], e[0]); + ROOT::Math::PtEtaPhiEVector p2(pt[1], eta[1], phi[1], e[1]); + return (p1 + p2).mass() / 1000.0; +} +""") + +# Define a new column with the invariant mass and perform final event selection +hists = {} +for p in processes: + # Make four vectors and compute invariant mass + df[p] = df[p].Define("m_yy", "ComputeInvariantMass(photon_pt[goodphotons], photon_eta[goodphotons], photon_phi[goodphotons], photon_E[goodphotons])") + + # Make additional kinematic cuts and select mass window + df[p] = df[p].Filter("photon_pt[goodphotons][0] / 1000.0 / m_yy > 0.35")\ + .Filter("photon_pt[goodphotons][1] / 1000.0 / m_yy > 0.25")\ + .Filter("m_yy > 105 && m_yy < 160") + + # Book histogram of the invariant mass with this selection + hists[p] = df[p].Histo1D( + ROOT.RDF.TH1DModel(p, "Diphoton invariant mass; m_{#gamma#gamma} [GeV];Events", 30, 105, 160), + "m_yy", "weight") + +# Run the event loop + +# RunGraphs allows to run the event loops of the separate RDataFrame graphs +# concurrently. This results in an improved usage of the available resources +# if each separate RDataFrame can not utilize all available resources, e.g., +# because not enough data is available. +ROOT.RDF.RunGraphs([hists[s] for s in ["ggH", "VBF", "data"]]) + +ggh = hists["ggH"].GetValue() +vbf = hists["VBF"].GetValue() +data = hists["data"].GetValue() + +# Create the plot + +# Set styles - not yet available for v7 +# ROOT.gROOT.SetStyle("ATLAS") + +# Create canvas with pads for main plot and data/MC ratio +c = RCanvas.Create("df104_HiggsToTwoPhotons") + +lower_pad = c.Draw[RPad](RPadPos(0,0.65), RPadExtent(1, 0.35)) +upper_pad = c.Draw[RPad](RPadPos(0,0), RPadExtent(1, 0.65)) + +upper_frame = upper_pad.GetOrCreateFrame() +upper_frame.AttrMargins().SetBottom(0).SetLeft(0.14).SetRight(0.05) +upper_frame.AttrX().SetNoLabels() + +lower_frame = lower_pad.GetOrCreateFrame() +lower_frame.AttrMargins().SetTop(0).SetLeft(0.14).SetRight(0.05).SetBottom(0.3) + +# Fit signal + background model to data +fit = ROOT.TF1("fit", "([0]+[1]*x+[2]*x^2+[3]*x^3)+[4]*exp(-0.5*((x-[5])/[6])^2)", 105, 160) +fit.FixParameter(5, 125.0) +fit.FixParameter(4, 119.1) +fit.FixParameter(6, 2.39) +fit.SetLineColor(2) +fit.SetLineStyle(1) +fit.SetLineWidth(2) +# do not draw fit function +data.Fit("fit", "0", "", 105, 160) + +# Draw data +data.SetMarkerStyle(20) +data.SetMarkerSize(1.2) +data.SetLineWidth(2) +data.SetLineColor(ROOT.kBlack) +data.SetMinimum(1e-3) +data.SetMaximum(8e3) +data.GetYaxis().SetLabelSize(0.045) +data.GetYaxis().SetTitleSize(0.05) +data.SetStats(0) +data.SetTitle("") + +data_drawable = upper_pad.Draw[TObjectDrawable](data, "E") + +# Draw fit +fit_drawable = upper_pad.Draw[TObjectDrawable](fit, "SAME") + +# Draw background +bkg = ROOT.TF1("bkg", "([0]+[1]*x+[2]*x^2+[3]*x^3)", 105, 160) +for i in range(4): + bkg.SetParameter(i, fit.GetParameter(i)) +bkg.SetLineColor(4) +bkg.SetLineStyle(2) +bkg.SetLineWidth(2) +bkg_drawable = upper_pad.Draw[TObjectDrawable](bkg, "SAME") + +# Scale simulated events with luminosity * cross-section / sum of weights +# and merge to single Higgs signal +lumi = 10064.0 +ggh.Scale(lumi * 0.102 / 55922617.6297) +vbf.Scale(lumi * 0.008518764 / 3441426.13711) +higgs = ggh.Clone() +higgs.Add(vbf) +higgs_drawable = upper_pad.Draw[TObjectDrawable](higgs, "HIST SAME") + + +# Draw ratio + +ratiobkg = ROOT.TH1I("zero", "", 10, 105, 160) +ratiobkg.SetLineColor(4) +ratiobkg.SetLineStyle(2) +ratiobkg.SetLineWidth(2) +ratiobkg.SetMinimum(-125) +ratiobkg.SetMaximum(250) +ratiobkg.GetXaxis().SetLabelSize(0.08) +ratiobkg.GetXaxis().SetTitleSize(0.12) +ratiobkg.GetXaxis().SetTitleOffset(1.0) +ratiobkg.GetYaxis().SetLabelSize(0.08) +ratiobkg.GetYaxis().SetTitleSize(0.09) +ratiobkg.GetYaxis().SetTitle("Data - Bkg.") +ratiobkg.GetYaxis().CenterTitle() +ratiobkg.GetYaxis().SetTitleOffset(0.7) +ratiobkg.GetYaxis().SetNdivisions(503, False) +ratiobkg.GetYaxis().ChangeLabel(-1, -1, 0) +ratiobkg.GetXaxis().SetTitle("m_{#gamma#gamma} [GeV]") +lower_pad.Draw[TObjectDrawable](ratiobkg, "AXIS") + +ratiosig = ROOT.TH1F("ratiosig", "ratiosig", 5500, 105, 160) +ratiosig.Eval(fit) +ratiosig.SetLineColor(2) +ratiosig.SetLineStyle(1) +ratiosig.SetLineWidth(2) +ratiosig.Add(bkg, -1) +lower_pad.Draw[TObjectDrawable](ratiosig, "SAME") + +ratiodata = data.Clone() +ratiodata.Add(bkg, -1) +for i in range(1, data.GetNbinsX()): + ratiodata.SetBinError(i, data.GetBinError(i)) + +lower_pad.Draw[TObjectDrawable](ratiodata, "E SAME") + +# Add legend +# legend.SetTextFont(42) +# legend.SetFillStyle(0) +# legend.SetBorderSize(0) +# legend.SetTextSize(0.05) +# legend.SetTextAlign(32) + +legend = upper_pad.Draw[RLegend](RPadPos(-0.05, 0.05), RPadExtent(0.3, 0.4)) +legend.AttrText().SetFont(4).SetSize(0.05).SetAlign(32) +legend.AttrBorder().SetStyle(0).SetWidth(0) +legend.AttrFill().SetStyle(0) + +legend.AddEntry(data_drawable, "Data") +legend.AddEntry(bkg_drawable, "Background") +legend.AddEntry(fit_drawable, "Signal + Bkg.") +legend.AddEntry(higgs_drawable, "Signal") + +# Add ATLAS label +upper_pad.Draw[RText](RPadPos(0.05, 0.88), "ATLAS").SetOnFrame().AttrText().SetFont(7).SetSize(0.05).SetAlign(11) + +upper_pad.Draw[RText](RPadPos(0.05 + 0.16, 0.88), "Open Data").SetOnFrame().AttrText().SetFont(4).SetSize(0.05).SetAlign(11) + +upper_pad.Draw[RText](RPadPos(0.05, 0.82), "#sqrt{s} = 13 TeV, 10 fb^{-1}").SetOnFrame().AttrText().SetFont(4).SetSize(0.04).SetAlign(11) + +# show canvas finally +c.SetSize(700, 780) +c.Show() + +# Save plot in PNG file +c.SaveAs("df104.png") +print("Saved figure to df104.png") From db144a46d111418d64d2b740a6080d66d7f2dcc7 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 16 Jun 2021 09:46:47 +0200 Subject: [PATCH 225/309] [rdrawable] specially handle TF1 object in TObjectDrawable While any new TF1 object automatically registered in global lists, one should immediately unregister it --- graf2d/gpadv7/src/TObjectDrawable.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 1a8992a9d9d25..239971bf602d4 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -30,13 +30,16 @@ using namespace ROOT::Experimental; //////////////////////////////////////////////////////////////////// -/// Checks object ownership - used for TH1 directory handling +/// Checks object ownership - used for TH1 directory handling and TF1 globals lists void TObjectDrawable::CheckOwnership(TObject *obj) { if (obj && obj->InheritsFrom("TH1")) { TMethodCall call(obj->IsA(), "SetDirectory", "nullptr"); call.Execute((void *)(obj)); + } else if (obj && obj->InheritsFrom("TF1")) { + TMethodCall call(obj->IsA(), "AddToGlobalList", "kFALSE"); + call.Execute((void *)(obj)); } } From 5e2fa07be56df6bf4d436fe29032350410ab6d21 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 16 Jun 2021 12:00:58 +0200 Subject: [PATCH 226/309] [rpad] do not try to oprimize dynamic_cast in RPadBase methods --- graf2d/gpadv7/src/RPadBase.cxx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/graf2d/gpadv7/src/RPadBase.cxx b/graf2d/gpadv7/src/RPadBase.cxx index d436c811755de..9b9ee249875d6 100644 --- a/graf2d/gpadv7/src/RPadBase.cxx +++ b/graf2d/gpadv7/src/RPadBase.cxx @@ -39,10 +39,8 @@ void RPadBase::UseStyle(const std::shared_ptr &style) void RPadBase::AddPrimitive(std::shared_ptr drawable) { - if (drawable->GetCssType() == "pad") { - auto pad = dynamic_cast(drawable.get()); - if (pad) pad->SetParent(this); - } + if (auto pad = dynamic_cast(drawable.get())) + pad->SetParent(this); fPrimitives.emplace_back(drawable); } @@ -201,10 +199,8 @@ std::shared_ptr RPadBase::GetOrCreateFrame() const std::shared_ptr RPadBase::GetFrame() const { for (auto &drawable : fPrimitives) { - if (drawable->GetCssType() == "frame") { - const std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared()); - if (frame) return frame; - } + if (const std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared())) + return frame; } return nullptr; } @@ -215,10 +211,8 @@ const std::shared_ptr RPadBase::GetFrame() const std::shared_ptr RPadBase::GetFrame() { for (auto &drawable : fPrimitives) { - if (drawable->GetCssType() == "frame") { - std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared()); - if (frame) return frame; - } + if (std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared())) + return frame; } return nullptr; } From 897256beb81c4b6f1bac391e2ac06e4539340dad Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 16 Jun 2021 15:00:02 +0200 Subject: [PATCH 227/309] [rdrawable] adjust TObjectDrawable internal methods --- graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx | 2 +- graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 6 +++--- graf2d/gpadv7/src/TObjectDrawable.cxx | 20 ++++++++----------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx index bb8f9d054dc0c..96c2e3861bfc9 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDisplayItem.hxx @@ -63,7 +63,7 @@ public: if (fOwner) delete fObject; } - void AddColor(int color_indx, const std::string &color_value) + void UpdateColor(int color_indx, const std::string &color_value) { auto pos = std::find(fColIndex.begin(), fColIndex.end(), color_indx); if (pos == fColIndex.end()) { diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index 16a42b510f950..abe4fd43c6ad4 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -50,7 +50,7 @@ private: RAttrText fAttrText{this, "text"}; /// CreateSpecials(int kind); @@ -80,8 +80,8 @@ public: kPalette = 6 ///< list of colors from palette }; - TObjectDrawable(TObject &obj); - TObjectDrawable(TObject &obj, const std::string &opt); + TObjectDrawable(const TObject &obj); + TObjectDrawable(const TObject &obj, const std::string &opt); TObjectDrawable(TObject *obj); TObjectDrawable(TObject *obj, const std::string &opt); TObjectDrawable(const std::shared_ptr &obj); diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 239971bf602d4..313aab3c18dcb 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -63,7 +63,7 @@ std::string TObjectDrawable::DetectCssType(const TObject *obj) //////////////////////////////////////////////////////////////////// /// Constructor, clones TObject instance -TObjectDrawable::TObjectDrawable(TObject &obj) : RDrawable(DetectCssType(&obj)) +TObjectDrawable::TObjectDrawable(const TObject &obj) : RDrawable(DetectCssType(&obj)) { fKind = kObject; auto clone = obj.Clone(); @@ -74,7 +74,7 @@ TObjectDrawable::TObjectDrawable(TObject &obj) : RDrawable(DetectCssType(&obj)) //////////////////////////////////////////////////////////////////// /// Constructor, clones TObject instance -TObjectDrawable::TObjectDrawable(TObject &obj, const std::string &opt) : TObjectDrawable(obj) +TObjectDrawable::TObjectDrawable(const TObject &obj, const std::string &opt) : TObjectDrawable(obj) { SetOpt(opt); } @@ -103,7 +103,7 @@ TObjectDrawable::TObjectDrawable(TObject *obj, const std::string &opt) : TObject TObjectDrawable::TObjectDrawable(const std::shared_ptr &obj) : RDrawable(DetectCssType(obj.get())) { fKind = kObject; - CheckOwnership(fObj.get()); + CheckOwnership(obj.get()); fObj = obj; } @@ -136,17 +136,13 @@ TObjectDrawable::~TObjectDrawable() = default; //////////////////////////////////////////////////////////////////// /// Convert TColor to RGB string for using with SVG -const char *TObjectDrawable::GetColorCode(TColor *col) +std::string TObjectDrawable::GetColorCode(TColor *col) { - static std::string code; - RColor rcol((uint8_t) (255*col->GetRed()), (uint8_t) (255*col->GetGreen()), (uint8_t) (255*col->GetBlue())); if (col->GetAlpha() != 1) rcol.SetAlphaFloat(col->GetAlpha()); - code = rcol.AsSVG(); - - return code.c_str(); + return rcol.AsSVG(); } //////////////////////////////////////////////////////////////////// @@ -164,7 +160,7 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) for (int n = 0; n <= cols->GetLast(); ++n) { auto col = dynamic_cast(cols->At(n)); if (!col) continue; - auto code = TString::Format("%d=%s", n, GetColorCode(col)); + auto code = TString::Format("%d=%s", n, GetColorCode(col).c_str()); arr->Add(new TObjString(code)); } @@ -181,7 +177,7 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) auto palette = TColor::GetPalette(); for (int n = 0; n < palette.GetSize(); ++n) { auto col = gROOT->GetColor(palette[n]); - arr->Add(new TObjString(GetColorCode(col))); + arr->Add(new TObjString(GetColorCode(col).c_str())); } return arr; @@ -208,7 +204,7 @@ void TObjectDrawable::ExtractObjectColors(std::unique_ptr &i if (*icol < 10) return; TColor *col = gROOT->GetColor(*icol); - if (col) item->AddColor(*icol, col->AsHexString()); + if (col) item->UpdateColor(*icol, GetColorCode(col)); }; ExtractColor("TAttLine", "fLineColor"); From 7a96014a3156f71f51d8a509ceea5b055a3f7de8 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 16 Jun 2021 15:14:42 +0200 Subject: [PATCH 228/309] [rdrawable] rename nolabels -> hidelabels in RAttrAxis --- graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx | 6 +++--- js/scripts/JSRoot.v7gpad.js | 6 +++--- tutorials/v7/df104.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx index 9200fa6e0adb7..5d4b4c72fa7bc 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx @@ -46,7 +46,7 @@ class RAttrAxis : public RAttrBase { RAttrValue fTicksSize{this, "ticks_size", 0.02_normal}; /// fTicksColor{this, "ticks_color", RColor::kBlack}; /// fTicksWidth{this, "ticks_width", 1}; /// fNoLabels{this, "nolabels", false}; /// fHideLabels{this, "hidelabels", false}; /// fLabelsOffset{this, "labels_offset", {}}; /// fLabelsCenter{this, "labels_center", false}; /// { this.ticksColor = this.v7EvalColor("ticks_color", ""); this.ticksWidth = this.v7EvalAttr("ticks_width", 1); this.labelsOffset = this.v7EvalLength("labels_offset", this.scaling_size, 0); - this.optionUnlab = this.v7EvalAttr("nolabels", false); + this.optionUnlab = this.v7EvalAttr("hidelabels", false); this.fTitle = this.v7EvalAttr("title", ""); @@ -1757,7 +1757,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.x_handle = new JSROOT.TAxisPainter(this.getDom(), this.xaxis, true); this.x_handle.setPadName(this.getPadName()); - this.x_handle.optionUnlab = this.v7EvalAttr("x_nolabels", false); + this.x_handle.optionUnlab = this.v7EvalAttr("x_hidelabels", false); this.x_handle.configureAxis("xaxis", this.xmin, this.xmax, this.scale_xmin, this.scale_xmax, this.swap_xy, this.swap_xy ? [0,h] : [0,w], { reverse: this.reverse_x, @@ -1770,7 +1770,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.y_handle = new JSROOT.TAxisPainter(this.getDom(), this.yaxis, true); this.y_handle.setPadName(this.getPadName()); - this.y_handle.optionUnlab = this.v7EvalAttr("y_nolabels", false); + this.y_handle.optionUnlab = this.v7EvalAttr("y_hidelabels", false); this.y_handle.configureAxis("yaxis", this.ymin, this.ymax, this.scale_ymin, this.scale_ymax, !this.swap_xy, this.swap_xy ? [0,w] : [0,h], { reverse: this.reverse_y, diff --git a/tutorials/v7/df104.py b/tutorials/v7/df104.py index 31c38139940e5..4d4a3acdc7e3b 100644 --- a/tutorials/v7/df104.py +++ b/tutorials/v7/df104.py @@ -105,7 +105,7 @@ upper_frame = upper_pad.GetOrCreateFrame() upper_frame.AttrMargins().SetBottom(0).SetLeft(0.14).SetRight(0.05) -upper_frame.AttrX().SetNoLabels() +upper_frame.AttrX().SetHideLabels() lower_frame = lower_pad.GetOrCreateFrame() lower_frame.AttrMargins().SetTop(0).SetLeft(0.14).SetRight(0.05).SetBottom(0.3) From c4ea8220a33d16e5136e7698ba7848955e1db386 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 16 Jun 2021 14:08:49 +0200 Subject: [PATCH 229/309] =?UTF-8?q?[RF]=20Fix=20warning:=20=E2=80=98arg?= =?UTF-8?q?=E2=80=99=20shadows=20member=20of=20RooTemplateProxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- roofit/roofitcore/inc/RooTemplateProxy.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/roofit/roofitcore/inc/RooTemplateProxy.h b/roofit/roofitcore/inc/RooTemplateProxy.h index 823db39f3ea34..ac1fe9fc505ad 100644 --- a/roofit/roofitcore/inc/RooTemplateProxy.h +++ b/roofit/roofitcore/inc/RooTemplateProxy.h @@ -245,10 +245,10 @@ class RooTemplateProxy : public RooArgProxy { // let's maybe not support overwriting owned args unless it becomes necessary throw std::runtime_error("Error in RooTemplateProxy: emplaceOwnedArg<>() called on a proxy already owning an arg."); } - auto arg = new U{std::forward(constructorArgs)...}; - setArg(*arg); + auto ownedArg = new U{std::forward(constructorArgs)...}; + setArg(*ownedArg); _ownArg = true; - return *arg; + return *ownedArg; } @@ -256,13 +256,13 @@ class RooTemplateProxy : public RooArgProxy { /// Move a new object held and owned by proxy. /// Can only be done if the proxy was non-owning before. template - U& putOwnedArg(std::unique_ptr arg) { + U& putOwnedArg(std::unique_ptr ownedArg) { if(_ownArg) { // let's maybe not support overwriting owned args unless it becomes necessary throw std::runtime_error("Error in RooTemplateProxy: putOwnedArg<>() called on a proxy already owning an arg."); } - auto argPtr = arg.get(); - setArg(*arg.release()); + auto argPtr = ownedArg.get(); + setArg(*ownedArg.release()); _ownArg = true; return *argPtr; } From 36eeeba25768879f94ee2edb315a29868ccb754b Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 17 Jun 2021 10:42:22 +0200 Subject: [PATCH 230/309] [skip-ci] fix typos (#8455) --- tutorials/graphics/gaxis3.C | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/graphics/gaxis3.C b/tutorials/graphics/gaxis3.C index d7b5fca45df13..564dd7fe1302a 100644 --- a/tutorials/graphics/gaxis3.C +++ b/tutorials/graphics/gaxis3.C @@ -11,7 +11,7 @@ /// - the new size (0 erase the label), /// - the new text alignment, /// - the new label color, -/// = the new label text. +/// - the new label text. /// /// \macro_image /// \macro_code @@ -19,7 +19,7 @@ /// \author Olivier Couet void gaxis3() { - TCanvas* c1 = new TCanvas("c1","Examples of Gaxis",10,10,800,400); + TCanvas* c1 = new TCanvas("c1","Examples of TGaxis",10,10,800,400); c1->Range(-6,-0.1,6,0.1); TGaxis *axis = new TGaxis(-5.5,0.,5.5,0.,0.0,100,510,""); From 8ddd5073378a065863fd384c54de59198d0e1e96 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 17 Jun 2021 11:31:01 +0200 Subject: [PATCH 231/309] [NFC] Remove installation instructions from README, point to website The installation instructions in the README were outdated: they only mentioned pre-compiled binaries, while https://root.cern/install offers a more complete overview of available installation channels. The building instructions were misleading (see e.g. https://root-forum.cern.ch/t/cmake-generate-step-failed-rhel8/45400/16) and incomplete (they don't mention pre-requisites and make certain assumptions about `pwd` and directory names). --- README.md | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 7f7759576bac9..e1d7e868b484d 100644 --- a/README.md +++ b/README.md @@ -51,32 +51,11 @@ These screenshots shows some of the plots (produced using ROOT) presented when t See more screenshots on our [gallery](https://root.cern/gallery). -## Download and Getting Started -See [root.cern download page](https://root.cern/downloading-root) for the latest binary releases. +## Installation and Getting Started +See https://root.cern/install for installation instructions. +For instructions on how to build ROOT from these source files, see https://root.cern/install/build_from_source. -[Getting started with ROOT.](https://root.cern/get_started) - -## Building -Clone the repo - - $ git clone https://github.com/root-project/root.git - -Make a directory for building - - $ mkdir build - $ cd build - -Run cmake and make - - $ cmake ../root - $ make -j n # where n is the number of cores - -Setup and run ROOT - - $ source bin/thisroot.sh - $ root - -[More information](https://root.cern/building-root) regarding building. +Our ["Getting started with ROOT"](https://root.cern/get_started) page is then the perfect place to get familiar with ROOT. ## Help and Support - [Forum](https://root.cern/forum/) From 9d401f0655ed2aa7d4aa7e660011526325a5dd05 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Thu, 17 Jun 2021 13:06:11 +0200 Subject: [PATCH 232/309] [codeowners] Move CMake responsibility from Oksana to Bertrand. --- .github/CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1c0189d6d4bf7..c1de82aa0e68f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -60,7 +60,7 @@ /gui/canvaspainter/ @Axel-Naumann @linev /ui5/ @linev -/cmake/ @oshadura -*.cmake @oshadura -*/CMakeLists.txt @oshadura -CMakeLists.txt @oshadura +/cmake/ @bellenot +*.cmake @bellenot +*/CMakeLists.txt @bellenot +CMakeLists.txt @bellenot From 48232ae082538bd36db6ef42a1488a05b3e9ac13 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 17 Jun 2021 14:04:25 +0200 Subject: [PATCH 233/309] [skip-ci] Fix TMVA tutorials typos (#8460) - remove trailing spaces - remove tabs --- tutorials/tmva/TMVAClassification.C | 2 +- .../tmva/TMVAClassificationApplication.C | 6 +- .../TMVAClassificationCategoryApplication.C | 4 +- tutorials/tmva/TMVACrossValidation.C | 12 +- .../tmva/TMVACrossValidationApplication.C | 8 +- .../tmva/TMVACrossValidationRegression.C | 6 +- tutorials/tmva/TMVAGAexample.C | 6 +- tutorials/tmva/TMVAGAexample2.C | 6 +- tutorials/tmva/TMVAMinimalClassification.C | 8 +- tutorials/tmva/TMVAMulticlassApplication.C | 2 +- .../tmva/TMVAMultipleBackgroundExample.C | 106 +++++++++--------- tutorials/tmva/TMVARegression.C | 6 +- tutorials/tmva/TMVARegressionApplication.C | 40 +++---- tutorials/tmva/TMVA_CNN_Classification.C | 8 +- tutorials/tmva/TMVA_Higgs_Classification.C | 6 +- tutorials/tmva/TMVA_RNN_Classification.C | 6 +- tutorials/tmva/tmva100_DataPreparation.py | 2 +- 17 files changed, 117 insertions(+), 117 deletions(-) diff --git a/tutorials/tmva/TMVAClassification.C b/tutorials/tmva/TMVAClassification.C index 77ef89bc8b9fe..b3f39ca3057c3 100644 --- a/tutorials/tmva/TMVAClassification.C +++ b/tutorials/tmva/TMVAClassification.C @@ -449,7 +449,7 @@ int TMVAClassification( TString myMethodList = "" ) // General layout. TString layoutString ("Layout=TANH|128,TANH|128,TANH|128,LINEAR"); - // Define Training strategy. One could define multiple stratgey string separated by the "|" delimiter + // Define Training strategy. One could define multiple strategy string separated by the "|" delimiter TString trainingStrategyString = ("TrainingStrategy=LearningRate=1e-2,Momentum=0.9," "ConvergenceSteps=20,BatchSize=100,TestRepetitions=1," diff --git a/tutorials/tmva/TMVAClassificationApplication.C b/tutorials/tmva/TMVAClassificationApplication.C index 431cbd8930caa..01acc7a003932 100644 --- a/tutorials/tmva/TMVAClassificationApplication.C +++ b/tutorials/tmva/TMVAClassificationApplication.C @@ -5,7 +5,7 @@ /// within an analysis module /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVAClassificationApplication +/// - Executable: TMVAClassificationApplication /// /// \macro_output /// \macro_code @@ -315,7 +315,7 @@ void TMVAClassificationApplication( TString myMethodList = "" ) // Return the MVA outputs and fill into histograms if (Use["CutsGA"]) { - // Cuts is a special case: give the desired signal efficienciy + // Cuts is a special case: give the desired signal efficiency Bool_t passed = reader->EvaluateMVA( "CutsGA method", effS ); if (passed) nSelCutsGA++; } @@ -382,7 +382,7 @@ void TMVAClassificationApplication( TString myMethodList = "" ) if (Use["CutsGA"]) { // test: retrieve cuts for particular signal efficiency - // CINT ignores dynamic_casts so we have to use a cuts-secific Reader function to acces the pointer + // CINT ignores dynamic_casts so we have to use a cuts-specific Reader function to acces the pointer TMVA::MethodCuts* mcuts = reader->FindCutsMVA( "CutsGA method" ) ; if (mcuts) { diff --git a/tutorials/tmva/TMVAClassificationCategoryApplication.C b/tutorials/tmva/TMVAClassificationCategoryApplication.C index e4591621d21b9..195c536786fec 100644 --- a/tutorials/tmva/TMVAClassificationCategoryApplication.C +++ b/tutorials/tmva/TMVAClassificationCategoryApplication.C @@ -5,7 +5,7 @@ /// (with categories) within an analysis module /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVAClassificationCategoryApplication +/// - Executable: TMVAClassificationCategoryApplication /// /// \macro_output /// \macro_code @@ -104,7 +104,7 @@ void TMVAClassificationCategoryApplication() // but of course you can use different ones and copy the values inside the event loop // TTree* theTree = (TTree*)input->Get("TreeS"); - std::cout << "--- Use signal sample for evalution" << std::endl; + std::cout << "--- Use signal sample for evaluation" << std::endl; theTree->SetBranchAddress( "var1", &var1 ); theTree->SetBranchAddress( "var2", &var2 ); theTree->SetBranchAddress( "var3", &var3 ); diff --git a/tutorials/tmva/TMVACrossValidation.C b/tutorials/tmva/TMVACrossValidation.C index fb47a73f725b8..d50f09f8fd6d9 100644 --- a/tutorials/tmva/TMVACrossValidation.C +++ b/tutorials/tmva/TMVACrossValidation.C @@ -4,7 +4,7 @@ /// This macro provides an example of how to use TMVA for k-folds cross /// evaluation. /// -/// As input data is used a toy-MC sample consisting of two guassian +/// As input data is used a toy-MC sample consisting of two gaussian /// distributions. /// /// The output file "TMVA.root" can be analysed with the use of dedicated @@ -174,7 +174,7 @@ int TMVACrossValidation(bool useRandomSplitting = false) // UInt_t numFolds = 2; TString analysisType = "Classification"; - + TString splitType = (useRandomSplitting) ? "Random" : "Deterministic"; // @@ -185,14 +185,14 @@ int TMVACrossValidation(bool useRandomSplitting = false) // random and independent of the data, generated only once. This last // property ensures that if a calibration is changed the same event will // still be assigned the same fold. - // + // // This can be used to use the cross validated classifiers in application, // a technique that can simplify statistical analysis. - // - // If you want to run TMVACrossValidationApplication, make sure you have + // + // If you want to run TMVACrossValidationApplication, make sure you have // run this tutorial with Deterministic splitting type, i.e. // with the option useRandomSPlitting = false - // + // TString splitExpr = (!useRandomSplitting) ? "int(fabs([eventID]))%int([NumFolds])" : ""; diff --git a/tutorials/tmva/TMVACrossValidationApplication.C b/tutorials/tmva/TMVACrossValidationApplication.C index bce5a5954f476..28aa54999274e 100644 --- a/tutorials/tmva/TMVACrossValidationApplication.C +++ b/tutorials/tmva/TMVACrossValidationApplication.C @@ -92,12 +92,12 @@ int TMVACrossValidationApplication() " splitExpr?" << std::endl; exit(0); } - + } { TString methodName = "Fisher"; TString weightfile = TString("dataset/weights/") + jobname + "_" + methodName + TString(".weights.xml"); - + Bool_t weightfileExists = (gSystem->AccessPathName(weightfile) == kFALSE); if (weightfileExists) { reader->BookMVA(methodName, weightfile); @@ -145,10 +145,10 @@ int TMVACrossValidationApplication() c->Divide(2,1); c->cd(1); histBDTG.DrawClone(); - c->cd(2); + c->cd(2); histFisher.DrawClone(); } - else + else { // Write histograms to output file TFile *target = new TFile("TMVACrossEvaluationApp.root", "RECREATE"); histBDTG.Write(); diff --git a/tutorials/tmva/TMVACrossValidationRegression.C b/tutorials/tmva/TMVACrossValidationRegression.C index 90c7915793689..4ad9d735ec6e1 100644 --- a/tutorials/tmva/TMVACrossValidationRegression.C +++ b/tutorials/tmva/TMVACrossValidationRegression.C @@ -4,7 +4,7 @@ /// This macro provides an example of how to use TMVA for k-folds cross /// evaluation. /// -/// As input data is used a toy-MC sample consisting of two guassian +/// As input data is used a toy-MC sample consisting of two gaussian /// distributions. /// /// The output file "TMVA.root" can be analysed with the use of dedicated @@ -108,7 +108,7 @@ int TMVACrossValidationRegression() TFile * inputFile = getDataFile(infileName); TMVA::DataLoader *dataloader=new TMVA::DataLoader("dataset"); - + dataloader->AddVariable("var1", "Variable 1", "units", 'F'); dataloader->AddVariable("var2", "Variable 2", "units", 'F'); @@ -142,7 +142,7 @@ int TMVACrossValidationRegression() // This sets up a CrossValidation class (which wraps a TMVA::Factory // internally) for 2-fold cross validation. The data will be split into the // two folds randomly if `splitExpr` is `""`. - // + // // One can also give a deterministic split using spectator variables. An // example would be e.g. `"int(fabs([spec1]))%int([NumFolds])"`. // diff --git a/tutorials/tmva/TMVAGAexample.C b/tutorials/tmva/TMVAGAexample.C index c9478c5a66ed6..33b8afc9e8f73 100644 --- a/tutorials/tmva/TMVAGAexample.C +++ b/tutorials/tmva/TMVAGAexample.C @@ -1,11 +1,11 @@ /// \file /// \ingroup tutorial_tmva /// \notebook -nodraw -/// This exectutable gives an example of a very simple use of the genetic algorithm +/// This executable gives an example of a very simple use of the genetic algorithm /// of TMVA /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVAGAexample +/// - Executable: TMVAGAexample /// /// \macro_output /// \macro_code @@ -36,7 +36,7 @@ class MyFitness : public IFitterTarget { // to (int). In this case the variable-range has to be chosen +1 ( to get 0..5, take Interval(0,6) ) // since the introduction of "Interval" ranges can be defined with a third parameter // which gives the number of bins within the interval. With that technique discrete values - // can be achieved easier. The random selection out of this discrete numbers is completly uniform. + // can be achieved easier. The random selection out of this discrete numbers is completely uniform. // Double_t EstimatorFunction( std::vector & factors ){ //return (10.- (int)factors.at(0) *factors.at(1) + (int)factors.at(2)); diff --git a/tutorials/tmva/TMVAGAexample2.C b/tutorials/tmva/TMVAGAexample2.C index e074e1e7d7d47..55d4d562f5f58 100644 --- a/tutorials/tmva/TMVAGAexample2.C +++ b/tutorials/tmva/TMVAGAexample2.C @@ -1,11 +1,11 @@ /// \file /// \ingroup tutorial_tmva /// \notebook -nodraw -/// This exectutable gives an example of a very simple use of the genetic algorithm +/// This executable gives an example of a very simple use of the genetic algorithm /// of TMVA. /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVAGAexample +/// - Executable: TMVAGAexample /// /// \macro_output /// \macro_code @@ -38,7 +38,7 @@ class MyFitness : public IFitterTarget { // to (int). In this case the variable-range has to be chosen +1 ( to get 0..5, take Interval(0,6) ) // since the introduction of "Interval" ranges can be defined with a third parameter // which gives the number of bins within the interval. With that technique discrete values - // can be achieved easier. The random selection out of this discrete numbers is completly uniform. + // can be achieved easier. The random selection out of this discrete numbers is completely uniform. // Double_t EstimatorFunction( std::vector & factors ){ //return (10.- (int)factors.at(0) *factors.at(1) + (int)factors.at(2)); diff --git a/tutorials/tmva/TMVAMinimalClassification.C b/tutorials/tmva/TMVAMinimalClassification.C index 4cc881c1d3d40..e05b92b870987 100644 --- a/tutorials/tmva/TMVAMinimalClassification.C +++ b/tutorials/tmva/TMVAMinimalClassification.C @@ -6,11 +6,11 @@ /// /// This is intended as a simple foundation to build on. It assumes you are /// familiar with TMVA already. As such concepts like the Factory, the DataLoader -/// and others are not explained. For descriptions and tutuorials use the TMVA +/// and others are not explained. For descriptions and tutorials use the TMVA /// User's Guide (https://root.cern.ch/root-user-guides-and-manuals under TMVA) /// or the more detailed examples provided with TMVA e.g. TMVAClassification.C. /// -/// Sets up a minimal binary classification example with two slighly overlapping +/// Sets up a minimal binary classification example with two slightly overlapping /// 2-D gaussian distributions and trains a BDT classifier to discriminate the /// data. /// @@ -63,7 +63,7 @@ TTree *genTree(Int_t nPoints, Double_t offset, Double_t scale, UInt_t seed = 100 } // -// Minimal setup for perfroming binary classification in TMVA. +// Minimal setup for performing binary classification in TMVA. // // Modify the setup to your liking and run with // `root -l -b -q TMVAMinimalClassification.C`. @@ -75,7 +75,7 @@ void TMVAMinimalClassification() TString outputFilename = "out.root"; TFile *outFile = new TFile(outputFilename, "RECREATE"); - // Data generatration + // Data generation TTree *signalTree = genTree(1000, 0.0, 2.0, 100); TTree *backgroundTree = genTree(1000, 1.0, 2.0, 101); diff --git a/tutorials/tmva/TMVAMulticlassApplication.C b/tutorials/tmva/TMVAMulticlassApplication.C index 70b82ced663ef..cef5aa25837d1 100644 --- a/tutorials/tmva/TMVAMulticlassApplication.C +++ b/tutorials/tmva/TMVAMulticlassApplication.C @@ -101,7 +101,7 @@ void TMVAMulticlassApplication( TString myMethodList = "" ) // book output histograms UInt_t nbin = 100; TH1F *histMLP_signal(0), *histBDTG_signal(0), *histFDAGA_signal(0), *histPDEFoam_signal(0); - TH1F *histDLCPU_signal(0), *histDLGPU_signal(0); + TH1F *histDLCPU_signal(0), *histDLGPU_signal(0); if (Use["MLP"]) histMLP_signal = new TH1F( "MVA_MLP_signal", "MVA_MLP_signal", nbin, 0., 1.1 ); if (Use["BDTG"]) diff --git a/tutorials/tmva/TMVAMultipleBackgroundExample.C b/tutorials/tmva/TMVAMultipleBackgroundExample.C index 5ec8b29dae111..7ca6fd703425a 100644 --- a/tutorials/tmva/TMVAMultipleBackgroundExample.C +++ b/tutorials/tmva/TMVAMultipleBackgroundExample.C @@ -5,10 +5,10 @@ /// Then in the application a tree is created with all signal and background /// events where the true class ID and the three classifier outputs are added /// finally with the application tree, the significance is maximized with the -/// help of the TMVA genetic algrorithm. +/// help of the TMVA genetic algorithm. /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVAGAexample +/// - Executable: TMVAGAexample /// /// \macro_output /// \macro_code @@ -92,7 +92,7 @@ void Training(){ // Boosted Decision Trees factory->BookMethod( dataloader, TMVA::Types::kBDT, "BDTG", - "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.6:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); + "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.6:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); factory->TrainAllMethods(); factory->TestAllMethods(); factory->EvaluateAllMethods(); @@ -128,7 +128,7 @@ void Training(){ // Boosted Decision Trees factory->BookMethod( dataloader, TMVA::Types::kBDT, "BDTG", - "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.6:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); + "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.6:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); factory->TrainAllMethods(); factory->TestAllMethods(); factory->EvaluateAllMethods(); @@ -164,7 +164,7 @@ void Training(){ // Boosted Decision Trees factory->BookMethod( dataloader, TMVA::Types::kBDT, "BDTG", - "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.5:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); + "!H:!V:NTrees=1000:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.5:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" ); factory->TrainAllMethods(); factory->TestAllMethods(); factory->EvaluateAllMethods(); @@ -246,29 +246,29 @@ void ApplicationCreateCombinedTree(){ // loop through signal and all background trees for( int treeNumber = 0; treeNumber < 4; ++treeNumber ) { if( treeNumber == 0 ){ - theTree = (TTree*)input->Get("TreeS"); - std::cout << "--- Select signal sample" << std::endl; -// theTree->SetBranchAddress( "weight", &weight ); - weight = 1; - classID = 0; + theTree = (TTree*)input->Get("TreeS"); + std::cout << "--- Select signal sample" << std::endl; +// theTree->SetBranchAddress( "weight", &weight ); + weight = 1; + classID = 0; }else if( treeNumber == 1 ){ - theTree = (TTree*)input->Get("TreeB0"); - std::cout << "--- Select background 0 sample" << std::endl; -// theTree->SetBranchAddress( "weight", &weight ); - weight = 1; - classID = 1; + theTree = (TTree*)input->Get("TreeB0"); + std::cout << "--- Select background 0 sample" << std::endl; +// theTree->SetBranchAddress( "weight", &weight ); + weight = 1; + classID = 1; }else if( treeNumber == 2 ){ - theTree = (TTree*)input->Get("TreeB1"); - std::cout << "--- Select background 1 sample" << std::endl; -// theTree->SetBranchAddress( "weight", &weight ); - weight = 1; - classID = 2; + theTree = (TTree*)input->Get("TreeB1"); + std::cout << "--- Select background 1 sample" << std::endl; +// theTree->SetBranchAddress( "weight", &weight ); + weight = 1; + classID = 2; }else if( treeNumber == 3 ){ - theTree = (TTree*)input->Get("TreeB2"); - std::cout << "--- Select background 2 sample" << std::endl; -// theTree->SetBranchAddress( "weight", &weight ); - weight = 1; - classID = 3; + theTree = (TTree*)input->Get("TreeB2"); + std::cout << "--- Select background 2 sample" << std::endl; +// theTree->SetBranchAddress( "weight", &weight ); + weight = 1; + classID = 3; } @@ -285,18 +285,18 @@ void ApplicationCreateCombinedTree(){ // Int_t nEvent = 100; for (Long64_t ievt=0; ievtGetEntry(ievt); + theTree->GetEntry(ievt); - // get the classifiers for each of the signal/background classifications - classifier0 = reader0->EvaluateMVA( method ); - classifier1 = reader1->EvaluateMVA( method ); - classifier2 = reader2->EvaluateMVA( method ); + // get the classifiers for each of the signal/background classifications + classifier0 = reader0->EvaluateMVA( method ); + classifier1 = reader1->EvaluateMVA( method ); + classifier2 = reader2->EvaluateMVA( method ); - outputTree->Fill(); + outputTree->Fill(); } @@ -362,17 +362,17 @@ public: efficiency = 0; if( weightsSignal > 0 ) - efficiency = weightsTruePositive/weightsSignal; + efficiency = weightsTruePositive/weightsSignal; purity = 0; if( weightsTruePositive+weightsFalsePositive > 0 ) - purity = weightsTruePositive/(weightsTruePositive+weightsFalsePositive); + purity = weightsTruePositive/(weightsTruePositive+weightsFalsePositive); Float_t effTimesPur = efficiency*purity; Float_t toMinimize = std::numeric_limits::max(); // set to the highest existing number if( effTimesPur > 0 ) // if larger than 0, take 1/x. This is the value to minimize - toMinimize = 1./(effTimesPur); // we want to minimize 1/efficiency*purity + toMinimize = 1./(effTimesPur); // we want to minimize 1/efficiency*purity // Print(); @@ -383,11 +383,11 @@ public: void Print(){ std::cout << std::endl; std::cout << "======================" << std::endl - << "Efficiency : " << efficiency << std::endl - << "Purity : " << purity << std::endl << std::endl - << "True positive weights : " << weightsTruePositive << std::endl - << "False positive weights: " << weightsFalsePositive << std::endl - << "Signal weights : " << weightsSignal << std::endl; + << "Efficiency : " << efficiency << std::endl + << "Purity : " << purity << std::endl << std::endl + << "True positive weights : " << weightsTruePositive << std::endl + << "False positive weights: " << weightsFalsePositive << std::endl + << "Signal weights : " << weightsSignal << std::endl; } Float_t nSignal; @@ -427,13 +427,13 @@ void MaximizeSignificance(){ ranges.push_back( new Interval(-1,1) ); ranges.push_back( new Interval(-1,1) ); - std::cout << "Classifier ranges (defined by the user)" << std::endl; + std::cout << "Classifier ranges (defined by the user)" << std::endl; for( std::vector::iterator it = ranges.begin(); it != ranges.end(); it++ ){ std::cout << " range: " << (*it)->GetMin() << " " << (*it)->GetMax() << std::endl; } - TChain* chain = new TChain("multiBkg"); - chain->Add("tmva_example_multiple_backgrounds__applied.root"); + TChain* chain = new TChain("multiBkg"); + chain->Add("tmva_example_multiple_backgrounds__applied.root"); IFitterTarget* myFitness = new MyFitness( chain ); @@ -447,19 +447,19 @@ void MaximizeSignificance(){ const TString opts( "PopSize=100:Steps=30" ); GeneticFitter mg( *myFitness, name, ranges, opts); - // mg.SetParameters( 4, 30, 200, 10,5, 0.95, 0.001 ); + // mg.SetParameters( 4, 30, 200, 10,5, 0.95, 0.001 ); std::vector result; Double_t estimator = mg.Run(result); - dynamic_cast(myFitness)->Print(); - std::cout << std::endl; + dynamic_cast(myFitness)->Print(); + std::cout << std::endl; - int n = 0; - for( std::vector::iterator it = result.begin(); it::iterator it = result.begin(); itBookMethod( dataloader, TMVA::Types::kPDEFoam, "PDEFoam", - "!H:!V:MultiTargetRegression=F:TargetSelection=Mpv:TailCut=0.001:VolFrac=0.0666:nActiveCells=500:nSampl=2000:nBin=5:Compress=T:Kernel=None:Nmin=10:VarTransform=None" ); + "!H:!V:MultiTargetRegression=F:TargetSelection=Mpv:TailCut=0.001:VolFrac=0.0666:nActiveCells=500:nSampl=2000:nBin=5:Compress=T:Kernel=None:Nmin=10:VarTransform=None" ); // K-Nearest Neighbour classifier (KNN) if (Use["KNN"]) @@ -242,7 +242,7 @@ void TMVARegression( TString myMethodList = "" ) factory->BookMethod( dataloader, TMVA::Types::kLD, "LD", "!H:!V:VarTransform=None" ); - // Function discrimination analysis (FDA) -- test of various fitters - the recommended one is Minuit (or GA or SA) + // Function discrimination analysis (FDA) -- test of various fitters - the recommended one is Minuit (or GA or SA) if (Use["FDA_MC"]) factory->BookMethod( dataloader, TMVA::Types::kFDA, "FDA_MC", "!H:!V:Formula=(0)+(1)*x0+(2)*x1:ParRanges=(-100,100);(-100,100);(-100,100):FitMethod=MC:SampleSize=100000:Sigma=0.1:VarTransform=D" ); diff --git a/tutorials/tmva/TMVARegressionApplication.C b/tutorials/tmva/TMVARegressionApplication.C index 402391cb9e0ab..2c395ae0e5439 100644 --- a/tutorials/tmva/TMVARegressionApplication.C +++ b/tutorials/tmva/TMVARegressionApplication.C @@ -6,7 +6,7 @@ /// /// - Project : TMVA - a Root-integrated toolkit for multivariate data analysis /// - Package : TMVA -/// - Exectuable: TMVARegressionApplication +/// - Executable: TMVARegressionApplication /// /// \macro_output /// \macro_code @@ -30,7 +30,7 @@ using namespace TMVA; -void TMVARegressionApplication( TString myMethodList = "" ) +void TMVARegressionApplication( TString myMethodList = "" ) { //--------------------------------------------------------------- // This loads the library @@ -41,18 +41,18 @@ void TMVARegressionApplication( TString myMethodList = "" ) // --- Mutidimensional likelihood and Nearest-Neighbour methods Use["PDERS"] = 0; - Use["PDEFoam"] = 1; + Use["PDEFoam"] = 1; Use["KNN"] = 1; - // + // // --- Linear Discriminant Analysis - Use["LD"] = 1; - // + Use["LD"] = 1; + // // --- Function Discriminant analysis Use["FDA_GA"] = 0; Use["FDA_MC"] = 0; Use["FDA_MT"] = 0; Use["FDA_GAMT"] = 0; - // + // // --- Neural Network Use["MLP"] = 0; #ifdef R__HAS_TMVACPU @@ -61,10 +61,10 @@ void TMVARegressionApplication( TString myMethodList = "" ) Use["DNN_CPU"] = 0; #endif - // - // --- Support Vector Machine + // + // --- Support Vector Machine Use["SVM"] = 0; - // + // // --- Boosted Decision Trees Use["BDT"] = 0; Use["BDTG"] = 1; @@ -95,7 +95,7 @@ void TMVARegressionApplication( TString myMethodList = "" ) // --- Create the Reader object - TMVA::Reader *reader = new TMVA::Reader( "!Color:!Silent" ); + TMVA::Reader *reader = new TMVA::Reader( "!Color:!Silent" ); // Create a set of variables and declare them to the reader // - the variable names MUST corresponds in name and type to those given in the weight file(s) used @@ -118,10 +118,10 @@ void TMVARegressionApplication( TString myMethodList = "" ) if (it->second) { TString methodName = it->first + " method"; TString weightfile = dir + prefix + "_" + TString(it->first) + ".weights.xml"; - reader->BookMVA( methodName, weightfile ); + reader->BookMVA( methodName, weightfile ); } } - + // Book output histograms TH1* hists[100]; Int_t nhists = -1; @@ -130,7 +130,7 @@ void TMVARegressionApplication( TString myMethodList = "" ) if (it->second) hists[++nhists] = h; } nhists++; - + // Prepare input tree (this must be replaced by your data source) // in this example, there is a toy tree with signal and one with background events // we'll later on use only the "signal" events for the test in this example. @@ -179,7 +179,7 @@ void TMVARegressionApplication( TString myMethodList = "" ) for (Int_t ih=0; ihGetTitle(); Float_t val = (reader->EvaluateRegression( title ))[0]; - hists[ih]->Fill( val ); + hists[ih]->Fill( val ); } } sw.Stop(); @@ -191,22 +191,22 @@ void TMVARegressionApplication( TString myMethodList = "" ) for (Int_t ih=0; ihWrite(); target->Close(); - std::cout << "--- Created root file: \"" << target->GetName() + std::cout << "--- Created root file: \"" << target->GetName() << "\" containing the MVA output histograms" << std::endl; - + delete reader; - + std::cout << "==> TMVARegressionApplication is done!" << std::endl << std::endl; } int main( int argc, char** argv ) { // Select methods (don't look at this code - not of interest) - TString methodList; + TString methodList; for (int i=1; i opt = {1, 1, 1, 1, 1}) - note in this case we are using a filer 3x3 and padding=1 and stride=1 so we get the output dimension of the conv layer equal to the input - - note we use after the first convolutional layer a batch normalization layer. This seems to help significatly the + - note we use after the first convolutional layer a batch normalization layer. This seems to help significantly the convergence - For the MaxPool layer: @@ -419,7 +419,7 @@ void TMVA_CNN_Classification(std::vector opt = {1, 1, 1, 1, 1}) Info("TMVA_CNN_Classification", "Building convolutional keras model"); // create python script which can be executed - // crceate 2 conv2d layer + maxpool + dense + // create 2 conv2d layer + maxpool + dense TMacro m; m.AddLine("import tensorflow"); m.AddLine("from tensorflow.keras.models import Sequential"); diff --git a/tutorials/tmva/TMVA_Higgs_Classification.C b/tutorials/tmva/TMVA_Higgs_Classification.C index 01c3d816010a1..25cca4fb9118e 100644 --- a/tutorials/tmva/TMVA_Higgs_Classification.C +++ b/tutorials/tmva/TMVA_Higgs_Classification.C @@ -194,7 +194,7 @@ We define first the DNN layout: - **input layout** : this defines the input data format for the DNN as ``input depth | height | width``. In case of a dense layer as first layer the input layout should be ``1 | 1 | number of input variables`` (features) - **batch layout** : this defines how are the input batch. It is related to input layout but not the same. - If the first layer is dense it should be ``1 | batch size ! number of variables`` (fetures) + If the first layer is dense it should be ``1 | batch size ! number of variables`` (features) *(note the use of the character `|` as separator of input parameters for DNN layout)* @@ -208,7 +208,7 @@ complex architectures *the different layers are separated by the ``","`` * -#### 2. Define Trainining Strategy +#### 2. Define Training Strategy We define here the training strategy parameters for the DNN. The parameters are separated by the ``","`` separator. One can then concatenate different training strategy with different parameters. The training strategy are separated by @@ -227,7 +227,7 @@ the ``"|"`` separator. #### 3. Define general DNN options -We define the general DNN options concateneting in the final string the previously defined layout and training strategy. +We define the general DNN options concatenating in the final string the previously defined layout and training strategy. Note we use the ``":"`` separator to separate the different higher level options, as in the other TMVA methods. In addition to input layout, batch layout and training strategy we add now: diff --git a/tutorials/tmva/TMVA_RNN_Classification.C b/tutorials/tmva/TMVA_RNN_Classification.C index 5bfec521963bf..eb26d03a2f7fc 100644 --- a/tutorials/tmva/TMVA_RNN_Classification.C +++ b/tutorials/tmva/TMVA_RNN_Classification.C @@ -36,7 +36,7 @@ /// Helper function to generate the time data set /// make some time data but not of fixed length. -/// use a poisson with mu = 5 and troncated at 10 +/// use a poisson with mu = 5 and truncated at 10 /// void MakeTimeData(int n, int ntime, int ndim ) { @@ -190,7 +190,7 @@ void TMVA_RNN_Classification(int use_type = 1) useKeras = false; #endif - int num_threads = 0; // use by default all threads + int num_threads = 0; // use by default all threads // do enable MT running if (num_threads >= 0) { ROOT::EnableImplicitMT(num_threads); @@ -434,7 +434,7 @@ the option string gSystem->Exec("python make_rnn_model.py"); if (gSystem->AccessPathName(modelName)) { - Warning("TMVA_RNN_Classification", "Error creating Keras recurrennt model file - Skip using Keras"); + Warning("TMVA_RNN_Classification", "Error creating Keras recurrent model file - Skip using Keras"); useKeras = false; } else { // book PyKeras method only if Keras model could be created diff --git a/tutorials/tmva/tmva100_DataPreparation.py b/tutorials/tmva/tmva100_DataPreparation.py index 57003ebc6eebd..a04d337cd3bcd 100644 --- a/tutorials/tmva/tmva100_DataPreparation.py +++ b/tutorials/tmva/tmva100_DataPreparation.py @@ -2,7 +2,7 @@ ## \ingroup tutorial_tmva ## \notebook -nodraw ## This tutorial illustrates how to prepare ROOT datasets to be nicely readable -## by most machine learning methods. This requires filtering the inital complex +## by most machine learning methods. This requires filtering the initial complex ## datasets and writing the data in a flat format. ## ## \macro_code From e411bdf2060fe00812a0087b1f2e4ec2cd7bed62 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 09:26:21 +0200 Subject: [PATCH 234/309] [rbrowsable] fix potential ownership problem If objects like TH1 or TF1 should be owned by TObjectHolder, unregister them from global lists which can destroy them --- .../inc/ROOT/Browsable/TObjectHolder.hxx | 9 ++++++- gui/browsable/src/TObjectHolder.cxx | 25 ++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/gui/browsable/inc/ROOT/Browsable/TObjectHolder.hxx b/gui/browsable/inc/ROOT/Browsable/TObjectHolder.hxx index b99ce22b06c07..74dff3d462a15 100644 --- a/gui/browsable/inc/ROOT/Browsable/TObjectHolder.hxx +++ b/gui/browsable/inc/ROOT/Browsable/TObjectHolder.hxx @@ -30,8 +30,15 @@ protected: void *AccessObject() final { return fOwner ? nullptr : fObj; } void *TakeObject() final; RHolder *DoCopy() const final { return new TObjectHolder(fObj); } + void ClearROOTOwnership(TObject *obj); public: - TObjectHolder(TObject *obj, bool owner = false) { fObj = obj; fOwner = owner; } + TObjectHolder(TObject *obj, bool owner = false) + { + fObj = obj; + fOwner = owner; + if (fOwner) ClearROOTOwnership(fObj); + } + virtual ~TObjectHolder() { if (fOwner) delete fObj; diff --git a/gui/browsable/src/TObjectHolder.cxx b/gui/browsable/src/TObjectHolder.cxx index 5ec75bc4193ca..010c8d630e9c0 100644 --- a/gui/browsable/src/TObjectHolder.cxx +++ b/gui/browsable/src/TObjectHolder.cxx @@ -13,9 +13,26 @@ using namespace ROOT::Experimental::Browsable; +/////////////////////////////////////////////////////////////////////////// +/// Check if object is not registered in some global lists +/// Prevent double deletion + +void TObjectHolder::ClearROOTOwnership(TObject *obj) +{ + if (obj && obj->InheritsFrom("TH1")) { + std::stringstream cmd; + cmd << "((TH1 *) " << std::hex << std::showbase << (size_t)obj << ")->SetDirectory(nullptr);"; + gROOT->ProcessLine(cmd.str().c_str()); + } else if (obj && obj->InheritsFrom("TF1")) { + std::stringstream cmd; + cmd << "((TF1 *) " << std::hex << std::showbase << (size_t)obj << ")->AddToGlobalList(kFALSE);"; + gROOT->ProcessLine(cmd.str().c_str()); + } +} + /////////////////////////////////////////////////////////////////////////// /// Return TObject instance with ownership -/// If object is not owned by the holder, it will be cloned (with few exceptions) +/// If object is not owned by the holder, it will be cloned (except TDirectory or TTree classes) void *TObjectHolder::TakeObject() { @@ -26,11 +43,7 @@ void *TObjectHolder::TakeObject() fOwner = false; } else if (fObj && !fObj->IsA()->InheritsFrom("TDirectory") && !fObj->IsA()->InheritsFrom("TTree")) { res = fObj->Clone(); - if (res && res->InheritsFrom("TH1")) { - std::stringstream cmd; - cmd << "((TH1 *) " << std::hex << std::showbase << (size_t)res << ")->SetDirectory(nullptr);"; - gROOT->ProcessLine(cmd.str().c_str()); - } + ClearROOTOwnership(res); } else { res = nullptr; } From 210de9652dd6e99b71cab7858fb19662c458ea09 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 17 Jun 2021 18:31:56 +0200 Subject: [PATCH 235/309] - simplify Doxyfile (#8451) --- documentation/doxygen/Doxyfile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/documentation/doxygen/Doxyfile b/documentation/doxygen/Doxyfile index c25f3f5d0caed..ecb25c4a9eed5 100644 --- a/documentation/doxygen/Doxyfile +++ b/documentation/doxygen/Doxyfile @@ -846,7 +846,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = . \ +INPUT = ./mainpage.md \ ../../core/base/ \ ../../core/dictgen/ \ ../../core/cont/ \ @@ -1025,16 +1025,10 @@ EXCLUDE_PATTERNS = */G__* \ */doc/v5* \ */win32gdk/gdk/* \ */bindings/pyroot/*.py \ - makeimage.C \ - makerootfile.C \ - libs.C \ - filter.cxx \ *gl2ps* \ *CsgOps* \ - converttonotebook.py \ - makeimage.py \ - parallelNotebooks.py \ LinkDef*.h \ + launcher.py \ */io/io/res/* \ */src/lexertk.hpp From 315c36241adf1bd68d469b671e96d45fa7112126 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 16 Jun 2021 15:05:56 +0200 Subject: [PATCH 236/309] [IO] Take TBufferMerger out of the Experimental namespace and deprecate the spelling ROOT::Experimental::TBufferMerger. --- io/io/inc/ROOT/TBufferMerger.hxx | 9 ++++++++- io/io/src/TBufferMerger.cxx | 4 +--- io/io/src/TBufferMergerFile.cxx | 2 -- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/io/io/inc/ROOT/TBufferMerger.hxx b/io/io/inc/ROOT/TBufferMerger.hxx index b0a3dc137b183..a9d87f4dcc887 100644 --- a/io/io/inc/ROOT/TBufferMerger.hxx +++ b/io/io/inc/ROOT/TBufferMerger.hxx @@ -14,6 +14,7 @@ #include "TFileMerger.h" #include "TMemFile.h" +#include "RConfig.h" /// R__DEPRECATED #include #include @@ -21,7 +22,6 @@ #include namespace ROOT { -namespace Experimental { class TBufferMergerFile; @@ -213,7 +213,14 @@ public: ClassDefOverride(TBufferMergerFile, 0); }; +namespace Experimental { +using TBufferMerger R__DEPRECATED( + 6, 28, "Please use ROOT::TBufferMerger instead of ROOT::Experimental::TBufferMerger.") = ::ROOT::TBufferMerger; +using TBufferMergerFile + R__DEPRECATED(6, 28, "Please use ROOT::TBufferMergerFile instead of ROOT::Experimental::TBufferMergerFile.") = + ::ROOT::TBufferMergerFile; } // namespace Experimental + } // namespace ROOT #endif diff --git a/io/io/src/TBufferMerger.cxx b/io/io/src/TBufferMerger.cxx index 74882f67669e3..88a9fd30afb14 100644 --- a/io/io/src/TBufferMerger.cxx +++ b/io/io/src/TBufferMerger.cxx @@ -19,7 +19,6 @@ #include namespace ROOT { -namespace Experimental { TBufferMerger::TBufferMerger(const char *name, Option_t *option, Int_t compress) { @@ -132,7 +131,7 @@ void TBufferMerger::MergeImpl() fMerger.Reset(); } -bool TBufferMerger::TryMerge(ROOT::Experimental::TBufferMergerFile *memfile) +bool TBufferMerger::TryMerge(ROOT::TBufferMergerFile *memfile) { if (fMergeMutex.try_lock()) { memfile->WriteStreamerInfo(); @@ -144,5 +143,4 @@ bool TBufferMerger::TryMerge(ROOT::Experimental::TBufferMergerFile *memfile) return false; } -} // namespace Experimental } // namespace ROOT diff --git a/io/io/src/TBufferMergerFile.cxx b/io/io/src/TBufferMergerFile.cxx index ce45ba1fe1eb8..dbdd96d72f4eb 100644 --- a/io/io/src/TBufferMergerFile.cxx +++ b/io/io/src/TBufferMergerFile.cxx @@ -14,7 +14,6 @@ #include "TBufferFile.h" namespace ROOT { -namespace Experimental { TBufferMergerFile::TBufferMergerFile(TBufferMerger &m) : TMemFile(m.fMerger.GetOutputFile()->GetName(), "RECREATE", "", @@ -58,5 +57,4 @@ Int_t TBufferMergerFile::Write(const char *name, Int_t opt, Int_t bufsize) return nbytes; } -} // namespace Experimental } // namespace ROOT From 87c65b00eadf4b60cb7443a45f42d78defa75424 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 16 Jun 2021 15:06:29 +0200 Subject: [PATCH 237/309] [IO][NFC] Reformat long lines in TBufferMerger.{hxx,cxx} --- io/io/inc/ROOT/TBufferMerger.hxx | 3 ++- io/io/src/TBufferMerger.cxx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/io/io/inc/ROOT/TBufferMerger.hxx b/io/io/inc/ROOT/TBufferMerger.hxx index a9d87f4dcc887..88b9bf5d94b0f 100644 --- a/io/io/inc/ROOT/TBufferMerger.hxx +++ b/io/io/inc/ROOT/TBufferMerger.hxx @@ -45,7 +45,8 @@ public: * @param option Output file creation options * @param compress Output file compression level */ - TBufferMerger(const char *name, Option_t *option = "RECREATE", Int_t compress = ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault); + TBufferMerger(const char *name, Option_t *option = "RECREATE", + Int_t compress = ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault); /** Constructor * @param output Output \c TFile diff --git a/io/io/src/TBufferMerger.cxx b/io/io/src/TBufferMerger.cxx index 88a9fd30afb14..f70be61a307bd 100644 --- a/io/io/src/TBufferMerger.cxx +++ b/io/io/src/TBufferMerger.cxx @@ -127,7 +127,8 @@ void TBufferMerger::MergeImpl() queue.pop(); } - fMerger.PartialMerge(TFileMerger::kAll | TFileMerger::kIncremental | TFileMerger::kDelayWrite | TFileMerger::kKeepCompression); + fMerger.PartialMerge(TFileMerger::kAll | TFileMerger::kIncremental | TFileMerger::kDelayWrite | + TFileMerger::kKeepCompression); fMerger.Reset(); } From 6f3dec858f2fd1d56fb236e46af93ae0aa2d246a Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 16 Jun 2021 16:44:58 +0200 Subject: [PATCH 238/309] Remove usages of deprecated spelling ROOT::Experimental::TBufferMerger --- io/io/test/TBufferMerger.cxx | 4 ++-- tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/io/io/test/TBufferMerger.cxx b/io/io/test/TBufferMerger.cxx index 19dbaa58b1bde..cfa9b6d6a3c19 100644 --- a/io/io/test/TBufferMerger.cxx +++ b/io/io/test/TBufferMerger.cxx @@ -16,7 +16,7 @@ #include "gtest/gtest.h" -using namespace ROOT::Experimental; +using namespace ROOT; static void Fill(TTree *tree, int init, int count) { @@ -228,7 +228,7 @@ TEST(TBufferMerger, SetMaxTreeSize) ROOT::EnableThreadSafety(); { - ROOT::Experimental::TBufferMerger merger{"tbuffermerger_setmaxtreesize.root"}; + TBufferMerger merger{"tbuffermerger_setmaxtreesize.root"}; auto tbmfile = merger.GetFile(); // std::shared_ptr diff --git a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx index 33e88dd09f566..5938016a2d3d5 100644 --- a/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx +++ b/tree/dataframe/inc/ROOT/RDF/ActionHelpers.hxx @@ -1468,8 +1468,8 @@ public: template class SnapshotHelperMT : public RActionImpl> { const unsigned int fNSlots; - std::unique_ptr fMerger; // must use a ptr because TBufferMerger is not movable - std::vector> fOutputFiles; + std::unique_ptr fMerger; // must use a ptr because TBufferMerger is not movable + std::vector> fOutputFiles; std::vector> fOutputTrees; std::vector fBranchAddressesNeedReset; // vector does not allow concurrent writing of different elements const std::string fFileName; // name of the output file name @@ -1601,14 +1601,14 @@ public: auto out_file = TFile::Open(fFileName.c_str(), fOptions.fMode.c_str(), /*ftitle=*/fFileName.c_str(), cs); if(!out_file) throw std::runtime_error("Snapshot: could not create output file " + fFileName); - fMerger = std::make_unique(std::unique_ptr(out_file)); + fMerger = std::make_unique(std::unique_ptr(out_file)); } void Finalize() { const bool allNullFiles = std::all_of(fOutputFiles.begin(), fOutputFiles.end(), - [](const std::shared_ptr &ptr) { return ptr == nullptr; }); + [](const std::shared_ptr &ptr) { return ptr == nullptr; }); R__ASSERT(!allNullFiles); auto fileWritten = false; From f710392bf8d14714734877d8183fcca89ce58f9c Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Wed, 16 Jun 2021 18:04:39 +0200 Subject: [PATCH 239/309] [IO] Add ROOT::TBufferMerger[File] to LinkDef --- io/io/inc/LinkDef.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io/io/inc/LinkDef.h b/io/io/inc/LinkDef.h index 46fa9cd483ffb..78faec568eb82 100644 --- a/io/io/inc/LinkDef.h +++ b/io/io/inc/LinkDef.h @@ -53,5 +53,7 @@ #pragma link C++ class ROOT::Internal::RRawFile+; #pragma link C++ class ROOT::Experimental::TBufferMerger; #pragma link C++ class ROOT::Experimental::TBufferMergerFile; +#pragma link C++ class ROOT::TBufferMerger; +#pragma link C++ class ROOT::TBufferMergerFile; #endif From d431b8070a20c1a0e800560ebb1b950e54a9d1e4 Mon Sep 17 00:00:00 2001 From: Enrico Guiraud Date: Thu, 17 Jun 2021 11:25:26 +0200 Subject: [PATCH 240/309] [IO] Remove deprecated spelling Experimental::TBufferMerger from LinkDef --- io/io/inc/LinkDef.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/io/io/inc/LinkDef.h b/io/io/inc/LinkDef.h index 78faec568eb82..292ba668f49c7 100644 --- a/io/io/inc/LinkDef.h +++ b/io/io/inc/LinkDef.h @@ -51,8 +51,6 @@ #pragma link C++ class TStreamerInfoActions::TActionSequence+; #pragma link C++ class TStreamerInfoActions::TConfiguration-; #pragma link C++ class ROOT::Internal::RRawFile+; -#pragma link C++ class ROOT::Experimental::TBufferMerger; -#pragma link C++ class ROOT::Experimental::TBufferMergerFile; #pragma link C++ class ROOT::TBufferMerger; #pragma link C++ class ROOT::TBufferMergerFile; From 6a1fc720775f7ff87855efc9579f21082da0c6c2 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 11:24:19 +0200 Subject: [PATCH 241/309] [rdrawable] fix bug in THStack handling List of hists was not processed properly, prevent analysis nullptr --- graf2d/gpadv7/src/TObjectDrawable.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 313aab3c18dcb..2d178b830787e 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -192,6 +192,8 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) void TObjectDrawable::ExtractObjectColors(std::unique_ptr &item, TObject *obj) { + if (!obj) return; + TClass *cl = obj->IsA(); auto ExtractColor = [&item, cl, obj](const char *class_name, const char *class_member) { @@ -245,10 +247,10 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct // do not call stack->GetHistogram() to avoid it auto-creation auto off1 = cl->GetDataMemberOffset("fHistogram"); if (off1 > 0) ExtractObjectColors(item, *((TObject **) ((char *) fObj.get() + off1))); - // here make identic to gHistogram, one also can use TMethodCall + // here make identical to fHistogram, one also can use TMethodCall auto off2 = cl->GetDataMemberOffset("fHists"); if (off2 > 0) { - TIter iter(*(TList **) (((char *) fObj.get() + off1))); + TIter iter(*(TList **) (((char *) fObj.get() + off2))); TObject *hist = nullptr; while ((hist = iter()) != nullptr) ExtractObjectColors(item, hist); From 658994c1f6faf3d35358839b9a801db83013ff08 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 12:57:40 +0200 Subject: [PATCH 242/309] [rdrawable] let use non-owned object in TObjectDrawable In case of TLegend or THStack original histogram or other TObject is cross-referenced. Therefore one should be able to reference such object and not copy/clone it --- graf2d/gpadv7/inc/ROOT/RDrawable.hxx | 2 + graf2d/gpadv7/inc/ROOT/RPadBase.hxx | 13 +++ graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx | 21 ++-- graf2d/gpadv7/src/TObjectDrawable.cxx | 114 +++++++++++++++------ tutorials/v7/df104.py | 31 +++--- 5 files changed, 122 insertions(+), 59 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RDrawable.hxx b/graf2d/gpadv7/inc/ROOT/RDrawable.hxx index c70668066075a..fd0186cc4bf7c 100644 --- a/graf2d/gpadv7/inc/ROOT/RDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/RDrawable.hxx @@ -190,6 +190,8 @@ protected: virtual std::unique_ptr Display(const RDisplayContext &); + void SetCssType(const std::string &csstype) { fCssType = csstype; } + virtual void OnDisplayItemDestroyed(RDisplayItem *) const {} virtual void SetDrawableVersion(Version_t vers) { fVersion = vers; } diff --git a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx index cb63d1c8f468e..d4de26c3f5e8d 100644 --- a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx @@ -112,6 +112,19 @@ public: return drawable; } + /// Add drawable of specified class T + template + std::shared_ptr Add(ARGS... args) + { + auto drawable = std::make_shared(args...); + + TestIfFrameRequired(drawable.get()); + + AddPrimitive(drawable); + + return drawable; + } + /// Add existing drawable instance to canvas std::shared_ptr Draw(std::shared_ptr &&drawable) { diff --git a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx index abe4fd43c6ad4..3ad7ffed8b5f7 100644 --- a/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx +++ b/graf2d/gpadv7/inc/ROOT/TObjectDrawable.hxx @@ -43,7 +43,8 @@ private: }; int fKind{kNone}; ///< object kind - Internal::RIOShared fObj; ///< The object to be painted + Internal::RIOShared fObj; ///< The object to be painted, owned by the drawable + const TObject *fExtObj{nullptr}; /// fOpt{this, "opt"}; /// &item, TObject *obj, const char *class_name, const char *class_member); - - static void ExtractObjectColors(std::unique_ptr &item, TObject *obj); + static void ExtractObjectColors(std::unique_ptr &item, const TObject *obj); static void CheckOwnership(TObject *obj); @@ -80,16 +79,20 @@ public: kPalette = 6 ///< list of colors from palette }; - TObjectDrawable(const TObject &obj); - TObjectDrawable(const TObject &obj, const std::string &opt); - TObjectDrawable(TObject *obj); - TObjectDrawable(TObject *obj, const std::string &opt); + TObjectDrawable(); + TObjectDrawable(TObject *obj, bool isowner = false); + TObjectDrawable(TObject *obj, const std::string &opt, bool isowner = false); TObjectDrawable(const std::shared_ptr &obj); TObjectDrawable(const std::shared_ptr &obj, const std::string &opt); TObjectDrawable(EKind kind, bool persistent = false); virtual ~TObjectDrawable(); - std::shared_ptr GetObject() const { return fObj.get_shared(); } + void Reset(); + + void Set(TObject *obj, bool isowner = false); + void Set(TObject *obj, const std::string &opt, bool isowner = false); + + const TObject *Get(); void SetOpt(const std::string &opt) { fOpt = opt; } std::string GetOpt() const { return fOpt; } diff --git a/graf2d/gpadv7/src/TObjectDrawable.cxx b/graf2d/gpadv7/src/TObjectDrawable.cxx index 2d178b830787e..b1e64084340f4 100644 --- a/graf2d/gpadv7/src/TObjectDrawable.cxx +++ b/graf2d/gpadv7/src/TObjectDrawable.cxx @@ -61,38 +61,30 @@ std::string TObjectDrawable::DetectCssType(const TObject *obj) } //////////////////////////////////////////////////////////////////// -/// Constructor, clones TObject instance +/// Default constructor -TObjectDrawable::TObjectDrawable(const TObject &obj) : RDrawable(DetectCssType(&obj)) +TObjectDrawable::TObjectDrawable() : RDrawable("tobject") { - fKind = kObject; - auto clone = obj.Clone(); - CheckOwnership(clone); - fObj = std::shared_ptr(clone); -} - -//////////////////////////////////////////////////////////////////// -/// Constructor, clones TObject instance - -TObjectDrawable::TObjectDrawable(const TObject &obj, const std::string &opt) : TObjectDrawable(obj) -{ - SetOpt(opt); } //////////////////////////////////////////////////////////////////// -/// Constructor, takes ownership over the object +/// Constructor, can take ownership over the object is isowner specified -TObjectDrawable::TObjectDrawable(TObject *obj) : RDrawable(DetectCssType(obj)) +TObjectDrawable::TObjectDrawable(TObject *obj, bool isowner) : RDrawable(DetectCssType(obj)) { fKind = kObject; - CheckOwnership(obj); - fObj = std::shared_ptr(obj); + if (isowner) { + CheckOwnership(obj); + fObj = std::shared_ptr(obj); + } else { + fExtObj = obj; + } } //////////////////////////////////////////////////////////////////// -/// Constructor, takes ownership over the object +/// Constructor, can take ownership over the object is isowner specified -TObjectDrawable::TObjectDrawable(TObject *obj, const std::string &opt) : TObjectDrawable(obj) +TObjectDrawable::TObjectDrawable(TObject *obj, const std::string &opt, bool isowner) : TObjectDrawable(obj, isowner) { SetOpt(opt); } @@ -133,6 +125,60 @@ TObjectDrawable::TObjectDrawable(EKind kind, bool persistent) : RDrawable("tobje TObjectDrawable::~TObjectDrawable() = default; + +//////////////////////////////////////////////////////////////////// +/// Reset object + +void TObjectDrawable::Reset() +{ + fKind = kNone; + fObj = nullptr; + fExtObj = nullptr; +} + + +//////////////////////////////////////////////////////////////////// +/// Return assigned object + +const TObject *TObjectDrawable::Get() +{ + // weak pointer - when object deleted outside only indirect way to handle it :( + if (fExtObj) { + if (!fExtObj->TestBit(TObject::kNotDeleted)) fExtObj = nullptr; + return fExtObj; + } + + return fObj.get(); +} + + +//////////////////////////////////////////////////////////////////// +/// Set object + +void TObjectDrawable::Set(TObject *obj, bool isowner) +{ + Reset(); + + SetCssType(DetectCssType(obj)); + fKind = kObject; + + if (isowner) { + CheckOwnership(obj); + fObj = std::shared_ptr(obj); + } else { + fExtObj = obj; + } +} + +//////////////////////////////////////////////////////////////////// +/// Set object + +void TObjectDrawable::Set(TObject *obj, const std::string &opt, bool isowner) +{ + Set(obj, isowner); + SetOpt(opt); +} + //////////////////////////////////////////////////////////////////// /// Convert TColor to RGB string for using with SVG @@ -190,7 +236,7 @@ std::unique_ptr TObjectDrawable::CreateSpecials(int kind) /// Check if object has specified color value and store it in display item /// Ensure that color matches on client side too -void TObjectDrawable::ExtractObjectColors(std::unique_ptr &item, TObject *obj) +void TObjectDrawable::ExtractObjectColors(std::unique_ptr &item, const TObject *obj) { if (!obj) return; @@ -236,21 +282,24 @@ void TObjectDrawable::ExtractObjectColors(std::unique_ptr &i std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ctxt) { if (GetVersion() > ctxt.GetLastVersion()) { - if ((fKind == kObject) || fObj) { - auto item = std::make_unique(*this, fKind, fObj.get()); - if ((fKind == kObject) && fObj) { - ExtractObjectColors(item, fObj.get()); + + auto obj = Get(); + + if ((fKind == kObject) || obj) { + auto item = std::make_unique(*this, fKind, obj); + if ((fKind == kObject) && obj) { + ExtractObjectColors(item, obj); // special handling of THStack to support any custom colors inside - if (strcmp(fObj->ClassName(), "THStack") == 0) { + if (strcmp(obj->ClassName(), "THStack") == 0) { TClass *cl = gROOT->GetClass("THStack"); // do not call stack->GetHistogram() to avoid it auto-creation auto off1 = cl->GetDataMemberOffset("fHistogram"); - if (off1 > 0) ExtractObjectColors(item, *((TObject **) ((char *) fObj.get() + off1))); + if (off1 > 0) ExtractObjectColors(item, *((TObject **) ((char *) obj + off1))); // here make identical to fHistogram, one also can use TMethodCall auto off2 = cl->GetDataMemberOffset("fHists"); if (off2 > 0) { - TIter iter(*(TList **) (((char *) fObj.get() + off2))); + TIter iter(*(TList **) (((char *) obj + off2))); TObject *hist = nullptr; while ((hist = iter()) != nullptr) ExtractObjectColors(item, hist); @@ -274,8 +323,9 @@ std::unique_ptr TObjectDrawable::Display(const RDisplayContext &ct void TObjectDrawable::PopulateMenu(RMenuItems &items) { - if (fKind == kObject) - items.PopulateObjectMenu(fObj.get(), fObj.get()->IsA()); + auto obj = Get(); + if ((fKind == kObject) && obj) + items.PopulateObjectMenu((void *)obj, obj->IsA()); } //////////////////////////////////////////////////////////////////// @@ -283,9 +333,9 @@ void TObjectDrawable::PopulateMenu(RMenuItems &items) void TObjectDrawable::Execute(const std::string &exec) { - if (fKind != kObject) return; + auto obj = Get(); - TObject *obj = fObj.get(); + if ((fKind != kObject) || !obj) return; std::string sub, ex = exec; if (ex.compare(0, 6, "xaxis#") == 0) { diff --git a/tutorials/v7/df104.py b/tutorials/v7/df104.py index 4d4a3acdc7e3b..a0cf05093d270 100644 --- a/tutorials/v7/df104.py +++ b/tutorials/v7/df104.py @@ -133,10 +133,12 @@ data.SetStats(0) data.SetTitle("") -data_drawable = upper_pad.Draw[TObjectDrawable](data, "E") +data_drawable = upper_pad.Add[TObjectDrawable]() +data_drawable.Set(data, "E") # Draw fit -fit_drawable = upper_pad.Draw[TObjectDrawable](fit, "SAME") +fit_drawable = upper_pad.Add[TObjectDrawable]() +fit_drawable.Set(fit, "SAME") # Draw background bkg = ROOT.TF1("bkg", "([0]+[1]*x+[2]*x^2+[3]*x^3)", 105, 160) @@ -145,7 +147,8 @@ bkg.SetLineColor(4) bkg.SetLineStyle(2) bkg.SetLineWidth(2) -bkg_drawable = upper_pad.Draw[TObjectDrawable](bkg, "SAME") +bkg_drawable = upper_pad.Add[TObjectDrawable]() +bkg_drawable.Set(bkg, "SAME") # Scale simulated events with luminosity * cross-section / sum of weights # and merge to single Higgs signal @@ -154,8 +157,8 @@ vbf.Scale(lumi * 0.008518764 / 3441426.13711) higgs = ggh.Clone() higgs.Add(vbf) -higgs_drawable = upper_pad.Draw[TObjectDrawable](higgs, "HIST SAME") - +higgs_drawable = upper_pad.Add[TObjectDrawable]() +higgs_drawable.Set(higgs, "HIST SAME") # Draw ratio @@ -176,7 +179,7 @@ ratiobkg.GetYaxis().SetNdivisions(503, False) ratiobkg.GetYaxis().ChangeLabel(-1, -1, 0) ratiobkg.GetXaxis().SetTitle("m_{#gamma#gamma} [GeV]") -lower_pad.Draw[TObjectDrawable](ratiobkg, "AXIS") +lower_pad.Add[TObjectDrawable]().Set(ratiobkg, "AXIS") ratiosig = ROOT.TH1F("ratiosig", "ratiosig", 5500, 105, 160) ratiosig.Eval(fit) @@ -184,22 +187,16 @@ ratiosig.SetLineStyle(1) ratiosig.SetLineWidth(2) ratiosig.Add(bkg, -1) -lower_pad.Draw[TObjectDrawable](ratiosig, "SAME") +lower_pad.Add[TObjectDrawable]().Set(ratiosig, "SAME") ratiodata = data.Clone() ratiodata.Add(bkg, -1) for i in range(1, data.GetNbinsX()): ratiodata.SetBinError(i, data.GetBinError(i)) -lower_pad.Draw[TObjectDrawable](ratiodata, "E SAME") - -# Add legend -# legend.SetTextFont(42) -# legend.SetFillStyle(0) -# legend.SetBorderSize(0) -# legend.SetTextSize(0.05) -# legend.SetTextAlign(32) +lower_pad.Add[TObjectDrawable]().Set(ratiodata, "E SAME") +# Add RLegend legend = upper_pad.Draw[RLegend](RPadPos(-0.05, 0.05), RPadExtent(0.3, 0.4)) legend.AttrText().SetFont(4).SetSize(0.05).SetAlign(32) legend.AttrBorder().SetStyle(0).SetWidth(0) @@ -210,11 +207,9 @@ legend.AddEntry(fit_drawable, "Signal + Bkg.") legend.AddEntry(higgs_drawable, "Signal") -# Add ATLAS label +# Add ATLAS labels upper_pad.Draw[RText](RPadPos(0.05, 0.88), "ATLAS").SetOnFrame().AttrText().SetFont(7).SetSize(0.05).SetAlign(11) - upper_pad.Draw[RText](RPadPos(0.05 + 0.16, 0.88), "Open Data").SetOnFrame().AttrText().SetFont(4).SetSize(0.05).SetAlign(11) - upper_pad.Draw[RText](RPadPos(0.05, 0.82), "#sqrt{s} = 13 TeV, 10 fb^{-1}").SetOnFrame().AttrText().SetFont(4).SetSize(0.04).SetAlign(11) # show canvas finally From 0f714b741b5377f51e19dd3881f8554c9f21064e Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 14:26:01 +0200 Subject: [PATCH 243/309] [RDF] adjust df105 tutorial to use proper drawing methods No need for extra subpad --- tutorials/dataframe/df105_WBosonAnalysis.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tutorials/dataframe/df105_WBosonAnalysis.py b/tutorials/dataframe/df105_WBosonAnalysis.py index 7efc0c06dbbcd..00d323f472d17 100644 --- a/tutorials/dataframe/df105_WBosonAnalysis.py +++ b/tutorials/dataframe/df105_WBosonAnalysis.py @@ -152,14 +152,11 @@ def merge_histos(label): # Set styles ROOT.gROOT.SetStyle("ATLAS") -# Create canvas with pad +# Create canvas c = ROOT.TCanvas("c", "", 600, 600) -pad = ROOT.TPad("upper_pad", "", 0, 0, 1, 1) -pad.SetTickx(False) -pad.SetTicky(False) -pad.SetLogy() -pad.Draw() -pad.cd() +c.SetTickx(0) +c.SetTicky(0) +c.SetLogy() # Draw stack with MC contributions stack = ROOT.THStack() @@ -201,7 +198,7 @@ def merge_histos(label): legend.AddEntry(ttbar, "t#bar{t}", "f") legend.AddEntry(diboson, "Diboson", "f") legend.AddEntry(singletop, "Single top", "f") -legend.Draw("SAME") +legend.Draw() # Add ATLAS label text = ROOT.TLatex() From db5185cfe4d2cd41fd848939f7e2d8a23cd85283 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 14:32:59 +0200 Subject: [PATCH 244/309] Introduce v7/df105.py tutorial It is replica of dataframe/df105_WBosonAnalysis.py with ROOT7 graphics Shows how THStack and TLegend can be used inside RCanvas Enables usage of df104 and df105 in regular tests --- tutorials/CMakeLists.txt | 5 +- tutorials/v7/df105.json | 79 ++++++++++++++ tutorials/v7/df105.py | 224 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 tutorials/v7/df105.json create mode 100644 tutorials/v7/df105.py diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index d6835d0b00ba6..ebfcc7fb50b2e 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -154,6 +154,8 @@ if(NOT xrootd) dataframe/df105_WBosonAnalysis.py dataframe/df106_HiggsToFourLeptons.py dataframe/df107_SingleTopAnalysis.py + v7/df104.py + v7/df105.py ) endif() @@ -279,7 +281,6 @@ if(root7) v7/filedialog.cxx v7/fitpanel.cxx v7/fitpanel6.cxx - v7/df104.py ) if(NOT davix) list(APPEND root7_veto v7/ntuple/ntpl003_lhcbOpenData.C) @@ -289,6 +290,8 @@ if(root7) if(NOT dataframe) list(APPEND root7_veto v7/global_temperatures.cxx) list(APPEND root7_veto v7/ntuple/ntpl004_dimuon.C) + list(APPEND root7_veto v7/df104.py) + list(APPEND root7_veto v7/df105.py) endif() else() file(GLOB v7_veto_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ v7/*.py v7/*.cxx v7/*/*.cxx v7/*.C v7/*/*.C) diff --git a/tutorials/v7/df105.json b/tutorials/v7/df105.json new file mode 100644 index 0000000000000..addf4ce8f0e25 --- /dev/null +++ b/tutorials/v7/df105.json @@ -0,0 +1,79 @@ +{ + "data" : [ + ["Data", "data_A", 1, 1, 9796409], + ["Data", "data_B", 1, 1, 34876159], + ["Data", "data_C", 1, 1, 51062653], + ["Data", "data_D", 1, 1, 72797894] + ], + "wjets" : [ + ["MC", "mc_364156.Wmunu_PTV0_70_CVetoBVeto", 15317.171239, 16619290.3298, 8395655], + ["MC", "mc_364157.Wmunu_PTV0_70_CFilterBVeto", 2431.204019, 5643599.11526, 3666435], + ["MC", "mc_364158.Wmunu_PTV0_70_BFilter", 828.465384, 10403012.6599, 5825714], + ["MC", "mc_364159.Wmunu_PTV70_140_CVetoBVeto", 617.439593, 5418398.88082, 5938327], + ["MC", "mc_364160.Wmunu_PTV70_140_CFilterBVeto", 225.006704, 3693885.78953, 4324088], + ["MC", "mc_364161.Wmunu_PTV70_140_BFilter", 76.213179, 7990084.35926, 7627337], + ["MC", "mc_364162.Wmunu_PTV140_280_CVetoBVeto", 198.635592, 6155495.28527, 4307536], + ["MC", "mc_364163.Wmunu_PTV140_280_CFilterBVeto", 96.233222, 5260811.17463, 3414229], + ["MC", "mc_364164.Wmunu_PTV140_280_BFilter", 36.348467, 7271557.26566, 10156709], + ["MC", "mc_364165.Wmunu_PTV280_500_CVetoBVeto", 38.299835, 4325283.67358, 2212380], + ["MC", "mc_364166.Wmunu_PTV280_500_CFilterBVeto", 22.395647, 2783968.68238, 1359827], + ["MC", "mc_364167.Wmunu_PTV280_500_BFilter", 8.768196, 2835707.22044, 1250346], + ["MC", "mc_364168.Wmunu_PTV500_1000", 14.558821, 5941704.99235, 2663211], + ["MC", "mc_364169.Wmunu_PTV1000_E_CMS", 1.198003, 4068015.22447, 1803723], + ["MC", "mc_364170.Wenu_PTV0_70_CVetoBVeto", 15324.216356, 16615214.8608, 7298003], + ["MC", "mc_364171.Wenu_PTV0_70_CFilterBVeto", 2430.656322, 5647044.71225, 3282722], + ["MC", "mc_364172.Wenu_PTV0_70_BFilter", 832.203758, 10407897.8772, 5152114], + ["MC", "mc_364173.Wenu_PTV70_140_CVetoBVeto", 618.6882, 5098540.19503, 5668671], + ["MC", "mc_364174.Wenu_PTV70_140_CFilterBVeto", 223.63946, 3661915.17878, 4252663], + ["MC", "mc_364175.Wenu_PTV70_140_BFilter", 94.875534, 3980401.78673, 3682270], + ["MC", "mc_364176.Wenu_PTV140_280_CVetoBVeto", 197.343129, 6121546.03361, 4347002], + ["MC", "mc_364177.Wenu_PTV140_280_CFilterBVeto", 96.277568, 5263243.42582, 2759996], + ["MC", "mc_364178.Wenu_PTV140_280_BFilter", 35.917295, 7327201.08884, 10298376], + ["MC", "mc_364179.Wenu_PTV280_500_CVetoBVeto", 38.340533, 4312357.01458, 2282542], + ["MC", "mc_364180.Wenu_PTV280_500_CFilterBVeto", 22.36999, 2778654.28759, 1431890], + ["MC", "mc_364181.Wenu_PTV280_500_BFilter", 9.586345, 2835314.68179, 1290392], + ["MC", "mc_364182.Wenu_PTV500_1000", 14.598599, 6003269.52809, 2821016], + ["MC", "mc_364183.Wenu_PTV1000_E_CMS", 1.197518, 4075236.23897, 1955306], + ["MC", "mc_364184.Wtaunu_PTV0_70_CVetoBVeto", 15324.887336, 11929044.1188, 445592], + ["MC", "mc_364185.Wtaunu_PTV0_70_CFilterBVeto", 2443.425881, 5671521.55269, 226449], + ["MC", "mc_364186.Wtaunu_PTV0_70_BFilter", 837.531038, 10498770.1084, 333628], + ["MC", "mc_364187.Wtaunu_PTV70_140_CVetoBVeto", 620.166885, 5427023.47527, 650945], + ["MC", "mc_364188.Wtaunu_PTV70_140_CFilterBVeto", 222.595303, 3719117.16117, 494987], + ["MC", "mc_364189.Wtaunu_PTV70_140_BFilter", 95.365521, 3969118.20687, 411187], + ["MC", "mc_364190.Wtaunu_PTV140_280_CVetoBVeto", 197.370776, 6166514.76606, 630080], + ["MC", "mc_364191.Wtaunu_PTV140_280_CFilterBVeto", 93.808553, 5085280.31607, 494208], + ["MC", "mc_364192.Wtaunu_PTV140_280_BFilter", 34.639523, 7291603.73991, 570262], + ["MC", "mc_364193.Wtaunu_PTV280_500_CVetoBVeto", 38.34009, 4322848.66983, 358142], + ["MC", "mc_364194.Wtaunu_PTV280_500_CFilterBVeto", 22.268425, 2772305.06916, 218066], + ["MC", "mc_364195.Wtaunu_PTV280_500_BFilter", 9.490847, 2830341.62344, 193784], + ["MC", "mc_364196.Wtaunu_PTV500_1000", 14.60345, 5932750.60186, 404545], + ["MC", "mc_364197.Wtaunu_PTV1000_E_CMS", 1.197324, 4057477.95297, 317213] + ], + "diboson" : [ + ["MC", "mc_363356.ZqqZll", 2.20355112, 3439266.11559, 906223], + ["MC", "mc_363358.WqqZll", 3.4328, 241438.72705, 868899], + ["MC", "mc_363359.WpqqWmlv", 24.708, 998250.783475, 1994768], + ["MC", "mc_363360.WplvWmqq", 24.724, 1069526.41899, 2082326], + ["MC", "mc_363489.WlvZqq", 11.42, 1111991.15979, 2084597], + ["MC", "mc_363490.llll", 1.2578, 7538705.8077, 1565698], + ["MC", "mc_363491.lllv", 4.6049, 5441475.00407, 2377339], + ["MC", "mc_363492.llvv", 12.466, 5039259.9696, 4034192], + ["MC", "mc_363493.lvvv", 3.2286, 1727991.07441, 1941620] + ], + "zjets" : [ + ["MC", "mc_361106.Zee", 1950.5295, 150277594200, 16442971], + ["MC", "mc_361107.Zmumu", 1950.6321, 147334691090, 12817061], + ["MC", "mc_361108.Ztautau", 1950.6321, 56171652547.3, 986942] + ], + "singletop" : [ + ["MC", "mc_410011.single_top_tchan", 44.152, 4986200, 1480867], + ["MC", "mc_410012.single_antitop_tchan", 26.276, 4989800, 1551985], + ["MC", "mc_410025.single_top_schan", 2.06121, 997800, 274207], + ["MC", "mc_410026.single_antitop_schan", 1.288662, 995400, 282567], + ["MC", "mc_410013.single_top_wtchan", 35.845486, 4865800, 898419], + ["MC", "mc_410014.single_antitop_wtchan", 35.824406, 4945600, 910949] + ], + "ttbar" : [ + ["MC", "mc_410000.ttbar_lep", 452.693559, 49296600, 15747840] + ] +} diff --git a/tutorials/v7/df105.py b/tutorials/v7/df105.py new file mode 100644 index 0000000000000..42c79d8a89195 --- /dev/null +++ b/tutorials/v7/df105.py @@ -0,0 +1,224 @@ +## \file +## \ingroup tutorial_dataframe +## \notebook -draw +## The W boson mass analysis from the ATLAS Open Data release of 2020, with RDataFrame. +## +## This tutorial is the analysis of the W boson mass taken from the ATLAS Open Data release in 2020 +## (http://opendata.atlas.cern/release/2020/documentation/). The data was recorded with the ATLAS detector +## during 2016 at a center-of-mass energy of 13 TeV. W bosons are produced frequently at the LHC and +## are an important background to studies of Standard Model processes, for example the Higgs boson analyses. +## +## The analysis is translated to a RDataFrame workflow processing up to 60 GB of simulated events and data. +## By default the analysis runs on a preskimmed dataset to reduce the runtime. The full dataset can be used with +## the --full-dataset argument and you can also run only on a fraction of the original dataset using the argument --lumi-scale. +## +## This macro is replica of tutorials/dataframe/df105_WBosonAnalysis.py, but with usage of ROOT7 graphics +## Run macro with python3 -i df105.py command to get interactive canvas +## +## \macro_image (rcanvas_js) +## \macro_code +## +## \date March 2020 +## \authors Stefan Wunsch (KIT, CERN) Sergey Linev (GSI) + +import ROOT +import json +import argparse +import os +from ROOT.Experimental import RCanvas, RText, RPadPos, TObjectDrawable + +# Argument parsing +parser = argparse.ArgumentParser() +parser.add_argument("--lumi-scale", type=float, default=0.001, + help="Run only on a fraction of the total available 10 fb^-1 (only usable together with --full-dataset)") +parser.add_argument("--full-dataset", action="store_true", default=False, + help="Use the full dataset (use --lumi-scale to run only on a fraction of it)") +parser.add_argument("-b", action="store_true", default=False, help="Use ROOT batch mode") +parser.add_argument("-t", action="store_true", default=False, help="Use implicit multi threading (for the full dataset only possible with --lumi-scale 1.0)") +args = parser.parse_args() + +if args.b: ROOT.gROOT.SetWebDisplay("batch") +if args.t: ROOT.EnableImplicitMT() + +if not args.full_dataset: lumi_scale = 0.001 # The preskimmed dataset contains only 0.01 fb^-1 +else: lumi_scale = args.lumi_scale +lumi = 10064.0 +print('Run on data corresponding to {:.2f} fb^-1 ...'.format(lumi * lumi_scale / 1000.0)) + +if args.full_dataset: dataset_path = "root://eospublic.cern.ch//eos/opendata/atlas/OutreachDatasets/2020-01-22" +else: dataset_path = "root://eospublic.cern.ch//eos/root-eos/reduced_atlas_opendata/w" + +# Create a ROOT dataframe for each dataset +# Note that we load the filenames from the external json file placed in the same folder than this script. +files = json.load(open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "df105.json"))) +processes = files.keys() +df = {} +xsecs = {} +sumws = {} +samples = [] +for p in processes: + for d in files[p]: + # Construct the dataframes + folder = d[0] # Folder name + sample = d[1] # Sample name + xsecs[sample] = d[2] # Cross-section + sumws[sample] = d[3] # Sum of weights + num_events = d[4] # Number of events + samples.append(sample) + df[sample] = ROOT.RDataFrame("mini", "{}/1lep/{}/{}.1lep.root".format(dataset_path, folder, sample)) + + # Scale down the datasets if requested + if args.full_dataset and lumi_scale < 1.0: + df[sample] = df[sample].Range(int(num_events * lumi_scale)) + +# Select events for the analysis + +# Just-in-time compile custom helper function performing complex computations +ROOT.gInterpreter.Declare(""" +bool GoodElectronOrMuon(int type, float pt, float eta, float phi, float e, float trackd0pv, float tracksigd0pv, float z0) +{ + ROOT::Math::PtEtaPhiEVector p(pt / 1000.0, eta, phi, e / 1000.0); + if (abs(z0 * sin(p.theta())) > 0.5) return false; + if (type == 11 && abs(eta) < 2.46 && (abs(eta) < 1.37 || abs(eta) > 1.52)) { + if (abs(trackd0pv / tracksigd0pv) > 5) return false; + return true; + } + if (type == 13 && abs(eta) < 2.5) { + if (abs(trackd0pv / tracksigd0pv) > 3) return false; + return true; + } + return false; +} +""") + +for s in samples: + # Select events with a muon or electron trigger and with a missing transverse energy larger than 30 GeV + df[s] = df[s].Filter("trigE || trigM")\ + .Filter("met_et > 30000") + + # Find events with exactly one good lepton + df[s] = df[s].Define("good_lep", "lep_isTightID && lep_pt > 35000 && lep_ptcone30 / lep_pt < 0.1 && lep_etcone20 / lep_pt < 0.1")\ + .Filter("ROOT::VecOps::Sum(good_lep) == 1") + + # Apply additional cuts in case the lepton is an electron or muon + df[s] = df[s].Define("idx", "ROOT::VecOps::ArgMax(good_lep)")\ + .Filter("GoodElectronOrMuon(lep_type[idx], lep_pt[idx], lep_eta[idx], lep_phi[idx], lep_E[idx], lep_trackd0pvunbiased[idx], lep_tracksigd0pvunbiased[idx], lep_z0[idx])") + +# Apply luminosity, scale factors and MC weights for simulated events +for s in samples: + if "data" in s: + df[s] = df[s].Define("weight", "1.0") + else: + df[s] = df[s].Define("weight", "scaleFactor_ELE * scaleFactor_MUON * scaleFactor_LepTRIGGER * scaleFactor_PILEUP * mcWeight * {} / {} * {}".format(xsecs[s], sumws[s], lumi)) + +# Compute transverse mass of the W boson using the lepton and the missing transverse energy and make a histogram +ROOT.gInterpreter.Declare(""" +float ComputeTransverseMass(float met_et, float met_phi, float lep_pt, float lep_eta, float lep_phi, float lep_e) +{ + ROOT::Math::PtEtaPhiEVector met(met_et, 0, met_phi, met_et); + ROOT::Math::PtEtaPhiEVector lep(lep_pt, lep_eta, lep_phi, lep_e); + return (met + lep).Mt() / 1000.0; +} +""") + +histos = {} +for s in samples: + df[s] = df[s].Define("mt_w", "ComputeTransverseMass(met_et, met_phi, lep_pt[idx], lep_eta[idx], lep_phi[idx], lep_E[idx])") + histos[s] = df[s].Histo1D(ROOT.RDF.TH1DModel(s, "mt_w", 24, 60, 180), "mt_w", "weight") + +# Run the event loop and merge histograms of the respective processes + +# RunGraphs allows to run the event loops of the separate RDataFrame graphs +# concurrently. This results in an improved usage of the available resources +# if each separate RDataFrame can not utilize all available resources, e.g., +# because not enough data is available. +ROOT.RDF.RunGraphs([histos[s] for s in samples]) + +def merge_histos(label): + h = None + for i, d in enumerate(files[label]): + t = histos[d[1]].GetValue() + if i == 0: h = t.Clone() + else: h.Add(t) + h.SetNameTitle(label, label) + return h + +data = merge_histos("data") +wjets = merge_histos("wjets") +zjets = merge_histos("zjets") +ttbar = merge_histos("ttbar") +diboson = merge_histos("diboson") +singletop = merge_histos("singletop") + +# Create the plot + +# Set styles +ROOT.gROOT.SetStyle("ATLAS") + +# Create canvas and configure frame with axis attributes +c = RCanvas.Create("df105_WBosonAnalysis") +frame = c.GetOrCreateFrame() +frame.AttrMargins().SetTop(0.05).SetLeft(0.16).SetRight(0.05).SetBottom(0.16) +# c.SetTickx(0) +# c.SetTicky(0) + +frame.AttrX().SetMinMax(60,180) +frame.AttrX().SetTitle("m_{T}^{W#rightarrow l#nu} [GeV]") +frame.AttrX().AttrTitle().SetSize(0.045) +frame.AttrX().SetTitleOffset(0.01) +frame.AttrX().AttrLabels().SetSize(0.04) + +frame.AttrY().SetMinMax(1, 1e10*args.lumi_scale) +frame.AttrY().SetLog() +frame.AttrY().SetTitle("Events") +frame.AttrY().AttrTitle().SetSize(0.045) +frame.AttrY().AttrLabels().SetSize(0.04) + +# instruct RFrame to draw axes +frame.SetDrawAxes(True) + +# Draw stack with MC contributions +stack = ROOT.THStack() +for h, color in zip( + [singletop, diboson, ttbar, zjets, wjets], + [(208, 240, 193), (195, 138, 145), (155, 152, 204), (248, 206, 104), (222, 90, 106)]): + h.SetLineWidth(1) + h.SetLineColor(1) + h.SetFillColor(ROOT.TColor.GetColor(*color)) + stack.Add(h) +c.Add[TObjectDrawable]().Set(stack, "HIST SAME") + +# Draw data +data.SetMarkerStyle(20) +data.SetMarkerSize(1.2) +data.SetLineWidth(2) +data.SetLineColor(ROOT.kBlack) +c.Add[TObjectDrawable]().Set(data, "E SAME") + +# Add TLegend while histograms packed in the THStack +legend = ROOT.TLegend(0.60, 0.65, 0.92, 0.92) +legend.SetTextFont(42) +legend.SetFillStyle(0) +legend.SetBorderSize(0) +legend.SetTextSize(0.04) +legend.SetTextAlign(32) +legend.AddEntry(data, "Data" ,"lep") +legend.AddEntry(wjets, "W+jets", "f") +legend.AddEntry(zjets, "Z+jets", "f") +legend.AddEntry(ttbar, "t#bar{t}", "f") +legend.AddEntry(diboson, "Diboson", "f") +legend.AddEntry(singletop, "Single top", "f") +c.Add[TObjectDrawable]().Set(legend) + +# Add ATLAS label +c.Add[RText](RPadPos(0.05, 0.88), "ATLAS").SetOnFrame().AttrText().SetFont(7).SetSize(0.04).SetAlign(11) +c.Add[RText](RPadPos(0.05 + 0.20, 0.88), "Open Data").SetOnFrame().AttrText().SetFont(4).SetSize(0.04).SetAlign(11) +c.Add[RText](RPadPos(0.05, 0.82), "#sqrt{{s}} = 13 TeV, {:.2f} fb^{{-1}}".format(lumi * args.lumi_scale / 1000.0)).SetOnFrame().AttrText().SetFont(4).SetSize(0.035).SetAlign(11) + +# show canvas finally +c.SetSize(600, 600) +c.Show() + +# Save the plot +c.SaveAs("df105.png") +print("Saved figure to df105.png") From 58a708f83e2cf238425676556eab84ca82882e62 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 14:34:46 +0200 Subject: [PATCH 245/309] [jsroot] dev 17/06/2021 with several fixes for TObjectDrawable Plus adjusted code for TPaletteAxis drawing --- js/scripts/JSRoot.core.js | 2 +- js/scripts/JSRoot.hist.js | 10 ++++------ js/scripts/JSRoot.v7gpad.js | 10 ++++++++-- js/scripts/JSRoot.v7hist.js | 4 ---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/scripts/JSRoot.core.js b/js/scripts/JSRoot.core.js index c5c94e53aca9b..177022f25f2fb 100644 --- a/js/scripts/JSRoot.core.js +++ b/js/scripts/JSRoot.core.js @@ -104,7 +104,7 @@ /** @summary JSROOT version date * @desc Release date in format day/month/year like "14/01/2021"*/ - JSROOT.version_date = "15/06/2021"; + JSROOT.version_date = "17/06/2021"; /** @summary JSROOT version id and date * @desc Produced by concatenation of {@link JSROOT.version_id} and {@link JSROOT.version_date} diff --git a/js/scripts/JSRoot.hist.js b/js/scripts/JSRoot.hist.js index 567bdc5f39368..151a3787d9bdd 100644 --- a/js/scripts/JSRoot.hist.js +++ b/js/scripts/JSRoot.hist.js @@ -3122,7 +3122,7 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { pal = JSROOT.create('TPave'); JSROOT.extend(pal, { _typename: "TPaletteAxis", fName: "TPave", fH: null, fAxis: JSROOT.create('TGaxis'), - fX1NDC: 0.91, fX2NDC: 0.95, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1 } ); + fX1NDC: 0.905, fX2NDC: 0.945, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1, $can_move: true } ); let zaxis = this.getHisto().fZaxis; @@ -3140,9 +3140,9 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { let frame_painter = this.getFramePainter(); // keep palette width - if (can_move && frame_painter) { - pal.fX2NDC = frame_painter.fX2NDC + 0.01 + (pal.fX2NDC - pal.fX1NDC); - pal.fX1NDC = frame_painter.fX2NDC + 0.01; + if (can_move && frame_painter && pal.$can_move) { + pal.fX2NDC = frame_painter.fX2NDC + 0.005 + (pal.fX2NDC - pal.fX1NDC); + pal.fX1NDC = frame_painter.fX2NDC + 0.005; pal.fY1NDC = frame_painter.fY1NDC; pal.fY2NDC = frame_painter.fY2NDC; } @@ -6671,8 +6671,6 @@ JSROOT.define(['d3', 'painter', 'gpad'], (d3, jsrp) => { painter._show_empty_bins = false; - painter._can_move_colz = true; - // special case for root 3D drawings - pad range is wired painter.checkPadRange(!painter.options.Mode3D && (painter.options.Contour != 14)); diff --git a/js/scripts/JSRoot.v7gpad.js b/js/scripts/JSRoot.v7gpad.js index 0e58be6203deb..111199f14e64a 100644 --- a/js/scripts/JSRoot.v7gpad.js +++ b/js/scripts/JSRoot.v7gpad.js @@ -1708,6 +1708,8 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { * @private */ RFramePainter.prototype.createXY = function(opts) { + if (this.self_drawaxes) return; + this.cleanXY(); // remove all previous configurations if (!opts) opts = {}; @@ -1755,7 +1757,11 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.scale_ymax = this.zoom_ymax; } - this.x_handle = new JSROOT.TAxisPainter(this.getDom(), this.xaxis, true); + let xaxis = this.xaxis, yaxis = this.yaxis; + if (!xaxis || xaxis._typename != "TAxis") xaxis = JSROOT.create("TAxis"); + if (!yaxis || yaxis._typename != "TAxis") yaxis = JSROOT.create("TAxis"); + + this.x_handle = new JSROOT.TAxisPainter(this.getDom(), xaxis, true); this.x_handle.setPadName(this.getPadName()); this.x_handle.optionUnlab = this.v7EvalAttr("x_hidelabels", false); @@ -1768,7 +1774,7 @@ JSROOT.define(['d3', 'painter'], (d3, jsrp) => { this.x_handle.assignFrameMembers(this,"x"); - this.y_handle = new JSROOT.TAxisPainter(this.getDom(), this.yaxis, true); + this.y_handle = new JSROOT.TAxisPainter(this.getDom(), yaxis, true); this.y_handle.setPadName(this.getPadName()); this.y_handle.optionUnlab = this.v7EvalAttr("y_hidelabels", false); diff --git a/js/scripts/JSRoot.v7hist.js b/js/scripts/JSRoot.v7hist.js index 225aeb3b602ea..1248d6d3e3349 100644 --- a/js/scripts/JSRoot.v7hist.js +++ b/js/scripts/JSRoot.v7hist.js @@ -2092,8 +2092,6 @@ JSROOT.define(['d3', 'painter', 'v7gpad'], (d3, jsrp) => { this.options.Color = !this.options.Color; } - this._can_move_colz = true; // indicate that next redraw can move Z scale - this.redraw(); } @@ -3768,8 +3766,6 @@ JSROOT.define(['d3', 'painter', 'v7gpad'], (d3, jsrp) => { painter._show_empty_bins = false; - painter._can_move_colz = true; - painter.scanContent(); return painter.callDrawFunc(); From 6419947f2a9750bb7a7c2f7e15a7a64e3ca70472 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 14:55:30 +0200 Subject: [PATCH 246/309] [rcanvas] introduce RPadBase::AddPad() method It is the only place where new sub-pad can be introduced. Make Pad constructor private. Divide(nx,xy) uses AddPad() --- graf2d/gpadv7/inc/ROOT/RPad.hxx | 22 ++++++++++++++-------- graf2d/gpadv7/inc/ROOT/RPadBase.hxx | 26 +++++++++++++------------- graf2d/gpadv7/src/RPadBase.cxx | 27 +++++++++++++++------------ tutorials/v7/df104.py | 6 +++--- 4 files changed, 45 insertions(+), 36 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RPad.hxx b/graf2d/gpadv7/inc/ROOT/RPad.hxx index 3f61c4c0e5f42..cd3c40a66cd9a 100644 --- a/graf2d/gpadv7/inc/ROOT/RPad.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPad.hxx @@ -34,14 +34,7 @@ class RPad: public RPadBase { RAttrLine fAttrLine{this, "border"}; /// Display(const RDisplayContext &) final; - -public: - /// Create a topmost, non-paintable pad. + /// Create default pad RPad() : RPadBase("pad") {} /// Create a pad. @@ -51,6 +44,19 @@ public: fSize = size; } + // Assign parent + void SetParent(RPadBase *parent) { fParent = parent; } + +protected: + + std::unique_ptr Display(const RDisplayContext &) final; + + +public: + + /// Constructor must be used only for I/O + RPad(TRootIOCtor*) : RPad() {} + /// Destructor to have a vtable. virtual ~RPad(); diff --git a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx index d4de26c3f5e8d..c3ff338f64dcf 100644 --- a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx @@ -66,8 +66,6 @@ protected: void SetDrawableVersion(Version_t vers) override; - void AddPrimitive(std::shared_ptr drawable); - public: using Primitives_t = std::vector>; @@ -76,13 +74,6 @@ public: void UseStyle(const std::shared_ptr &style) override; - /// Divide this pad into a grid of subpads with padding in between. - /// \param nHoriz Number of horizontal pads. - /// \param nVert Number of vertical pads. - /// \param padding Padding between pads. - /// \returns vector of vector (ret[x][y]) of created pads. - std::vector>> Divide(int nHoriz, int nVert, const RPadExtent &padding = {}); - /// Add object to be painted. /// Correspondent drawable will be created via GetDrawable() function which should be defined and be accessed at calling time. /// If required, extra arguments for GetDrawable() function can be provided. @@ -94,7 +85,7 @@ public: TestIfFrameRequired(drawable.get()); - AddPrimitive(drawable); + fPrimitives.emplace_back(drawable); return drawable; } @@ -107,7 +98,7 @@ public: TestIfFrameRequired(drawable.get()); - AddPrimitive(drawable); + fPrimitives.emplace_back(drawable); return drawable; } @@ -120,7 +111,7 @@ public: TestIfFrameRequired(drawable.get()); - AddPrimitive(drawable); + fPrimitives.emplace_back(drawable); return drawable; } @@ -132,7 +123,7 @@ public: auto dr = std::move(drawable); - AddPrimitive(dr); + fPrimitives.emplace_back(dr); return dr; } @@ -202,6 +193,15 @@ public: std::shared_ptr GetFrame(); const std::shared_ptr GetFrame() const; + std::shared_ptr AddPad(const RPadPos &, const RPadExtent &); + + /// Divide this pad into a grid of subpads with padding in between. + /// \param nHoriz Number of horizontal pads. + /// \param nVert Number of vertical pads. + /// \param padding Padding between pads. + /// \returns vector of vector (ret[x][y]) of created pads. + std::vector>> Divide(int nHoriz, int nVert, const RPadExtent &padding = {}); + /// Access to the top-most canvas, if any (const version). virtual const RCanvas *GetCanvas() const = 0; diff --git a/graf2d/gpadv7/src/RPadBase.cxx b/graf2d/gpadv7/src/RPadBase.cxx index 9b9ee249875d6..a9e8c263cefe3 100644 --- a/graf2d/gpadv7/src/RPadBase.cxx +++ b/graf2d/gpadv7/src/RPadBase.cxx @@ -34,17 +34,6 @@ void RPadBase::UseStyle(const std::shared_ptr &style) drawable->UseStyle(style); } -/////////////////////////////////////////////////////////////////////////// -/// Add primitive - -void RPadBase::AddPrimitive(std::shared_ptr drawable) -{ - if (auto pad = dynamic_cast(drawable.get())) - pad->SetParent(this); - - fPrimitives.emplace_back(drawable); -} - /////////////////////////////////////////////////////////////////////////// /// Find primitive with specified id @@ -143,6 +132,20 @@ void RPadBase::DisplayPrimitives(RPadBaseDisplayItem &paditem, RDisplayContext & } } +/////////////////////////////////////////////////////////////////////////// +/// Add subpad + +std::shared_ptr RPadBase::AddPad(const RPadPos &pos, const RPadExtent &extent) +{ + auto pad = new RPad(pos, extent); + + pad->SetParent(this); + std::shared_ptr pshared(pad); + + fPrimitives.emplace_back(pshared); + return pshared; +} + /////////////////////////////////////////////////////////////////////////// /// Divide pad on nHoriz X nVert subpads /// Return array of array of pads @@ -171,7 +174,7 @@ RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding) RPadPos subPos = offset; subPos *= {1. * iHoriz, 1. * iVert}; - auto subpad = Draw(subPos, size); + auto subpad = AddPad(subPos, size); ret.back().emplace_back(subpad); } diff --git a/tutorials/v7/df104.py b/tutorials/v7/df104.py index a0cf05093d270..fd5db9e4a84f2 100644 --- a/tutorials/v7/df104.py +++ b/tutorials/v7/df104.py @@ -21,7 +21,7 @@ import ROOT import os -from ROOT.Experimental import RCanvas, RPad, RText, RLegend, RPadPos, RPadExtent, TObjectDrawable +from ROOT.Experimental import RCanvas, RText, RLegend, RPadPos, RPadExtent, TObjectDrawable # Enable multi-threading ROOT.ROOT.EnableImplicitMT() @@ -100,8 +100,8 @@ # Create canvas with pads for main plot and data/MC ratio c = RCanvas.Create("df104_HiggsToTwoPhotons") -lower_pad = c.Draw[RPad](RPadPos(0,0.65), RPadExtent(1, 0.35)) -upper_pad = c.Draw[RPad](RPadPos(0,0), RPadExtent(1, 0.65)) +lower_pad = c.AddPad(RPadPos(0,0.65), RPadExtent(1, 0.35)) +upper_pad = c.AddPad(RPadPos(0,0), RPadExtent(1, 0.65)) upper_frame = upper_pad.GetOrCreateFrame() upper_frame.AttrMargins().SetBottom(0).SetLeft(0.14).SetRight(0.05) From 6b4e7b3fda6e5b3c1d584163fbcce6124f0b464f Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 17 Jun 2021 15:10:19 +0200 Subject: [PATCH 247/309] [rcanvas] inctorduce RPadBase::AddFrame method It adds RFrame to current list of primitives. Replaces GetOrCreateFrame --- graf2d/gpadv7/inc/ROOT/RPadBase.hxx | 4 ++-- graf2d/gpadv7/src/RPadBase.cxx | 6 +++--- graf2d/gpadv7/test/rpave.cxx | 2 +- tutorials/v7/df104.py | 4 ++-- tutorials/v7/df105.py | 2 +- tutorials/v7/draw_frame.cxx | 2 +- tutorials/v7/draw_rh1_large.cxx | 2 +- tutorials/v7/draw_rh2_colz.cxx | 2 +- tutorials/v7/draw_rh2_large.cxx | 2 +- tutorials/v7/draw_rh3_large.cxx | 2 +- tutorials/v7/draw_symlog.cxx | 6 +++--- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx index c3ff338f64dcf..12fb8cf973de6 100644 --- a/graf2d/gpadv7/inc/ROOT/RPadBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RPadBase.hxx @@ -53,7 +53,7 @@ private: void TestIfFrameRequired(const RDrawable *drawable) { if (drawable->IsFrameRequired()) - GetOrCreateFrame(); + AddFrame(); } protected: @@ -189,7 +189,7 @@ public: /// Wipe the pad by clearing the list of primitives. void Wipe() { fPrimitives.clear(); } - std::shared_ptr GetOrCreateFrame(); + std::shared_ptr AddFrame(); std::shared_ptr GetFrame(); const std::shared_ptr GetFrame() const; diff --git a/graf2d/gpadv7/src/RPadBase.cxx b/graf2d/gpadv7/src/RPadBase.cxx index a9e8c263cefe3..206ac5a7b6dd8 100644 --- a/graf2d/gpadv7/src/RPadBase.cxx +++ b/graf2d/gpadv7/src/RPadBase.cxx @@ -183,10 +183,10 @@ RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding) } ///////////////////////////////////////////////////////////////////////////////////////////////// -/// Get a frame object for the pad. -/// If frame not exists - creates and add to the end of primitives list +/// Add a frame object for the pad. +/// If frame already exists - just return it -std::shared_ptr RPadBase::GetOrCreateFrame() +std::shared_ptr RPadBase::AddFrame() { auto frame = GetFrame(); if (!frame) { diff --git a/graf2d/gpadv7/test/rpave.cxx b/graf2d/gpadv7/test/rpave.cxx index 9edbc2423e1b0..f465b45afb70e 100644 --- a/graf2d/gpadv7/test/rpave.cxx +++ b/graf2d/gpadv7/test/rpave.cxx @@ -14,7 +14,7 @@ TEST(Primitives, RPave) { RCanvas canv; - auto frame = canv.GetOrCreateFrame(); + auto frame = canv.AddFrame(); auto pave = canv.Draw(); pave->AttrBorder().SetColor(RColor::kRed).SetWidth(3); diff --git a/tutorials/v7/df104.py b/tutorials/v7/df104.py index fd5db9e4a84f2..a20fee81e9cf3 100644 --- a/tutorials/v7/df104.py +++ b/tutorials/v7/df104.py @@ -103,11 +103,11 @@ lower_pad = c.AddPad(RPadPos(0,0.65), RPadExtent(1, 0.35)) upper_pad = c.AddPad(RPadPos(0,0), RPadExtent(1, 0.65)) -upper_frame = upper_pad.GetOrCreateFrame() +upper_frame = upper_pad.AddFrame() upper_frame.AttrMargins().SetBottom(0).SetLeft(0.14).SetRight(0.05) upper_frame.AttrX().SetHideLabels() -lower_frame = lower_pad.GetOrCreateFrame() +lower_frame = lower_pad.AddFrame() lower_frame.AttrMargins().SetTop(0).SetLeft(0.14).SetRight(0.05).SetBottom(0.3) # Fit signal + background model to data diff --git a/tutorials/v7/df105.py b/tutorials/v7/df105.py index 42c79d8a89195..68971385169f0 100644 --- a/tutorials/v7/df105.py +++ b/tutorials/v7/df105.py @@ -157,7 +157,7 @@ def merge_histos(label): # Create canvas and configure frame with axis attributes c = RCanvas.Create("df105_WBosonAnalysis") -frame = c.GetOrCreateFrame() +frame = c.AddFrame() frame.AttrMargins().SetTop(0.05).SetLeft(0.16).SetRight(0.05).SetBottom(0.16) # c.SetTickx(0) # c.SetTicky(0) diff --git a/tutorials/v7/draw_frame.cxx b/tutorials/v7/draw_frame.cxx index 19fece44bd1f0..2921d92cd6c69 100644 --- a/tutorials/v7/draw_frame.cxx +++ b/tutorials/v7/draw_frame.cxx @@ -41,7 +41,7 @@ void draw_frame() auto canvas = RCanvas::Create("Canvas Title"); // configure RFrame with direct API calls - auto frame = canvas->GetOrCreateFrame(); + auto frame = canvas->AddFrame(); // frame->AttrFill().SetColor(RColor::kBlue); frame->AttrBorder().SetColor(RColor::kBlue); frame->AttrBorder().SetWidth(3); diff --git a/tutorials/v7/draw_rh1_large.cxx b/tutorials/v7/draw_rh1_large.cxx index a8f547eb37553..0da745fe8eb9e 100644 --- a/tutorials/v7/draw_rh1_large.cxx +++ b/tutorials/v7/draw_rh1_large.cxx @@ -47,7 +47,7 @@ void draw_rh1_large() // Create a canvas to be displayed. auto canvas = RCanvas::Create("Canvas Title"); - auto frame = canvas->GetOrCreateFrame(); + auto frame = canvas->AddFrame(); frame->SetGridX(true).SetGridY(true); frame->AttrX().SetZoom(nbins*0.2, nbins*0.8); diff --git a/tutorials/v7/draw_rh2_colz.cxx b/tutorials/v7/draw_rh2_colz.cxx index b2620a6a15c33..94c9752668fc3 100644 --- a/tutorials/v7/draw_rh2_colz.cxx +++ b/tutorials/v7/draw_rh2_colz.cxx @@ -46,7 +46,7 @@ void draw_rh2_colz() // Create a canvas to be displayed. auto canvas = RCanvas::Create("Canvas Title"); - auto frame = canvas->GetOrCreateFrame(); + auto frame = canvas->AddFrame(); // should we made special style for frame with palette? frame->AttrMargins().SetRight(0.2_normal); diff --git a/tutorials/v7/draw_rh2_large.cxx b/tutorials/v7/draw_rh2_large.cxx index b48e8a0805de9..d6997e84e76b1 100644 --- a/tutorials/v7/draw_rh2_large.cxx +++ b/tutorials/v7/draw_rh2_large.cxx @@ -48,7 +48,7 @@ void draw_rh2_large() // Create a canvas to be displayed. auto canvas = RCanvas::Create("Canvas Title"); - auto frame = canvas->GetOrCreateFrame(); + auto frame = canvas->AddFrame(); // should we made special style for frame with palette? // frame->AttrMargins().SetRight(0.2_normal); diff --git a/tutorials/v7/draw_rh3_large.cxx b/tutorials/v7/draw_rh3_large.cxx index b7e80f92c8a85..6ebc2cea6c6ca 100644 --- a/tutorials/v7/draw_rh3_large.cxx +++ b/tutorials/v7/draw_rh3_large.cxx @@ -50,7 +50,7 @@ void draw_rh3_large() // Create a canvas to be displayed. auto canvas = RCanvas::Create("Canvas Title"); - auto frame = canvas->GetOrCreateFrame(); + auto frame = canvas->AddFrame(); // should we made special style for frame with palette? // frame->AttrMargins().SetRight(0.2_normal); diff --git a/tutorials/v7/draw_symlog.cxx b/tutorials/v7/draw_symlog.cxx index 9b831f4c2bf10..a35e65f7f587a 100644 --- a/tutorials/v7/draw_symlog.cxx +++ b/tutorials/v7/draw_symlog.cxx @@ -40,21 +40,21 @@ void draw_symlog() auto pads = canvas->Divide(1, 3); // first pad with linear scales - auto frame1 = pads[0][0]->GetOrCreateFrame(); + auto frame1 = pads[0][0]->AddFrame(); frame1->SetDrawAxes(true); frame1->AttrX().SetMinMax(-40, 1040).SetTitle("x linear").SetTitleCenter(); frame1->AttrY().SetMinMax(1,1e4).SetLog().SetTitle("y log").SetTitleCenter(); pads[0][0]->Draw("linear scale")->SetMargin(0.01_normal).SetHeight(0.1_normal); // second pad with log scales, negative values missing - auto frame2 = pads[0][1]->GetOrCreateFrame(); + auto frame2 = pads[0][1]->AddFrame(); frame2->SetDrawAxes(true); frame2->AttrX().SetMinMax(0.05,1.2e3).SetLog().SetTitle("x log").SetTitleCenter(); frame2->AttrY().SetMinMax(1,1e4).SetLog().SetTitle("y log").SetTitleCenter(); pads[0][1]->Draw("log scale, missing points")->SetMargin(0.01_normal).SetHeight(0.1_normal); // third pad with symlog scales - auto frame3 = pads[0][2]->GetOrCreateFrame(); + auto frame3 = pads[0][2]->AddFrame(); frame3->SetDrawAxes(true); // configure synlog scale with 10 for linear range, rest will be logarithmic, including negative frame3->AttrX().SetMinMax(-10,1.2e3).SetSymlog(10).SetTitle("x symlog").SetTitleCenter(); From 8aa2f145f8c7b5994a608caeee03e221891532f3 Mon Sep 17 00:00:00 2001 From: AdvaitDhingra <62119114+AdvaitDhingra@users.noreply.github.com> Date: Mon, 14 Jun 2021 21:34:53 +0200 Subject: [PATCH 248/309] Added Warning to TString constuctor The user now gets a warning in the TString::TString constructor if the input string is shorter than the requested size. --- core/base/src/TString.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/base/src/TString.cxx b/core/base/src/TString.cxx index 280f3affdeac0..b1632aa35e142 100644 --- a/core/base/src/TString.cxx +++ b/core/base/src/TString.cxx @@ -131,6 +131,9 @@ TString::TString(const char *cs, Ssiz_t n) Zero(); return; } + if (strlen(cs) < n) { + Warning("TString::TString", "Input string is shorter than requested size."); + } char *data = Init(n, n); memcpy(data, cs, n); } From a9d24058bb0188872651b77a250637ad0a566bc3 Mon Sep 17 00:00:00 2001 From: AdvaitDhingra <62119114+AdvaitDhingra@users.noreply.github.com> Date: Mon, 14 Jun 2021 21:38:07 +0200 Subject: [PATCH 249/309] TF1 CONV if statement fix The length of formula is now chached and reused. Furthermore strncmp is used instead of TString for preformance reasons. --- core/base/src/TString.cxx | 2 +- hist/hist/src/TF1.cxx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/base/src/TString.cxx b/core/base/src/TString.cxx index b1632aa35e142..9179e49d56f9c 100644 --- a/core/base/src/TString.cxx +++ b/core/base/src/TString.cxx @@ -131,7 +131,7 @@ TString::TString(const char *cs, Ssiz_t n) Zero(); return; } - if (strlen(cs) < n) { + if (strlen(cs) < (size_t)n) { Warning("TString::TString", "Input string is shorter than requested size."); } char *data = Init(n, n); diff --git a/hist/hist/src/TF1.cxx b/hist/hist/src/TF1.cxx index 885decc1d93c3..fd1fd19c79e10 100644 --- a/hist/hist/src/TF1.cxx +++ b/hist/hist/src/TF1.cxx @@ -530,13 +530,13 @@ TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EA fXmax = xmin; } // Create rep formula (no need to add to gROOT list since we will add the TF1 object) - + const auto formulaLength = strlen(formula); // First check if we are making a convolution - if (TString(formula, 5) == "CONV(" && formula[strlen(formula) - 1] == ')') { + if (strncmp(formula, "CONV(", 5) == 0 && formula[formulaLength - 1] == ')') { // Look for single ',' delimiter int delimPosition = -1; int parenCount = 0; - for (unsigned int i = 5; i < strlen(formula) - 1; i++) { + for (unsigned int i = 5; i < formulaLength - 1; i++) { if (formula[i] == '(') parenCount++; else if (formula[i] == ')') @@ -553,7 +553,7 @@ TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EA // Having found the delimiter, define the first and second formulas TString formula1 = TString(TString(formula)(5, delimPosition - 5)); - TString formula2 = TString(TString(formula)(delimPosition + 1, strlen(formula) - 1 - (delimPosition + 1))); + TString formula2 = TString(TString(formula)(delimPosition + 1, formulaLength - 1 - (delimPosition + 1))); // remove spaces from these formulas formula1.ReplaceAll(' ', ""); formula2.ReplaceAll(' ', ""); @@ -605,11 +605,11 @@ TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EA } // Then check if we need NSUM syntax: - } else if (TString(formula, 5) == "NSUM(" && formula[strlen(formula) - 1] == ')') { + } else if (strncmp(formula, "NSUM(", 5) == 0 && formula[formulaLength - 1] == ')') { // using comma as delimiter char delimiter = ','; // first, remove "NSUM(" and ")" and spaces - TString formDense = TString(formula)(5,strlen(formula)-5-1); + TString formDense = TString(formula)(5,formulaLength-5-1); formDense.ReplaceAll(' ', ""); // make sure standard functions are defined (e.g. gaus, expo) From f7ee1a3c2c7c4c6a3497235e5037147f630365a5 Mon Sep 17 00:00:00 2001 From: moneta Date: Wed, 26 May 2021 16:44:32 +0200 Subject: [PATCH 250/309] Fix setting convolution range when using the CONV operator. Thsi fixes ROOT issue #8252 --- hist/hist/src/TF1.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hist/hist/src/TF1.cxx b/hist/hist/src/TF1.cxx index fd1fd19c79e10..3a4110642d637 100644 --- a/hist/hist/src/TF1.cxx +++ b/hist/hist/src/TF1.cxx @@ -568,6 +568,8 @@ TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EA // std::cout << "functions have been defined" << std::endl; TF1Convolution *conv = new TF1Convolution(function1, function2); + // make sure we use the right range for the convolution + conv->SetRange(xmin,xmax); // (note: currently ignoring `useFFT` option) fNpar = conv->GetNpar(); From a3c8cc092d91039fa69619fdcf33a07d1f73283a Mon Sep 17 00:00:00 2001 From: moneta Date: Mon, 31 May 2021 18:38:24 +0200 Subject: [PATCH 251/309] fix handling of extra range for FFT convolution --- hist/hist/src/TF1.cxx | 4 +--- hist/hist/src/TF1Convolution.cxx | 13 +++++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/hist/hist/src/TF1.cxx b/hist/hist/src/TF1.cxx index 3a4110642d637..7255e7ba1e0fb 100644 --- a/hist/hist/src/TF1.cxx +++ b/hist/hist/src/TF1.cxx @@ -567,9 +567,7 @@ TF1::TF1(const char *name, const char *formula, Double_t xmin, Double_t xmax, EA // std::cout << "functions have been defined" << std::endl; - TF1Convolution *conv = new TF1Convolution(function1, function2); - // make sure we use the right range for the convolution - conv->SetRange(xmin,xmax); + TF1Convolution *conv = new TF1Convolution(function1, function2,xmin,xmax); // (note: currently ignoring `useFFT` option) fNpar = conv->GetNpar(); diff --git a/hist/hist/src/TF1Convolution.cxx b/hist/hist/src/TF1Convolution.cxx index 6f071846721b5..ab602115e06e6 100644 --- a/hist/hist/src/TF1Convolution.cxx +++ b/hist/hist/src/TF1Convolution.cxx @@ -90,11 +90,14 @@ void TF1Convolution::InitializeDataMembers(TF1* function1, TF1* function2, Bool_ fFunction1->SetBit(TF1::kNotGlobal, kTRUE); fFunction2->SetBit(TF1::kNotGlobal, kTRUE); - // add by default an extra 10% on each side + // use by default range of first function fFunction1->GetRange(fXmin, fXmax); - Double_t range = fXmax - fXmin; - fXmin -= 0.1*range; - fXmax += 0.1*range; + // when using FFT add by default an extra 10% on each side + if (useFFT) { + Double_t range = fXmax - fXmin; + fXmin -= 0.1*range; + fXmax += 0.1*range; + } fNofParams1 = fFunction1->GetNpar(); fNofParams2 = fFunction2->GetNpar(); fParams1 = std::vector(fNofParams1); @@ -150,6 +153,7 @@ TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Double_t xmin, Do if (xmin < xmax) { fXmin = xmin; fXmax = xmax; + if (useFFT) SetExtraRange(0.1); } else { Info("TF1Convolution", "Using default range [-inf, inf] for TF1Convolution"); SetRange(-TMath::Infinity(), TMath::Infinity()); @@ -186,6 +190,7 @@ TF1Convolution::TF1Convolution(TString formula, Double_t xmin, Double_t xmax, B if (xmin < xmax) { fXmin = xmin; fXmax = xmax; + if (useFFT) SetExtraRange(0.1); } else { Info("TF1Convolution", "Using default range [-inf, inf] for TF1Convolution"); SetRange(-TMath::Infinity(), TMath::Infinity()); From 6d6989d1c52b875092eb7c4b36896f59b902c63c Mon Sep 17 00:00:00 2001 From: Lorenzo Moneta Date: Tue, 1 Jun 2021 11:50:01 +0200 Subject: [PATCH 252/309] Fix a bug in TF1Convolution::SetExtraRange --- hist/hist/src/TF1Convolution.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TF1Convolution.cxx b/hist/hist/src/TF1Convolution.cxx index ab602115e06e6..8f798f7c9d241 100644 --- a/hist/hist/src/TF1Convolution.cxx +++ b/hist/hist/src/TF1Convolution.cxx @@ -426,7 +426,7 @@ void TF1Convolution::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double void TF1Convolution::SetExtraRange(Double_t percentage) { if (percentage<0) return; - double range = fXmax = fXmin; + double range = fXmax - fXmin; fXmin -= percentage * range; fXmax += percentage * range; fFlagGraph = false; // to indicate we need to re-do the convolution From d93287c93adb259bf0975cdbabaa288df76866ad Mon Sep 17 00:00:00 2001 From: Lorenzo Moneta Date: Wed, 16 Jun 2021 12:31:17 +0200 Subject: [PATCH 253/309] Add a new static data member in TF1Convolution defining the default used extra range. Add also a static setter function to define a new value. Update and improve doxygen documentation --- hist/hist/inc/TF1Convolution.h | 3 ++ hist/hist/src/TF1Convolution.cxx | 64 ++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/hist/hist/inc/TF1Convolution.h b/hist/hist/inc/TF1Convolution.h index f550f2c938cac..020b40ef467b1 100644 --- a/hist/hist/inc/TF1Convolution.h +++ b/hist/hist/inc/TF1Convolution.h @@ -35,6 +35,7 @@ class TF1Convolution : public TF1AbsComposition { Int_t fNofPoints; ///< Number of point for FFT array Bool_t fFlagFFT; ///< Choose FFT or numerical convolution Bool_t fFlagGraph = false; ///GetRange(fXmin, fXmax); // when using FFT add by default an extra 10% on each side if (useFFT) { - Double_t range = fXmax - fXmin; - fXmin -= 0.1*range; - fXmax += 0.1*range; + SetExtraRange(fgExtraRangeFraction); } fNofParams1 = fFunction1->GetNpar(); fNofParams2 = fFunction2->GetNpar(); @@ -129,7 +130,7 @@ void TF1Convolution::InitializeDataMembers(TF1* function1, TF1* function2, Bool_ } //////////////////////////////////////////////////////////////////////////////// -/// constructor without arguments +/// constructor without arguments. TF1Convolution::TF1Convolution() { @@ -137,7 +138,7 @@ TF1Convolution::TF1Convolution() } //////////////////////////////////////////////////////////////////////////////// -/// constructor from the two function pointer and a flag is using FFT +/// constructor from the two function pointer and a flag is using FFT. TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Bool_t useFFT) { @@ -145,7 +146,7 @@ TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Bool_t useFFT) } //////////////////////////////////////////////////////////////////////////////// -/// Constructor from the two function pointer and the convolution range +/// Constructor from the two function pointer and the convolution range. TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Double_t xmin, Double_t xmax, Bool_t useFFT) { @@ -153,7 +154,7 @@ TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Double_t xmin, Do if (xmin < xmax) { fXmin = xmin; fXmax = xmax; - if (useFFT) SetExtraRange(0.1); + if (useFFT) SetExtraRange(fgExtraRangeFraction); } else { Info("TF1Convolution", "Using default range [-inf, inf] for TF1Convolution"); SetRange(-TMath::Infinity(), TMath::Infinity()); @@ -161,7 +162,7 @@ TF1Convolution::TF1Convolution(TF1* function1, TF1* function2, Double_t xmin, Do } //////////////////////////////////////////////////////////////////////////////// -/// Constructor from a formula expression as f1 * f2 where f1 and f2 are two functions known to ROOT +/// Constructor from a formula expression as f1 * f2 where f1 and f2 are two functions known to ROOT. TF1Convolution::TF1Convolution(TString formula, Double_t xmin, Double_t xmax, Bool_t useFFT) { @@ -190,7 +191,7 @@ TF1Convolution::TF1Convolution(TString formula, Double_t xmin, Double_t xmax, B if (xmin < xmax) { fXmin = xmin; fXmax = xmax; - if (useFFT) SetExtraRange(0.1); + if (useFFT) SetExtraRange(fgExtraRangeFraction); } else { Info("TF1Convolution", "Using default range [-inf, inf] for TF1Convolution"); SetRange(-TMath::Infinity(), TMath::Infinity()); @@ -198,11 +199,11 @@ TF1Convolution::TF1Convolution(TString formula, Double_t xmin, Double_t xmax, B } //////////////////////////////////////////////////////////////////////////////// -/// constructor from 2 function names where f1 and f2 are two functions known to -/// ROOT +/// Constructor from 2 function names where f1 and f2 are two functions known to +/// ROOT. /// -/// if the function names are not known to ROOT, tries to interpret them as -/// TFormula +/// If the function names are not known to ROOT, tries to interpret them as +/// TFormula. TF1Convolution::TF1Convolution(TString formula1, TString formula2, Double_t xmin, Double_t xmax, Bool_t useFFT) { TF1::InitStandardFunctions(); @@ -233,7 +234,7 @@ TF1Convolution::TF1Convolution(TString formula1, TString formula2, Double_t xmi } //////////////////////////////////////////////////////////////////////////////// -/// Copy constructor (necessary to hold unique_ptr as member variable) +/// Copy constructor (necessary to hold unique_ptr as member variable). TF1Convolution::TF1Convolution(const TF1Convolution &conv) { @@ -251,7 +252,7 @@ TF1Convolution &TF1Convolution::operator=(const TF1Convolution &rhs) } //////////////////////////////////////////////////////////////////////////////// -/// Perform the FFT of the two functions +/// Perform the FFT of the two functions. void TF1Convolution::MakeFFTConv() { @@ -322,6 +323,7 @@ void TF1Convolution::MakeFFTConv() } //////////////////////////////////////////////////////////////////////////////// +/// Perform FFT convolution. Double_t TF1Convolution::EvalFFTConv(Double_t t) { @@ -336,10 +338,11 @@ Double_t TF1Convolution::EvalFFTConv(Double_t t) //////////////////////////////////////////////////////////////////////////////// /// Perform numerical convolution. -/// Could in principle cache the integral in a Graph as it is done for the FFTW +/// Double_t TF1Convolution::EvalNumConv(Double_t t) { + /// Could in principle cache the integral in a Graph as it is done for the FFTW TF1Convolution_EvalWrapper fconv( *fFunction1, *fFunction2, t); Double_t result = 0; @@ -372,6 +375,7 @@ Double_t TF1Convolution::operator()(const Double_t *x, const Double_t *p) } //////////////////////////////////////////////////////////////////////////////// +/// Set the number of points used for the FFT convolution. void TF1Convolution::SetNofPointsFFT(Int_t n) { @@ -382,6 +386,7 @@ void TF1Convolution::SetNofPointsFFT(Int_t n) } //////////////////////////////////////////////////////////////////////////////// +/// Set the vector of parameters p for the convolution function g(x,p) = f1 * f2. void TF1Convolution::SetParameters(const Double_t *params) { @@ -413,6 +418,7 @@ void TF1Convolution::SetParameters(const Double_t *params) } //////////////////////////////////////////////////////////////////////////////// +/// Set the parameter values for the convolution function. void TF1Convolution::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double_t p3, Double_t p4, Double_t p5, Double_t p6, Double_t p7) @@ -422,6 +428,10 @@ void TF1Convolution::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double } //////////////////////////////////////////////////////////////////////////////// +/// Set the fraction of extra range used when doing an FFT convolution. +/// The extra range is often needed to avoid mirroring effect of the resulting convolution +/// function at the borders. +/// By default an extra range of 0.1 is used. void TF1Convolution::SetExtraRange(Double_t percentage) { @@ -433,6 +443,9 @@ void TF1Convolution::SetExtraRange(Double_t percentage) } //////////////////////////////////////////////////////////////////////////////// +/// Set the actual range used for the convolution. +/// In case a or b are -inf or +inf and FFT convolution is used, then the +/// range of the first function will be used and extended by the default extra range fraction. void TF1Convolution::SetRange(Double_t a, Double_t b) { @@ -449,12 +462,25 @@ void TF1Convolution::SetRange(Double_t a, Double_t b) if (a ==-TMath::Infinity()) fXmin = fFunction1 -> GetXmin(); if ( b== TMath::Infinity()) fXmax = fFunction1 -> GetXmax(); // add a spill over of 10% in this case - SetExtraRange(0.1); + SetExtraRange(fgExtraRangeFraction); } fFlagGraph = false; // to indicate we need to re-do the convolution } //////////////////////////////////////////////////////////////////////////////// +/// Set the default extra range fraction used when doing a FFT convolution. +/// By default the value is 0.1 (10%). +/// The function return the previous default defined value. + +Double_t TF1Convolution::SetDefaultExtraRange(Double_t fraction) +{ + Double_t prevValue = fgExtraRangeFraction; + fgExtraRangeFraction = fraction; + return prevValue; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Get the range used for the convolution. void TF1Convolution::GetRange(Double_t &a, Double_t &b) const { @@ -463,7 +489,7 @@ void TF1Convolution::GetRange(Double_t &a, Double_t &b) const } //////////////////////////////////////////////////////////////////////////////// -/// Update the two component functions of the convolution +/// Update the two component functions of the convolution. void TF1Convolution::Update() { From 47d84bc08a6c61831c62726e672564253e1e3db8 Mon Sep 17 00:00:00 2001 From: "Harshal.S" Date: Thu, 17 Jun 2021 17:20:19 +0530 Subject: [PATCH 254/309] [RF] Added pythonizations for RooFit DecayType enum and refactored existing ones. --- .../ROOT/pythonization/_roofit/__init__.py | 39 ++++++++- .../_roofit/_rooabscollection.py | 36 ++++++++ .../ROOT/pythonization/_roofit/_rooabsdata.py | 46 ++++++---- .../ROOT/pythonization/_roofit/_rooabspdf.py | 86 ++++++++++++------- .../ROOT/pythonization/_roofit/_rooabsreal.py | 56 ++++++++---- .../_roofit/_rooabsreallvalue.py | 55 ++++++++++++ .../ROOT/pythonization/_roofit/_roochi2var.py | 40 +++++++++ .../pythonization/_roofit/_roodatahist.py | 48 +++++++++++ .../ROOT/pythonization/_roofit/_roodataset.py | 55 ++++++++++++ .../ROOT/pythonization/_roofit/_roodecays.py | 71 +++++++++++++++ .../pythonization/_roofit/_roogenfitstudy.py | 41 +++++++++ .../ROOT/pythonization/_roofit/_roomcstudy.py | 79 +++++++++++++++++ .../pythonization/_roofit/_roomsgservice.py | 51 +++++++++++ .../ROOT/pythonization/_roofit/_roonllvar.py | 40 +++++++++ .../ROOT/pythonization/_roofit/_rooprodpdf.py | 52 +++++++++++ .../pythonization/_roofit/_roosimultaneous.py | 22 ++--- .../pythonization/_roofit/_roosimwstool.py | 50 +++++++++++ .../pythonization/_roofit/_rooworkspace.py | 5 +- .../ROOT/pythonization/_roofit/_utils.py | 31 ++++++- 19 files changed, 814 insertions(+), 89 deletions(-) create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreallvalue.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roochi2var.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodatahist.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodataset.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodecays.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roogenfitstudy.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomcstudy.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomsgservice.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roonllvar.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooprodpdf.py create mode 100644 bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimwstool.py diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py index 92062145b0956..ca54ef11e4cf7 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/__init__.py @@ -19,14 +19,49 @@ from ._rooabsdata import RooAbsData from ._rooabspdf import RooAbsPdf from ._rooabsreal import RooAbsReal +from ._rooabsreallvalue import RooAbsRealLValue from ._rooarglist import RooArgList from ._rooargset import RooArgSet -from ._rooworkspace import RooWorkspace +from ._roochi2var import RooChi2Var +from ._roodatahist import RooDataHist +from ._roodataset import RooDataSet +from ._roodecays import RooDecay, RooBDecay, RooBCPGenDecay, RooBCPEffDecay, RooBMixDecay +from ._roogenfitstudy import RooGenFitStudy +from ._roomcstudy import RooMCStudy +from ._roomsgservice import RooMsgService +from ._roonllvar import RooNLLVar +from ._rooprodpdf import RooProdPdf from ._roosimultaneous import RooSimultaneous +from ._roosimwstool import RooSimWSTool +from ._rooworkspace import RooWorkspace # list of python classes that are used to pythonize RooFit classes -python_classes = [RooAbsCollection, RooAbsData, RooAbsPdf, RooAbsReal, RooArgList, RooArgSet, RooSimultaneous, RooWorkspace] +python_classes = [ + RooAbsCollection, + RooAbsData, + RooAbsPdf, + RooAbsReal, + RooAbsRealLValue, + RooArgList, + RooArgSet, + RooBCPGenDecay, + RooBCPEffDecay, + RooBDecay, + RooBMixDecay, + RooChi2Var, + RooDataHist, + RooDataSet, + RooDecay, + RooGenFitStudy, + RooMCStudy, + RooMsgService, + RooNLLVar, + RooProdPdf, + RooSimultaneous, + RooSimWSTool, + RooWorkspace, +] # create a dictionary for convenient access to python classes python_classes_dict = dict() diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py index e7ffcc894a5d5..5dc73902c98af 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py @@ -1,5 +1,6 @@ # Authors: # * Jonas Rembser 05/2021 +# * Harshal Shende 06/2021 ################################################################################ # Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # @@ -10,6 +11,35 @@ ################################################################################ +r""" +/** +\class RooAbsCollection +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooAbsCollection that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooAbsCollection::printLatex. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +params.printLatex(ROOT.RooFit.Sibling(initParams), ROOT.RooFit.Columns(2)) + +# With keyword arguments: +params.printLatex(Sibling=initParams, Columns =2) + +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs from libcppyy import SetOwnership @@ -17,3 +47,9 @@ class RooAbsCollection(object): def addOwned(self, arg, silent=False): self._addOwned(arg, silent) SetOwnership(arg, False) + + def printLatex(self, *args, **kwargs): + # Redefinition of `RooAbsCollection.printLatex` for keyword arguments. + # The keywords must correspond to the CmdArg of the `printLatex` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._printLatex(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsdata.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsdata.py index b9515568ff019..789382ef587c2 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsdata.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsdata.py @@ -1,6 +1,7 @@ # Authors: # * Hinnerk C. Schmidt 02/2021 # * Jonas Rembser 03/2021 +# * Harshal Shende 06/2021 ################################################################################ # Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # @@ -11,7 +12,7 @@ ################################################################################ -r''' +r""" /** \class RooAbsData \brief \parblock \endparblock @@ -22,7 +23,7 @@ ## PyROOT Some member functions of RooAbsData that take a RooCmdArg as argument also support keyword arguments. -So far, this applies to RooAbsData::plotOn. +This applies to RooAbsData::plotOn, RooAbsData::createHistogram, RooAbsData::reduce, RooAbsData::statOn. For example, the following code is equivalent in PyROOT: \code{.py} # Directly passing a RooCmdArg: @@ -36,25 +37,32 @@ \endhtmlonly */ -''' +""" -from ._utils import _getter +from ._utils import _kwargs_to_roocmdargs class RooAbsData(object): def plotOn(self, *args, **kwargs): - """ - Docstring - """ - # Redefinition of `RooAbsReal.plotOn` for keyword arguments. - # the keywords must correspond to the CmdArg of the `plotOn` function. - # Parameters: - # self: instance of `RooAbsReal` class - # *args: arguments passed to `plotOn` - # **kwargs: keyword arguments passed to `plotOn` - - if not kwargs: - return self._plotOn(*args) - else: - nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) - return self._plotOn(*nargs) + # Redefinition of `RooAbsData.plotOn` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotOn(*args, **kwargs) + + def createHistogram(self, *args, **kwargs): + # Redefinition of `RooAbsData.createHistogram` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createHistogram` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createHistogram(*args, **kwargs) + + def reduce(self, *args, **kwargs): + # Redefinition of `RooAbsData.reduce` for keyword arguments. + # The keywords must correspond to the CmdArg of the `reduce` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._reduce(*args, **kwargs) + + def statOn(self, *args, **kwargs): + # Redefinition of `RooAbsData.statOn` for keyword arguments. + # The keywords must correspond to the CmdArg of the `statOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._statOn(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabspdf.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabspdf.py index 042f947627d6c..ef409c8dd3005 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabspdf.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabspdf.py @@ -10,7 +10,7 @@ # For the list of contributors see $ROOTSYS/README/CREDITS. # ################################################################################ -r''' +r""" /** \class RooAbsPdf \brief \parblock \endparblock @@ -21,7 +21,8 @@ ## PyROOT Some member functions of RooAbsPdf that take a RooCmdArg as argument also support keyword arguments. -So far, this applies to RooAbsPdf::fitTo and RooAbsPdf::plotOn. +So far, this applies to RooAbsPdf::fitTo, RooAbsPdf::plotOn, RooAbsPdf::generate, RooAbsPdf::paramOn, RooAbsPdf::createCdf, +RooAbsPdf::generateBinned, RooAbsPdf::createChi2, RooAbsPdf::prepareMultiGen and RooAbsPdf::createNLL. For example, the following code is equivalent in PyROOT: \code{.py} # Directly passing a RooCmdArg: @@ -35,42 +36,63 @@ \endhtmlonly */ -''' - +""" from ._rooabsreal import RooAbsReal -from ._utils import _getter +from ._utils import _kwargs_to_roocmdargs class RooAbsPdf(RooAbsReal): def fitTo(self, *args, **kwargs): - """ - Docstring - """ # Redefinition of `RooAbsPdf.fitTo` for keyword arguments. - # the keywords must correspond to the CmdArg of the `fitTo` function. - # Parameters: - # self: instance of `RooAbsPdf` class - # *args: arguments passed to `fitTo` - # **kwargs: keyword arguments passed to `fitTo` - if not kwargs: - return self._fitTo(*args) - else: - nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) - return self._fitTo(*nargs) + # The keywords must correspond to the CmdArg of the `fitTo` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._fitTo(*args, **kwargs) def plotOn(self, *args, **kwargs): - """ - Docstring - """ - # Redefinition of `RooAbsReal.plotOn` for keyword arguments. - # the keywords must correspond to the CmdArg of the `plotOn` function. - # Parameters: - # self: instance of `RooAbsReal` class - # *args: arguments passed to `plotOn` - # **kwargs: keyword arguments passed to `plotOn` - if not kwargs: - return self._plotOn(*args) - else: - nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) - return self._plotOn(*nargs) + # Redefinition of `RooAbsPdf.plotOn` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotOn(*args, **kwargs) + + def generate(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.generate` for keyword arguments. + # The keywords must correspond to the CmdArg of the `generate` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._generate(*args, **kwargs) + + def paramOn(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.paramOn` for keyword arguments. + # The keywords must correspond to the CmdArg of the `paramOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._paramOn(*args, **kwargs) + + def createNLL(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.createNLL` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createNLL` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createNLL(*args, **kwargs) + + def createChi2(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.createChi2` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createChi2` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createChi2(*args, **kwargs) + + def createCdf(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.createCdf` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createCdf` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createCdf(*args, **kwargs) + + def generateBinned(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.generateBinned` for keyword arguments. + # The keywords must correspond to the CmdArg of the `generateBinned` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._generateBinned(*args, **kwargs) + + def prepareMultiGen(self, *args, **kwargs): + # Redefinition of `RooAbsPdf.prepareMultiGen` for keyword arguments. + # The keywords must correspond to the CmdArg of the `prepareMultiGen` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._prepareMultiGen(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreal.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreal.py index bf1112705080c..447d6f3447e9b 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreal.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreal.py @@ -1,6 +1,7 @@ # Authors: # * Hinnerk C. Schmidt 02/2021 # * Jonas Rembser 03/2021 +# * Harshal Shende 06/2021 ################################################################################ # Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # @@ -11,7 +12,7 @@ ################################################################################ -r''' +r""" /** \class RooAbsReal \brief \parblock \endparblock @@ -22,7 +23,8 @@ ## PyROOT Some member functions of RooAbsReal that take a RooCmdArg as argument also support keyword arguments. -So far, this applies to RooAbsReal::plotOn. +So far, this applies to RooAbsReal::plotOn, RooAbsReal::createHistogram, RooAbsReal::chi2FitTo, +RooAbsReal::createChi2, RooAbsReal::createRunningIntegral and RooAbsReal::createIntegral For example, the following code is equivalent in PyROOT: \code{.py} # Directly passing a RooCmdArg: @@ -36,24 +38,44 @@ \endhtmlonly */ -''' +""" -from ._utils import _getter +from ._utils import _kwargs_to_roocmdargs class RooAbsReal(object): def plotOn(self, *args, **kwargs): - """ - Docstring - """ # Redefinition of `RooAbsReal.plotOn` for keyword arguments. - # the keywords must correspond to the CmdArg of the `plotOn` function. - # Parameters: - # self: instance of `RooAbsReal` class - # *args: arguments passed to `plotOn` - # **kwargs: keyword arguments passed to `plotOn` - if not kwargs: - return self._plotOn(*args) - else: - nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) - return self._plotOn(*nargs) + # The keywords must correspond to the CmdArg of the `plotOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotOn(*args, **kwargs) + + def createHistogram(self, *args, **kwargs): + # Redefinition of `RooAbsReal.createHistogram` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createHistogram` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createHistogram(*args, **kwargs) + + def createIntegral(self, *args, **kwargs): + # Redefinition of `RooAbsReal.createIntegral` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createIntegral` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createIntegral(*args, **kwargs) + + def createRunningIntegral(self, *args, **kwargs): + # Redefinition of `RooAbsReal.createRunningIntegral` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createRunningIntegral` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createRunningIntegral(*args, **kwargs) + + def createChi2(self, *args, **kwargs): + # Redefinition of `RooAbsReal.createChi2` for keyword arguments. + # The keywords must correspond to the CmdArg of the `createChi2` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createChi2(*args, **kwargs) + + def chi2FitTo(self, *args, **kwargs): + # Redefinition of `RooAbsReal.chi2FitTo` for keyword arguments. + # The keywords must correspond to the CmdArg of the `chi2FitTo` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._chi2FitTo(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreallvalue.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreallvalue.py new file mode 100644 index 0000000000000..646537b62b66a --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabsreallvalue.py @@ -0,0 +1,55 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooAbsRealLValue +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooAbsRealLValue that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooAbsRealLValue::createHistogram and RooAbsRealLValue::frame. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +frame = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("RooPlot with decorations"), ROOT.RooFit.Bins(40)) + +# With keyword arguments: +frame = x.frame(Name="xframe", Title="RooPlot with decorations", Bins=40) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooAbsRealLValue(object): + def createHistogram(self, *args, **kwargs): + # Redefinition of `RooAbsRealLValue.createHistogram` for keyword arguments. + # the keywords must correspond to the CmdArg of the `createHistogram` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._createHistogram(*args, **kwargs) + + def frame(self, *args, **kwargs): + # Redefinition of `RooAbsRealLValue.frame` for keyword arguments. + # the keywords must correspond to the CmdArg of the `frame` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._frame(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roochi2var.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roochi2var.py new file mode 100644 index 0000000000000..06a07f729349c --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roochi2var.py @@ -0,0 +1,40 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooChi2Var +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Constructor of RooChi2Var takes a RooCmdArg as argument also supports keyword arguments. + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooChi2Var(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooChi2Var` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodatahist.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodatahist.py new file mode 100644 index 0000000000000..0edaa5117ba32 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodatahist.py @@ -0,0 +1,48 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooDataHist +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Constructor of RooDataHist takes a RooCmdArg as argument also supports keyword arguments. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +dh = ROOT.RooDataHist("dh", "dh", ROOT.RooArgList(x), ROOT.RooFit.Import("SampleA", histo)) + +# With keyword arguments: +dh = ROOT.RooDataHist("dh", "dh", ROOT.RooArgList(x), Import=("SampleA", histo)) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooDataHist(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooDataHist` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodataset.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodataset.py new file mode 100644 index 0000000000000..1c8d536ff7f47 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodataset.py @@ -0,0 +1,55 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooDataSet +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooDataSet that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooDataSet() constructor and RooDataSet::plotOnXY. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet(x, y), ROOT.RooFit.StoreError(ROOT.RooArgSet(x, y))) + +# With keyword arguments: +dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet(x, y), StoreError=(ROOT.RooArgSet(x, y))) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooDataSet(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooDataSet` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) + + def plotOnXY(self, *args, **kwargs): + # Redefinition of `RooDataSet.plotOnXY` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotOnXY` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotOnXY(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodecays.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodecays.py new file mode 100644 index 0000000000000..835a2fc6e776e --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roodecays.py @@ -0,0 +1,71 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooDecay +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some constructors of classes like RooDecay, RooBDecay, RooBCPGenDecay, RooBCPEffDecay and RooBMixDecay that take an enum +DecayType as argument also support keyword arguments. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing keyword argument with string corresponding to enum value name: +decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, tau, tm, type="DoubleSided") + +# With enum value: +decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, tau, tm, ROOT.RooDecay.DoubleSided) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _decaytype_string_to_enum + + +class RooDecay(object): + def __init__(self, *args, **kwargs): + kwargs = _decaytype_string_to_enum(self, kwargs) + self._init(*args, **kwargs) + + +class RooBDecay(object): + def __init__(self, *args, **kwargs): + kwargs = _decaytype_string_to_enum(self, kwargs) + self._init(*args, **kwargs) + + +class RooBCPGenDecay(object): + def __init__(self, *args, **kwargs): + kwargs = _decaytype_string_to_enum(self, kwargs) + self._init(*args, **kwargs) + + +class RooBCPEffDecay(object): + def __init__(self, *args, **kwargs): + kwargs = _decaytype_string_to_enum(self, kwargs) + self._init(*args, **kwargs) + + +class RooBMixDecay(object): + def __init__(self, *args, **kwargs): + kwargs = _decaytype_string_to_enum(self, kwargs) + self._init(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roogenfitstudy.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roogenfitstudy.py new file mode 100644 index 0000000000000..60eec65e0ec62 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roogenfitstudy.py @@ -0,0 +1,41 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooGenFitStudy +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooGenFitStudy that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooGenFitStudy::setGenConfig. + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooGenFitStudy(object): + def setGenConfig(self, *args, **kwargs): + # Redefinition of `RooGenFitStudy.setGenConfig` for keyword arguments. + # The keywords must correspond to the CmdArg of the `setGenConfig` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._setGenConfig(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomcstudy.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomcstudy.py new file mode 100644 index 0000000000000..515d51c42dd5f --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomcstudy.py @@ -0,0 +1,79 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooMCStudy +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooMCStudy that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to constructor RooMCStudy(), RooMCStudy::plotParamOn, RooMCStudy::plotParam, RooMCStudy::plotNLL, RooMCStudy::plotError and RooMCStudy::plotPull. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +frame3 = mcstudy.plotPull(mean, ROOT.RooFit.Bins(40), ROOT.RooFit.FitGauss(True)) + +# With keyword arguments: +frame3 = mcstudy.plotPull(mean, Bins=40, FitGauss=True) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooMCStudy(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooMCStudy` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) + + def plotParamOn(self, *args, **kwargs): + # Redefinition of `RooMCStudy.plotParamOn` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotParamOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotParamOn(*args, **kwargs) + + def plotParam(self, *args, **kwargs): + # Redefinition of `RooMCStudy.plotParam` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotParam` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotParam(*args, **kwargs) + + def plotNLL(self, *args, **kwargs): + # Redefinition of `RooMCStudy.plotNLL` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotNLL` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotNLL(*args, **kwargs) + + def plotError(self, *args, **kwargs): + # Redefinition of `RooMCStudy.plotError` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotError` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotError(*args, **kwargs) + + def plotPull(self, *args, **kwargs): + # Redefinition of `RooMCStudy.plotPull` for keyword arguments. + # The keywords must correspond to the CmdArg of the `plotPull` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotPull(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomsgservice.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomsgservice.py new file mode 100644 index 0000000000000..d9aa82290d27b --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roomsgservice.py @@ -0,0 +1,51 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooMsgService +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooMsgService that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooMsgService::addStream. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +ROOT.RooMsgService.instance().addStream( + ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Tracing), ROOT.RooFit.ClassName("RooGaussian") +) + +# With keyword arguments: +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, Topic = ROOT.RooFit.Tracing, ClassName = "RooGaussian") +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooMsgService(object): + def addStream(self, *args, **kwargs): + # Redefinition of `RooMsgService.addStream` for keyword arguments. + # The keywords must correspond to the CmdArg of the `addStream` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._addStream(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roonllvar.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roonllvar.py new file mode 100644 index 0000000000000..feb89915fdaba --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roonllvar.py @@ -0,0 +1,40 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooNLLVar +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +RooNLLVar() constructor takes a RooCmdArg as argument also supports keyword arguments. + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooNLLVar(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooNLLVar` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooprodpdf.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooprodpdf.py new file mode 100644 index 0000000000000..61a98bc278478 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooprodpdf.py @@ -0,0 +1,52 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooProdPdf +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +RooProdPdf() constructor takes a RooCmdArg as argument also supports keyword arguments. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +model = ROOT.RooProdPdf( + "model", "model", ROOT.RooArgSet(shapePdf), ROOT.RooFit.Conditional(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) +) + +# With keyword arguments: +model = ROOT.RooProdPdf( + "model", "model", ROOT.RooArgSet(shapePdf), Conditional=(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) +) +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooProdPdf(object): + def __init__(self, *args, **kwargs): + # Redefinition of `RooProdPdf` constructor for keyword arguments. + # The keywords must correspond to the CmdArg of the constructor function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + self._init(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py index cb8ce60a0a991..0e57c859fec9d 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimultaneous.py @@ -11,7 +11,7 @@ ################################################################################ -r''' +r""" /** \class RooSimultaneous \brief \parblock \endparblock @@ -37,24 +37,14 @@ \endhtmlonly */ -''' +""" +from ._utils import _kwargs_to_roocmdargs -from ._utils import _getter class RooSimultaneous(object): def plotOn(self, *args, **kwargs): - """ - Docstring - """ # Redefinition of `RooSimultaneous.plotOn` for keyword arguments. - # the keywords must correspond to the CmdArg of the `plotOn` function. - # Parameters: - # self: instance of `RooSimultaneous` class - # *args: arguments passed to `plotOn` - # **kwargs: keyword arguments passed to `plotOn` - if not kwargs: - return self._plotOn(*args) - else: - nargs = args + tuple((_getter(k, v) for k, v in kwargs.items())) - return self._plotOn(*nargs) + # The keywords must correspond to the CmdArg of the `plotOn` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._plotOn(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimwstool.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimwstool.py new file mode 100644 index 0000000000000..b143c397b1f46 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_roosimwstool.py @@ -0,0 +1,50 @@ +# Authors: +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 + +################################################################################ +# Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + + +r""" +/** +\class RooSimWSTool +\brief \parblock \endparblock +\htmlonly +
+\endhtmlonly + +## PyROOT + +Some member functions of RooSimWSTool that take a RooCmdArg as argument also support keyword arguments. +So far, this applies to RooSimWSTool::build. +For example, the following code is equivalent in PyROOT: +\code{.py} +# Directly passing a RooCmdArg: +sct.build("model_sim2", "model", ROOT.RooFit.SplitParam("p0", "c,d")) + +# With keyword arguments: +sct.build("model_sim2", "model", SplitParam=("p0", "c,d")) + +\endcode + +\htmlonly +
+\endhtmlonly +*/ +""" + +from ._utils import _kwargs_to_roocmdargs + + +class RooSimWSTool(object): + def build(self, *args, **kwargs): + # Redefinition of `RooSimWSTool.build` for keyword arguments. + # The keywords must correspond to the CmdArg of the `build` function. + args, kwargs = _kwargs_to_roocmdargs(*args, **kwargs) + return self._build(*args, **kwargs) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooworkspace.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooworkspace.py index 4ff35ba8f7ef7..57b4e1330cfa1 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooworkspace.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooworkspace.py @@ -9,7 +9,7 @@ ################################################################################ -r''' +r""" /** \class RooWorkspace \brief \parblock \endparblock @@ -31,7 +31,8 @@ \endhtmlonly */ -''' +""" + class RooWorkspace(object): def Import(self, *args, **kwargs): diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_utils.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_utils.py index 84e62e123dbbb..bb0ead7331e34 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_utils.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_utils.py @@ -1,5 +1,7 @@ # Authors: # * Hinnerk C. Schmidt 02/2021 +# * Jonas Rembser 06/2021 +# * Harshal Shende 06/2021 ################################################################################ # Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. # @@ -9,7 +11,6 @@ # For the list of contributors see $ROOTSYS/README/CREDITS. # ################################################################################ - import cppyy @@ -25,3 +26,31 @@ def _getter(k, v): else: attr = getattr(cppyy.gbl.RooFit, k)(v) return attr + + +def _kwargs_to_roocmdargs(*args, **kwargs): + """Helper function to check kwargs and pythonize the arguments using _getter""" + if kwargs: + args = args + tuple((_getter(k, v) for k, v in kwargs.items())) + return args, {} + + +def _decaytype_string_to_enum(caller, kwargs): + """Helper function to pythonize DecayType enums and check for enum value names.""" + type_key = "type" + + if type_key in kwargs: + val = kwargs[type_key] + if isinstance(val, str): + try: + kwargs[type_key] = getattr(caller.__class__, val) + except AttributeError as error: + raise ValueError( + "Unsupported decay type passed to " + + caller.__class__.__name__ + + ". Supported decay types are : 'SingleSided', 'DoubleSided', 'Flipped'" + ) + except Exception as exception: + raise exception + + return kwargs From e6e80d59ec59e4d0901200d75ac4162f3a7d950d Mon Sep 17 00:00:00 2001 From: "Harshal.S" Date: Thu, 17 Jun 2021 23:03:07 +0530 Subject: [PATCH 255/309] [RF] Pythonized and Formatted RooFit Tutorial Files --- tutorials/roofit/rf101_basics.py | 4 ++-- tutorials/roofit/rf103_interprfuncs.py | 4 ++-- tutorials/roofit/rf104_classfactory.py | 4 ++-- tutorials/roofit/rf105_funcbinding.py | 6 +++--- tutorials/roofit/rf106_plotdecoration.py | 6 +++--- tutorials/roofit/rf107_plotstyles.py | 12 +++++------- tutorials/roofit/rf108_plotbinning.py | 6 +++--- tutorials/roofit/rf110_normintegration.py | 4 ++-- tutorials/roofit/rf111_derivatives.py | 4 ++-- tutorials/roofit/rf201_composite.py | 2 +- tutorials/roofit/rf202_extendedmlfit.py | 2 +- tutorials/roofit/rf203_ranges.py | 2 +- tutorials/roofit/rf204a_extendedLikelihood.py | 6 +++--- tutorials/roofit/rf205_compplot.py | 2 +- tutorials/roofit/rf208_convolution.py | 2 +- tutorials/roofit/rf209_anaconv.py | 6 +++--- tutorials/roofit/rf210_angularconv.py | 4 ++-- tutorials/roofit/rf211_paramconv.py | 8 ++++---- tutorials/roofit/rf301_composition.py | 2 +- tutorials/roofit/rf302_utilfuncs.py | 16 ++++------------ tutorials/roofit/rf304_uncorrprod.py | 4 ++-- tutorials/roofit/rf305_condcorrprod.py | 5 +---- tutorials/roofit/rf306_condpereventerrors.py | 12 +++++------- tutorials/roofit/rf307_fullpereventerrors.py | 10 ++++------ tutorials/roofit/rf308_normintegration2d.py | 4 ++-- tutorials/roofit/rf309_ndimplot.py | 16 +++++++--------- tutorials/roofit/rf310_sliceplot.py | 8 ++++---- tutorials/roofit/rf311_rangeplot.py | 4 ++-- tutorials/roofit/rf313_paramranges.py | 2 +- tutorials/roofit/rf314_paramfitrange.py | 4 ++-- tutorials/roofit/rf315_projectpdf.py | 2 +- tutorials/roofit/rf316_llratioplot.py | 8 ++++---- tutorials/roofit/rf401_importttreethx.py | 16 ++++++++-------- tutorials/roofit/rf402_datahandling.py | 2 +- tutorials/roofit/rf404_categories.py | 2 +- tutorials/roofit/rf405_realtocatfuncs.py | 4 ++-- tutorials/roofit/rf407_latextables.py | 8 ++++---- tutorials/roofit/rf501_simultaneouspdf.py | 4 ++-- tutorials/roofit/rf504_simwstool.py | 4 ++-- tutorials/roofit/rf506_msgservice.py | 10 +++------- tutorials/roofit/rf603_multicpu.py | 4 ++-- tutorials/roofit/rf605_profilell.py | 8 +++----- tutorials/roofit/rf606_nllerrorhandling.py | 4 ++-- tutorials/roofit/rf609_xychi2fit.py | 10 +++++----- tutorials/roofit/rf610_visualerror.py | 8 ++++---- tutorials/roofit/rf701_efficiencyfit.py | 6 +++--- tutorials/roofit/rf702_efficiencyfit_2D.py | 15 ++++----------- tutorials/roofit/rf703_effpdfprod.py | 6 +++--- tutorials/roofit/rf704_amplitudefit.py | 4 ++-- tutorials/roofit/rf705_linearmorph.py | 6 +++--- tutorials/roofit/rf706_histpdf.py | 4 ++-- tutorials/roofit/rf707_kernelestimation.py | 12 +++++------- tutorials/roofit/rf708_bphysics.py | 18 +++++++++--------- tutorials/roofit/rf801_mcstudy.py | 18 +++++++++--------- tutorials/roofit/rf901_numintconfig.py | 4 ++-- tutorials/roofit/rf902_numgenconfig.py | 2 +- tutorials/roofit/rf903_numintcache.py | 2 +- 57 files changed, 164 insertions(+), 198 deletions(-) diff --git a/tutorials/roofit/rf101_basics.py b/tutorials/roofit/rf101_basics.py index 021e84be3208d..b3036634fb352 100644 --- a/tutorials/roofit/rf101_basics.py +++ b/tutorials/roofit/rf101_basics.py @@ -22,7 +22,7 @@ gauss = ROOT.RooGaussian("gauss", "gaussian PDF", x, mean, sigma) # Construct plot frame in 'x' -xframe = x.frame(ROOT.RooFit.Title("Gaussian pdf")) # RooPlot +xframe = x.frame(Title="Gaussian pdf") # RooPlot # Plot model and change parameter values # --------------------------------------------------------------------------- @@ -42,7 +42,7 @@ # Make a second plot frame in x and draw both the # data and the pdf in the frame -xframe2 = x.frame(ROOT.RooFit.Title("Gaussian pdf with data")) # RooPlot +xframe2 = x.frame(Title="Gaussian pdf with data") # RooPlot data.plotOn(xframe2) gauss.plotOn(xframe2) diff --git a/tutorials/roofit/rf103_interprfuncs.py b/tutorials/roofit/rf103_interprfuncs.py index 4da258fadb607..9049554fbd2e9 100644 --- a/tutorials/roofit/rf103_interprfuncs.py +++ b/tutorials/roofit/rf103_interprfuncs.py @@ -35,7 +35,7 @@ genpdf.fitTo(data) # Make a plot of the data and the pdf overlaid -xframe = x.frame(ROOT.RooFit.Title("Interpreted expression pdf")) +xframe = x.frame(Title="Interpreted expression pdf") data.plotOn(xframe) genpdf.plotOn(xframe) @@ -72,7 +72,7 @@ r.Print() # Plot data on frame and overlay projection of g2 -xframe2 = x.frame(ROOT.RooFit.Title("Tailored Gaussian pdf")) +xframe2 = x.frame(Title="Tailored Gaussian pdf") data2.plotOn(xframe2) g2.plotOn(xframe2) diff --git a/tutorials/roofit/rf104_classfactory.py b/tutorials/roofit/rf104_classfactory.py index 3e4b4b35dc4a7..455e8905c53cd 100644 --- a/tutorials/roofit/rf104_classfactory.py +++ b/tutorials/roofit/rf104_classfactory.py @@ -64,7 +64,7 @@ pdf = ROOT.MyPdfV3("pdf", "pdf", y, a, b) # Generate toy data from pdf and plot data and pdf on frame -frame1 = y.frame(ROOT.RooFit.Title("Compiled class MyPdfV3")) +frame1 = y.frame(Title="Compiled class MyPdfV3") data = pdf.generate(ROOT.RooArgSet(y), 1000) pdf.fitTo(data) data.plotOn(frame1) @@ -93,7 +93,7 @@ genpdf.fitTo(data2) # Make a plot of the data and the pdf overlaid -frame2 = x.frame(ROOT.RooFit.Title("Compiled version of pdf of rf103")) +frame2 = x.frame(Title="Compiled version of pdf of rf103") data2.plotOn(frame2) genpdf.plotOn(frame2) diff --git a/tutorials/roofit/rf105_funcbinding.py b/tutorials/roofit/rf105_funcbinding.py index 07f5dbc0478e7..fcb4c03c83068 100644 --- a/tutorials/roofit/rf105_funcbinding.py +++ b/tutorials/roofit/rf105_funcbinding.py @@ -31,7 +31,7 @@ erf.Print() # Plot erf on frame -frame1 = x.frame(ROOT.RooFit.Title("TMath.Erf bound as ROOT.RooFit function")) +frame1 = x.frame(Title="TMath.Erf bound as ROOT.RooFit function") erf.plotOn(frame1) # Bind ROOT::Math::beta_pdf C function @@ -62,7 +62,7 @@ beta.fitTo(data) # Plot data and pdf on frame -frame2 = x2.frame(ROOT.RooFit.Title("ROOT.Math.Beta bound as ROOT.RooFit pdf")) +frame2 = x2.frame(Title="ROOT.Math.Beta bound as ROOT.RooFit pdf") data.plotOn(frame2) beta.plotOn(frame2) @@ -82,7 +82,7 @@ rfa1.Print() # Make plot frame in observable, TF1 binding function -frame3 = x3.frame(ROOT.RooFit.Title("TF1 bound as ROOT.RooFit function")) +frame3 = x3.frame(Title="TF1 bound as ROOT.RooFit function") rfa1.plotOn(frame3) c = ROOT.TCanvas("rf105_funcbinding", "rf105_funcbinding", 1200, 400) diff --git a/tutorials/roofit/rf106_plotdecoration.py b/tutorials/roofit/rf106_plotdecoration.py index 56384d1196266..787e4065751d2 100644 --- a/tutorials/roofit/rf106_plotdecoration.py +++ b/tutorials/roofit/rf106_plotdecoration.py @@ -30,7 +30,7 @@ # ------------------------------------- # Overlay projection of gauss on data -frame = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("RooPlot with decorations"), ROOT.RooFit.Bins(40)) +frame = x.frame(Name="xframe", Title="RooPlot with decorations", Bins=40) data.plotOn(frame) gauss.plotOn(frame) @@ -38,14 +38,14 @@ # ----------------------------------------------------- # Left edge of box starts at 55% of Xaxis) -gauss.paramOn(frame, ROOT.RooFit.Layout(0.55)) +gauss.paramOn(frame, Layout=0.55) # Add box with data statistics # ------------------------------------------------------- # X size of box is from 55% to 99% of Xaxis range, of box is at 80% of # Yaxis range) -data.statOn(frame, ROOT.RooFit.Layout(0.55, 0.99, 0.8)) +data.statOn(frame, Layout=(0.55, 0.99, 0.8)) # Add text and arrow # ----------------------------------- diff --git a/tutorials/roofit/rf107_plotstyles.py b/tutorials/roofit/rf107_plotstyles.py index 19397e881bfa1..791aa06b83526 100644 --- a/tutorials/roofit/rf107_plotstyles.py +++ b/tutorials/roofit/rf107_plotstyles.py @@ -32,18 +32,16 @@ # ------------------------------- # Make four plot frames to demonstrate various plotting features -frame1 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Red Curve / SumW2 Histo errors"), ROOT.RooFit.Bins(20)) -frame2 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Dashed Curve / No XError bars"), ROOT.RooFit.Bins(20)) -frame3 = x.frame(ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Filled Curve / Blue Histo"), ROOT.RooFit.Bins(20)) -frame4 = x.frame( - ROOT.RooFit.Name("xframe"), ROOT.RooFit.Title("Partial Range / Filled Bar chart"), ROOT.RooFit.Bins(20) -) +frame1 = x.frame(Name="xframe", Title="Red Curve / SumW2 Histo errors", Bins=20) +frame2 = x.frame(Name="xframe", Title="Dashed Curve / No XError bars", Bins=20) +frame3 = x.frame(Name="xframe", Title="Filled Curve / Blue Histo", Bins=20) +frame4 = x.frame(Name="xframe", Title="Partial Range / Filled Bar chart", Bins=20) # Data plotting styles # --------------------------------------- # Use sqrt(sum(weights^2)) error instead of Poisson errors -data.plotOn(frame1, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) +data.plotOn(frame1, DataError=ROOT.RooAbsData.SumW2) # Remove horizontal error bars data.plotOn(frame2, XErrorSize=0) diff --git a/tutorials/roofit/rf108_plotbinning.py b/tutorials/roofit/rf108_plotbinning.py index 0ee52099a790f..5b07c0266e517 100644 --- a/tutorials/roofit/rf108_plotbinning.py +++ b/tutorials/roofit/rf108_plotbinning.py @@ -34,7 +34,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct Bdecay (x) gauss -bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, ROOT.RooBMixDecay.DoubleSided) +bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, type="DoubleSided") # Sample data from model # -------------------------------------------- @@ -58,7 +58,7 @@ tbins.addUniform(15, 0, 15) # Make plot with specified binning -dtframe = dt.frame(ROOT.RooFit.Range(-15, 15), ROOT.RooFit.Title("dt distribution with custom binning")) +dtframe = dt.frame(Range=(-15, 15), Title="dt distribution with custom binning") data.plotOn(dtframe, Binning=tbins) bmix.plotOn(dtframe) @@ -84,7 +84,7 @@ abins.addBoundaryPair(6) # Create plot frame in dt -aframe = dt.frame(ROOT.RooFit.Range(-10, 10), ROOT.RooFit.Title("mixState asymmetry distribution with custom binning")) +aframe = dt.frame(Range=(-10, 10), Title="mixState asymmetry distribution with custom binning") # Plot mixState asymmetry of data with specified customg binning data.plotOn(aframe, Asymmetry=mixState, Binning=abins) diff --git a/tutorials/roofit/rf110_normintegration.py b/tutorials/roofit/rf110_normintegration.py index c36afc44df7a0..642e7bd839f82 100644 --- a/tutorials/roofit/rf110_normintegration.py +++ b/tutorials/roofit/rf110_normintegration.py @@ -46,7 +46,7 @@ # ROOT.This is the fraction of of pdf gx_Norm[x] which is in the # range named "signal" xset = ROOT.RooArgSet(x) -igx_sig = gx.createIntegral(xset, ROOT.RooFit.NormSet(xset), ROOT.RooFit.Range("signal")) +igx_sig = gx.createIntegral(xset, NormSet=xset, Range="signal") print("gx_Int[x|signal]_Norm[x] = ", igx_sig.getVal()) # Construct cumulative distribution function from pdf @@ -57,7 +57,7 @@ gx_cdf = gx.createCdf(ROOT.RooArgSet(x)) # Plot cdf of gx versus x -frame = x.frame(ROOT.RooFit.Title("cdf of Gaussian pdf")) +frame = x.frame(Title="cdf of Gaussian pdf") gx_cdf.plotOn(frame) # Draw plot on canvas diff --git a/tutorials/roofit/rf111_derivatives.py b/tutorials/roofit/rf111_derivatives.py index 6644385fc0504..feb7c8bad8376 100644 --- a/tutorials/roofit/rf111_derivatives.py +++ b/tutorials/roofit/rf111_derivatives.py @@ -37,7 +37,7 @@ d3gdx3 = gauss.derivative(x, 3) # Construct plot frame in 'x' -xframe = x.frame(ROOT.RooFit.Title("d(Gauss)/dx")) +xframe = x.frame(Title="d(Gauss)/dx") # Plot gauss in frame (i.e. in x) gauss.plotOn(xframe) @@ -58,7 +58,7 @@ d3gds3 = gauss.derivative(sigma, 3) # Construct plot frame in 'sigma' -sframe = sigma.frame(ROOT.RooFit.Title("d(Gauss)/d(sigma)"), ROOT.RooFit.Range(0.0, 2.0)) +sframe = sigma.frame(Title="d(Gauss)/d(sigma)", Range=(0.0, 2.0)) # Plot gauss in frame (i.e. in x) gauss.plotOn(sframe) diff --git a/tutorials/roofit/rf201_composite.py b/tutorials/roofit/rf201_composite.py index 364396e995c9a..118780afe19b3 100644 --- a/tutorials/roofit/rf201_composite.py +++ b/tutorials/roofit/rf201_composite.py @@ -60,7 +60,7 @@ model.fitTo(data) # Plot data and PDF overlaid -xframe = x.frame(ROOT.RooFit.Title("Example of composite pdf=(sig1+sig2)+bkg")) +xframe = x.frame(Title="Example of composite pdf=(sig1+sig2)+bkg") data.plotOn(xframe) model.plotOn(xframe) diff --git a/tutorials/roofit/rf202_extendedmlfit.py b/tutorials/roofit/rf202_extendedmlfit.py index 72ed7192b15e5..d23d3338ebd3c 100644 --- a/tutorials/roofit/rf202_extendedmlfit.py +++ b/tutorials/roofit/rf202_extendedmlfit.py @@ -55,7 +55,7 @@ # Plot data and PDF overlaid, expected number of events for pdf projection normalization # rather than observed number of events (==data.numEntries()) -xframe = x.frame(ROOT.RooFit.Title("extended ML fit example")) +xframe = x.frame(Title="extended ML fit example") data.plotOn(xframe) model.plotOn(xframe, Normalization=dict(scaleFactor=1.0, scaleType=ROOT.RooAbsReal.RelativeExpected)) diff --git a/tutorials/roofit/rf203_ranges.py b/tutorials/roofit/rf203_ranges.py index c6a1ad90f8221..7f9b20c856b9d 100644 --- a/tutorials/roofit/rf203_ranges.py +++ b/tutorials/roofit/rf203_ranges.py @@ -50,7 +50,7 @@ # --------------------------------------- # Make plot frame in x and add data and fitted model -frame = x.frame(ROOT.RooFit.Title("Fitting a sub range")) +frame = x.frame(Title="Fitting a sub range") modelData.plotOn(frame) model.plotOn(frame, Range="Full", LineColor=ROOT.kRed, LineStyle=ROOT.kDashed) # Add shape in full ranged dashed model.plotOn(frame) # By default only fitted range is shown diff --git a/tutorials/roofit/rf204a_extendedLikelihood.py b/tutorials/roofit/rf204a_extendedLikelihood.py index 0ce965a63d922..8267fb4e3712a 100644 --- a/tutorials/roofit/rf204a_extendedLikelihood.py +++ b/tutorials/roofit/rf204a_extendedLikelihood.py @@ -72,7 +72,7 @@ r = model1.fitTo(data, Save=True) r.Print() -frame = x.frame(ROOT.RooFit.Title("Full range fitted")) +frame = x.frame(Title="Full range fitted") data.plotOn(frame) model1.plotOn(frame, VisualizeError=r) model1.plotOn(frame) @@ -91,7 +91,7 @@ r2 = model2.fitTo(data, Range="left,right", Save=True) r2.Print() -frame2 = x.frame(ROOT.RooFit.Title("Fit in left/right sideband")) +frame2 = x.frame(Title="Fit in left/right sideband") data.plotOn(frame2) model2.plotOn(frame2, VisualizeError=r2) model2.plotOn(frame2) @@ -111,7 +111,7 @@ r3 = model3.fitTo(data, Range="leftToMiddle", Save=True) r3.Print() -frame3 = x.frame(ROOT.RooFit.Title("Fit from left to middle")) +frame3 = x.frame(Title="Fit from left to middle") data.plotOn(frame3) model3.plotOn(frame3, VisualizeError=r3) model3.plotOn(frame3) diff --git a/tutorials/roofit/rf205_compplot.py b/tutorials/roofit/rf205_compplot.py index bffa3d55a30da..ba72fcc1b36fa 100644 --- a/tutorials/roofit/rf205_compplot.py +++ b/tutorials/roofit/rf205_compplot.py @@ -52,7 +52,7 @@ data = model.generate(ROOT.RooArgSet(x), 1000) # Plot data and complete PDF overlaid -xframe = x.frame(ROOT.RooFit.Title("Component plotting of pdf=(sig1+sig2)+(bkg1+bkg2)")) +xframe = x.frame(Title="Component plotting of pdf=(sig1+sig2)+(bkg1+bkg2)") data.plotOn(xframe) model.plotOn(xframe) diff --git a/tutorials/roofit/rf208_convolution.py b/tutorials/roofit/rf208_convolution.py index df56107a5e9f6..83e8f252cb981 100644 --- a/tutorials/roofit/rf208_convolution.py +++ b/tutorials/roofit/rf208_convolution.py @@ -50,7 +50,7 @@ lxg.fitTo(data) # Plot data, pdf, landau (X) gauss pdf -frame = t.frame(ROOT.RooFit.Title("landau (x) gauss convolution")) +frame = t.frame(Title="landau (x) gauss convolution") data.plotOn(frame) lxg.plotOn(frame) landau.plotOn(frame, LineStyle=ROOT.kDashed) diff --git a/tutorials/roofit/rf209_anaconv.py b/tutorials/roofit/rf209_anaconv.py index 05f33cbcf6484..574cb65f9c28c 100644 --- a/tutorials/roofit/rf209_anaconv.py +++ b/tutorials/roofit/rf209_anaconv.py @@ -28,10 +28,10 @@ tm = ROOT.RooTruthModel("tm", "truth model", dt) # Construct decay(t) (x) delta(t) -decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, tau, tm, ROOT.RooDecay.DoubleSided) +decay_tm = ROOT.RooDecay("decay_tm", "decay", dt, tau, tm, type="DoubleSided") # Plot pdf (dashed) -frame = dt.frame(ROOT.RooFit.Title("Bdecay (x) resolution")) +frame = dt.frame(Title="Bdecay (x) resolution") decay_tm.plotOn(frame, LineStyle=ROOT.kDashed) # B-physics pdf with Gaussian resolution @@ -43,7 +43,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct decay(t) (x) gauss1(t) -decay_gm1 = ROOT.RooDecay("decay_gm1", "decay", dt, tau, gm1, ROOT.RooDecay.DoubleSided) +decay_gm1 = ROOT.RooDecay("decay_gm1", "decay", dt, tau, gm1, type="DoubleSided") # Plot pdf decay_gm1.plotOn(frame) diff --git a/tutorials/roofit/rf210_angularconv.py b/tutorials/roofit/rf210_angularconv.py index 5b953488d7986..0c8dd47a7eb35 100644 --- a/tutorials/roofit/rf210_angularconv.py +++ b/tutorials/roofit/rf210_angularconv.py @@ -60,7 +60,7 @@ Mpsi.fitTo(data_psi) # Plot cos(psi) frame with Mf(cpsi) -frame1 = psi.frame(ROOT.RooFit.Title("Cyclical convolution in angle psi")) +frame1 = psi.frame(Title="Cyclical convolution in angle psi") data_psi.plotOn(frame1) Mpsi.plotOn(frame1) @@ -93,7 +93,7 @@ Mcpsi.fitTo(data_cpsi) # Plot cos(psi) frame with Mf(cpsi) -frame2 = cpsi.frame(ROOT.RooFit.Title("Same convolution in psi, in cos(psi)")) +frame2 = cpsi.frame(Title="Same convolution in psi, in cos(psi)") data_cpsi.plotOn(frame2) Mcpsi.plotOn(frame2) diff --git a/tutorials/roofit/rf211_paramconv.py b/tutorials/roofit/rf211_paramconv.py index f1e5f0268c13e..5ca64a71a0ebf 100644 --- a/tutorials/roofit/rf211_paramconv.py +++ b/tutorials/roofit/rf211_paramconv.py @@ -49,7 +49,7 @@ projModel.fitTo(d, Verbose=True) # Plot data and fitted p.d.f. -frame = x.frame(ROOT.RooFit.Bins(25)) +frame = x.frame(Bins=25) d.plotOn(frame) projModel.plotOn(frame) @@ -57,9 +57,9 @@ hh = model.createHistogram( "hh", x, - ROOT.RooFit.Binning(50), - ROOT.RooFit.YVar(mean, ROOT.RooFit.Binning(50)), - ROOT.RooFit.ConditionalObservables(ROOT.RooArgSet(mean)), + Binning=50, + YVar=(mean, ROOT.RooFit.Binning(50)), + ConditionalObservables=ROOT.RooArgSet(mean), ) hh.SetTitle("histogram of model(x|mean)") hh.SetLineColor(ROOT.kBlue) diff --git a/tutorials/roofit/rf301_composition.py b/tutorials/roofit/rf301_composition.py index ba56d2f18e4cc..0ec35ef7e3bd1 100644 --- a/tutorials/roofit/rf301_composition.py +++ b/tutorials/roofit/rf301_composition.py @@ -48,7 +48,7 @@ model.plotOn(yframe) # Make two-dimensional plot in x vs y -hh_model = model.createHistogram("hh_model", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) +hh_model = model.createHistogram("hh_model", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) hh_model.SetLineColor(ROOT.kBlue) # Make canvas and draw ROOT.RooPlots diff --git a/tutorials/roofit/rf302_utilfuncs.py b/tutorials/roofit/rf302_utilfuncs.py index 63360d72e8d68..8a76a19666993 100644 --- a/tutorials/roofit/rf302_utilfuncs.py +++ b/tutorials/roofit/rf302_utilfuncs.py @@ -63,18 +63,10 @@ # ---------------------------- # Make two-dimensional plots in x vs y -hh_model_1 = model_1.createHistogram( - "hh_model_1", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) -) -hh_model_2 = model_2.createHistogram( - "hh_model_2", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) -) -hh_model_3 = model_3.createHistogram( - "hh_model_3", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) -) -hh_model_4 = model_4.createHistogram( - "hh_model_4", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50)) -) +hh_model_1 = model_1.createHistogram("hh_model_1", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) +hh_model_2 = model_2.createHistogram("hh_model_2", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) +hh_model_3 = model_3.createHistogram("hh_model_3", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) +hh_model_4 = model_4.createHistogram("hh_model_4", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) hh_model_1.SetLineColor(ROOT.kBlue) hh_model_2.SetLineColor(ROOT.kBlue) hh_model_3.SetLineColor(ROOT.kBlue) diff --git a/tutorials/roofit/rf304_uncorrprod.py b/tutorials/roofit/rf304_uncorrprod.py index 4e7bf726ac78b..80efc0287528c 100644 --- a/tutorials/roofit/rf304_uncorrprod.py +++ b/tutorials/roofit/rf304_uncorrprod.py @@ -43,13 +43,13 @@ # Plot x distribution of data and projection of gaussxy x = Int(dy) # gaussxy(x,y) -xframe = x.frame(ROOT.RooFit.Title("X projection of gauss(x)*gauss(y)")) +xframe = x.frame(Title="X projection of gauss(x)*gauss(y)") data.plotOn(xframe) gaussxy.plotOn(xframe) # Plot x distribution of data and projection of gaussxy y = Int(dx) # gaussxy(x,y) -yframe = y.frame(ROOT.RooFit.Title("Y projection of gauss(x)*gauss(y)")) +yframe = y.frame(Title="Y projection of gauss(x)*gauss(y)") data.plotOn(yframe) gaussxy.plotOn(yframe) diff --git a/tutorials/roofit/rf305_condcorrprod.py b/tutorials/roofit/rf305_condcorrprod.py index a5ae6a8f01ac8..3c194d2931cba 100644 --- a/tutorials/roofit/rf305_condcorrprod.py +++ b/tutorials/roofit/rf305_condcorrprod.py @@ -39,10 +39,7 @@ # Create gaussx(x,sx|y) * gaussy(y) model = ROOT.RooProdPdf( - "model", - "gaussx(x|y)*gaussy(y)", - ROOT.RooArgSet(gaussy), - ROOT.RooFit.Conditional(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)), + "model", "gaussx(x|y)*gaussy(y)", ROOT.RooArgSet(gaussy), Conditional=(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)) ) # Sample, fit and plot product pdf diff --git a/tutorials/roofit/rf306_condpereventerrors.py b/tutorials/roofit/rf306_condpereventerrors.py index 0c9570709eb9b..03401ff2cf4de 100644 --- a/tutorials/roofit/rf306_condpereventerrors.py +++ b/tutorials/roofit/rf306_condpereventerrors.py @@ -25,7 +25,7 @@ # Construct decay(dt) (x) gauss1(dt|dterr) tau = ROOT.RooRealVar("tau", "tau", 1.548) -decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, ROOT.RooDecay.DoubleSided) +decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, type="DoubleSided") # Construct fake 'external' data with per-event error # ------------------------------------------------------------------------------------------------------ @@ -39,7 +39,7 @@ # Specify external dataset with dterr values to use decay_dm as # conditional pdf -data = decay_gm.generate(ROOT.RooArgSet(dt), ROOT.RooFit.ProtoData(expDataDterr)) +data = decay_gm.generate(ROOT.RooArgSet(dt), ProtoData=expDataDterr) # Fit conditional decay_dm(dt|dterr) # --------------------------------------------------------------------- @@ -51,19 +51,17 @@ # --------------------------------------------------------------------- # Make two-dimensional plot of conditional pdf in (dt,dterr) -hh_decay = decay_gm.createHistogram( - "hh_decay", dt, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50)) -) +hh_decay = decay_gm.createHistogram("hh_decay", dt, Binning=50, YVar=(dterr, ROOT.RooFit.Binning(50))) hh_decay.SetLineColor(ROOT.kBlue) # Plot decay_gm(dt|dterr) at various values of dterr -frame = dt.frame(ROOT.RooFit.Title("Slices of decay(dt|dterr) at various dterr")) +frame = dt.frame(Title="Slices of decay(dt|dterr) at various dterr") for ibin in range(0, 100, 20): dterr.setBin(ibin) decay_gm.plotOn(frame, Normalization=5.0) # Make projection of data an dt -frame2 = dt.frame(ROOT.RooFit.Title("Projection of decay(dt|dterr) on dt")) +frame2 = dt.frame(Title="Projection of decay(dt|dterr) on dt") data.plotOn(frame2) # Make projection of decay(dt|dterr) on dt. diff --git a/tutorials/roofit/rf307_fullpereventerrors.py b/tutorials/roofit/rf307_fullpereventerrors.py index 8bd3d4e0bc411..667db5e276821 100644 --- a/tutorials/roofit/rf307_fullpereventerrors.py +++ b/tutorials/roofit/rf307_fullpereventerrors.py @@ -25,7 +25,7 @@ # Construct decay(dt) (x) gauss1(dt|dterr) tau = ROOT.RooRealVar("tau", "tau", 1.548) -decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, ROOT.RooDecay.DoubleSided) +decay_gm = ROOT.RooDecay("decay_gm", "decay", dt, tau, gm, type="DoubleSided") # Construct empirical pdf for per-event error # ----------------------------------------------------------------- @@ -44,7 +44,7 @@ # Construct production of conditional decay_dm(dt|dterr) with empirical # pdfErr(dterr) model = ROOT.RooProdPdf( - "model", "model", ROOT.RooArgSet(pdfErr), ROOT.RooFit.Conditional(ROOT.RooArgSet(decay_gm), ROOT.RooArgSet(dt)) + "model", "model", ROOT.RooArgSet(pdfErr), Conditional=(ROOT.RooArgSet(decay_gm), ROOT.RooArgSet(dt)) ) # (Alternatively you could also use the landau shape pdfDtErr) @@ -68,13 +68,11 @@ # --------------------------------------------------------------------- # Make two-dimensional plot of conditional pdf in (dt,dterr) -hh_model = model.createHistogram( - "hh_model", dt, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(dterr, ROOT.RooFit.Binning(50)) -) +hh_model = model.createHistogram("hh_model", dt, Binning=50, YVar=(dterr, ROOT.RooFit.Binning(50))) hh_model.SetLineColor(ROOT.kBlue) # Make projection of data an dt -frame = dt.frame(ROOT.RooFit.Title("Projection of model(dt|dterr) on dt")) +frame = dt.frame(Title="Projection of model(dt|dterr) on dt") data.plotOn(frame) model.plotOn(frame) diff --git a/tutorials/roofit/rf308_normintegration2d.py b/tutorials/roofit/rf308_normintegration2d.py index 6da702e117869..2153f4c7230f3 100644 --- a/tutorials/roofit/rf308_normintegration2d.py +++ b/tutorials/roofit/rf308_normintegration2d.py @@ -65,7 +65,7 @@ # ROOT.This is the fraction of of pdf gxy_Norm[x,y] which is in the # range named "signal" -igxy_sig = gxy.createIntegral(x_and_y, ROOT.RooFit.NormSet(x_and_y), ROOT.RooFit.Range("signal")) +igxy_sig = gxy.createIntegral(x_and_y, NormSet=x_and_y, Range="signal") print("gx_Int[x,y|signal]_Norm[x,y] = ", igxy_sig.getVal()) # Construct cumulative distribution function from pdf @@ -76,7 +76,7 @@ gxy_cdf = gxy.createCdf(ROOT.RooArgSet(x, y)) # Plot cdf of gx versus x -hh_cdf = gxy_cdf.createHistogram("hh_cdf", x, ROOT.RooFit.Binning(40), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(40))) +hh_cdf = gxy_cdf.createHistogram("hh_cdf", x, Binning=40, YVar=(y, ROOT.RooFit.Binning(40))) hh_cdf.SetLineColor(ROOT.kBlue) c = ROOT.TCanvas("rf308_normintegration2d", "rf308_normintegration2d", 600, 600) diff --git a/tutorials/roofit/rf309_ndimplot.py b/tutorials/roofit/rf309_ndimplot.py index c5d2c11671f3d..12a7564b18b0e 100644 --- a/tutorials/roofit/rf309_ndimplot.py +++ b/tutorials/roofit/rf309_ndimplot.py @@ -38,9 +38,7 @@ # hh_data = data.createHistogram("hh_data",x, ROOT.RooFit.Binning(20), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20))) # hh_data = data.createHistogram("x,y", 20, 20) # does not work, see # https://root.cern.ch/phpBB3/viewtopic.php?t=16648 -hh_data = ROOT.RooAbsData.createHistogram( - data, "x,y", x, ROOT.RooFit.Binning(20), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20)) -) +hh_data = ROOT.RooAbsData.createHistogram(data, "x,y", x, Binning=20, YVar=(y, ROOT.RooFit.Binning(20))) # Create and fill ROOT 2D histogram (50x50 bins) with sampling of pdf # hh_pdf = model.createHistogram("hh_model",x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) @@ -67,18 +65,18 @@ data3, "hh_data3", x, - ROOT.RooFit.Binning(8), - ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)), - ROOT.RooFit.ZVar(z, ROOT.RooFit.Binning(8)), + Binning=8, + YVar=(y, ROOT.RooFit.Binning(8)), + ZVar=(z, ROOT.RooFit.Binning(8)), ) # Create and fill ROOT 2D histogram (20x20x20 bins) with sampling of pdf hh_pdf3 = model3.createHistogram( "hh_model3", x, - ROOT.RooFit.Binning(20), - ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(20)), - ROOT.RooFit.ZVar(z, ROOT.RooFit.Binning(20)), + Binning=20, + YVar=(y, ROOT.RooFit.Binning(20)), + ZVar=(z, ROOT.RooFit.Binning(20)), ) hh_pdf3.SetFillColor(ROOT.kBlue) diff --git a/tutorials/roofit/rf310_sliceplot.py b/tutorials/roofit/rf310_sliceplot.py index 790f905da1d0b..3b9bb481ce5ff 100644 --- a/tutorials/roofit/rf310_sliceplot.py +++ b/tutorials/roofit/rf310_sliceplot.py @@ -39,7 +39,7 @@ gm1 = ROOT.RooGaussModel("gm1", "gauss model 1", dt, bias1, sigma1) # Construct a decay pdf, with single gaussian resolution model -bmix_gm1 = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, ROOT.RooBMixDecay.DoubleSided) +bmix_gm1 = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, gm1, type="DoubleSided") # Generate BMixing data with above set of event errors data = bmix_gm1.generate(ROOT.RooArgSet(dt, tagFlav, mixState), 20000) @@ -49,7 +49,7 @@ # Create frame, data and pdf projection (integrated over tagFlav and # mixState) -frame = dt.frame(ROOT.RooFit.Title("Inclusive decay distribution")) +frame = dt.frame(Title="Inclusive decay distribution") data.plotOn(frame) bmix_gm1.plotOn(frame) @@ -57,7 +57,7 @@ # ------------------------------------------------------------------------------------------- # Create frame, data (mixed only) -frame2 = dt.frame(ROOT.RooFit.Title("Decay distribution of mixed events")) +frame2 = dt.frame(Title="Decay distribution of mixed events") data.plotOn(frame2, Cut="mixState==mixState::mixed") # Position slice in mixState at "mixed" and plot slice of pdf in mixstate @@ -65,7 +65,7 @@ bmix_gm1.plotOn(frame2, Slice=(mixState, "mixed")) # Create frame, data (unmixed only) -frame3 = dt.frame(ROOT.RooFit.Title("Decay distribution of unmixed events")) +frame3 = dt.frame(Title="Decay distribution of unmixed events") data.plotOn(frame3, Cut="mixState==mixState::unmixed") # Position slice in mixState at "unmixed" and plot slice of pdf in diff --git a/tutorials/roofit/rf311_rangeplot.py b/tutorials/roofit/rf311_rangeplot.py index a422b589a873f..6f96c780cfac9 100644 --- a/tutorials/roofit/rf311_rangeplot.py +++ b/tutorials/roofit/rf311_rangeplot.py @@ -40,7 +40,7 @@ # ------------------------------------------------- # Make plain projection of data and pdf on x observable -frame = x.frame(ROOT.RooFit.Title("Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) +frame = x.frame(Title="Projection of 3D data and pdf on X", Bins=40) data.plotOn(frame) model.plotOn(frame) @@ -52,7 +52,7 @@ z.setRange("sigRegion", -1, 1) # Make plot frame -frame2 = x.frame(ROOT.RooFit.Title("Same projection on X in signal range of (Y,Z)"), ROOT.RooFit.Bins(40)) +frame2 = x.frame(Title="Same projection on X in signal range of (Y,Z)", Bins=40) # Plot subset of data in which all observables are inside "sigRegion" # For observables that do not have an explicit "sigRegion" range defined (e.g. observable) diff --git a/tutorials/roofit/rf313_paramranges.py b/tutorials/roofit/rf313_paramranges.py index be66e54dd74c4..61a88d9e675c0 100644 --- a/tutorials/roofit/rf313_paramranges.py +++ b/tutorials/roofit/rf313_paramranges.py @@ -51,7 +51,7 @@ intPdf = pxyz.createIntegral(ROOT.RooArgSet(x, y, z), ROOT.RooArgSet(x, y, z), "R") # Plot value of integral as function of pdf parameter z0 -frame = z0.frame(ROOT.RooFit.Title("Integral of pxyz over x,y, in region R")) +frame = z0.frame(Title="Integral of pxyz over x,y, in region R") intPdf.plotOn(frame) c = ROOT.TCanvas("rf313_paramranges", "rf313_paramranges", 600, 600) diff --git a/tutorials/roofit/rf314_paramfitrange.py b/tutorials/roofit/rf314_paramfitrange.py index 8a2d44a29ecbe..68ff95f9f2f93 100644 --- a/tutorials/roofit/rf314_paramfitrange.py +++ b/tutorials/roofit/rf314_paramfitrange.py @@ -42,7 +42,7 @@ ) # Generate dataset with t values that observe (t>tmin) -dacc = model.generate(ROOT.RooArgSet(t), ROOT.RooFit.ProtoData(tmp)) +dacc = model.generate(ROOT.RooArgSet(t), ProtoData=tmp) # Fit pdf to data in acceptance region # ----------------------------------------------------------------------- @@ -53,7 +53,7 @@ # --------------------------------------------------------------------------------- # Make plot frame, datasets and overlay model -frame = t.frame(ROOT.RooFit.Title("Fit to data with per-event acceptance")) +frame = t.frame(Title="Fit to data with per-event acceptance") dall.plotOn(frame, MarkerColor=ROOT.kRed, LineColor=ROOT.kRed) model.plotOn(frame) dacc.plotOn(frame) diff --git a/tutorials/roofit/rf315_projectpdf.py b/tutorials/roofit/rf315_projectpdf.py index b593ef5235dd0..705930a5a7a23 100644 --- a/tutorials/roofit/rf315_projectpdf.py +++ b/tutorials/roofit/rf315_projectpdf.py @@ -40,7 +40,7 @@ "model", "gaussx(x|y)*gaussy(y)", ROOT.RooArgSet(gaussy), - ROOT.RooFit.Conditional(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)), + Conditional=(ROOT.RooArgSet(gaussx), ROOT.RooArgSet(x)), ) # Marginalize m(x,y) to m(x) diff --git a/tutorials/roofit/rf316_llratioplot.py b/tutorials/roofit/rf316_llratioplot.py index 9f717f50a0e41..7fad635b4b0c2 100644 --- a/tutorials/roofit/rf316_llratioplot.py +++ b/tutorials/roofit/rf316_llratioplot.py @@ -42,7 +42,7 @@ # ------------------------------------------------- # Make plain projection of data and pdf on x observable -frame = x.frame(ROOT.RooFit.Title("Projection of 3D data and pdf on X"), ROOT.RooFit.Bins(40)) +frame = x.frame(Title="Projection of 3D data and pdf on X", Bins=40) data.plotOn(frame) model.plotOn(frame) @@ -64,10 +64,10 @@ data.addColumn(llratio_func) # Extract the subset of data with large signal likelihood -dataSel = data.reduce(ROOT.RooFit.Cut("llratio>0.7")) +dataSel = data.reduce(Cut="llratio>0.7") # Make plot frame -frame2 = x.frame(ROOT.RooFit.Title("Same projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) +frame2 = x.frame(Title="Same projection on X with LLratio(y,z)>0.7", Bins=40) # Plot select data on frame dataSel.plotOn(frame2) @@ -81,7 +81,7 @@ # Calculate LL ratio for each generated event and select MC events with # llratio)0.7 mcprojData.addColumn(llratio_func) -mcprojDataSel = mcprojData.reduce(ROOT.RooFit.Cut("llratio>0.7")) +mcprojDataSel = mcprojData.reduce(Cut="llratio>0.7") # Project model on x, projected observables (y,z) with Monte Carlo technique # on set of events with the same llratio cut as was applied to data diff --git a/tutorials/roofit/rf401_importttreethx.py b/tutorials/roofit/rf401_importttreethx.py index 08cf02957678c..ad4e15a469634 100644 --- a/tutorials/roofit/rf401_importttreethx.py +++ b/tutorials/roofit/rf401_importttreethx.py @@ -72,10 +72,10 @@ def makeTTree(): "dh", "dh", ROOT.RooArgList(x), - ROOT.RooFit.Index(c), ROOT.RooFit.Import("SampleA", hh_1), ROOT.RooFit.Import("SampleB", hh_2), - ROOT.RooFit.Import("SampleC", hh_3), + Import=("SampleC", hh_3), + Index=c, ) dh.Print() @@ -100,12 +100,12 @@ def makeTTree(): z = ROOT.RooRealVar("z", "z", -10, 10) # Import only observables (y,z) -ds = ROOT.RooDataSet("ds", "ds", ROOT.RooArgSet(x, y), ROOT.RooFit.Import(tree)) +ds = ROOT.RooDataSet("ds", "ds", ROOT.RooArgSet(x, y), Import=tree) ds.Print() # Import observables (x,y,z) but only event for which (y+z<0) is ROOT.True # Import observables (x,y,z) but only event for which (y+z<0) is ROOT.True -ds2 = ROOT.RooDataSet("ds2", "ds2", ROOT.RooArgSet(x, y, z), ROOT.RooFit.Import(tree), ROOT.RooFit.Cut("y+z<0")) +ds2 = ROOT.RooDataSet("ds2", "ds2", ROOT.RooArgSet(x, y, z), Import=tree, Cut="y+z<0") ds2.Print() # Importing integer ROOT TTree branches @@ -113,7 +113,7 @@ def makeTTree(): # Import integer tree branch as ROOT.RooRealVar i = ROOT.RooRealVar("i", "i", 0, 5) -ds3 = ROOT.RooDataSet("ds3", "ds3", ROOT.RooArgSet(i, x), ROOT.RooFit.Import(tree)) +ds3 = ROOT.RooDataSet("ds3", "ds3", ROOT.RooArgSet(i, x), Import=tree) ds3.Print() # Define category i @@ -123,7 +123,7 @@ def makeTTree(): # Import integer tree branch as ROOT.RooCategory (only events with i==0 and i==1 # will be imported as those are the only defined states) -ds4 = ROOT.RooDataSet("ds4", "ds4", ROOT.RooArgSet(icat, x), ROOT.RooFit.Import(tree)) +ds4 = ROOT.RooDataSet("ds4", "ds4", ROOT.RooArgSet(icat, x), Import=tree) ds4.Print() # Import multiple RooDataSets into a RooDataSet @@ -140,10 +140,10 @@ def makeTTree(): "dsABC", "dsABC", ROOT.RooArgSet(x, y), - ROOT.RooFit.Index(c), ROOT.RooFit.Import("SampleA", dsA), ROOT.RooFit.Import("SampleB", dsB), - ROOT.RooFit.Import("SampleC", dsC), + Index=c, + Import=("SampleC", dsC), ) dsABC.Print() diff --git a/tutorials/roofit/rf402_datahandling.py b/tutorials/roofit/rf402_datahandling.py index 75c37dd6cba31..ac2f6c5dd115f 100644 --- a/tutorials/roofit/rf402_datahandling.py +++ b/tutorials/roofit/rf402_datahandling.py @@ -116,7 +116,7 @@ dh = ROOT.RooDataHist("dh", "binned version of d", ROOT.RooArgSet(x, y), d) dh.Print("v") -yframe = y.frame(ROOT.RooFit.Bins(10), ROOT.RooFit.Title("Operations on binned datasets")) +yframe = y.frame(Bins=10, Title="Operations on binned datasets") dh.plotOn(yframe) # plot projection of 2D binned data on y # Examine the statistics of a binned dataset diff --git a/tutorials/roofit/rf404_categories.py b/tutorials/roofit/rf404_categories.py index 4a5959d31fdda..5d9b938b68651 100644 --- a/tutorials/roofit/rf404_categories.py +++ b/tutorials/roofit/rf404_categories.py @@ -76,5 +76,5 @@ tagCat.addToRange("soso", "NetTagger-2") # Use category range in dataset reduction specification -goodData = data.reduce(ROOT.RooFit.CutRange("good")) +goodData = data.reduce(CutRange="good") goodData.table(tagCat).Print("v") diff --git a/tutorials/roofit/rf405_realtocatfuncs.py b/tutorials/roofit/rf405_realtocatfuncs.py index 299d4b7b11d53..6c1b3fb2830b0 100644 --- a/tutorials/roofit/rf405_realtocatfuncs.py +++ b/tutorials/roofit/rf405_realtocatfuncs.py @@ -50,7 +50,7 @@ data.addColumn(xRegion) # Make plot of data in x -xframe = x.frame(ROOT.RooFit.Title("Demo of threshold and binning mapping functions")) +xframe = x.frame(Title="Demo of threshold and binning mapping functions") data.plotOn(xframe) # Use calculated category to select sideband data @@ -84,7 +84,7 @@ # Construct subset of data matching range "alt" but only for the first # 5000 events and plot it on the frame -dataSel = data.reduce(ROOT.RooFit.CutRange("alt"), ROOT.RooFit.EventRange(0, 5000)) +dataSel = data.reduce(CutRange="alt", EventRange=(0, 5000)) dataSel.plotOn(xframe, MarkerColor=ROOT.kGreen, LineColor=ROOT.kGreen) c = ROOT.TCanvas("rf405_realtocatfuncs", "rf405_realtocatfuncs", 600, 600) diff --git a/tutorials/roofit/rf407_latextables.py b/tutorials/roofit/rf407_latextables.py index 72bc240b4fabe..98ac2d88264f1 100644 --- a/tutorials/roofit/rf407_latextables.py +++ b/tutorials/roofit/rf407_latextables.py @@ -67,14 +67,14 @@ params.printLatex() # Print parameter list in LaTeX for (names values|names values) -params.printLatex(ROOT.RooFit.Columns(2)) +params.printLatex(Columns=2) # Print two parameter lists side by side (name values initvalues) -params.printLatex(ROOT.RooFit.Sibling(initParams)) +params.printLatex(Sibling=initParams) # Print two parameter lists side by side (name values initvalues|name # values initvalues) -params.printLatex(ROOT.RooFit.Sibling(initParams), ROOT.RooFit.Columns(2)) +params.printLatex(Sibling=initParams, Columns=2) # Write LaTex table to file -params.printLatex(ROOT.RooFit.Sibling(initParams), ROOT.RooFit.OutputFile("rf407_latextables.tex")) +params.printLatex(Sibling=initParams, OutputFile="rf407_latextables.tex") diff --git a/tutorials/roofit/rf501_simultaneouspdf.py b/tutorials/roofit/rf501_simultaneouspdf.py index d591fdd42c12f..109961988576d 100644 --- a/tutorials/roofit/rf501_simultaneouspdf.py +++ b/tutorials/roofit/rf501_simultaneouspdf.py @@ -95,7 +95,7 @@ # ---------------------------------------------------------------- # Make a frame for the physics sample -frame1 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Physics sample")) +frame1 = x.frame(Bins=30, Title="Physics sample") # Plot all data tagged as physics sample combData.plotOn(frame1, Cut="sample==sample::physics") @@ -112,7 +112,7 @@ ) # The same plot for the control sample slice -frame2 = x.frame(ROOT.RooFit.Bins(30), ROOT.RooFit.Title("Control sample")) +frame2 = x.frame(Bins=30, Title="Control sample") combData.plotOn(frame2, Cut="sample==sample::control") simPdf.plotOn(frame2, Slice=(sample, "control"), ProjWData=(sampleSet, combData)) simPdf.plotOn( diff --git a/tutorials/roofit/rf504_simwstool.py b/tutorials/roofit/rf504_simwstool.py index 6eea420b1be79..8071b33cd9e88 100644 --- a/tutorials/roofit/rf504_simwstool.py +++ b/tutorials/roofit/rf504_simwstool.py @@ -62,7 +62,7 @@ # = model_run2(x) if c=="run2" # # Returned pdf is owned by the workspace -model_sim = sct.build("model_sim", "model", ROOT.RooFit.SplitParam("m", "c")) +model_sim = sct.build("model_sim", "model", SplitParam=("m", "c")) # Print tree structure of model model_sim.Print("t") @@ -78,7 +78,7 @@ # ----------------------------------------------------------------------------------------- # Build another simultaneous pdf using a composite split in states c X d -model_sim2 = sct.build("model_sim2", "model", ROOT.RooFit.SplitParam("p0", "c,d")) +model_sim2 = sct.build("model_sim2", "model", SplitParam=("p0", "c,d")) # Print tree structure of self model model_sim2.Print("t") diff --git a/tutorials/roofit/rf506_msgservice.py b/tutorials/roofit/rf506_msgservice.py index 6872c55484c44..b63b8d62a3006 100644 --- a/tutorials/roofit/rf506_msgservice.py +++ b/tutorials/roofit/rf506_msgservice.py @@ -58,9 +58,7 @@ # ----------------------------------------------------------------------- # Show DEBUG level message on function tracing, ROOT.RooGaussian only -ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Tracing), ROOT.RooFit.ClassName("RooGaussian") -) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, Topic=ROOT.RooFit.Tracing, ClassName="RooGaussian") # Perform a fit to generate some tracing messages model.fitTo(data, Verbose=True) @@ -70,9 +68,7 @@ # Show DEBUG level message on function tracing on all objects, output to # file -ROOT.RooMsgService.instance().addStream( - ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Tracing), ROOT.RooFit.OutputFile("rf506_debug.log") -) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, Topic=ROOT.RooFit.Tracing, OutputFile="rf506_debug.log") # Perform a fit to generate some tracing messages model.fitTo(data, Verbose=True) @@ -84,7 +80,7 @@ # --------------------------------------------------------------------- # Show DEBUG level messages on client/server link state management -ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.LinkStateMgmt)) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, Topic=ROOT.RooFit.LinkStateMgmt) ROOT.RooMsgService.instance().Print("v") # Clone composite pdf g to trigger some link state management activity diff --git a/tutorials/roofit/rf603_multicpu.py b/tutorials/roofit/rf603_multicpu.py index 0403cd4709b03..091577f975966 100644 --- a/tutorials/roofit/rf603_multicpu.py +++ b/tutorials/roofit/rf603_multicpu.py @@ -60,10 +60,10 @@ # Calculate likelihood ratio for each event, subset of events with high # signal likelihood data.addColumn(llratio_func) -dataSel = data.reduce(ROOT.RooFit.Cut("llratio>0.7")) +dataSel = data.reduce(Cut="llratio>0.7") # Make plot frame and plot data -frame = x.frame(ROOT.RooFit.Title("Projection on X with LLratio(y,z)>0.7"), ROOT.RooFit.Bins(40)) +frame = x.frame(Title="Projection on X with LLratio(y,z)>0.7", Bins=40) dataSel.plotOn(frame) # Perform parallel projection using MC integration of pdf using given input dataSet. diff --git a/tutorials/roofit/rf605_profilell.py b/tutorials/roofit/rf605_profilell.py index ce83524042cac..8235a5f2aaa38 100644 --- a/tutorials/roofit/rf605_profilell.py +++ b/tutorials/roofit/rf605_profilell.py @@ -40,19 +40,17 @@ # --------------------------------------------------- # Construct unbinned likelihood -nll = model.createNLL(data, ROOT.RooFit.NumCPU(2)) +nll = model.createNLL(data, NumCPU=2) # Minimize likelihood w.r.t all parameters before making plots ROOT.RooMinimizer(nll).migrad() # Plot likelihood scan frac -frame1 = frac.frame(ROOT.RooFit.Bins(10), ROOT.RooFit.Range(0.01, 0.95), ROOT.RooFit.Title("LL and profileLL in frac")) +frame1 = frac.frame(Bins=10, Range=(0.01, 0.95), Title="LL and profileLL in frac") nll.plotOn(frame1, ROOT.RooFit.ShiftToZero()) # Plot likelihood scan in sigma_g2 -frame2 = sigma_g2.frame( - ROOT.RooFit.Bins(10), ROOT.RooFit.Range(3.3, 5.0), ROOT.RooFit.Title("LL and profileLL in sigma_g2") -) +frame2 = sigma_g2.frame(Bins=10, Range=(3.3, 5.0), Title="LL and profileLL in sigma_g2") nll.plotOn(frame2, ROOT.RooFit.ShiftToZero()) # Construct profile likelihood in frac diff --git a/tutorials/roofit/rf606_nllerrorhandling.py b/tutorials/roofit/rf606_nllerrorhandling.py index a004ba01e3199..53f109dd6b1a0 100644 --- a/tutorials/roofit/rf606_nllerrorhandling.py +++ b/tutorials/roofit/rf606_nllerrorhandling.py @@ -35,7 +35,7 @@ # Plot model and data # -------------------------------------- -frame1 = m.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Argus model and data")) +frame1 = m.frame(Bins=40, Title="Argus model and data") data.plotOn(frame1) argus.plotOn(frame1) @@ -79,7 +79,7 @@ # but if an likelihood value evaluates with error, corresponding value # on the curve will be set to the value given in EvalErrorValue(). -frame2 = m0.frame(ROOT.RooFit.Range(5.288, 5.293), ROOT.RooFit.Title("-log(L) scan vs m0, regions masked")) +frame2 = m0.frame(Range=(5.288, 5.293), Title="-log(L) scan vs m0, regions masked") nll.plotOn( frame2, ROOT.RooFit.ShiftToZero(), PrintEvalErrors=-1, EvalErrorValue=(nll.getVal() + 10), LineColor=ROOT.kRed ) diff --git a/tutorials/roofit/rf609_xychi2fit.py b/tutorials/roofit/rf609_xychi2fit.py index efe434eaf8a01..7d14e2187846b 100644 --- a/tutorials/roofit/rf609_xychi2fit.py +++ b/tutorials/roofit/rf609_xychi2fit.py @@ -25,7 +25,7 @@ x = ROOT.RooRealVar("x", "x", -11, 11) y = ROOT.RooRealVar("y", "y", -10, 200) -dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet(x, y), ROOT.RooFit.StoreError(ROOT.RooArgSet(x, y))) +dxy = ROOT.RooDataSet("dxy", "dxy", ROOT.RooArgSet(x, y), StoreError=(ROOT.RooArgSet(x, y))) # Fill an example dataset with X,err(X),Y,err(Y) values for i in range(10): @@ -47,18 +47,18 @@ f = ROOT.RooPolyVar("f", "f", x, ROOT.RooArgList(b, a, ROOT.RooFit.RooConst(1))) # Plot dataset in X-Y interpretation -frame = x.frame(ROOT.RooFit.Title("Chi^2 fit of function set of (X#pmdX,Y#pmdY) values")) -dxy.plotOnXY(frame, ROOT.RooFit.YVar(y)) +frame = x.frame(Title="Chi^2 fit of function set of (X#pmdX,Y#pmdY) values") +dxy.plotOnXY(frame, YVar=y) # Fit chi^2 using X and Y errors -f.chi2FitTo(dxy, ROOT.RooFit.YVar(y)) +f.chi2FitTo(dxy, YVar=y) # Overlay fitted function f.plotOn(frame) # Alternative: fit chi^2 integrating f(x) over ranges defined by X errors, rather # than taking point at center of bin -f.chi2FitTo(dxy, ROOT.RooFit.YVar(y), ROOT.RooFit.Integrate(True)) +f.chi2FitTo(dxy, YVar=y, Integrate=True) # Overlay alternate fit result f.plotOn(frame, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) diff --git a/tutorials/roofit/rf610_visualerror.py b/tutorials/roofit/rf610_visualerror.py index ee257546c77b8..f04ec59f79b64 100644 --- a/tutorials/roofit/rf610_visualerror.py +++ b/tutorials/roofit/rf610_visualerror.py @@ -39,7 +39,7 @@ # ------------------------------------- # Make plot frame -frame = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("P.d.f with visualized 1-sigma error band")) +frame = x.frame(Bins=40, Title="P.d.f with visualized 1-sigma error band") d.plotOn(frame) # Visualize 1-sigma error encoded in fit result 'r' as orange band using linear error propagation @@ -97,7 +97,7 @@ # ------------------------------------------------------ # Make plot frame -frame2 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from (m,m2)")) +frame2 = x.frame(Bins=40, Title="Visualization of 2-sigma partial error from (m,m2)") # Visualize partial error. For partial error visualization the covariance matrix is first reduced as follows # ___ -1 @@ -119,7 +119,7 @@ frame2.SetMinimum(0) # Make plot frame -frame3 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from (s,s2)")) +frame3 = x.frame(Bins=40, Title="Visualization of 2-sigma partial error from (s,s2)") # Propagate partial error due to yield parameter using linear and sampling # method @@ -131,7 +131,7 @@ frame3.SetMinimum(0) # Make plot frame -frame4 = x.frame(ROOT.RooFit.Bins(40), ROOT.RooFit.Title("Visualization of 2-sigma partial error from fsig")) +frame4 = x.frame(Bins=40, Title="Visualization of 2-sigma partial error from fsig") # Propagate partial error due to yield parameter using linear and sampling # method diff --git a/tutorials/roofit/rf701_efficiencyfit.py b/tutorials/roofit/rf701_efficiencyfit.py index 0f5f134723f01..253b778bba937 100644 --- a/tutorials/roofit/rf701_efficiencyfit.py +++ b/tutorials/roofit/rf701_efficiencyfit.py @@ -44,7 +44,7 @@ # (These are _only_ needed to generate some toy MC here to be used later) shapePdf = ROOT.RooPolynomial("shapePdf", "shapePdf", x, ROOT.RooArgList(ROOT.RooFit.RooConst(-0.095))) model = ROOT.RooProdPdf( - "model", "model", ROOT.RooArgSet(shapePdf), ROOT.RooFit.Conditional(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) + "model", "model", ROOT.RooArgSet(shapePdf), Conditional=(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) ) # Generate some toy data from model @@ -60,12 +60,12 @@ # -------------------------------------------------------- # Plot distribution of all events and accepted fraction of events on frame -frame1 = x.frame(ROOT.RooFit.Bins(20), ROOT.RooFit.Title("Data (all, accepted)")) +frame1 = x.frame(Bins=20, Title="Data (all, accepted)") data.plotOn(frame1) data.plotOn(frame1, Cut="cut==cut::accept", MarkerColor=ROOT.kRed, LineColor=ROOT.kRed) # Plot accept/reject efficiency on data overlay fitted efficiency curve -frame2 = x.frame(ROOT.RooFit.Bins(20), ROOT.RooFit.Title("Fitted efficiency")) +frame2 = x.frame(Bins=20, Title="Fitted efficiency") data.plotOn(frame2, Efficiency=cut) # needs ROOT version >= 5.21 effFunc.plotOn(frame2, LineColor=ROOT.kRed) diff --git a/tutorials/roofit/rf702_efficiencyfit_2D.py b/tutorials/roofit/rf702_efficiencyfit_2D.py index 80b89ffd690ba..229c5d8c9d1f3 100644 --- a/tutorials/roofit/rf702_efficiencyfit_2D.py +++ b/tutorials/roofit/rf702_efficiencyfit_2D.py @@ -59,7 +59,7 @@ ) shapePdf = ROOT.RooProdPdf("shapePdf", "shapePdf", ROOT.RooArgList(shapePdfX, shapePdfY)) model = ROOT.RooProdPdf( - "model", "model", ROOT.RooArgSet(shapePdf), ROOT.RooFit.Conditional(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) + "model", "model", ROOT.RooArgSet(shapePdf), Conditional=(ROOT.RooArgSet(effPdf), ROOT.RooArgSet(cut)) ) # Generate some toy data from model @@ -75,18 +75,11 @@ # -------------------------------------------------------- # Make 2D histograms of all data, data and efficiency function -hh_data_all = ROOT.RooAbsData.createHistogram( - data, "hh_data_all", x, ROOT.RooFit.Binning(8), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)) -) +hh_data_all = ROOT.RooAbsData.createHistogram(data, "hh_data_all", x, Binning=(8), YVar=(y, ROOT.RooFit.Binning(8))) hh_data_sel = ROOT.RooAbsData.createHistogram( - data, - "hh_data_sel", - x, - ROOT.RooFit.Binning(8), - ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(8)), - ROOT.RooFit.Cut("cut==cut::accept"), + data, "hh_data_sel", x, Binning=8, YVar=(y, ROOT.RooFit.Binning(8)), Cut="cut==cut::accept" ) -hh_eff = effFunc.createHistogram("hh_eff", x, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(50))) +hh_eff = effFunc.createHistogram("hh_eff", x, Binning=50, YVar=(y, ROOT.RooFit.Binning(50))) # Some adjustsment for good visualization hh_data_all.SetMinimum(0) diff --git a/tutorials/roofit/rf703_effpdfprod.py b/tutorials/roofit/rf703_effpdfprod.py index 15a210f831b12..e8e1439c0aeaf 100644 --- a/tutorials/roofit/rf703_effpdfprod.py +++ b/tutorials/roofit/rf703_effpdfprod.py @@ -36,10 +36,10 @@ # Plot efficiency, pdf # ---------------------------------------- -frame1 = t.frame(ROOT.RooFit.Title("Efficiency")) +frame1 = t.frame(Title="Efficiency") eff.plotOn(frame1, LineColor=ROOT.kRed) -frame2 = t.frame(ROOT.RooFit.Title("Pdf with and without efficiency")) +frame2 = t.frame(Title="Pdf with and without efficiency") model.plotOn(frame2, LineStyle=ROOT.kDashed) modelEff.plotOn(frame2) @@ -55,7 +55,7 @@ modelEff.fitTo(data) # Plot generated data and overlay fitted pdf -frame3 = t.frame(ROOT.RooFit.Title("Fitted pdf with efficiency")) +frame3 = t.frame(Title="Fitted pdf with efficiency") data.plotOn(frame3) modelEff.plotOn(frame3) diff --git a/tutorials/roofit/rf704_amplitudefit.py b/tutorials/roofit/rf704_amplitudefit.py index f5cc8d724f65f..d5050ca9100ea 100644 --- a/tutorials/roofit/rf704_amplitudefit.py +++ b/tutorials/roofit/rf704_amplitudefit.py @@ -68,8 +68,8 @@ # ------------------------------------------- # Make 2D plots of amplitudes -hh_cos = ampl1.createHistogram("hh_cos", t, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) -hh_sin = ampl2.createHistogram("hh_sin", t, ROOT.RooFit.Binning(50), ROOT.RooFit.YVar(cosa, ROOT.RooFit.Binning(50))) +hh_cos = ampl1.createHistogram("hh_cos", t, Binning=50, YVar=(cosa, ROOT.RooFit.Binning(50))) +hh_sin = ampl2.createHistogram("hh_sin", t, Binning=50, YVar=(cosa, ROOT.RooFit.Binning(50))) hh_cos.SetLineColor(ROOT.kBlue) hh_sin.SetLineColor(ROOT.kRed) diff --git a/tutorials/roofit/rf705_linearmorph.py b/tutorials/roofit/rf705_linearmorph.py index 9da70ac73a9d1..2823e3eb7b88e 100644 --- a/tutorials/roofit/rf705_linearmorph.py +++ b/tutorials/roofit/rf705_linearmorph.py @@ -73,7 +73,7 @@ # ----------------------------------------------------------------------- # Create 2D histogram -hh = lmorph.createHistogram("hh", x, ROOT.RooFit.Binning(40), ROOT.RooFit.YVar(alpha, ROOT.RooFit.Binning(40))) +hh = lmorph.createHistogram("hh", x, Binning=40, YVar=(alpha, ROOT.RooFit.Binning(40))) hh.SetLineColor(ROOT.kBlue) # Fit pdf to dataset with alpha=0.8 @@ -88,7 +88,7 @@ lmorph.fitTo(data, Verbose=True) # Plot fitted pdf and data overlaid -frame2 = x.frame(ROOT.RooFit.Bins(100)) +frame2 = x.frame(Bins=100) data.plotOn(frame2) lmorph.plotOn(frame2) @@ -96,7 +96,7 @@ # ----------------------------------------- # Show scan -log(L) of dataset w.r.t alpha -frame3 = alpha.frame(ROOT.RooFit.Bins(100), ROOT.RooFit.Range(0.1, 0.9)) +frame3 = alpha.frame(Bins=100, Range=(0.1, 0.9)) # Make 2D pdf of histogram nll = ROOT.RooNLLVar("nll", "nll", lmorph, data) diff --git a/tutorials/roofit/rf706_histpdf.py b/tutorials/roofit/rf706_histpdf.py index f3fffe7281cc2..4da573a550912 100644 --- a/tutorials/roofit/rf706_histpdf.py +++ b/tutorials/roofit/rf706_histpdf.py @@ -33,7 +33,7 @@ histpdf1 = ROOT.RooHistPdf("histpdf1", "histpdf1", ROOT.RooArgSet(x), hist1, 0) # Plot unbinned data and histogram pdf overlaid -frame1 = x.frame(ROOT.RooFit.Title("Low statistics histogram pdf"), ROOT.RooFit.Bins(100)) +frame1 = x.frame(Title="Low statistics histogram pdf", Bins=100) data1.plotOn(frame1) histpdf1.plotOn(frame1) @@ -51,7 +51,7 @@ histpdf2 = ROOT.RooHistPdf("histpdf2", "histpdf2", ROOT.RooArgSet(x), hist2, 2) # Plot unbinned data and histogram pdf overlaid -frame2 = x.frame(ROOT.RooFit.Title("High stats histogram pdf with interpolation"), ROOT.RooFit.Bins(100)) +frame2 = x.frame(Title="High stats histogram pdf with interpolation", Bins=100) data2.plotOn(frame2) histpdf2.plotOn(frame2) diff --git a/tutorials/roofit/rf707_kernelestimation.py b/tutorials/roofit/rf707_kernelestimation.py index e0a471cbf504b..a878bffe0eeb1 100644 --- a/tutorials/roofit/rf707_kernelestimation.py +++ b/tutorials/roofit/rf707_kernelestimation.py @@ -40,13 +40,13 @@ kest3 = ROOT.RooKeysPdf("kest1", "kest1", x, data1, ROOT.RooKeysPdf.MirrorBoth, 2) # Plot kernel estimation pdfs with and without mirroring over data -frame = x.frame(ROOT.RooFit.Title("Adaptive kernel estimation pdf with and w/o mirroring"), ROOT.RooFit.Bins(20)) +frame = x.frame(Title="Adaptive kernel estimation pdf with and w/o mirroring", Bins=20) data1.plotOn(frame) kest1.plotOn(frame) kest2.plotOn(frame, LineStyle=ROOT.kDashed, LineColor=ROOT.kRed) # Plot kernel estimation pdfs with regular and increased bandwidth -frame2 = x.frame(ROOT.RooFit.Title("Adaptive kernel estimation pdf with regular, bandwidth")) +frame2 = x.frame(Title="Adaptive kernel estimation pdf with regular, bandwidth") kest1.plotOn(frame2) kest3.plotOn(frame2, LineColor=ROOT.kMagenta) @@ -75,13 +75,11 @@ kest5 = ROOT.RooNDKeysPdf("kest5", "kest5", ROOT.RooArgList(x, y), data2, "am", 2) # Create a histogram of the data -hh_data = ROOT.RooAbsData.createHistogram( - data2, "hh_data", x, ROOT.RooFit.Binning(10), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(10)) -) +hh_data = ROOT.RooAbsData.createHistogram(data2, "hh_data", x, Binning=10, YVar=(y, ROOT.RooFit.Binning(10))) # Create histogram of the 2d kernel estimation pdfs -hh_pdf = kest4.createHistogram("hh_pdf", x, ROOT.RooFit.Binning(25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) -hh_pdf2 = kest5.createHistogram("hh_pdf2", x, ROOT.RooFit.Binning(25), ROOT.RooFit.YVar(y, ROOT.RooFit.Binning(25))) +hh_pdf = kest4.createHistogram("hh_pdf", x, Binning=25, YVar=(y, ROOT.RooFit.Binning(25))) +hh_pdf2 = kest5.createHistogram("hh_pdf2", x, Binning=25, YVar=(y, ROOT.RooFit.Binning(25))) hh_pdf.SetLineColor(ROOT.kBlue) hh_pdf2.SetLineColor(ROOT.kMagenta) diff --git a/tutorials/roofit/rf708_bphysics.py b/tutorials/roofit/rf708_bphysics.py index f2aacced2d77e..43d4c6a40a0be 100644 --- a/tutorials/roofit/rf708_bphysics.py +++ b/tutorials/roofit/rf708_bphysics.py @@ -39,7 +39,7 @@ tm = ROOT.RooTruthModel("tm", "truth model", dt) # Construct Bdecay with mixing -bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, tm, ROOT.RooBMixDecay.DoubleSided) +bmix = ROOT.RooBMixDecay("bmix", "decay", dt, mixState, tagFlav, tau, dm, w, dw, tm, type="DoubleSided") # Plot pdf in various slices # --------------------------------------------------- @@ -50,7 +50,7 @@ # Plot B0 and B0bar tagged data separately # For all plots below B0 and B0 tagged data will look somewhat differently # if the flavor tagging mistag rate for B0 and B0 is different (i.e. dw!=0) -frame1 = dt.frame(ROOT.RooFit.Title("B decay distribution with mixing (B0/B0bar)")) +frame1 = dt.frame(Title="B decay distribution with mixing (B0/B0bar)") data.plotOn(frame1, Cut="tagFlav==tagFlav::B0") bmix.plotOn(frame1, Slice=(tagFlav, "B0")) @@ -59,7 +59,7 @@ bmix.plotOn(frame1, Slice=(tagFlav, "B0bar"), LineColor=ROOT.kCyan) # Plot mixed slice for B0 and B0bar tagged data separately -frame2 = dt.frame(ROOT.RooFit.Title("B decay distribution of mixed events (B0/B0bar)")) +frame2 = dt.frame(Title="B decay distribution of mixed events (B0/B0bar)") data.plotOn(frame2, Cut="mixState==mixState::mixed&&tagFlav==tagFlav::B0") bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0"), Slice=(mixState, "mixed")) @@ -68,7 +68,7 @@ bmix.plotOn(frame2, ROOT.RooFit.Slice(tagFlav, "B0bar"), Slice=(mixState, "mixed"), LineColor=ROOT.kCyan) # Plot unmixed slice for B0 and B0bar tagged data separately -frame3 = dt.frame(ROOT.RooFit.Title("B decay distribution of unmixed events (B0/B0bar)")) +frame3 = dt.frame(Title="B decay distribution of unmixed events (B0/B0bar)") data.plotOn(frame3, Cut="mixState==mixState::unmixed&&tagFlav==tagFlav::B0") bmix.plotOn(frame3, ROOT.RooFit.Slice(tagFlav, "B0"), Slice=(mixState, "unmixed")) @@ -90,7 +90,7 @@ # Construct Bdecay with CP violation bcp = ROOT.RooBCPEffDecay( - "bcp", "bcp", dt, tagFlav, tau, dm, w, CPeigen, absLambda, argLambda, effR, dw, tm, ROOT.RooBCPEffDecay.DoubleSided + "bcp", "bcp", dt, tagFlav, tau, dm, w, CPeigen, absLambda, argLambda, effR, dw, tm, type="DoubleSided" ) # Plot scenario 1 - sin(2b)=0.7, |l|=1 @@ -100,7 +100,7 @@ data2 = bcp.generate(ROOT.RooArgSet(dt, tagFlav), 10000) # Plot B0 and B0bar tagged data separately -frame4 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(|l|=1,Im(l)=0.7) (B0/B0bar)")) +frame4 = dt.frame(Title="B decay distribution with CPV(|l|=1,Im(l)=0.7) (B0/B0bar)") data2.plotOn(frame4, Cut="tagFlav==tagFlav::B0") bcp.plotOn(frame4, Slice=(tagFlav, "B0")) @@ -118,7 +118,7 @@ # Plot B0 and B0bar tagged data separately (sin2b = 0.7 plus direct CPV # |l|=0.5) -frame5 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(|l|=0.7,Im(l)=0.7) (B0/B0bar)")) +frame5 = dt.frame(Title="B decay distribution with CPV(|l|=0.7,Im(l)=0.7) (B0/B0bar)") data3.plotOn(frame5, Cut="tagFlav==tagFlav::B0") bcp.plotOn(frame5, Slice=(tagFlav, "B0")) @@ -150,7 +150,7 @@ # Construct generic B decay pdf using above user coefficients bcpg = ROOT.RooBDecay( - "bcpg", "bcpg", dt, tau, DG, ROOT.RooFit.RooConst(1), fsinh, fcos, fsin, dm, tm, ROOT.RooBDecay.DoubleSided + "bcpg", "bcpg", dt, tau, DG, ROOT.RooFit.RooConst(1), fsinh, fcos, fsin, dm, tm, type="DoubleSided" ) # Plot - Im(l)=0.7, e(l)=0.7 |l|=1, G/G=0.5 @@ -160,7 +160,7 @@ data4 = bcpg.generate(ROOT.RooArgSet(dt, tagFlav), 10000) # Plot B0 and B0bar tagged data separately -frame6 = dt.frame(ROOT.RooFit.Title("B decay distribution with CPV(Im(l)=0.7,Re(l)=0.7,|l|=1,dG/G=0.5) (B0/B0bar)")) +frame6 = dt.frame(Title="B decay distribution with CPV(Im(l)=0.7,Re(l)=0.7,|l|=1,dG/G=0.5) (B0/B0bar)") data4.plotOn(frame6, Cut="tagFlav==tagFlav::B0") bcpg.plotOn(frame6, Slice=(tagFlav, "B0")) diff --git a/tutorials/roofit/rf801_mcstudy.py b/tutorials/roofit/rf801_mcstudy.py index 3cb93f3255040..064125460b15a 100644 --- a/tutorials/roofit/rf801_mcstudy.py +++ b/tutorials/roofit/rf801_mcstudy.py @@ -62,10 +62,10 @@ mcstudy = ROOT.RooMCStudy( model, ROOT.RooArgSet(x), - ROOT.RooFit.Binned(True), - ROOT.RooFit.Silence(), - ROOT.RooFit.Extended(), - ROOT.RooFit.FitOptions(ROOT.RooFit.Save(True), ROOT.RooFit.PrintEvalErrors(0)), + Binned=True, + Silence=True, + Extended=True, + FitOptions=(ROOT.RooFit.Save(True), ROOT.RooFit.PrintEvalErrors(0)), ) # Generate and fit events @@ -79,16 +79,16 @@ # Make plots of the distributions of mean, error on mean and the pull of # mean -frame1 = mcstudy.plotParam(mean, ROOT.RooFit.Bins(40)) -frame2 = mcstudy.plotError(mean, ROOT.RooFit.Bins(40)) -frame3 = mcstudy.plotPull(mean, ROOT.RooFit.Bins(40), ROOT.RooFit.FitGauss(True)) +frame1 = mcstudy.plotParam(mean, Bins=40) +frame2 = mcstudy.plotError(mean, Bins=40) +frame3 = mcstudy.plotPull(mean, Bins=40, FitGauss=True) # Plot distribution of minimized likelihood frame4 = mcstudy.plotNLL(ROOT.RooFit.Bins(40)) # Make some histograms from the parameter dataset -hh_cor_a0_s1f = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a1, ROOT.RooFit.YVar(sig1frac)) -hh_cor_a0_a1 = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a0, ROOT.RooFit.YVar(a1)) +hh_cor_a0_s1f = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a1, YVar=sig1frac) +hh_cor_a0_a1 = ROOT.RooAbsData.createHistogram(mcstudy.fitParDataSet(), "hh", a0, YVar=a1) # Access some of the saved fit results from individual toys corrHist000 = mcstudy.fitResult(0).correlationHist("c000") diff --git a/tutorials/roofit/rf901_numintconfig.py b/tutorials/roofit/rf901_numintconfig.py index 352ddcbb1da9d..42edf93e17667 100644 --- a/tutorials/roofit/rf901_numintconfig.py +++ b/tutorials/roofit/rf901_numintconfig.py @@ -43,7 +43,7 @@ # Activate debug-level messages for topic integration to be able to follow # actions below -ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, ROOT.RooFit.Topic(ROOT.RooFit.Integration)) +ROOT.RooMsgService.instance().addStream(ROOT.RooFit.DEBUG, Topic=ROOT.RooFit.Integration) # Calculate integral over landau with default choice of numeric integrator intLandau = landau.createIntegral(ROOT.RooArgSet(x)) @@ -61,7 +61,7 @@ print("WARNING: RooAdaptiveGaussKronrodIntegrator is not existing because ROOT is built without Mathmore support") # Calculate integral over landau with custom integral specification -intLandau2 = landau.createIntegral(ROOT.RooArgSet(x), ROOT.RooFit.NumIntConfig(customConfig)) +intLandau2 = landau.createIntegral(ROOT.RooArgSet(x), NumIntConfig=customConfig) val2 = intLandau2.getVal() print(" [2] int_dx landau(x) = ", val2) diff --git a/tutorials/roofit/rf902_numgenconfig.py b/tutorials/roofit/rf902_numgenconfig.py index f372365581635..fb809fc221923 100644 --- a/tutorials/roofit/rf902_numgenconfig.py +++ b/tutorials/roofit/rf902_numgenconfig.py @@ -29,7 +29,7 @@ ROOT.RooAbsPdf.defaultGeneratorConfig().method1D(False, False).setLabel("RooAcceptReject") # Generate 10Kevt using ROOT.RooAcceptReject -data_ar = model.generate(ROOT.RooArgSet(x), 10000, verbose=True) +data_ar = model.generate(ROOT.RooArgSet(x), 10000, Verbose=True) data_ar.Print() # Adjusting default config for a specific pdf diff --git a/tutorials/roofit/rf903_numintcache.py b/tutorials/roofit/rf903_numintcache.py index 08af66fdd6834..38f3847288a41 100644 --- a/tutorials/roofit/rf903_numintcache.py +++ b/tutorials/roofit/rf903_numintcache.py @@ -92,7 +92,7 @@ def getWorkspace(mode): # Projection on x (always slow as 2D integral over Y, at fitted value of a # is not cached) -framex = w.var("x").frame(ROOT.RooFit.Title("Projection of 3D model on X")) +framex = w.var("x").frame(Title="Projection of 3D model on X") d.plotOn(framex) w.pdf("model").plotOn(framex) From bacc1b5f201f4d94142035910355ba97781f581c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 17 Jun 2021 11:54:04 +0200 Subject: [PATCH 256/309] [RF] Import remaining RooFit Python examples translated by Clemens Lange --- tutorials/roofit/rf102_dataimport.py | 141 +++++++++++++++++++ tutorials/roofit/rf109_chi2residpull.py | 84 ++++++++++++ tutorials/roofit/rf207_comptools.py | 112 +++++++++++++++ tutorials/roofit/rf303_conditional.py | 98 ++++++++++++++ tutorials/roofit/rf403_weightedevts.py | 158 ++++++++++++++++++++++ tutorials/roofit/rf503_wspaceread.py | 63 +++++++++ tutorials/roofit/rf508_listsetmanip.py | 151 +++++++++++++++++++++ tutorials/roofit/rf602_chi2fit.py | 70 ++++++++++ tutorials/roofit/rf802_mcstudy_addons.py | 93 +++++++++++++ tutorials/roofit/rf803_mcstudy_addons2.py | 118 ++++++++++++++++ tutorials/roofit/rf804_mcstudy_constr.py | 85 ++++++++++++ 11 files changed, 1173 insertions(+) create mode 100644 tutorials/roofit/rf102_dataimport.py create mode 100644 tutorials/roofit/rf109_chi2residpull.py create mode 100644 tutorials/roofit/rf207_comptools.py create mode 100644 tutorials/roofit/rf303_conditional.py create mode 100644 tutorials/roofit/rf403_weightedevts.py create mode 100644 tutorials/roofit/rf503_wspaceread.py create mode 100644 tutorials/roofit/rf508_listsetmanip.py create mode 100644 tutorials/roofit/rf602_chi2fit.py create mode 100644 tutorials/roofit/rf802_mcstudy_addons.py create mode 100644 tutorials/roofit/rf803_mcstudy_addons2.py create mode 100644 tutorials/roofit/rf804_mcstudy_constr.py diff --git a/tutorials/roofit/rf102_dataimport.py b/tutorials/roofit/rf102_dataimport.py new file mode 100644 index 0000000000000..dbf4d1581abb5 --- /dev/null +++ b/tutorials/roofit/rf102_dataimport.py @@ -0,0 +1,141 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## 'BASIC FUNCTIONALITY' RooFit tutorial macro #102 +## Importing data from ROOT TTrees and THx histograms +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +import ROOT +from array import array + + +def makeTH1(): + + # Create ROOT ROOT.TH1 filled with a Gaussian distribution + + hh = ROOT.TH1D("hh", "hh", 25, -10, 10) + for i in range(100): + hh.Fill(ROOT.gRandom.Gaus(0, 3)) + return hh + + +def makeTTree(): + # Create ROOT ROOT.TTree filled with a Gaussian distribution in x and a + # uniform distribution in y + + tree = ROOT.TTree("tree", "tree") + px = array("d", [0]) + py = array("d", [0]) + tree.Branch("x", px, "x/D") + tree.Branch("y", py, "y/D") + for i in range(100): + px[0] = ROOT.gRandom.Gaus(0, 3) + py[0] = ROOT.gRandom.Uniform() * 30 - 15 + tree.Fill() + return tree + + +############################ +# Importing ROOT histograms +############################ +# Import ROOT TH1 into a RooDataHist +# --------------------------------------------------------- +# Create a ROOT TH1 histogram +hh = makeTH1() + +# Declare observable x +x = ROOT.RooRealVar("x", "x", -10, 10) + +# Create a binned dataset that imports contents of ROOT.TH1 and associates +# its contents to observable 'x' +dh = ROOT.RooDataHist("dh", "dh", ROOT.RooArgList(x), ROOT.RooFit.Import(hh)) + +# Plot and fit a RooDataHist +# --------------------------------------------------- +# Make plot of binned dataset showing Poisson error bars (ROOT.RooFit +# default) +frame = x.frame(ROOT.RooFit.Title("Imported ROOT.TH1 with Poisson error bars")) +dh.plotOn(frame) + +# Fit a Gaussian p.d.f to the data +mean = ROOT.RooRealVar("mean", "mean", 0, -10, 10) +sigma = ROOT.RooRealVar("sigma", "sigma", 3, 0.1, 10) +gauss = ROOT.RooGaussian("gauss", "gauss", x, mean, sigma) +gauss.fitTo(dh) +gauss.plotOn(frame) + +# Plot and fit a RooDataHist with internal errors +# --------------------------------------------------------------------------------------------- + +# If histogram has custom error (i.e. its contents is does not originate from a Poisson process +# but e.g. is a sum of weighted events) you can data with symmetric 'sum-of-weights' error instead +# (same error bars as shown by ROOT) +frame2 = x.frame(ROOT.RooFit.Title("Imported ROOT.TH1 with internal errors")) +dh.plotOn(frame2, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) +gauss.plotOn(frame2) + +# Please note that error bars shown (Poisson or SumW2) are for visualization only, the are NOT used +# in a maximum likelihood fit +# +# A (binned) ML fit will ALWAYS assume the Poisson error interpretation of data (the mathematical definition +# of likelihood does not take any external definition of errors). Data with non-unit weights can only be correctly +# fitted with a chi^2 fit (see rf602_chi2fit.py) +# +# Importing ROOT TTrees +# ----------------------------------------------------------- +# Import ROOT TTree into a RooDataSet + +tree = makeTTree() + +# Define 2nd observable y +y = ROOT.RooRealVar("y", "y", -10, 10) + +# Construct unbinned dataset importing tree branches x and y matching between branches and ROOT.RooRealVars +# is done by name of the branch/RRV +# +# Note that ONLY entries for which x,y have values within their allowed ranges as defined in +# ROOT.RooRealVar x and y are imported. Since the y values in the import tree are in the range [-15,15] +# and RRV y defines a range [-10,10] this means that the ROOT.RooDataSet +# below will have less entries than the ROOT.TTree 'tree' + +ds = ROOT.RooDataSet("ds", "ds", ROOT.RooArgSet(x, y), ROOT.RooFit.Import(tree)) + +# Plot data set with multiple binning choices +# ------------------------------------------------------------------------------------ +# Print number of events in dataset +ds.Print() + +# Print unbinned dataset with default frame binning (100 bins) +frame3 = y.frame(ROOT.RooFit.Title("Unbinned data shown in default frame binning")) +ds.plotOn(frame3) + +# Print unbinned dataset with custom binning choice (20 bins) +frame4 = y.frame(ROOT.RooFit.Title("Unbinned data shown with custom binning")) +ds.plotOn(frame4, ROOT.RooFit.Binning(20)) + +# Draw all frames on a canvas +c = ROOT.TCanvas("rf102_dataimport", "rf102_dataimport", 800, 800) +c.Divide(2, 2) +c.cd(1) +ROOT.gPad.SetLeftMargin(0.15) +frame.GetYaxis().SetTitleOffset(1.4) +frame.Draw() +c.cd(2) +ROOT.gPad.SetLeftMargin(0.15) +frame2.GetYaxis().SetTitleOffset(1.4) +frame2.Draw() +c.cd(3) +ROOT.gPad.SetLeftMargin(0.15) +frame3.GetYaxis().SetTitleOffset(1.4) +frame3.Draw() +c.cd(4) +ROOT.gPad.SetLeftMargin(0.15) +frame4.GetYaxis().SetTitleOffset(1.4) +frame4.Draw() + +c.SaveAs("rf102_dataimport.png") diff --git a/tutorials/roofit/rf109_chi2residpull.py b/tutorials/roofit/rf109_chi2residpull.py new file mode 100644 index 0000000000000..90a955301289c --- /dev/null +++ b/tutorials/roofit/rf109_chi2residpull.py @@ -0,0 +1,84 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## 'BASIC FUNCTIONALITY' RooFit tutorial macro #109 +## Calculating chi^2 from histograms and curves in ROOT.RooPlots, +## making histogram of residual and pull distributions +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +from __future__ import print_function +import ROOT + +# Set up model +# --------------------- + +# Create observables +x = ROOT.RooRealVar("x", "x", -10, 10) + +# Create Gaussian +sigma = ROOT.RooRealVar("sigma", "sigma", 3, 0.1, 10) +mean = ROOT.RooRealVar("mean", "mean", 0, -10, 10) +gauss = ROOT.RooGaussian("gauss", "gauss", x, mean, sigma) + +# Generate a sample of 1000 events with sigma=3 +data = gauss.generate(ROOT.RooArgSet(x), 10000) + +# Change sigma to 3.15 +sigma = 3.15 + +# Plot data and slightly distorted model +# --------------------------------------------------------------------------- + +# Overlay projection of gauss with sigma=3.15 on data with sigma=3.0 +frame1 = x.frame(ROOT.RooFit.Title("Data with distorted Gaussian pdf"), ROOT.RooFit.Bins(40)) +data.plotOn(frame1, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) +gauss.plotOn(frame1) + +# Calculate chi^2 +# ------------------------------ + +# Show the chi^2 of the curve w.r.t. the histogram +# If multiple curves or datasets live in the frame you can specify +# the name of the relevant curve and/or dataset in chiSquare() +print("chi^2 = ", frame1.chiSquare()) + +# Show residual and pull dists +# ------------------------------------------------------- + +# Construct a histogram with the residuals of the data w.r.t. the curve +hresid = frame1.residHist() + +# Construct a histogram with the pulls of the data w.r.t the curve +hpull = frame1.pullHist() + +# Create a frame to draw the residual distribution and add the +# distribution to the frame +frame2 = x.frame(ROOT.RooFit.Title("Residual Distribution")) +frame2.addPlotable(hresid, "P") + +# Create a frame to draw the pull distribution and add the distribution to +# the frame +frame3 = x.frame(ROOT.RooFit.Title("Pull Distribution")) +frame3.addPlotable(hpull, "P") + +c = ROOT.TCanvas("rf109_chi2residpull", "rf109_chi2residpull", 900, 300) +c.Divide(3) +c.cd(1) +ROOT.gPad.SetLeftMargin(0.15) +frame1.GetYaxis().SetTitleOffset(1.6) +frame1.Draw() +c.cd(2) +ROOT.gPad.SetLeftMargin(0.15) +frame2.GetYaxis().SetTitleOffset(1.6) +frame2.Draw() +c.cd(3) +ROOT.gPad.SetLeftMargin(0.15) +frame3.GetYaxis().SetTitleOffset(1.6) +frame3.Draw() + +c.SaveAs("rf109_chi2residpull.png") diff --git a/tutorials/roofit/rf207_comptools.py b/tutorials/roofit/rf207_comptools.py new file mode 100644 index 0000000000000..e6aa72778fcbb --- /dev/null +++ b/tutorials/roofit/rf207_comptools.py @@ -0,0 +1,112 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## 'ADDITION AND CONVOLUTION' RooFit tutorial macro #207 +## Tools and utilities for manipulation of composite objects +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +import ROOT + +# Set up composite pdf dataset +# -------------------------------------------------------- + +# Declare observable x +x = ROOT.RooRealVar("x", "x", 0, 10) + +# Create two Gaussian PDFs g1(x,mean1,sigma) anf g2(x,mean2,sigma) and +# their parameters +mean = ROOT.RooRealVar("mean", "mean of gaussians", 5) +sigma = ROOT.RooRealVar("sigma", "width of gaussians", 0.5) +sig = ROOT.RooGaussian("sig", "Signal component 1", x, mean, sigma) + +# Build Chebychev polynomial p.d.f. +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +bkg1 = ROOT.RooChebychev("bkg1", "Background 1", x, ROOT.RooArgList(a0, a1)) + +# Build expontential pdf +alpha = ROOT.RooRealVar("alpha", "alpha", -1) +bkg2 = ROOT.RooExponential("bkg2", "Background 2", x, alpha) + +# Sum the background components into a composite background p.d.f. +bkg1frac = ROOT.RooRealVar("bkg1frac", "fraction of component 1 in background", 0.2, 0.0, 1.0) +bkg = ROOT.RooAddPdf("bkg", "Signal", ROOT.RooArgList(bkg1, bkg2), ROOT.RooArgList(bkg1frac)) + +# Sum the composite signal and background +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) + +# Create dummy dataset that has more observables than the above pdf +y = ROOT.RooRealVar("y", "y", -10, 10) +data = ROOT.RooDataSet("data", "data", ROOT.RooArgSet(x, y)) + +# Basic information requests +# --------------------------------------------- + + +# Get list of observables +# --------------------------------------------- + +# Get list of observables of pdf in context of a dataset +# +# Observables are define each context as the variables +# shared between a model and a dataset. In self case +# that is the variable 'x' + +model_obs = model.getObservables(data) +model_obs.Print("v") + +# Get list of parameters +# ------------------------------------------- + +# Get list of parameters, list of observables +model_params = model.getParameters(ROOT.RooArgSet(x)) +model_params.Print("v") + +# Get list of parameters, a dataset +# (Gives identical results to operation above) +model_params2 = model.getParameters(data) +model_params2.Print() + +# Get list of components +# ------------------------------------------- + +# Get list of component objects, top-level node +model_comps = model.getComponents() +model_comps.Print("v") + +# Modifications to structure of composites +# ------------------------------------------- + +# Create a second Gaussian +sigma2 = ROOT.RooRealVar("sigma2", "width of gaussians", 1) +sig2 = ROOT.RooGaussian("sig2", "Signal component 1", x, mean, sigma2) + +# Create a sum of the original Gaussian plus the second Gaussian +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sigsum = ROOT.RooAddPdf("sigsum", "sig+sig2", ROOT.RooArgList(sig, sig2), ROOT.RooArgList(sig1frac)) + +# Construct a customizer utility to customize model +cust = ROOT.RooCustomizer(model, "cust") + +# Instruct the customizer to replace node 'sig' with node 'sigsum' +sigsum = ROOT.RooRealVar() # just define some kind of RooFit type +cust.replaceArg(sig, sigsum) + +# Build a clone of the input pdf according to the above customization +# instructions. Each node that requires modified is clone so that the +# original pdf remained untouched. The name of each cloned node is that +# of the original node suffixed by the name of the customizer object +# +# The returned head node own all nodes that were cloned as part of +# the build process so when cust_clone is deleted so will all other +# nodes that were created in the process. +cust_clone = cust.build(ROOT.kTRUE) + +# Print structure of clone of model with sig.sigsum replacement. +cust_clone.Print("t") diff --git a/tutorials/roofit/rf303_conditional.py b/tutorials/roofit/rf303_conditional.py new file mode 100644 index 0000000000000..0f662ab1d3672 --- /dev/null +++ b/tutorials/roofit/rf303_conditional.py @@ -0,0 +1,98 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## 'MULTIDIMENSIONAL MODELS' RooFit tutorial macro #303 +## Use of tailored p.d.f as conditional p.d.fs.s +## +## pdf = gauss(x,f(y),sx | y ) with f(y) = a0 + a1*y +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +import ROOT + + +def makeFakeDataXY(): + x = ROOT.RooRealVar("x", "x", -10, 10) + y = ROOT.RooRealVar("y", "y", -10, 10) + coord = ROOT.RooArgSet(x, y) + + d = ROOT.RooDataSet("d", "d", ROOT.RooArgSet(x, y)) + + for i in range(10000): + tmpy = ROOT.gRandom.Gaus(0, 10) + tmpx = ROOT.gRandom.Gaus(0.5 * tmpy, 1) + if (abs(tmpy) < 10) and (abs(tmpx) < 10): + x = tmpx + y = tmpy + d.add(coord) + + return d + + +# Set up composed model gauss(x, m(y), s) +# ----------------------------------------------------------------------- + +# Create observables +x = ROOT.RooRealVar("x", "x", -10, 10) +y = ROOT.RooRealVar("y", "y", -10, 10) + +# Create function f(y) = a0 + a1*y +a0 = ROOT.RooRealVar("a0", "a0", -0.5, -5, 5) +a1 = ROOT.RooRealVar("a1", "a1", -0.5, -1, 1) +fy = ROOT.RooPolyVar("fy", "fy", y, ROOT.RooArgList(a0, a1)) + +# Creat gauss(x,f(y),s) +sigma = ROOT.RooRealVar("sigma", "width of gaussian", 0.5, 0.1, 2.0) +model = ROOT.RooGaussian("model", "Gaussian with shifting mean", x, fy, sigma) + +# Obtain fake external experimental dataset with values for x and y +expDataXY = makeFakeDataXY() + +# Generate data from conditional p.d.f. model(x|y) +# --------------------------------------------------------------------------------------------- + +# Make subset of experimental data with only y values +expDataY = expDataXY.reduce(ROOT.RooArgSet(y)) + +# Generate 10000 events in x obtained from _conditional_ model(x|y) with y +# values taken from experimental data +data = model.generate(ROOT.RooArgSet(x), ROOT.RooFit.ProtoData(expDataY)) +data.Print() + +# Fit conditional p.d.f model(x|y) to data +# --------------------------------------------------------------------------------------------- + +model.fitTo(expDataXY, ROOT.RooFit.ConditionalObservables(ROOT.RooArgSet(y))) + +# Project conditional p.d.f on x and y dimensions +# --------------------------------------------------------------------------------------------- + +# Plot x distribution of data and projection of model x = 1/Ndata +# sum(data(y_i)) model(x;y_i) +xframe = x.frame() +expDataXY.plotOn(xframe) +model.plotOn(xframe, ROOT.RooFit.ProjWData(expDataY)) + +# Speed up (and approximate) projection by using binned clone of data for +# projection +binnedDataY = expDataY.binnedClone() +model.plotOn( + xframe, ROOT.RooFit.ProjWData(binnedDataY), ROOT.RooFit.LineColor(ROOT.kCyan), ROOT.RooFit.LineStyle(ROOT.kDotted) +) + +# Show effect of projection with too coarse binning +(expDataY.get().find("y")).setBins(5) +binnedDataY2 = expDataY.binnedClone() +model.plotOn(xframe, ROOT.RooFit.ProjWData(binnedDataY2), ROOT.RooFit.LineColor(ROOT.kRed)) + +# Make canvas and draw ROOT.RooPlots +c = ROOT.TCanvas("rf303_conditional", "rf303_conditional", 600, 460) +ROOT.gPad.SetLeftMargin(0.15) +xframe.GetYaxis().SetTitleOffset(1.2) +xframe.Draw() + +c.SaveAs("rf303_conditional.png") diff --git a/tutorials/roofit/rf403_weightedevts.py b/tutorials/roofit/rf403_weightedevts.py new file mode 100644 index 0000000000000..41050d3adbf94 --- /dev/null +++ b/tutorials/roofit/rf403_weightedevts.py @@ -0,0 +1,158 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## +## 'DATA AND CATEGORIES' RooFit tutorial macro #403 +## +## Using weights in unbinned datasets +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +from __future__ import print_function +import ROOT + + +# Create observable and unweighted dataset +# ------------------------------------------- + +# Declare observable +x = ROOT.RooRealVar("x", "x", -10, 10) +x.setBins(40) + +# Construction a uniform pdf +p0 = ROOT.RooPolynomial("px", "px", x) + +# Sample 1000 events from pdf +data = p0.generate(ROOT.RooArgSet(x), 1000) + +# Calculate weight and make dataset weighted +# -------------------------------------------------- + +# Construct formula to calculate (fake) weight for events +wFunc = ROOT.RooFormulaVar("w", "event weight", "(x*x+10)", ROOT.RooArgList(x)) + +# Add column with variable w to previously generated dataset +w = data.addColumn(wFunc) + +# Dataset d is now a dataset with two observable (x,w) with 1000 entries +data.Print() + +# Instruct dataset wdata in interpret w as event weight rather than as +# observable +wdata = ROOT.RooDataSet(data.GetName(), data.GetTitle(), data, data.get(), "", w.GetName()) + +# Dataset d is now a dataset with one observable (x) with 1000 entries and +# a sum of weights of ~430K +wdata.Print() + +# Unbinned ML fit to weighted data +# --------------------------------------------------------------- + +# Construction quadratic polynomial pdf for fitting +a0 = ROOT.RooRealVar("a0", "a0", 1) +a1 = ROOT.RooRealVar("a1", "a1", 0, -1, 1) +a2 = ROOT.RooRealVar("a2", "a2", 1, 0, 10) +p2 = ROOT.RooPolynomial("p2", "p2", x, ROOT.RooArgList(a0, a1, a2), 0) + +# Fit quadratic polynomial to weighted data + +# NOTE: A plain Maximum likelihood fit to weighted data does in general +# NOT result in correct error estimates, individual +# event weights represent Poisson statistics themselves. +# +# Fit with 'wrong' errors +r_ml_wgt = p2.fitTo(wdata, ROOT.RooFit.Save()) + +# A first order correction to estimated parameter errors in an +# (unbinned) ML fit can be obtained by calculating the +# covariance matrix as +# +# V' = V C-1 V +# +# where V is the covariance matrix calculated from a fit +# to -logL = - sum [ w_i log f(x_i) ] and C is the covariance +# matrix calculated from -logL' = -sum [ w_i^2 log f(x_i) ] +# (i.e. the weights are applied squared) +# +# A fit in self mode can be performed as follows: + +r_ml_wgt_corr = p2.fitTo(wdata, ROOT.RooFit.Save(), ROOT.RooFit.SumW2Error(ROOT.kTRUE)) + +# Plot weighted data and fit result +# --------------------------------------------------------------- + +# Construct plot frame +frame = x.frame(ROOT.RooFit.Title("Unbinned ML fit, chi^2 fit to weighted data")) + +# Plot data using sum-of-weights-squared error rather than Poisson errors +wdata.plotOn(frame, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) + +# Overlay result of 2nd order polynomial fit to weighted data +p2.plotOn(frame) + +# ML fit of pdf to equivalent unweighted dataset +# --------------------------------------------------------------------- + +# Construct a pdf with the same shape as p0 after weighting +genPdf = ROOT.RooGenericPdf("genPdf", "x*x+10", ROOT.RooArgList(x)) + +# Sample a dataset with the same number of events as data +data2 = genPdf.generate(ROOT.RooArgSet(x), 1000) + +# Sample a dataset with the same number of weights as data +data3 = genPdf.generate(ROOT.RooArgSet(x), 43000) + +# Fit the 2nd order polynomial to both unweighted datasets and save the +# results for comparison +r_ml_unw10 = p2.fitTo(data2, ROOT.RooFit.Save()) +r_ml_unw43 = p2.fitTo(data3, ROOT.RooFit.Save()) + +# Chis2 fit of pdf to binned weighted dataset +# --------------------------------------------------------------------------- + +# Construct binned clone of unbinned weighted dataset +binnedData = wdata.binnedClone() +binnedData.Print("v") + +# Perform chi2 fit to binned weighted dataset using sum-of-weights errors +# +# NB: Within the usual approximations of a chi2 fit, chi2 fit to weighted +# data using sum-of-weights-squared errors does give correct error +# estimates +chi2 = ROOT.RooChi2Var("chi2", "chi2", p2, binnedData, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2)) +m = ROOT.RooMinuit(chi2) +m.migrad() +m.hesse() + +# Plot chi^2 fit result on frame as well +r_chi2_wgt = m.save() +p2.plotOn(frame, ROOT.RooFit.LineStyle(ROOT.kDashed), ROOT.RooFit.LineColor(ROOT.kRed)) + +# Compare fit results of chi2, L fits to (un)weighted data +# ------------------------------------------------------------ + +# Note that ML fit on 1Kevt of weighted data is closer to result of ML fit on 43Kevt of unweighted data +# than to 1Kevt of unweighted data, the reference chi^2 fit with SumW2 error gives a result closer to +# that of an unbinned ML fit to 1Kevt of unweighted data. + +print("==> ML Fit results on 1K unweighted events") +r_ml_unw10.Print() +print("==> ML Fit results on 43K unweighted events") +r_ml_unw43.Print() +print("==> ML Fit results on 1K weighted events with a summed weight of 43K") +r_ml_wgt.Print() +print("==> Corrected ML Fit results on 1K weighted events with a summed weight of 43K") +r_ml_wgt_corr.Print() +print("==> Chi2 Fit results on 1K weighted events with a summed weight of 43K") +r_chi2_wgt.Print() + +c = ROOT.TCanvas("rf403_weightedevts", "rf403_weightedevts", 600, 600) +ROOT.gPad.SetLeftMargin(0.15) +frame.GetYaxis().SetTitleOffset(1.8) +frame.Draw() + +c.SaveAs("rf403_weightedevts.png") diff --git a/tutorials/roofit/rf503_wspaceread.py b/tutorials/roofit/rf503_wspaceread.py new file mode 100644 index 0000000000000..4a3d25fe790e7 --- /dev/null +++ b/tutorials/roofit/rf503_wspaceread.py @@ -0,0 +1,63 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## +## 'ORGANIZATION AND SIMULTANEOUS FITS' RooFit tutorial macro #503 +## +## Reading and using a workspace +## +## The input file for self macro is generated by rf502_wspaceread.py +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +import ROOT + + +# Read workspace from file +# ----------------------------------------------- + +# Open input file with workspace (generated by rf14_wspacewrite) +f = ROOT.TFile("rf502_workspace.root") + +# Retrieve workspace from file +w = f.Get("w") + +# Retrieve pdf, data from workspace +# ----------------------------------------------------------------- + +# Retrieve x, and data from workspace +x = w.var("x") +model = w.pdf("model") +data = w.data("modelData") + +# Print structure of composite p.d.f. +model.Print("t") + +# Fit model to data, plot model +# --------------------------------------------------------- + +# Fit model to data +model.fitTo(data) + +# Plot data and PDF overlaid +xframe = x.frame(ROOT.RooFit.Title("Model and data read from workspace")) +data.plotOn(xframe) +model.plotOn(xframe) + +# Overlay the background component of model with a dashed line +model.plotOn(xframe, ROOT.RooFit.Components("bkg"), ROOT.RooFit.LineStyle(ROOT.kDashed)) + +# Overlay the background+sig2 components of model with a dotted line +model.plotOn(xframe, ROOT.RooFit.Components("bkg,sig2"), ROOT.RooFit.LineStyle(ROOT.kDotted)) + +# Draw the frame on the canvas +c = ROOT.TCanvas("rf503_wspaceread", "rf503_wspaceread", 600, 600) +ROOT.gPad.SetLeftMargin(0.15) +xframe.GetYaxis().SetTitleOffset(1.4) +xframe.Draw() + +c.SaveAs("rf503_wspaceread.png") diff --git a/tutorials/roofit/rf508_listsetmanip.py b/tutorials/roofit/rf508_listsetmanip.py new file mode 100644 index 0000000000000..eafca1c5e8669 --- /dev/null +++ b/tutorials/roofit/rf508_listsetmanip.py @@ -0,0 +1,151 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## +## 'ORGANIZATION AND SIMULTANEOUS FITS' RooFit tutorial macro #508 +## +## RooArgSet and RooArgList tools and tricks +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +from __future__ import print_function +import ROOT + + +# Create dummy objects +# --------------------------------------- + +# Create some variables +a = ROOT.RooRealVar("a", "a", 1, -10, 10) +b = ROOT.RooRealVar("b", "b", 2, -10, 10) +c = ROOT.RooRealVar("c", "c", 3, -10, 10) +d = ROOT.RooRealVar("d", "d", 4, -10, 10) +x = ROOT.RooRealVar("x", "x", 0, -10, 10) +c.setError(0.5) +a.setConstant() +b.setConstant() + +# Create a category +e = ROOT.RooCategory("e", "e") +e.defineType("sig") +e.defineType("bkg") + +# Create a pdf +g = ROOT.RooGaussian("g", "g", x, a, b) + +# Creating, killing RooArgSets +# ------------------------------------------------------- + +# A ROOT.RooArgSet is a set of RooAbsArg objects. Each object in the set must have +# a unique name + +# Set constructors exists with up to 9 initial arguments +s = ROOT.RooArgSet(a, b) + +# At any time objects can be added with add() +s.add(e) + +# Add up to 9 additional arguments in one call +# s.add(ROOT.RooArgSet(c, d)) +s.add(c) +s.add(d) + +# Sets can contain any type of RooAbsArg, pdf and functions +s.add(g) + +# Remove element d +s.remove(d) + +# Accessing RooArgSet contents +# ------------------------------------------------------- + +# You can look up objects by name +aptr = s.find("a") + +# Construct a subset by name +subset1 = s.selectByName("a,b,c") + +# Construct asubset by attribute +subset2 = s.selectByAttrib("Constant", ROOT.kTRUE) + +# Construct the subset of overlapping contents with another set +s1 = ROOT.RooArgSet(a, b, c) +s2 = ROOT.RooArgSet(c, d, e) +subset3 = s1.selectCommon(s2) + +# Owning RooArgSets +# --------------------------------- + +# Create a RooArgSet that owns its components +# A set either owns all of its components or none, +# so once addOwned() is used, add() can no longer be +# used and will result in an error message + +ac = a.clone("a") +bc = b.clone("b") +cc = c.clone("c") + +s3 = ROOT.RooArgSet() +# s3.addOwned(ROOT.RooArgSet(ac, bc, cc)) +s3.addOwned(ac) +s3.addOwned(bc) +s3.addOwned(cc) + +# Another possibility is to add an owned clone +# of an object instead of the original +# s3.addClone(ROOT.RooArgSet(d, e, g)) +s3.addClone(d) +s3.addClone(e) +s3.addClone(g) + +# A clone of a owning set is non-owning and its +# contents is owned by the originating owning set +sclone = s3.Clone("sclone") + +# To make a clone of a set and its contents use +# the snapshot method +sclone2 = s3.snapshot() + +# If a set contains function objects, the head node +# is cloned in a snapshot. To make a snapshot of all +# servers of a function object do as follows. The result +# of a RooArgSet snapshot with deepCloning option is a set +# of cloned objects, all their clone (recursive) server +# dependencies, together form a self-consistent +# set that is free of external dependencies + +sclone3 = s3.snapshot(ROOT.kTRUE) + +# Set printing +# ------------------------ + +# Inline printing only show list of names of contained objects +print("sclone = ", sclone) + +# Plain print shows the same, by name of the set +sclone.Print() + +# Standard printing shows one line for each item with the items name, name +# and value +sclone.Print("s") + +# Verbose printing adds each items arguments, and 'extras' as defined by +# the object +sclone.Print("v") + +# Using RooArgLists +# --------------------------------- + +# List constructors exists with up to 9 initial arguments +l = ROOT.RooArgList(a, b, c, d) + +# Lists have an explicit order and allow multiple arguments with the same +# name +l.add(ROOT.RooArgList(a, b, c, d)) + +# Access by index is provided +arg4 = l.at(4) diff --git a/tutorials/roofit/rf602_chi2fit.py b/tutorials/roofit/rf602_chi2fit.py new file mode 100644 index 0000000000000..f924eca1a32f2 --- /dev/null +++ b/tutorials/roofit/rf602_chi2fit.py @@ -0,0 +1,70 @@ +## \file +## \ingroup tutorial_roofit +## \notebook +## +## 'LIKELIHOOD AND MINIMIZATION' RooFit tutorial macro #602 +## +## Setting up a chi^2 fit to a binned dataset +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange +## \author Wouter Verkerke (C version) + +from __future__ import print_function +import ROOT + + +# Set up model +# --------------------- + +# Declare observable x +x = ROOT.RooRealVar("x", "x", 0, 10) + +# Create two Gaussian PDFs g1(x,mean1,sigma) anf g2(x,mean2,sigma) and +# their parameters +mean = ROOT.RooRealVar("mean", "mean of gaussians", 5) +sigma1 = ROOT.RooRealVar("sigma1", "width of gaussians", 0.5) +sigma2 = ROOT.RooRealVar("sigma2", "width of gaussians", 1) + +sig1 = ROOT.RooGaussian("sig1", "Signal component 1", x, mean, sigma1) +sig2 = ROOT.RooGaussian("sig2", "Signal component 2", x, mean, sigma2) + +# Build Chebychev polynomial p.d.f. +a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) + +# Sum the signal components into a composite signal p.d.f. +sig1frac = ROOT.RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0.0, 1.0) +sig = ROOT.RooAddPdf("sig", "Signal", ROOT.RooArgList(sig1, sig2), ROOT.RooArgList(sig1frac)) + +# Sum the composite signal and background +bkgfrac = ROOT.RooRealVar("bkgfrac", "fraction of background", 0.5, 0.0, 1.0) +model = ROOT.RooAddPdf("model", "g1+g2+a", ROOT.RooArgList(bkg, sig), ROOT.RooArgList(bkgfrac)) + +# Create biuned dataset +# ----------------------------------------- + +d = model.generate(ROOT.RooArgSet(x), 10000) +dh = d.binnedClone() + +# Construct a chi^2 of the data and the model. +# When a p.d.f. is used in a chi^2 fit, probability density scaled +# by the number of events in the dataset to obtain the fit function +# If model is an extended p.d.f, expected number events is used +# instead of the observed number of events. +ll = ROOT.RooLinkedList() +model.chi2FitTo(dh, ll) + +# NB: It is also possible to fit a ROOT.RooAbsReal function to a ROOT.RooDataHist +# using chi2FitTo(). + +# Note that entries with zero bins are _not_ allowed +# for a proper chi^2 calculation and will give error +# messages +dsmall = d.reduce(ROOT.RooFit.EventRange(1, 100)) +dhsmall = dsmall.binnedClone() +chi2_lowstat = ROOT.RooChi2Var("chi2_lowstat", "chi2", model, dhsmall) +print(chi2_lowstat.getVal()) diff --git a/tutorials/roofit/rf802_mcstudy_addons.py b/tutorials/roofit/rf802_mcstudy_addons.py new file mode 100644 index 0000000000000..198ed65d6aa07 --- /dev/null +++ b/tutorials/roofit/rf802_mcstudy_addons.py @@ -0,0 +1,93 @@ +## \ingroup tutorial_roofit +## \notebook +## +## 'VALIDATION AND MC STUDIES' RooFit tutorial macro #802 +## +## RooMCStudy: using separate fit and generator models, the chi^2 calculator model +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange + + +import ROOT + + +# Create model +# ----------------------- + +# Observables, parameters +x = ROOT.RooRealVar("x", "x", -10, 10) +x.setBins(10) +mean = ROOT.RooRealVar("mean", "mean of gaussian", 0) +sigma = ROOT.RooRealVar("sigma", "width of gaussian", 5, 1, 10) + +# Create Gaussian pdf +gauss = ROOT.RooGaussian("gauss", "gaussian PDF", x, mean, sigma) + +# Create manager with chi^2 add-on module +# ---------------------------------------------------------------------------- + +# Create study manager for binned likelihood fits of a Gaussian pdf in 10 +# bins +mcs = ROOT.RooMCStudy(gauss, ROOT.RooArgSet(x), ROOT.RooFit.Silence(), ROOT.RooFit.Binned()) + +# Add chi^2 calculator module to mcs +chi2mod = ROOT.RooChi2MCSModule() +mcs.addModule(chi2mod) + +# Generate 1000 samples of 1000 events +mcs.generateAndFit(2000, 1000) + +# Fill histograms with distributions chi2 and prob(chi2,ndf) that +# are calculated by ROOT.RooChiMCSModule +hist_chi2 = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "chi2") +hist_prob = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "prob") + +# Create manager with separate fit model +# ---------------------------------------------------------------------------- + +# Create alternate pdf with shifted mean +mean2 = ROOT.RooRealVar("mean2", "mean of gaussian 2", 0.5) +gauss2 = ROOT.RooGaussian("gauss2", "gaussian PDF2", x, mean2, sigma) + +# Create study manager with separate generation and fit model. ROOT.This configuration +# is set up to generate bad fits as the fit and generator model have different means +# and the mean parameter is not floating in the fit +mcs2 = ROOT.RooMCStudy( + gauss2, ROOT.RooArgSet(x), ROOT.RooFit.FitModel(gauss), ROOT.RooFit.Silence(), ROOT.RooFit.Binned() +) + +# Add chi^2 calculator module to mcs +chi2mod2 = ROOT.RooChi2MCSModule() +mcs2.addModule(chi2mod2) + +# Generate 1000 samples of 1000 events +mcs2.generateAndFit(2000, 1000) + +# Fill histograms with distributions chi2 and prob(chi2,ndf) that +# are calculated by ROOT.RooChiMCSModule +hist2_chi2 = ROOT.RooAbsData.createHistogram(mcs2.fitParDataSet(), "chi2") +hist2_prob = ROOT.RooAbsData.createHistogram(mcs2.fitParDataSet(), "prob") +hist2_chi2.SetLineColor(ROOT.kRed) +hist2_prob.SetLineColor(ROOT.kRed) + +c = ROOT.TCanvas("rf802_mcstudy_addons", "rf802_mcstudy_addons", 800, 400) +c.Divide(2) +c.cd(1) +ROOT.gPad.SetLeftMargin(0.15) +hist_chi2.GetYaxis().SetTitleOffset(1.4) +hist_chi2.Draw() +hist2_chi2.Draw("esame") +c.cd(2) +ROOT.gPad.SetLeftMargin(0.15) +hist_prob.GetYaxis().SetTitleOffset(1.4) +hist_prob.Draw() +hist2_prob.Draw("esame") + +c.SaveAs("rf802_mcstudy_addons.png") + +# Make RooMCStudy object available on command line after +# macro finishes +ROOT.gDirectory.Add(mcs) diff --git a/tutorials/roofit/rf803_mcstudy_addons2.py b/tutorials/roofit/rf803_mcstudy_addons2.py new file mode 100644 index 0000000000000..abbfeaa56880d --- /dev/null +++ b/tutorials/roofit/rf803_mcstudy_addons2.py @@ -0,0 +1,118 @@ +## \ingroup tutorial_roofit +## \notebook +## +## 'VALIDATION AND MC STUDIES' RooFit tutorial macro #803 +## +## RooMCStudy: Using the randomizer and profile likelihood add-on models +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange + + +import ROOT + + +# Create model +# ----------------------- + +# Simulation of signal and background of top quark decaying into +# 3 jets with background + +# Observable +mjjj = ROOT.RooRealVar("mjjj", "m(3jet) (GeV)", 100, 85.0, 350.0) + +# Signal component (Gaussian) +mtop = ROOT.RooRealVar("mtop", "m(top)", 162) +wtop = ROOT.RooRealVar("wtop", "m(top) resolution", 15.2) +sig = ROOT.RooGaussian("sig", "top signal", mjjj, mtop, wtop) + +# Background component (Chebychev) +c0 = ROOT.RooRealVar("c0", "Chebychev coefficient 0", -0.846, -1.0, 1.0) +c1 = ROOT.RooRealVar("c1", "Chebychev coefficient 1", 0.112, -1.0, 1.0) +c2 = ROOT.RooRealVar("c2", "Chebychev coefficient 2", 0.076, -1.0, 1.0) +bkg = ROOT.RooChebychev("bkg", "combinatorial background", mjjj, ROOT.RooArgList(c0, c1, c2)) + +# Composite model +nsig = ROOT.RooRealVar("nsig", "number of signal events", 53, 0, 1e3) +nbkg = ROOT.RooRealVar("nbkg", "number of background events", 103, 0, 5e3) +model = ROOT.RooAddPdf("model", "model", ROOT.RooArgList(sig, bkg), ROOT.RooArgList(nsig, nbkg)) + +# Create manager +# --------------------------- + +# Configure manager to perform binned extended likelihood fits (Binned(), ROOT.RooFit.Extended()) on data generated +# with a Poisson fluctuation on Nobs (Extended()) +mcs = ROOT.RooMCStudy( + model, + ROOT.RooArgSet(mjjj), + ROOT.RooFit.Binned(), + ROOT.RooFit.Silence(), + ROOT.RooFit.Extended(ROOT.kTRUE), + ROOT.RooFit.FitOptions(ROOT.RooFit.Extended(ROOT.kTRUE), ROOT.RooFit.PrintEvalErrors(-1)), +) + +# Customize manager +# --------------------------------- + +# Add module that randomizes the summed value of nsig+nbkg +# sampling from a uniform distribution between 0 and 1000 +# +# In general one can randomize a single parameter, a +# sum of N parameters, either a uniform or a Gaussian +# distribution. Multiple randomization can be executed +# by a single randomizer module + +randModule = ROOT.RooRandomizeParamMCSModule() +randModule.sampleSumUniform(ROOT.RooArgSet(nsig, nbkg), 50, 500) +mcs.addModule(randModule) + +# Add profile likelihood calculation of significance. Redo each +# fit while keeping parameter nsig fixed to zero. For each toy, +# the difference in -log(L) of both fits is stored, well +# a simple significance interpretation of the delta(-logL) +# Dnll = 0.5 sigma^2 + +sigModule = ROOT.RooDLLSignificanceMCSModule(nsig, 0) +mcs.addModule(sigModule) + +# Run manager, make plots +# --------------------------------------------- + +# Run 1000 experiments. ROOT.This configuration will generate a fair number +# of (harmless) MINUIT warnings due to the instability of the Chebychev polynomial fit +# at low statistics. +mcs.generateAndFit(500) + +# Make some plots +dll_vs_ngen = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "ngen,dll_nullhypo_nsig", -40, -40) +z_vs_ngen = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "ngen,significance_nullhypo_nsig", -40, -40) +errnsig_vs_ngen = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "ngen,nsigerr", -40, -40) +errnsig_vs_nsig = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "nsig,nsigerr", -40, -40) + +# Draw plots on canvas +c = ROOT.TCanvas("rf803_mcstudy_addons2", "rf802_mcstudy_addons2", 800, 800) +c.Divide(2, 2) +c.cd(1) +ROOT.gPad.SetLeftMargin(0.15) +dll_vs_ngen.GetYaxis().SetTitleOffset(1.6) +dll_vs_ngen.Draw("box") +c.cd(2) +ROOT.gPad.SetLeftMargin(0.15) +z_vs_ngen.GetYaxis().SetTitleOffset(1.6) +z_vs_ngen.Draw("box") +c.cd(3) +ROOT.gPad.SetLeftMargin(0.15) +errnsig_vs_ngen.GetYaxis().SetTitleOffset(1.6) +errnsig_vs_ngen.Draw("box") +c.cd(4) +ROOT.gPad.SetLeftMargin(0.15) +errnsig_vs_nsig.GetYaxis().SetTitleOffset(1.6) +errnsig_vs_nsig.Draw("box") + +c.SaveAs("rf803_mcstudy_addons2.png") + +# Make ROOT.RooMCStudy object available on command line after +# macro finishes +ROOT.gDirectory.Add(mcs) diff --git a/tutorials/roofit/rf804_mcstudy_constr.py b/tutorials/roofit/rf804_mcstudy_constr.py new file mode 100644 index 0000000000000..26982987952ac --- /dev/null +++ b/tutorials/roofit/rf804_mcstudy_constr.py @@ -0,0 +1,85 @@ +## \ingroup tutorial_roofit +## \notebook +## +## 'VALIDATION AND MC STUDIES' RooFit tutorial macro #804 +## +## Using RooMCStudy on models with constraints +## +## \macro_code +## +## \date February 2018 +## \author Clemens Lange + + +import ROOT + + +# Create model with parameter constraint +# --------------------------------------------------------------------------- + +# Observable +x = ROOT.RooRealVar("x", "x", -10, 10) + +# Signal component +m = ROOT.RooRealVar("m", "m", 0, -10, 10) +s = ROOT.RooRealVar("s", "s", 2, 0.1, 10) +g = ROOT.RooGaussian("g", "g", x, m, s) + +# Background component +p = ROOT.RooPolynomial("p", "p", x) + +# Composite model +f = ROOT.RooRealVar("f", "f", 0.4, 0.0, 1.0) +sum = ROOT.RooAddPdf("sum", "sum", ROOT.RooArgList(g, p), ROOT.RooArgList(f)) + +# Construct constraint on parameter f +fconstraint = ROOT.RooGaussian("fconstraint", "fconstraint", f, ROOT.RooFit.RooConst(0.7), ROOT.RooFit.RooConst(0.1)) + +# Multiply constraint with p.d.f +sumc = ROOT.RooProdPdf("sumc", "sum with constraint", ROOT.RooArgList(sum, fconstraint)) + +# Setup toy study with model +# --------------------------------------------------- + +# Perform toy study with internal constraint on f +mcs = ROOT.RooMCStudy( + sumc, + ROOT.RooArgSet(x), + ROOT.RooFit.Constrain(ROOT.RooArgSet(f)), + ROOT.RooFit.Silence(), + ROOT.RooFit.Binned(), + ROOT.RooFit.FitOptions(ROOT.RooFit.PrintLevel(-1)), +) + +# Run 500 toys of 2000 events. +# Before each toy is generated, value for the f is sampled from the constraint pdf and +# that value is used for the generation of that toy. +mcs.generateAndFit(500, 2000) + +# Make plot of distribution of generated value of f parameter +h_f_gen = ROOT.RooAbsData.createHistogram(mcs.fitParDataSet(), "f_gen", -40) + +# Make plot of distribution of fitted value of f parameter +frame1 = mcs.plotParam(f, ROOT.RooFit.Bins(40)) +frame1.SetTitle("Distribution of fitted f values") + +# Make plot of pull distribution on f +frame2 = mcs.plotPull(f, ROOT.RooFit.Bins(40), ROOT.RooFit.FitGauss()) +frame1.SetTitle("Distribution of f pull values") + +c = ROOT.TCanvas("rf804_mcstudy_constr", "rf804_mcstudy_constr", 1200, 400) +c.Divide(3) +c.cd(1) +ROOT.gPad.SetLeftMargin(0.15) +h_f_gen.GetYaxis().SetTitleOffset(1.4) +h_f_gen.Draw() +c.cd(2) +ROOT.gPad.SetLeftMargin(0.15) +frame1.GetYaxis().SetTitleOffset(1.4) +frame1.Draw() +c.cd(3) +ROOT.gPad.SetLeftMargin(0.15) +frame2.GetYaxis().SetTitleOffset(1.4) +frame2.Draw() + +c.SaveAs("rf804_mcstudy_constr.png") From 9bdc8539b01b0c711fafaf2f8c6471ed4c0990b8 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 17 Jun 2021 14:11:09 +0200 Subject: [PATCH 257/309] [RF] Add pythonization for RooAbsCollection::AddClone RooAbsCollection::AddClone returns a pointer to the clone that it owns. By default, Python will assume ownership and delete the clone that is owned by the RooAbsCollection. With this commit, Python releases the ownership. This fixes a crash in the rf508_listsetmanip.py tutorial. --- .../python/ROOT/pythonization/_roofit/_rooabscollection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py index 5dc73902c98af..5364d1d1b0893 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py +++ b/bindings/pyroot/pythonizations/python/ROOT/pythonization/_roofit/_rooabscollection.py @@ -44,6 +44,11 @@ class RooAbsCollection(object): + + def addClone(self, arg, silent=False): + clonedArg = self._addClone(arg, silent) + SetOwnership(clonedArg, False) + def addOwned(self, arg, silent=False): self._addOwned(arg, silent) SetOwnership(arg, False) From f7456d4a2e700a646a4aa26e381001f26c4b9d4a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 17 Jun 2021 14:16:00 +0200 Subject: [PATCH 258/309] [RF] Don't use RooRealVar operator= because it doesn't work in pyROOT --- tutorials/roofit/rf109_chi2residpull.C | 2 +- tutorials/roofit/rf109_chi2residpull.py | 2 +- tutorials/roofit/rf303_conditional.C | 4 ++-- tutorials/roofit/rf303_conditional.py | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tutorials/roofit/rf109_chi2residpull.C b/tutorials/roofit/rf109_chi2residpull.C index 599e742b5758f..44f6ba9d21d9c 100644 --- a/tutorials/roofit/rf109_chi2residpull.C +++ b/tutorials/roofit/rf109_chi2residpull.C @@ -39,7 +39,7 @@ void rf109_chi2residpull() RooDataSet *data = gauss.generate(x, 10000); // Change sigma to 3.15 - sigma = 3.15; + sigma.setVal(3.15); // P l o t d a t a a n d s l i g h t l y d i s t o r t e d m o d e l // --------------------------------------------------------------------------- diff --git a/tutorials/roofit/rf109_chi2residpull.py b/tutorials/roofit/rf109_chi2residpull.py index 90a955301289c..ad742e64e0f4f 100644 --- a/tutorials/roofit/rf109_chi2residpull.py +++ b/tutorials/roofit/rf109_chi2residpull.py @@ -29,7 +29,7 @@ data = gauss.generate(ROOT.RooArgSet(x), 10000) # Change sigma to 3.15 -sigma = 3.15 +sigma.setVal(3.15) # Plot data and slightly distorted model # --------------------------------------------------------------------------- diff --git a/tutorials/roofit/rf303_conditional.C b/tutorials/roofit/rf303_conditional.C index 495fb989ac007..d303d7c91c606 100644 --- a/tutorials/roofit/rf303_conditional.C +++ b/tutorials/roofit/rf303_conditional.C @@ -100,8 +100,8 @@ RooDataSet *makeFakeDataXY() Double_t tmpy = gRandom->Gaus(0, 10); Double_t tmpx = gRandom->Gaus(0.5 * tmpy, 1); if (fabs(tmpy) < 10 && fabs(tmpx) < 10) { - x = tmpx; - y = tmpy; + x.setVal(tmpx); + y.setVal(tmpy); d->add(coord); } } diff --git a/tutorials/roofit/rf303_conditional.py b/tutorials/roofit/rf303_conditional.py index 0f662ab1d3672..5d3ec31517042 100644 --- a/tutorials/roofit/rf303_conditional.py +++ b/tutorials/roofit/rf303_conditional.py @@ -20,14 +20,14 @@ def makeFakeDataXY(): y = ROOT.RooRealVar("y", "y", -10, 10) coord = ROOT.RooArgSet(x, y) - d = ROOT.RooDataSet("d", "d", ROOT.RooArgSet(x, y)) + d = ROOT.RooDataSet("d", "d", coord) for i in range(10000): tmpy = ROOT.gRandom.Gaus(0, 10) tmpx = ROOT.gRandom.Gaus(0.5 * tmpy, 1) if (abs(tmpy) < 10) and (abs(tmpx) < 10): - x = tmpx - y = tmpy + x.setVal(tmpx) + y.setVal(tmpy) d.add(coord) return d From 9d6be920011c4c79958f5d10fb58e42810b74ce1 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 17 Jun 2021 14:18:48 +0200 Subject: [PATCH 259/309] [RF] Syncronize new RooFit Python tutorials with C versions The RooFit Python tutorials translated by Clemens Lange some time ago are syncronized with the current C++ versions of the tutorials. Plot output and numerical output is identical now. Also, some crashes related to the Python ownership model and deletion order were fixed. --- tutorials/roofit/rf102_dataimport.py | 46 ++++++++++++++++++++++-- tutorials/roofit/rf207_comptools.py | 9 +++-- tutorials/roofit/rf602_chi2fit.py | 2 +- tutorials/roofit/rf802_mcstudy_addons.py | 16 +++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/tutorials/roofit/rf102_dataimport.py b/tutorials/roofit/rf102_dataimport.py index dbf4d1581abb5..87661e77b1212 100644 --- a/tutorials/roofit/rf102_dataimport.py +++ b/tutorials/roofit/rf102_dataimport.py @@ -105,6 +105,38 @@ def makeTTree(): ds = ROOT.RooDataSet("ds", "ds", ROOT.RooArgSet(x, y), ROOT.RooFit.Import(tree)) +# Use ascii import/export for datasets +# ------------------------------------------------------------------------------------ + + +def write_dataset(ds, filename): + # Write data to output stream + outstream = ROOT.std.ofstream(filename) + # Optionally, adjust the stream here (e.g. std::setprecision) + ds.write(outstream) + outstream.close() + + +write_dataset(ds, "rf102_testData.txt") + +# Read data from input stream. The variables of the dataset need to be supplied +# to the RooDataSet::read() function. +print("\n-----------------------\nReading data from ASCII") +dataReadBack = ROOT.RooDataSet.read( + "rf102_testData.txt", + ROOT.RooArgList(x, y), # variables to be read. If the file has more fields, these are ignored. + "D", # Prints if a RooFit message stream listens for debug messages. Use Q for quiet. +) + +dataReadBack.Print("V") + +print("\nOriginal data, line 20:") +ds.get(20).Print("V") + +print("\nRead-back data, line 20:") +dataReadBack.get(20).Print("V") + + # Plot data set with multiple binning choices # ------------------------------------------------------------------------------------ # Print number of events in dataset @@ -118,9 +150,13 @@ def makeTTree(): frame4 = y.frame(ROOT.RooFit.Title("Unbinned data shown with custom binning")) ds.plotOn(frame4, ROOT.RooFit.Binning(20)) +frame5 = y.frame(ROOT.RooFit.Title("Unbinned data read back from ASCII file")) +ds.plotOn(frame5, ROOT.RooFit.Binning(20)) +dataReadBack.plotOn(frame5, ROOT.RooFit.Binning(20), ROOT.RooFit.MarkerColor(ROOT.kRed), ROOT.RooFit.MarkerStyle(5)) + # Draw all frames on a canvas c = ROOT.TCanvas("rf102_dataimport", "rf102_dataimport", 800, 800) -c.Divide(2, 2) +c.Divide(3, 2) c.cd(1) ROOT.gPad.SetLeftMargin(0.15) frame.GetYaxis().SetTitleOffset(1.4) @@ -129,13 +165,17 @@ def makeTTree(): ROOT.gPad.SetLeftMargin(0.15) frame2.GetYaxis().SetTitleOffset(1.4) frame2.Draw() -c.cd(3) +c.cd(4) ROOT.gPad.SetLeftMargin(0.15) frame3.GetYaxis().SetTitleOffset(1.4) frame3.Draw() -c.cd(4) +c.cd(5) ROOT.gPad.SetLeftMargin(0.15) frame4.GetYaxis().SetTitleOffset(1.4) frame4.Draw() +c.cd(6) +ROOT.gPad.SetLeftMargin(0.15) +frame4.GetYaxis().SetTitleOffset(1.4) +frame5.Draw() c.SaveAs("rf102_dataimport.png") diff --git a/tutorials/roofit/rf207_comptools.py b/tutorials/roofit/rf207_comptools.py index e6aa72778fcbb..e81c1d868cffa 100644 --- a/tutorials/roofit/rf207_comptools.py +++ b/tutorials/roofit/rf207_comptools.py @@ -26,7 +26,7 @@ # Build Chebychev polynomial p.d.f. a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", 0.2, 0.0, 1.0) bkg1 = ROOT.RooChebychev("bkg1", "Background 1", x, ROOT.RooArgList(a0, a1)) # Build expontential pdf @@ -95,7 +95,6 @@ cust = ROOT.RooCustomizer(model, "cust") # Instruct the customizer to replace node 'sig' with node 'sigsum' -sigsum = ROOT.RooRealVar() # just define some kind of RooFit type cust.replaceArg(sig, sigsum) # Build a clone of the input pdf according to the above customization @@ -110,3 +109,9 @@ # Print structure of clone of model with sig.sigsum replacement. cust_clone.Print("t") + +# The RooCustomizer has the be deleted first. +# Otherwise, it might happen that `sig` or `sigsum` are deleted first, in which +# case the internal TLists in the RooCustomizer will complain about deleted +# objects. +del cust diff --git a/tutorials/roofit/rf602_chi2fit.py b/tutorials/roofit/rf602_chi2fit.py index f924eca1a32f2..5f68caa20a810 100644 --- a/tutorials/roofit/rf602_chi2fit.py +++ b/tutorials/roofit/rf602_chi2fit.py @@ -33,7 +33,7 @@ # Build Chebychev polynomial p.d.f. a0 = ROOT.RooRealVar("a0", "a0", 0.5, 0.0, 1.0) -a1 = ROOT.RooRealVar("a1", "a1", -0.2, 0.0, 1.0) +a1 = ROOT.RooRealVar("a1", "a1", 0.2, 0.0, 1.0) bkg = ROOT.RooChebychev("bkg", "Background", x, ROOT.RooArgList(a0, a1)) # Sum the signal components into a composite signal p.d.f. diff --git a/tutorials/roofit/rf802_mcstudy_addons.py b/tutorials/roofit/rf802_mcstudy_addons.py index 198ed65d6aa07..43f3d681fd509 100644 --- a/tutorials/roofit/rf802_mcstudy_addons.py +++ b/tutorials/roofit/rf802_mcstudy_addons.py @@ -20,7 +20,7 @@ # Observables, parameters x = ROOT.RooRealVar("x", "x", -10, 10) x.setBins(10) -mean = ROOT.RooRealVar("mean", "mean of gaussian", 0) +mean = ROOT.RooRealVar("mean", "mean of gaussian", 0, -2., 1.8) sigma = ROOT.RooRealVar("sigma", "width of gaussian", 5, 1, 10) # Create Gaussian pdf @@ -49,7 +49,7 @@ # ---------------------------------------------------------------------------- # Create alternate pdf with shifted mean -mean2 = ROOT.RooRealVar("mean2", "mean of gaussian 2", 0.5) +mean2 = ROOT.RooRealVar("mean2", "mean of gaussian 2", 2.0) gauss2 = ROOT.RooGaussian("gauss2", "gaussian PDF2", x, mean2, sigma) # Create study manager with separate generation and fit model. ROOT.This configuration @@ -66,6 +66,14 @@ # Generate 1000 samples of 1000 events mcs2.generateAndFit(2000, 1000) +# Request a the pull plot of mean. The pulls will be one-sided because +# `mean` is limited to 1.8. +# Note that RooFit will have trouble to compute the pulls because the parameters +# are called `mean` in the fit, but `mean2` in the generator model. It is not obvious +# that these are related. RooFit will nevertheless compute pulls, but complain that +# this is risky. +pullMeanFrame = mcs2.plotPull(mean) + # Fill histograms with distributions chi2 and prob(chi2,ndf) that # are calculated by ROOT.RooChiMCSModule hist2_chi2 = ROOT.RooAbsData.createHistogram(mcs2.fitParDataSet(), "chi2") @@ -74,7 +82,7 @@ hist2_prob.SetLineColor(ROOT.kRed) c = ROOT.TCanvas("rf802_mcstudy_addons", "rf802_mcstudy_addons", 800, 400) -c.Divide(2) +c.Divide(3) c.cd(1) ROOT.gPad.SetLeftMargin(0.15) hist_chi2.GetYaxis().SetTitleOffset(1.4) @@ -85,6 +93,8 @@ hist_prob.GetYaxis().SetTitleOffset(1.4) hist_prob.Draw() hist2_prob.Draw("esame") +c.cd(3) +pullMeanFrame.Draw() c.SaveAs("rf802_mcstudy_addons.png") From b18850809e7dad7f68174f1bee6c83b7f4dc4b3d Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 18 Jun 2021 14:03:24 +0200 Subject: [PATCH 260/309] [skip-ci] move the group tutorials definition in tutorials/index.md (#8479) --- tutorials/README | 46 -------- tutorials/cocoa/index.md | 9 +- tutorials/cont/index.md | 3 - tutorials/dataframe/index.md | 8 +- tutorials/demos.C | 47 ++++---- tutorials/eve/index.md | 3 - tutorials/fft/index.md | 3 - tutorials/fit/index.md | 3 - tutorials/fitsio/index.md | 3 - tutorials/foam/index.md | 28 ++--- tutorials/geom/index.md | 3 - tutorials/gl/index.md | 3 - tutorials/graphics/index.md | 3 - tutorials/graphs/index.md | 3 - tutorials/gui/index.md | 3 - tutorials/hist/index.md | 3 - tutorials/histfactory/index.md | 3 - tutorials/http/index.md | 3 - tutorials/image/index.md | 3 - tutorials/index.md | 201 +++++++++++++++++++++++++++++++++ tutorials/io/index.md | 4 - tutorials/legacy/index.md | 11 +- tutorials/math/index.md | 3 - tutorials/matrix/index.md | 3 - tutorials/mc/index.md | 3 - tutorials/multicore/index.md | 3 - tutorials/net/index.md | 3 - tutorials/physics/index.md | 3 - tutorials/proof/index.md | 5 - tutorials/pyroot/index.md | 3 - tutorials/pythia/index.md | 3 - tutorials/quadp/index.md | 3 - tutorials/r/index.md | 3 - tutorials/roofit/index.md | 3 - tutorials/roostats/index.md | 3 - tutorials/spectrum/index.md | 3 - tutorials/splot/index.md | 3 - tutorials/sql/index.md | 3 - tutorials/tmva/index.md | 3 - tutorials/tree/index.md | 3 - tutorials/unfold/index.md | 8 +- tutorials/unuran/index.md | 3 - tutorials/v7/index.md | 9 +- tutorials/vecops/index.md | 3 - tutorials/xml/index.md | 3 - 45 files changed, 269 insertions(+), 209 deletions(-) delete mode 100644 tutorials/README delete mode 100644 tutorials/cont/index.md delete mode 100644 tutorials/eve/index.md delete mode 100644 tutorials/fft/index.md delete mode 100644 tutorials/fit/index.md delete mode 100644 tutorials/fitsio/index.md delete mode 100644 tutorials/geom/index.md delete mode 100644 tutorials/gl/index.md delete mode 100644 tutorials/graphics/index.md delete mode 100644 tutorials/graphs/index.md delete mode 100644 tutorials/gui/index.md delete mode 100644 tutorials/hist/index.md delete mode 100644 tutorials/histfactory/index.md delete mode 100644 tutorials/http/index.md delete mode 100644 tutorials/image/index.md delete mode 100644 tutorials/io/index.md delete mode 100644 tutorials/math/index.md delete mode 100644 tutorials/matrix/index.md delete mode 100644 tutorials/mc/index.md delete mode 100644 tutorials/multicore/index.md delete mode 100644 tutorials/net/index.md delete mode 100644 tutorials/physics/index.md delete mode 100644 tutorials/pyroot/index.md delete mode 100644 tutorials/pythia/index.md delete mode 100644 tutorials/quadp/index.md delete mode 100644 tutorials/r/index.md delete mode 100644 tutorials/roofit/index.md delete mode 100644 tutorials/roostats/index.md delete mode 100644 tutorials/spectrum/index.md delete mode 100644 tutorials/splot/index.md delete mode 100644 tutorials/sql/index.md delete mode 100644 tutorials/tmva/index.md delete mode 100644 tutorials/tree/index.md delete mode 100644 tutorials/unuran/index.md delete mode 100644 tutorials/vecops/index.md delete mode 100644 tutorials/xml/index.md diff --git a/tutorials/README b/tutorials/README deleted file mode 100644 index fdd95b33e1135..0000000000000 --- a/tutorials/README +++ /dev/null @@ -1,46 +0,0 @@ -You can execute the scripts in $ROOTSYS/tutorials (or sub-directories) -by setting your current directory in the script directory or from any -user directory with write access. -Several tutorials create new files. If you have write access to -the tutorials directory, the new files will be created in the tutorials -directory, otherwise they will be created in the user directory. - -You can start by executing the standard ROOT demos with a session like - root > .x demos.C -or - root > .x $ROOTSYS/tutorials/demos.C - -You can execute the standard ROOT graphics benchmark with - root > .x benchmarks.C -or - root > .x $ROOTSYS/tutorials/benchmarks.C - -The $ROOTSYS/tutorials directory include several sub-directories - --fft: Fast Fourier Transform with the fftw package --fit: Several examples illustrating minimization/fitting --foam: Random generator in multi-dimensional space --geom: Examples of use of the geometry package (TGeo classes) --gl: Visualisation with OpenGL --graphics: Basic graphics --graphs: Use of TGraph, TGraphErrors, etc --gui: Scripts to create Graphics User Interface --hist: Histograming --image: Image Processing --io: Input/Output --math: Maths and Statistics functions --matrix: Matrices (TMatrix) examples --mlp: Neural networks with TMultiLayerPerceptron --net: Network classes (client/server examples) --physics: LorentzVectors, phase space --pyroot: python tutorials --pythia: Example with pythia6 --quadp: Quadratic Programming --smatrix: Matrices with a templated package --spectrum: Peak finder, background, deconvolutions --splot: Example of the TSplot class (signal/background estimator) --sql: Interfaces to SQL (mysql, oracle, etc) --thread: Using Threads --tree: Creating Trees, Playing with Trees --unuran: Interface with the unuram random generator library --xml: Writing/Reading xml files diff --git a/tutorials/cocoa/index.md b/tutorials/cocoa/index.md index aecbcff99b4bf..b27eb420a63a5 100644 --- a/tutorials/cocoa/index.md +++ b/tutorials/cocoa/index.md @@ -1,4 +1,7 @@ -\defgroup tutorial_cocoa Tutorials specific to Mac/Cocoa -\ingroup Tutorials -\brief Various examples showing graphics done with the Mac graphics system Cocoa. +\addtogroup tutorial_cocoa + +@{ + These examples run only on Mac/Os + +@} \ No newline at end of file diff --git a/tutorials/cont/index.md b/tutorials/cont/index.md deleted file mode 100644 index f287dbf0345ec..0000000000000 --- a/tutorials/cont/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_cont Containers tutorials -\ingroup Tutorials -\brief Examples showing the "containers' classes" usage. diff --git a/tutorials/dataframe/index.md b/tutorials/dataframe/index.md index 268ae15d65e00..8dcac58db6676 100644 --- a/tutorials/dataframe/index.md +++ b/tutorials/dataframe/index.md @@ -1,6 +1,6 @@ -\defgroup tutorial_dataframe Data Frame tutorials -\ingroup Tutorials -\brief These examples show various features of [RDataFrame](classROOT_1_1RDataFrame.html): ROOT's declarative analysis interface. +\addtogroup tutorial_dataframe + +@{ [RDataFrame](classROOT_1_1RDataFrame.html) offers a high level interface for the analysis of data stored in [TTree](classTTree.html)s, [CSV files](classROOT_1_1RDF_1_1RCsvDS.html) and [other data formats](classROOT_1_1RDF_1_1RDataSource.html). @@ -19,3 +19,5 @@ histoB->Draw(); // HistoB has already been filled, no event loop is run here ~~~ Explore the examples below or go to [RDataFrame's user guide](classROOT_1_1RDataFrame.html). + +@} \ No newline at end of file diff --git a/tutorials/demos.C b/tutorials/demos.C index d9ceaf2c4532e..829d9563020de 100644 --- a/tutorials/demos.C +++ b/tutorials/demos.C @@ -18,29 +18,30 @@ void demos() { gROOT->SetMacroPath(Form("%s:%s",current,dirName.Data())); TControlBar *bar = new TControlBar("vertical", "Demos",10,10); - bar->AddButton("Help Demos",".x demoshelp.C", "Click Here For Help on Running the Demos"); - bar->AddButton("browser", "new TBrowser;", "Start the ROOT Browser"); - bar->AddButton("framework", ".x graphics/framework.C","An Example of Object Oriented User Interface"); - bar->AddButton("first", ".x graphics/first.C", "An Example of Slide with Root"); - bar->AddButton("hsimple", ".x hsimple.C", "An Example Creating Histograms/Ntuples on File"); - bar->AddButton("hsum", ".x hist/hsum.C", "Filling Histograms and Some Graphics Options"); - bar->AddButton("formula1", ".x graphics/formula1.C","Simple Formula and Functions"); - bar->AddButton("surfaces", ".x graphs/surfaces.C", "Surface Drawing Options"); - bar->AddButton("fillrandom",".x hist/fillrandom.C", "Histograms with Random Numbers from a Function"); - bar->AddButton("fit1", ".x fit/fit1.C", "A Simple Fitting Example"); - bar->AddButton("multifit", ".x fit/multifit.C", "Fitting in Subranges of Histograms"); - bar->AddButton("h1draw", ".x hist/h1draw.C", "Drawing Options for 1D Histograms"); - bar->AddButton("graph", ".x graphs/graph.C", "Example of a Simple Graph"); - bar->AddButton("gerrors", ".x graphs/gerrors.C", "Example of a Graph with Error Bars"); - bar->AddButton("tornado", ".x graphics/tornado.C", "Examples of 3-D PolyMarkers"); - bar->AddButton("shapes", ".x geom/shapes.C", "The Geometry Shapes"); - bar->AddButton("geometry", ".x geom/geometry.C", "Creation of the NA49 Geometry File"); - bar->AddButton("na49view", ".x geom/na49view.C", "Two Views of the NA49 Detector Geometry"); - bar->AddButton("file", ".x io/file.C", "The ROOT File Format"); - bar->AddButton("fildir", ".x io/fildir.C", "The ROOT File, Directories and Keys"); - bar->AddButton("tree", ".x tree/tree.C", "The Tree Data Structure"); - bar->AddButton("ntuple1", ".x tree/ntuple1.C", "Ntuples and Selections"); - bar->AddButton("rootmarks", ".x rootmarks.C", "Prints an Estimated ROOTMARKS for Your Machine"); + bar->AddButton("Help Demos", ".x demoshelp.C", "Click Here For Help on Running the Demos"); + bar->AddButton("browser", "new TBrowser;", "Start the ROOT Browser"); + bar->AddButton("framework", ".x graphics/framework.C", "An Example of Object Oriented User Interface"); + bar->AddButton("first", ".x graphics/first.C", "An Example of Slide with Root"); + bar->AddButton("hsimple", ".x hsimple.C", "An Example Creating Histograms/Ntuples on File"); + bar->AddButton("hsum", ".x hist/hsum.C", "Filling Histograms and Some Graphics Options"); + bar->AddButton("formula1", ".x graphics/formula1.C", "Simple Formula and Functions"); + bar->AddButton("surfaces", ".x graphs/surfaces.C", "Surface Drawing Options"); + bar->AddButton("fillrandom", ".x hist/fillrandom.C", "Histograms with Random Numbers from a Function"); + bar->AddButton("fit1", ".x fit/fit1.C", "A Simple Fitting Example"); + bar->AddButton("multifit", ".x fit/multifit.C", "Fitting in Subranges of Histograms"); + bar->AddButton("h1draw", ".x hist/h1draw.C", "Drawing Options for 1D Histograms"); + bar->AddButton("graph", ".x graphs/graph.C", "Example of a Simple Graph"); + bar->AddButton("gerrors", ".x graphs/gerrors.C", "Example of a Graph with Error Bars"); + bar->AddButton("tornado", ".x graphics/tornado.C", "Examples of 3-D PolyMarkers"); + bar->AddButton("shapes", ".x geom/shapes.C", "The Geometry Shapes"); + bar->AddButton("geometry", ".x geom/geometry.C", "Creation of the NA49 Geometry File"); + bar->AddButton("na49view", ".x geom/na49view.C", "Two Views of the NA49 Detector Geometry"); + bar->AddButton("file", ".x io/file.C", "The ROOT File Format"); + bar->AddButton("fildir", ".x io/fildir.C", "The ROOT File, Directories and Keys"); + bar->AddButton("tree", ".x tree/tree.C", "The Tree Data Structure"); + bar->AddButton("ntuple1", ".x tree/ntuple1.C", "Ntuples and Selections"); + bar->AddButton("benchmarks", ".x legacy/benchmarks.C", "Runs several tests and produces an benchmark report"); + bar->AddButton("rootmarks", ".x legacy/rootmarks.C", "Prints an Estimated ROOTMARKS for Your Machine"); bar->SetButtonWidth(90); bar->Show(); gROOT->SaveContext(); diff --git a/tutorials/eve/index.md b/tutorials/eve/index.md deleted file mode 100644 index 9040ed5ce7106..0000000000000 --- a/tutorials/eve/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_eve Event display tutorials -\ingroup Tutorials -\brief Examples showing the "Event display classes" usage. diff --git a/tutorials/fft/index.md b/tutorials/fft/index.md deleted file mode 100644 index 785a5d4f2a016..0000000000000 --- a/tutorials/fft/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_fft Fast Fourier Transforms tutorials -\ingroup Tutorials -\brief Example showing the Fast Fourier Transforms interface in ROOT. \ No newline at end of file diff --git a/tutorials/fit/index.md b/tutorials/fit/index.md deleted file mode 100644 index cbe27422e0671..0000000000000 --- a/tutorials/fit/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_fit Fit Tutorials -\ingroup Tutorials -\brief These tutorials illustrate the main fitting features. Their names are related to the aspect which is treated in the code. diff --git a/tutorials/fitsio/index.md b/tutorials/fitsio/index.md deleted file mode 100644 index 2ee7d4bb75005..0000000000000 --- a/tutorials/fitsio/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_FITS FITS files interface tutorials -\ingroup Tutorials -\brief Examples showing the FITS file interface. diff --git a/tutorials/foam/index.md b/tutorials/foam/index.md index 030fdb5bfafdc..a35232c733a1a 100644 --- a/tutorials/foam/index.md +++ b/tutorials/foam/index.md @@ -1,6 +1,6 @@ -\defgroup tutorial_FOAM FOAM tutorials -\ingroup Tutorials -\brief Examples showing how to use FOAM. +\addtogroup tutorial_FOAM + +@{ ### What is FOAM ? @@ -15,9 +15,9 @@ the ROOT shell. For more difficult problems the full FOAM may be better. ### How to run application programs ? The application program can be run in two modes: it can be simply -intepreted by CINT or compiled. The first method is simpler but +interpreted by CLING or compiled. The first method is simpler but results in slower execution. The second method employs ACLiC - -The Automatic Compiler of Libraries, which automaticates the +The Automatic Compiler of Libraries, which automatizes the process of compilation and linking. In $(ROOTSYS)/tutorials there are 3 demonstration programs: @@ -27,13 +27,13 @@ is a simple example how to run FOAM in interactive mode. To run this macro issue the following simple command from the Linux shell: -```cpp +``` root foam_kanwa.C ``` -or from CINT: +or from CLING: -```cpp +``` root [0] .x foam_kanwa.C ``` @@ -50,9 +50,9 @@ abstract class TFoamIntegrand. User can modify interface to integrand function according to their needs but they should always remember to define Density method which provides the density distribution. -Enter CINT interpreter and type: +Enter CLING interpreter and type: -```cpp +``` root [0] gSystem->Load("libFoam.so") root [1] .x foam_demo.C+ ``` @@ -66,12 +66,14 @@ including distribution function will be written to disk. demonstrates persistency of FOAM classes. To run this macro type: -```cpp +``` root [0] .x foam_demopers.C ``` Program reads the FOAM object from disk, checks its consistency and prints geometry of cells. Next starts the -the generation. It can be interpreted directly by CINT +the generation. It can be interpreted directly by CLING because compiled TFDISTR class is already available in -foam_demo_C.so library. +`foam_demo_C.so` library. + +@} \ No newline at end of file diff --git a/tutorials/geom/index.md b/tutorials/geom/index.md deleted file mode 100644 index 9f8294fcd2465..0000000000000 --- a/tutorials/geom/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_geom Geometry tutorials -\ingroup Tutorials -\brief Various ROOT geometry package examples. diff --git a/tutorials/gl/index.md b/tutorials/gl/index.md deleted file mode 100644 index 046e715103040..0000000000000 --- a/tutorials/gl/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_gl OpenGL tutorials -\ingroup Tutorials -\brief Various examples showing the OpenGL graphics in ROOT. diff --git a/tutorials/graphics/index.md b/tutorials/graphics/index.md deleted file mode 100644 index bc7e9ca3682e7..0000000000000 --- a/tutorials/graphics/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_graphics Graphics tutorials -\ingroup Tutorials -\brief Various examples showing the basic ROOT graphics. diff --git a/tutorials/graphs/index.md b/tutorials/graphs/index.md deleted file mode 100644 index 9c90e5cddc26d..0000000000000 --- a/tutorials/graphs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_graphs Graphs tutorials -\ingroup Tutorials -\brief Examples showing the "graphs classes" usage. diff --git a/tutorials/gui/index.md b/tutorials/gui/index.md deleted file mode 100644 index 3b51a05b8eea1..0000000000000 --- a/tutorials/gui/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_gui GUI tutorials -\ingroup Tutorials -\brief Example code which illustrates how to use the ROOT GUI. diff --git a/tutorials/hist/index.md b/tutorials/hist/index.md deleted file mode 100644 index c4b8ed9873d59..0000000000000 --- a/tutorials/hist/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_hist Histograms tutorials -\ingroup Tutorials -\brief Examples showing the "histograms' classes" usage. diff --git a/tutorials/histfactory/index.md b/tutorials/histfactory/index.md deleted file mode 100644 index 17ea9c90d7d63..0000000000000 --- a/tutorials/histfactory/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_histfactory HistFactory Tutorials -\ingroup Tutorials -\brief These tutorials illustrate the usage of the histfactory. diff --git a/tutorials/http/index.md b/tutorials/http/index.md deleted file mode 100644 index a8d00bfa4cf7b..0000000000000 --- a/tutorials/http/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_http HTTP tutorials -\ingroup Tutorials -\brief Examples showing the HTTP interface. \ No newline at end of file diff --git a/tutorials/image/index.md b/tutorials/image/index.md deleted file mode 100644 index ab5023220e8ae..0000000000000 --- a/tutorials/image/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_image Image tutorials -\ingroup Tutorials -\brief Examples showing the TImage class usage. diff --git a/tutorials/index.md b/tutorials/index.md index 314b3d20cdf0d..163e525356c45 100644 --- a/tutorials/index.md +++ b/tutorials/index.md @@ -1,2 +1,203 @@ \defgroup Tutorials Tutorials \brief A collection of C++ macros, Python scripts and notebooks helping to learn ROOT by example. + +You can execute the scripts in `$ROOTSYS/tutorials` (or sub-directories) +by setting your current directory in the script directory or from any +user directory with write access. + +Several tutorials create new files. If you have write access to +the tutorials directory, the new files will be created in the tutorials +directory, otherwise they will be created in the user directory. + +You can start by executing the standard ROOT demos with a session like: + +``` + root > .x demos.C +``` +or + +``` + root > .x $ROOTSYS/tutorials/demos.C +``` + +You can execute the standard ROOT graphics benchmark with + +``` + root > .x benchmarks.C +``` + +or + +``` + root > .x $ROOTSYS/tutorials/benchmarks.C +``` + +The `$ROOTSYS/tutorials` directory includes several sub-directories: + +\defgroup tutorial_hist Histograms tutorials +\ingroup Tutorials +\brief Examples showing the "histograms' classes" usage. + +\defgroup tutorial_tree Tree tutorials +\ingroup Tutorials +\brief Example code which illustrates how to use ROOT trees and ntuples. + +\defgroup tutorial_dataframe Data Frame tutorials +\ingroup Tutorials +\brief These examples show various features of [RDataFrame](classROOT_1_1RDataFrame.html): ROOT's declarative analysis interface. + +\defgroup tutorial_v7 ROOT 7 tutorials +\ingroup Tutorials +\brief Various examples showing the ROOT 7 interface. + +\defgroup tutorial_FOAM FOAM tutorials +\ingroup Tutorials +\brief Examples showing how to use FOAM. + +\defgroup tutorial_cont Containers tutorials +\ingroup Tutorials +\brief Examples showing the "containers' classes" usage. + +\defgroup tutorial_eve Event display tutorials +\ingroup Tutorials +\brief Examples showing the "Event display classes" usage. + +\defgroup tutorial_geom Geometry tutorials +\ingroup Tutorials +\brief Various ROOT geometry package examples. + +\defgroup tutorial_fft Fast Fourier Transforms tutorials +\ingroup Tutorials +\brief Example showing the Fast Fourier Transforms interface in ROOT. + +\defgroup tutorial_fit Fit Tutorials +\ingroup Tutorials +\brief These tutorials illustrate the main fitting features. Their names are related to the aspect which is treated in the code. + +\defgroup tutorial_roofit RooFit Tutorials +\ingroup Tutorials +\brief These tutorials illustrate the main features of RooFit: the name of the examples and their short description help in figuring out their objective. + +\defgroup tutorial_graphs Graphs tutorials +\ingroup Tutorials +\brief Examples showing the "graphs classes" usage. + +\defgroup tutorial_graphics Graphics tutorials +\ingroup Tutorials +\brief Various examples showing the basic ROOT graphics. + +\defgroup tutorial_gl OpenGL tutorials +\ingroup Tutorials +\brief Various examples showing the OpenGL graphics in ROOT. + +\defgroup tutorial_cocoa Tutorials specific to Mac/Cocoa +\ingroup Tutorials +\brief Various examples showing graphics done with the Mac graphics system Cocoa. + +\defgroup tutorial_gui GUI tutorials +\ingroup Tutorials +\brief Example code which illustrates how to use the ROOT GUI. + +\defgroup tutorial_histfactory HistFactory Tutorials +\ingroup Tutorials +\brief These tutorials illustrate the usage of the histfactory. + +\defgroup tutorial_http HTTP tutorials +\ingroup Tutorials +\brief Examples showing the HTTP interface. + +\defgroup tutorial_image Image tutorials +\ingroup Tutorials +\brief Examples showing the TImage class usage. + +\defgroup tutorial_io IO tutorials +\ingroup Tutorials +\brief These tutorials illustrate some of the capabilities of the ROOT IO subsystem. + +\defgroup tutorial_math Math tutorials +\ingroup Tutorials +\brief Examples showing the Math classes. + +\defgroup tutorial_matrix Matrix tutorials +\ingroup Tutorials +\brief Examples showing how to use TMatrix. + +\defgroup tutorial_mc Monte Carlo tutorials +\ingroup Tutorials +\brief Monte Carlo examples. + +\defgroup tutorial_multicore Multicore tutorials +\ingroup Tutorials +\brief These examples aim to illustrate the multicore features of ROOT, such as thread awareness and safety, multithreading and multiprocessing. + +\defgroup tutorial_net Net tutorials +\ingroup Tutorials +\brief Examples showing the net classes. + +\defgroup tutorial_physics Physics tutorials +\ingroup Tutorials +\brief Physics examples. + +\defgroup tutorial_pyroot PyRoot tutorials +\ingroup Tutorials +\brief Selected examples illustrating how to use ROOT's Python interface: PyROOT. + +\defgroup tutorial_pythia Pythia tutorials +\ingroup Tutorials +\brief Examples showing the pythia usage. + +\defgroup tutorial_quadp Quadratic programming package. +\ingroup Tutorials +\brief Example showing the usage of the quadratic programming package quadp. + +\defgroup tutorial_r R tutorials +\ingroup Tutorials +\brief Examples showing the R interface. + +\defgroup tutorial_roostats RooStats Tutorials +\ingroup Tutorials +\brief These tutorials illustrate the main features of RooStats. + +\defgroup tutorial_spectrum Spectrum tutorials +\ingroup Tutorials +\brief Examples showing the TSpectrum and TSpectrumPainter usage. + +\defgroup tutorial_splot TSPlot tutorials +\ingroup Tutorials +\brief This tutorial illustrates the use of class TSPlot. + +\defgroup tutorial_sql SQL tutorials +\ingroup Tutorials +\brief Examples showing the SQL classes. + +\defgroup tutorial_tmva TMVA tutorials +\ingroup Tutorials +\brief Example code which illustrates how to use the TMVA toolkit + +\defgroup tutorial_unfold TUnfold tutorials +\ingroup Tutorials +\brief Test programs for the classes TUnfold and related + +\defgroup tutorial_unuran Unuran tutorials +\ingroup Tutorials +\brief Examples showing unuran capabilities. + +\defgroup tutorial_vecops VecOps tutorials +\ingroup Tutorials +\brief These examples show the functionalities of the VecOps utilities. + +\defgroup tutorial_FITS FITS files interface tutorials +\ingroup Tutorials +\brief Examples showing the FITS file interface. + +\defgroup tutorial_xml XML tutorials +\ingroup Tutorials +\brief XML examples. + +\defgroup tutorial_proof Proof tutorials +\ingroup Tutorials +\brief These examples aim to illustrate the usage of PROOF + +\defgroup tutorial_legacy Legacy tutorials +\ingroup Tutorials +\brief Legacy Tutorials diff --git a/tutorials/io/index.md b/tutorials/io/index.md deleted file mode 100644 index 7fd0568f02d2c..0000000000000 --- a/tutorials/io/index.md +++ /dev/null @@ -1,4 +0,0 @@ -\defgroup tutorial_io IO tutorials -\ingroup Tutorials -\brief These tutorials illustrate some of the capabilities of the ROOT IO subsystem. - diff --git a/tutorials/legacy/index.md b/tutorials/legacy/index.md index 4b5c58bd46104..236a88a4ecc55 100644 --- a/tutorials/legacy/index.md +++ b/tutorials/legacy/index.md @@ -1,5 +1,8 @@ -\defgroup tutorial_legacy Legacy tutorials -\ingroup Tutorials -\brief Legacy Tutorials +\addtogroup tutorial_legacy -Some of ROOT's tutorials demonstrate interfaces that are not recommended anymore, because ROOT or C++ itself now offer superior ones. These have been moved here "for the record". +@{ + +Some of ROOT's tutorials demonstrate interfaces that are not recommended anymore, because +ROOT or C++ itself now offer superior ones. These have been moved here "for the record". + +@} diff --git a/tutorials/math/index.md b/tutorials/math/index.md deleted file mode 100644 index 21c0bf04f1476..0000000000000 --- a/tutorials/math/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_math Math tutorials -\ingroup Tutorials -\brief Examples showing the Math classes. diff --git a/tutorials/matrix/index.md b/tutorials/matrix/index.md deleted file mode 100644 index 3234ace251a16..0000000000000 --- a/tutorials/matrix/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_matrix Matrix tutorials -\ingroup Tutorials -\brief Examples showing how to use TMatrix. diff --git a/tutorials/mc/index.md b/tutorials/mc/index.md deleted file mode 100644 index 109e539caed83..0000000000000 --- a/tutorials/mc/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_mc Monte Carlo tutorials -\ingroup Tutorials -\brief Monte Carlo examples. diff --git a/tutorials/multicore/index.md b/tutorials/multicore/index.md deleted file mode 100644 index 9a689a1cd1e02..0000000000000 --- a/tutorials/multicore/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_multicore Multicore tutorials -\ingroup Tutorials -\brief These examples aim to illustrate the multicore features of ROOT, such as thread awareness and safety, multithreading and multiprocessing. diff --git a/tutorials/net/index.md b/tutorials/net/index.md deleted file mode 100644 index 98687524a12dd..0000000000000 --- a/tutorials/net/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_net Net tutorials -\ingroup Tutorials -\brief Examples showing the net classes. diff --git a/tutorials/physics/index.md b/tutorials/physics/index.md deleted file mode 100644 index 25b17ac36bac9..0000000000000 --- a/tutorials/physics/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_physics Physics tutorials -\ingroup Tutorials -\brief Physics examples. diff --git a/tutorials/proof/index.md b/tutorials/proof/index.md index fa26a4cb4eca3..2325cbab85000 100644 --- a/tutorials/proof/index.md +++ b/tutorials/proof/index.md @@ -1,8 +1,3 @@ -\defgroup tutorial_proof Proof tutorials -\ingroup Tutorials -\brief These examples aim to illustrate the usage of PROOF - - \defgroup tutorial_ProcFileElements ProcFileElements \ingroup tutorial_proof \brief Class to hold information about the processed elements of a file diff --git a/tutorials/pyroot/index.md b/tutorials/pyroot/index.md deleted file mode 100644 index af499cbdf4188..0000000000000 --- a/tutorials/pyroot/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_pyroot PyRoot tutorials -\ingroup Tutorials -\brief Selected examples illustrating how to use ROOT's Python interface: PyROOT. diff --git a/tutorials/pythia/index.md b/tutorials/pythia/index.md deleted file mode 100644 index 57debac9645ac..0000000000000 --- a/tutorials/pythia/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_pythia Pythia tutorials -\ingroup Tutorials -\brief Examples showing the pythia usage. diff --git a/tutorials/quadp/index.md b/tutorials/quadp/index.md deleted file mode 100644 index 0f27d416869de..0000000000000 --- a/tutorials/quadp/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_quadp Quadratic programming package. -\ingroup Tutorials -\brief Example showing the usage of the quadratic programming package quadp. diff --git a/tutorials/r/index.md b/tutorials/r/index.md deleted file mode 100644 index a6d91bf0ef515..0000000000000 --- a/tutorials/r/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_r R tutorials -\ingroup Tutorials -\brief Examples showing the R interface. \ No newline at end of file diff --git a/tutorials/roofit/index.md b/tutorials/roofit/index.md deleted file mode 100644 index 1e2ca6b9d6b6d..0000000000000 --- a/tutorials/roofit/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_roofit RooFit Tutorials -\ingroup Tutorials -\brief These tutorials illustrate the main features of RooFit: the name of the examples and their short description help in figuring out their objective. diff --git a/tutorials/roostats/index.md b/tutorials/roostats/index.md deleted file mode 100644 index e528416fe5ed3..0000000000000 --- a/tutorials/roostats/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_roostats RooStats Tutorials -\ingroup Tutorials -\brief These tutorials illustrate the main features of RooStats. diff --git a/tutorials/spectrum/index.md b/tutorials/spectrum/index.md deleted file mode 100644 index 22be0e8632bd1..0000000000000 --- a/tutorials/spectrum/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_spectrum Spectrum tutorials -\ingroup Tutorials -\brief Examples showing the TSpectrum and TSpectrumPainter usage. diff --git a/tutorials/splot/index.md b/tutorials/splot/index.md deleted file mode 100644 index 87cf8263036a0..0000000000000 --- a/tutorials/splot/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_splot TSPlot tutorials -\ingroup Tutorials -\brief This tutorial illustrates the use of class TSPlot. diff --git a/tutorials/sql/index.md b/tutorials/sql/index.md deleted file mode 100644 index d083f718bde12..0000000000000 --- a/tutorials/sql/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_sql SQL tutorials -\ingroup Tutorials -\brief Examples showing the SQL classes. diff --git a/tutorials/tmva/index.md b/tutorials/tmva/index.md deleted file mode 100644 index 237cd830616dd..0000000000000 --- a/tutorials/tmva/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_tmva TMVA tutorials -\ingroup Tutorials -\brief Example code which illustrates how to use the TMVA toolkit diff --git a/tutorials/tree/index.md b/tutorials/tree/index.md deleted file mode 100644 index 1cdc93c5ffb92..0000000000000 --- a/tutorials/tree/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_tree Tree tutorials -\ingroup Tutorials -\brief Example code which illustrates how to use ROOT trees and ntuples. diff --git a/tutorials/unfold/index.md b/tutorials/unfold/index.md index 98029a7a189fe..81d72c0318115 100644 --- a/tutorials/unfold/index.md +++ b/tutorials/unfold/index.md @@ -1,6 +1,6 @@ -\defgroup tutorial_unfold TUnfold tutorials -\ingroup Tutorials -\brief Test programs for the classes TUnfold and related +\addtogroup tutorial_unfold + +@{ TUnfold is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,3 +14,5 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TUnfold. If not, see . + +@} diff --git a/tutorials/unuran/index.md b/tutorials/unuran/index.md deleted file mode 100644 index 1e384d2777635..0000000000000 --- a/tutorials/unuran/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_unuran Unuran tutorials -\ingroup Tutorials -\brief Examples showing unuran capabilities. diff --git a/tutorials/v7/index.md b/tutorials/v7/index.md index 1638218322faa..87faf75667f80 100644 --- a/tutorials/v7/index.md +++ b/tutorials/v7/index.md @@ -1,4 +1,7 @@ -\defgroup tutorial_v7 ROOT 7 tutorials -\ingroup Tutorials -\brief Various examples showing the ROOT 7 interface. +\addtogroup tutorial_v7 + +@{ + \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! + +@} \ No newline at end of file diff --git a/tutorials/vecops/index.md b/tutorials/vecops/index.md deleted file mode 100644 index b3e9d976cdbf6..0000000000000 --- a/tutorials/vecops/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_vecops VecOps tutorials -\ingroup Tutorials -\brief These examples show the functionalities of the VecOps utilities. diff --git a/tutorials/xml/index.md b/tutorials/xml/index.md deleted file mode 100644 index a6693c4ce57db..0000000000000 --- a/tutorials/xml/index.md +++ /dev/null @@ -1,3 +0,0 @@ -\defgroup tutorial_xml XML tutorials -\ingroup Tutorials -\brief XML examples. From f0ca6a56847019814a1f250a8b547b0e6bc4dd30 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Fri, 18 Jun 2021 14:08:54 +0200 Subject: [PATCH 261/309] fix typo (#8480) --- math/mathcore/src/TStatistic.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/mathcore/src/TStatistic.cxx b/math/mathcore/src/TStatistic.cxx index 82588b794209c..81ed39d5ff509 100644 --- a/math/mathcore/src/TStatistic.cxx +++ b/math/mathcore/src/TStatistic.cxx @@ -64,7 +64,7 @@ TStatistic::~TStatistic() /// sum of squared weights and sum of (value*weight), one extra value is added to the /// statistic. For the sum of squared (value*weight) pairs, the function uses formula 1.4 /// in Chan-Golub, LeVeque : Algorithms for computing the Sample Variance (1983), -/// genralized by LM for the case of weights: +/// generalized by LM for the case of weights: /// \f[ /// \frac{w_j}{\sum_{i=0}^{j} w_i \cdot \sum_{i=0}^{j-1} w_i} \cdot /// \left( From 496601a81406b433853803655cbaefa353e38ba3 Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Sat, 12 Jun 2021 06:33:56 +0200 Subject: [PATCH 262/309] Add namespace to LinkDef This addresses test failures like: 998/1157 Test #997: tutorial-v7-draw_mt.cxx .............................................***Failed 8.47 sec Processing /builddir/build/BUILD/root-6.25.01/tutorials/v7/draw_mt.cxx... IncrementalExecutor::executeFunction: symbol '_ZN4ROOT12Experimental7HistLogEv' unresolved while linking [cling interface function]! You are probably missing the definition of ROOT::Experimental::HistLog() Maybe you need to load the corresponding shared library? CMake Error at /builddir/build/BUILD/root-6.25.01/x86_64-redhat-linux-gnu/RootTestDriver.cmake:237 (message): error code: 1 1007/1157 Test #1007: tutorial-v7-draw_subpads.cxx ........................................***Failed 6.81 sec Processing /builddir/build/BUILD/root-6.25.01/tutorials/v7/draw_subpads.cxx... IncrementalExecutor::executeFunction: symbol '_ZN4ROOT12Experimental7HistLogEv' unresolved while linking [cling interface function]! You are probably missing the definition of ROOT::Experimental::HistLog() Maybe you need to load the corresponding shared library? CMake Error at /builddir/build/BUILD/root-6.25.01/x86_64-redhat-linux-gnu/RootTestDriver.cmake:237 (message): error code: 1 1017/1157 Test #1005: tutorial-v7-draw_rh3.cxx ............................................***Failed 28.52 sec Processing /builddir/build/BUILD/root-6.25.01/tutorials/v7/draw_rh3.cxx... IncrementalExecutor::executeFunction: symbol '_ZN4ROOT12Experimental7HistLogEv' unresolved while linking [cling interface function]! You are probably missing the definition of ROOT::Experimental::HistLog() Maybe you need to load the corresponding shared library? CMake Error at /builddir/build/BUILD/root-6.25.01/x86_64-redhat-linux-gnu/RootTestDriver.cmake:237 (message): error code: 1 --- hist/histv7/inc/LinkDef.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hist/histv7/inc/LinkDef.h b/hist/histv7/inc/LinkDef.h index 3c64caf5fb33a..b30b9062048d8 100644 --- a/hist/histv7/inc/LinkDef.h +++ b/hist/histv7/inc/LinkDef.h @@ -54,4 +54,6 @@ #pragma link C++ class tuple+; #pragma link C++ class tuple+; #pragma link C++ class tuple+; + +#pragma link C++ namespace ROOT::Experimental; #endif From 645d3d0664085d4d29373192d462feee931f202e Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 16 Jun 2021 13:53:19 +0200 Subject: [PATCH 263/309] [RF] Fix missing initializer warnings in MemPoolForRooSets.h --- roofit/roofitcore/src/MemPoolForRooSets.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/roofit/roofitcore/src/MemPoolForRooSets.h b/roofit/roofitcore/src/MemPoolForRooSets.h index 8e47262b92f13..16f853c491d39 100644 --- a/roofit/roofitcore/src/MemPoolForRooSets.h +++ b/roofit/roofitcore/src/MemPoolForRooSets.h @@ -63,7 +63,8 @@ class MemPoolForRooSets { Arena() : ownedMemory{static_cast(TStorage::ObjectAlloc(2 * POOLSIZE * sizeof(RooSet_t)))}, memBegin{ownedMemory}, nextItem{ownedMemory}, - memEnd{memBegin + 2 * POOLSIZE} + memEnd{memBegin + 2 * POOLSIZE}, + cycle{} {} Arena(const Arena &) = delete; @@ -72,7 +73,8 @@ class MemPoolForRooSets { memBegin{other.memBegin}, nextItem{other.nextItem}, memEnd{other.memEnd}, refCount{other.refCount}, totCount{other.totCount}, - assigned{other.assigned} + assigned{other.assigned}, + cycle{} { // Needed for unique ownership other.ownedMemory = nullptr; From ccdf269f6991ece812e688d27afd8d48b14342c1 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:00:35 +0200 Subject: [PATCH 264/309] [ntuple] Change the type of `RPageSink::fOptions` to `std::unique_ptr` Using a `std::unique_ptr<>` avoids object slicing in case `fOptions` points to an instance of a derived class. a derived --- tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx | 4 ++++ tree/ntuple/v7/inc/ROOT/RPageStorage.hxx | 4 ++-- tree/ntuple/v7/src/RPageSinkBuf.cxx | 2 +- tree/ntuple/v7/src/RPageStorage.cxx | 4 ++-- tree/ntuple/v7/src/RPageStorageDaos.cxx | 8 ++++---- tree/ntuple/v7/src/RPageStorageFile.cxx | 8 ++++---- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx index 2f7c2794a4c84..5c87eeee33a53 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx @@ -52,6 +52,10 @@ class RNTupleWriteOptions { bool fUseBufferedWrite = true; public: + virtual ~RNTupleWriteOptions() = default; + virtual std::unique_ptr Clone() const + { return std::make_unique(*this); } + int GetCompression() const { return fCompression; } void SetCompression(int val) { fCompression = val; } void SetCompression(RCompressionSetting::EAlgorithm algorithm, int compressionLevel) { diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx index 8fe63cc9c5a78..a63c56503c54c 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorage.hxx @@ -164,7 +164,7 @@ protected: std::unique_ptr fCounters; RNTupleMetrics fMetrics; - RNTupleWriteOptions fOptions; + std::unique_ptr fOptions; /// Helper to zip pages and header/footer; includes a 16MB (kMAXZIPBUF) zip buffer. /// There could be concrete page sinks that don't need a compressor. Therefore, and in order to stay consistent @@ -226,7 +226,7 @@ public: const RNTupleWriteOptions &options = RNTupleWriteOptions()); EPageStorageType GetType() final { return EPageStorageType::kSink; } /// Returns the sink's write options. - const RNTupleWriteOptions &GetWriteOptions() const { return fOptions; } + const RNTupleWriteOptions &GetWriteOptions() const { return *fOptions; } ColumnHandle_t AddColumn(DescriptorId_t fieldId, const RColumn &column) final; void DropColumn(ColumnHandle_t /*columnHandle*/) final {} diff --git a/tree/ntuple/v7/src/RPageSinkBuf.cxx b/tree/ntuple/v7/src/RPageSinkBuf.cxx index fe30137aa4f27..541757b4fd525 100644 --- a/tree/ntuple/v7/src/RPageSinkBuf.cxx +++ b/tree/ntuple/v7/src/RPageSinkBuf.cxx @@ -63,7 +63,7 @@ ROOT::Experimental::Detail::RPageSinkBuf::CommitPageImpl(ColumnHandle_t columnHa fTaskScheduler->AddTask([this, zipItem, colId = columnHandle.fId] { zipItem->fSealedPage = SealPage(zipItem->fPage, *fBufferedColumns.at(colId).GetHandle().fColumn->GetElement(), - fOptions.GetCompression(), zipItem->fBuf.get() + GetWriteOptions().GetCompression(), zipItem->fBuf.get() ); }); diff --git a/tree/ntuple/v7/src/RPageStorage.cxx b/tree/ntuple/v7/src/RPageStorage.cxx index beb029d69999c..aaf5c315e688b 100644 --- a/tree/ntuple/v7/src/RPageStorage.cxx +++ b/tree/ntuple/v7/src/RPageStorage.cxx @@ -229,7 +229,7 @@ void ROOT::Experimental::Detail::RPageSource::EnableDefaultMetrics(const std::st ROOT::Experimental::Detail::RPageSink::RPageSink(std::string_view name, const RNTupleWriteOptions &options) - : RPageStorage(name), fMetrics(""), fOptions(options) + : RPageStorage(name), fMetrics(""), fOptions(options.Clone()) { } @@ -297,7 +297,7 @@ void ROOT::Experimental::Detail::RPageSink::Create(RNTupleModel &model) columnRange.fColumnId = i; columnRange.fFirstElementIndex = 0; columnRange.fNElements = 0; - columnRange.fCompressionSettings = fOptions.GetCompression(); + columnRange.fCompressionSettings = GetWriteOptions().GetCompression(); fOpenColumnRanges.emplace_back(columnRange); RClusterDescriptor::RPageRange pageRange; pageRange.fColumnId = i; diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index ec3e194d7bdbd..e66656ca94cda 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -133,7 +133,7 @@ void ROOT::Experimental::Detail::RPageSinkDaos::CreateImpl(const RNTupleModel & descriptor.SerializeHeader(buffer.get()); auto zipBuffer = std::make_unique(szHeader); - auto szZipHeader = fCompressor->Zip(buffer.get(), szHeader, fOptions.GetCompression(), + auto szZipHeader = fCompressor->Zip(buffer.get(), szHeader, GetWriteOptions().GetCompression(), [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } ); WriteNTupleHeader(zipBuffer.get(), szZipHeader, szHeader); } @@ -146,7 +146,7 @@ ROOT::Experimental::Detail::RPageSinkDaos::CommitPageImpl(ColumnHandle_t columnH RPageStorage::RSealedPage sealedPage; { RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip); - sealedPage = SealPage(page, *element, fOptions.GetCompression()); + sealedPage = SealPage(page, *element, GetWriteOptions().GetCompression()); } fCounters->fSzZip.Add(page.GetSize()); @@ -192,7 +192,7 @@ void ROOT::Experimental::Detail::RPageSinkDaos::CommitDatasetImpl() descriptor.SerializeFooter(buffer.get()); auto zipBuffer = std::make_unique(szFooter); - auto szZipFooter = fCompressor->Zip(buffer.get(), szFooter, fOptions.GetCompression(), + auto szZipFooter = fCompressor->Zip(buffer.get(), szFooter, GetWriteOptions().GetCompression(), [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } ); WriteNTupleFooter(zipBuffer.get(), szZipFooter, szFooter); WriteNTupleAnchor(); @@ -226,7 +226,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSinkDaos::ReservePage(ColumnHandle_t columnHandle, std::size_t nElements) { if (nElements == 0) - nElements = fOptions.GetNElementsPerPage(); + nElements = GetWriteOptions().GetNElementsPerPage(); auto elementSize = columnHandle.fColumn->GetElement()->GetSize(); return fPageAllocator->NewPage(columnHandle.fId, elementSize, nElements); } diff --git a/tree/ntuple/v7/src/RPageStorageFile.cxx b/tree/ntuple/v7/src/RPageStorageFile.cxx index ea15f0b2b6738..e2ec8cf5f00a1 100644 --- a/tree/ntuple/v7/src/RPageStorageFile.cxx +++ b/tree/ntuple/v7/src/RPageStorageFile.cxx @@ -93,7 +93,7 @@ void ROOT::Experimental::Detail::RPageSinkFile::CreateImpl(const RNTupleModel & descriptor.SerializeHeader(buffer.get()); auto zipBuffer = std::make_unique(szHeader); - auto szZipHeader = fCompressor->Zip(buffer.get(), szHeader, fOptions.GetCompression(), + auto szZipHeader = fCompressor->Zip(buffer.get(), szHeader, GetWriteOptions().GetCompression(), [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } ); fWriter->WriteNTupleHeader(zipBuffer.get(), szZipHeader, szHeader); } @@ -127,7 +127,7 @@ ROOT::Experimental::Detail::RPageSinkFile::CommitPageImpl(ColumnHandle_t columnH RPageStorage::RSealedPage sealedPage; { RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip); - sealedPage = SealPage(page, *element, fOptions.GetCompression()); + sealedPage = SealPage(page, *element, GetWriteOptions().GetCompression()); } fCounters->fSzZip.Add(page.GetSize()); @@ -167,7 +167,7 @@ void ROOT::Experimental::Detail::RPageSinkFile::CommitDatasetImpl() descriptor.SerializeFooter(buffer.get()); auto zipBuffer = std::make_unique(szFooter); - auto szZipFooter = fCompressor->Zip(buffer.get(), szFooter, fOptions.GetCompression(), + auto szZipFooter = fCompressor->Zip(buffer.get(), szFooter, GetWriteOptions().GetCompression(), [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } ); fWriter->WriteNTupleFooter(zipBuffer.get(), szZipFooter, szFooter); fWriter->Commit(); @@ -178,7 +178,7 @@ ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSinkFile::ReservePage(ColumnHandle_t columnHandle, std::size_t nElements) { if (nElements == 0) - nElements = fOptions.GetNElementsPerPage(); + nElements = GetWriteOptions().GetNElementsPerPage(); auto elementSize = columnHandle.fColumn->GetElement()->GetSize(); return fPageAllocator->NewPage(columnHandle.fId, elementSize, nElements); } From 936de997c9f429582a36b3563ff46426c3898faa Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:02:03 +0200 Subject: [PATCH 265/309] [ntuple] Move string serialization functions to RNTupleUtil Move the `{Serialize,Deserialize}String` functions to the `ROOT::Experimental::Internal::RNTupleSerialization` namespace where they may be reused by other parts of RNTuple. --- tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx | 3 +++ tree/ntuple/v7/src/RNTupleDescriptor.cxx | 22 ---------------------- tree/ntuple/v7/src/RNTupleUtil.cxx | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx index 393a5b239cc66..6f50dddc956b7 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleUtil.hxx @@ -50,6 +50,9 @@ std::uint32_t SerializeUInt16(std::uint16_t val, void *buffer); std::uint32_t DeserializeInt16(const void *buffer, std::int16_t *val); std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t *val); +std::uint32_t SerializeString(const std::string &val, void *buffer); +std::uint32_t DeserializeString(const void *buffer, std::string *val); + } // namespace RNTupleSerialization void PrintRNTuple(const RNTuple& ntuple, std::ostream& output); diff --git a/tree/ntuple/v7/src/RNTupleDescriptor.cxx b/tree/ntuple/v7/src/RNTupleDescriptor.cxx index df806ac225519..aba32abd67c9e 100644 --- a/tree/ntuple/v7/src/RNTupleDescriptor.cxx +++ b/tree/ntuple/v7/src/RNTupleDescriptor.cxx @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -65,27 +64,6 @@ std::uint32_t DeserializeClusterSize(const void *buffer, ROOT::Experimental::Clu return nbytes; } -std::uint32_t SerializeString(const std::string &val, void *buffer) -{ - if (buffer != nullptr) { - auto pos = reinterpret_cast(buffer); - pos += SerializeUInt32(val.length(), pos); - memcpy(pos, val.data(), val.length()); - } - return SerializeUInt32(val.length(), nullptr) + val.length(); -} - -std::uint32_t DeserializeString(const void *buffer, std::string *val) -{ - auto base = reinterpret_cast(buffer); - auto bytes = base; - std::uint32_t length; - bytes += DeserializeUInt32(buffer, &length); - val->resize(length); - memcpy(&(*val)[0], bytes, length); - return bytes + length - base; -} - std::uint32_t SerializeLocator(const ROOT::Experimental::RClusterDescriptor::RLocator &val, void *buffer) { // In order to keep the meta-data small, we don't wrap the locator in a frame diff --git a/tree/ntuple/v7/src/RNTupleUtil.cxx b/tree/ntuple/v7/src/RNTupleUtil.cxx index b4385145b3a52..c9259947590c7 100644 --- a/tree/ntuple/v7/src/RNTupleUtil.cxx +++ b/tree/ntuple/v7/src/RNTupleUtil.cxx @@ -18,6 +18,7 @@ #include "ROOT/RLogger.hxx" #include "ROOT/RMiniFile.hxx" +#include #include ROOT::Experimental::RLogChannel &ROOT::Experimental::NTupleLog() { @@ -126,6 +127,27 @@ std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t *val) return DeserializeInt16(buffer, reinterpret_cast(val)); } +std::uint32_t SerializeString(const std::string &val, void *buffer) +{ + if (buffer != nullptr) { + auto pos = reinterpret_cast(buffer); + pos += SerializeUInt32(val.length(), pos); + memcpy(pos, val.data(), val.length()); + } + return SerializeUInt32(val.length(), nullptr) + val.length(); +} + +std::uint32_t DeserializeString(const void *buffer, std::string *val) +{ + auto base = reinterpret_cast(buffer); + auto bytes = base; + std::uint32_t length; + bytes += DeserializeUInt32(buffer, &length); + val->resize(length); + memcpy(&(*val)[0], bytes, length); + return bytes + length - base; +} + } // namespace RNTupleSerialization void PrintRNTuple(const RNTuple& ntuple, std::ostream& output) { From 94a222882ede3b75b246c33f459a6addd105e7a7 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:02:03 +0200 Subject: [PATCH 266/309] [ntuple,daos] Use a fixed object class to generate ntuple-metadata OIDs Use `OC_SX` (distribute among all targets) for OIDs that relate to ntuple metadata, e.g. header/footer. --- tree/ntuple/v7/src/RPageStorageDaos.cxx | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index e66656ca94cda..aa9e254f7b74b 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -67,6 +67,8 @@ static constexpr std::uint64_t kAttributeKey = 0x4243544b5344422d; static constexpr daos_obj_id_t kOidAnchor{std::uint64_t(-1), 0}; static constexpr daos_obj_id_t kOidHeader{std::uint64_t(-2), 0}; static constexpr daos_obj_id_t kOidFooter{std::uint64_t(-3), 0}; + +static constexpr daos_oclass_id_t kCidMetadata = OC_SX; } // namespace @@ -202,7 +204,8 @@ void ROOT::Experimental::Detail::RPageSinkDaos::CommitDatasetImpl() void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleHeader( const void *data, size_t nbytes, size_t lenHeader) { - fDaosContainer->WriteSingleAkey(data, nbytes, kOidHeader, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(data, nbytes, kOidHeader, kDistributionKey, + kAttributeKey, kCidMetadata); fNTupleAnchor.fLenHeader = lenHeader; fNTupleAnchor.fNBytesHeader = nbytes; } @@ -210,7 +213,8 @@ void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleHeader( void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleFooter( const void *data, size_t nbytes, size_t lenFooter) { - fDaosContainer->WriteSingleAkey(data, nbytes, kOidFooter, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(data, nbytes, kOidFooter, kDistributionKey, + kAttributeKey, kCidMetadata); fNTupleAnchor.fLenFooter = lenFooter; fNTupleAnchor.fNBytesFooter = nbytes; } @@ -219,7 +223,8 @@ void ROOT::Experimental::Detail::RPageSinkDaos::WriteNTupleAnchor() { const auto ntplSize = RDaosNTupleAnchor::GetSize(); auto buffer = std::make_unique(ntplSize); fNTupleAnchor.Serialize(buffer.get()); - fDaosContainer->WriteSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, kAttributeKey); + fDaosContainer->WriteSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, + kAttributeKey, kCidMetadata); } ROOT::Experimental::Detail::RPage @@ -285,18 +290,21 @@ ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceDao RDaosNTupleAnchor ntpl; const auto ntplSize = RDaosNTupleAnchor::GetSize(); auto buffer = std::make_unique(ntplSize); - fDaosContainer->ReadSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(buffer.get(), ntplSize, kOidAnchor, kDistributionKey, + kAttributeKey, kCidMetadata); ntpl.Deserialize(buffer.get()); buffer = std::make_unique(ntpl.fLenHeader); auto zipBuffer = std::make_unique(ntpl.fNBytesHeader); - fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesHeader, kOidHeader, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesHeader, kOidHeader, kDistributionKey, + kAttributeKey, kCidMetadata); fDecompressor->Unzip(zipBuffer.get(), ntpl.fNBytesHeader, ntpl.fLenHeader, buffer.get()); descBuilder.SetFromHeader(buffer.get()); buffer = std::make_unique(ntpl.fLenFooter); zipBuffer = std::make_unique(ntpl.fNBytesFooter); - fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesFooter, kOidFooter, kDistributionKey, kAttributeKey); + fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesFooter, kOidFooter, kDistributionKey, + kAttributeKey, kCidMetadata); fDecompressor->Unzip(zipBuffer.get(), ntpl.fNBytesFooter, ntpl.fLenFooter, buffer.get()); descBuilder.AddClustersFromFooter(buffer.get()); From e32c215c176fef56852b125dae8c735acf0aeec7 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:04:38 +0200 Subject: [PATCH 267/309] [ntuple,daos] Enable customization of object class for user data OIDs Enable customizing the object class for user data OIDs via `RNTupleWriteOptionsDaos`. --- tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx | 21 +++++++++++++ tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx | 14 ++++++--- tree/ntuple/v7/src/RPageStorageDaos.cxx | 31 ++++++++++++++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx index 5c87eeee33a53..4e6deb8d9151b 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx @@ -75,6 +75,27 @@ public: void SetUseBufferedWrite(bool val) { fUseBufferedWrite = val; } }; +// clang-format off +/** +\class ROOT::Experimental::RNTupleWriteOptionsDaos +\ingroup NTuple +\brief DAOS-specific user-tunable settings for storing ntuples +*/ +// clang-format on +class RNTupleWriteOptionsDaos : public RNTupleWriteOptions { + std::string fObjectClass{"RP_XSF"}; + +public: + virtual ~RNTupleWriteOptionsDaos() = default; + std::unique_ptr Clone() const override + { return std::make_unique(*this); } + + const std::string &GetObjectClass() const { return fObjectClass; } + /// Set the object class used to generate OIDs that relate to user data. Any + /// `OC_xxx` constant defined in `daos_obj_class.h` may be used here without + /// the OC_ prefix. + void SetObjectClass(const std::string &val) { fObjectClass = val; } +}; // clang-format off /** diff --git a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx index f85087b787135..4ad5e2b1fc245 100644 --- a/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RPageStorageDaos.hxx @@ -45,7 +45,8 @@ class RDaosContainer; \ingroup NTuple \brief Entry point for an RNTuple in a DAOS container. It encodes essential information to read the ntuple; currently, it contains (un)compressed size of -the header/footer blobs. +the header/footer blobs and the object class for user data OIDs. +The length of a serialized anchor cannot be greater than the value returned by the `GetSize` function. */ // clang-format on struct RDaosNTupleAnchor { @@ -59,20 +60,22 @@ struct RDaosNTupleAnchor { std::uint32_t fNBytesFooter = 0; /// The size of the uncompressed ntuple footer std::uint32_t fLenFooter = 0; + /// The object class for user data OIDs, e.g. `SX` + std::string fObjClass{}; bool operator ==(const RDaosNTupleAnchor &other) const { return fVersion == other.fVersion && fNBytesHeader == other.fNBytesHeader && fLenHeader == other.fLenHeader && fNBytesFooter == other.fNBytesFooter && - fLenFooter == other.fLenFooter; + fLenFooter == other.fLenFooter && + fObjClass == other.fObjClass; } std::uint32_t Serialize(void *buffer) const; std::uint32_t Deserialize(const void *buffer); - static std::uint32_t GetSize() - { return RDaosNTupleAnchor().Serialize(nullptr); } + static std::uint32_t GetSize(); }; // clang-format off @@ -179,6 +182,9 @@ public: RSealedPage &sealedPage) final; std::unique_ptr LoadCluster(DescriptorId_t clusterId, const ColumnSet_t &columns) final; + + /// Return the object class used for user data OIDs in this ntuple. + std::string GetObjectClass() const; }; diff --git a/tree/ntuple/v7/src/RPageStorageDaos.cxx b/tree/ntuple/v7/src/RPageStorageDaos.cxx index aa9e254f7b74b..9b6b509e75363 100644 --- a/tree/ntuple/v7/src/RPageStorageDaos.cxx +++ b/tree/ntuple/v7/src/RPageStorageDaos.cxx @@ -86,8 +86,9 @@ ROOT::Experimental::Detail::RDaosNTupleAnchor::Serialize(void *buffer) const bytes += SerializeUInt32(fLenHeader, bytes); bytes += SerializeUInt32(fNBytesFooter, bytes); bytes += SerializeUInt32(fLenFooter, bytes); + bytes += SerializeString(fObjClass, bytes); } - return 20; + return SerializeString(fObjClass, nullptr) + 20; } std::uint32_t @@ -100,7 +101,15 @@ ROOT::Experimental::Detail::RDaosNTupleAnchor::Deserialize(const void *buffer) bytes += DeserializeUInt32(bytes, &fLenHeader); bytes += DeserializeUInt32(bytes, &fNBytesFooter); bytes += DeserializeUInt32(bytes, &fLenFooter); - return 20; + bytes += DeserializeString(bytes, &fObjClass); + return SerializeString(fObjClass, nullptr) + 20; +} + +std::uint32_t +ROOT::Experimental::Detail::RDaosNTupleAnchor::GetSize() +{ + return RDaosNTupleAnchor().Serialize(nullptr) + + ROOT::Experimental::Detail::RDaosObject::ObjClassId::kOCNameMaxLength; } @@ -125,9 +134,16 @@ ROOT::Experimental::Detail::RPageSinkDaos::~RPageSinkDaos() = default; void ROOT::Experimental::Detail::RPageSinkDaos::CreateImpl(const RNTupleModel & /* model */) { + auto opts = dynamic_cast(fOptions.get()); + fNTupleAnchor.fObjClass = opts ? opts->GetObjectClass() : RNTupleWriteOptionsDaos().GetObjectClass(); + auto oclass = RDaosObject::ObjClassId(fNTupleAnchor.fObjClass); + if (oclass.IsUnknown()) + throw ROOT::Experimental::RException(R__FAIL("Unknown object class " + fNTupleAnchor.fObjClass)); + auto args = ParseDaosURI(fURI); auto pool = std::make_shared(args.fPoolUuid, args.fSvcReplicas); fDaosContainer = std::make_unique(pool, args.fContainerUuid, /*create =*/ true); + fDaosContainer->SetDefaultObjectClass(oclass); const auto &descriptor = fDescriptorBuilder.GetDescriptor(); auto szHeader = descriptor.GetHeaderSize(); @@ -294,6 +310,11 @@ ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceDao kAttributeKey, kCidMetadata); ntpl.Deserialize(buffer.get()); + auto oclass = RDaosObject::ObjClassId(ntpl.fObjClass); + if (oclass.IsUnknown()) + throw ROOT::Experimental::RException(R__FAIL("Unknown object class " + ntpl.fObjClass)); + fDaosContainer->SetDefaultObjectClass(oclass); + buffer = std::make_unique(ntpl.fLenHeader); auto zipBuffer = std::make_unique(ntpl.fNBytesHeader); fDaosContainer->ReadSingleAkey(zipBuffer.get(), ntpl.fNBytesHeader, kOidHeader, kDistributionKey, @@ -312,6 +333,12 @@ ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceDao } +std::string ROOT::Experimental::Detail::RPageSourceDaos::GetObjectClass() const +{ + return fDaosContainer->GetDefaultObjectClass().ToString(); +} + + void ROOT::Experimental::Detail::RPageSourceDaos::LoadSealedPage( DescriptorId_t columnId, const RClusterIndex &clusterIndex, RSealedPage &sealedPage) { From 9b4c7da8c7155d4fb9b18b5050bc18a2ba476140 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:04:43 +0200 Subject: [PATCH 268/309] [ntuple,daos] Add `RNTupleWriteOptionsDaos` unit test --- tree/ntuple/v7/test/ntuple_storage_daos.cxx | 39 +++++++++++++++++++-- tree/ntuple/v7/test/ntuple_test.hxx | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tree/ntuple/v7/test/ntuple_storage_daos.cxx b/tree/ntuple/v7/test/ntuple_storage_daos.cxx index 5ab814e817138..c4fb273014046 100644 --- a/tree/ntuple/v7/test/ntuple_storage_daos.cxx +++ b/tree/ntuple/v7/test/ntuple_storage_daos.cxx @@ -1,6 +1,7 @@ #include "ntuple_test.hxx" +#include -TEST(RNTuple, Basics) +TEST(RPageStorageDaos, Basics) { std::string daosUri("daos://" R__DAOS_TEST_POOL ":1/a947484e-e3bc-48cb-8f71-3292c19b59a4"); @@ -30,7 +31,7 @@ TEST(RNTuple, Basics) EXPECT_EQ(12.0, *rdPt); } -TEST(RNTuple, Extended) +TEST(RPageStorageDaos, Extended) { std::string daosUri("daos://" R__DAOS_TEST_POOL ":1/a947484e-e3bc-48cb-8f71-3292c19b59a4"); @@ -68,3 +69,37 @@ TEST(RNTuple, Extended) } EXPECT_EQ(chksumRead, chksumWrite); } + +TEST(RPageStorageDaos, Options) +{ + std::string daosUri("daos://" R__DAOS_TEST_POOL ":1/a947484e-e3bc-48cb-8f71-3292c19b59a4"); + + { + auto model = RNTupleModel::Create(); + + RNTupleWriteOptionsDaos options; + options.SetObjectClass("UNKNOWN"); + try { + auto ntuple = RNTupleWriter::Recreate(std::move(model), "ntuple", daosUri, options); + FAIL() << "unknown object class should throw"; + } catch (const RException& err) { + EXPECT_THAT(err.what(), testing::HasSubstr("UNKNOWN")); + } + } + + { + auto model = RNTupleModel::Create(); + auto wrPt = model->MakeField("pt", 42.0); + + RNTupleWriteOptionsDaos options; + options.SetObjectClass("RP_XSF"); + auto ntuple = RNTupleWriter::Recreate(std::move(model), "ntuple", daosUri, options); + ntuple->Fill(); + ntuple->CommitCluster(); + } + + ROOT::Experimental::Detail::RPageSourceDaos source("ntuple", daosUri, RNTupleReadOptions()); + source.Attach(); + EXPECT_STREQ("RP_XSF", source.GetObjectClass().c_str()); + EXPECT_EQ(1U, source.GetNEntries()); +} diff --git a/tree/ntuple/v7/test/ntuple_test.hxx b/tree/ntuple/v7/test/ntuple_test.hxx index 531b086b1d917..1cac47dd0d77b 100644 --- a/tree/ntuple/v7/test/ntuple_test.hxx +++ b/tree/ntuple/v7/test/ntuple_test.hxx @@ -80,6 +80,7 @@ using RNTupleReader = ROOT::Experimental::RNTupleReader; using RNTupleReadOptions = ROOT::Experimental::RNTupleReadOptions; using RNTupleWriter = ROOT::Experimental::RNTupleWriter; using RNTupleWriteOptions = ROOT::Experimental::RNTupleWriteOptions; +using RNTupleWriteOptionsDaos = ROOT::Experimental::RNTupleWriteOptionsDaos; using RNTupleMetrics = ROOT::Experimental::Detail::RNTupleMetrics; using RNTupleModel = ROOT::Experimental::RNTupleModel; using RNTuplePlainCounter = ROOT::Experimental::Detail::RNTuplePlainCounter; From 14b8e838bb5e8a711aaa6e8b4c52108873bed211 Mon Sep 17 00:00:00 2001 From: Javier Lopez-Gomez Date: Wed, 16 Jun 2021 21:04:43 +0200 Subject: [PATCH 269/309] [ntuple,daos] Change default object class for user data OIDs `OC_RP_XSF` -> `OC_SX` The `OC_SX` object class (i.e. distribute data among all targets) is probably a more reasonable default. This parameter can be changed per-ntuple via `RNTupleWriteOptionsDaos`. --- tree/ntuple/v7/inc/ROOT/RDaos.hxx | 2 +- tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tree/ntuple/v7/inc/ROOT/RDaos.hxx b/tree/ntuple/v7/inc/ROOT/RDaos.hxx index 761bcba594123..a801d16b89220 100644 --- a/tree/ntuple/v7/inc/ROOT/RDaos.hxx +++ b/tree/ntuple/v7/inc/ROOT/RDaos.hxx @@ -155,7 +155,7 @@ private: daos_handle_t fContainerHandle{}; uuid_t fContainerUuid{}; std::shared_ptr fPool; - ObjClassId_t fDefaultObjectClass{OC_RP_XSF}; + ObjClassId_t fDefaultObjectClass{OC_SX}; /** \brief Perform a vector read/write operation on different objects. diff --git a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx index 4e6deb8d9151b..07004821cc257 100644 --- a/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx +++ b/tree/ntuple/v7/inc/ROOT/RNTupleOptions.hxx @@ -83,7 +83,7 @@ public: */ // clang-format on class RNTupleWriteOptionsDaos : public RNTupleWriteOptions { - std::string fObjectClass{"RP_XSF"}; + std::string fObjectClass{"SX"}; public: virtual ~RNTupleWriteOptionsDaos() = default; From 66278e49fbb329744c584a324eebcb12c3b1a9cc Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 09:18:53 +0200 Subject: [PATCH 270/309] [rdrawable] use union in RAttrBase class for exclusive members drawable, parent or attributes container are exclusive and therefore can be placed in union. First step to reduce size of attributes class --- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 51 +++++++++------ graf2d/gpadv7/src/RAttrBase.cxx | 95 +++++++++++++++++++--------- 2 files changed, 95 insertions(+), 51 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index 9db04b47822fa..98935fcc8dfee 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -32,13 +32,30 @@ class RAttrBase { friend class RAttrMap; - RDrawable *fDrawable{nullptr}; /// fOwnAttr; ///< own instance when deep copy is created, persistent for RColor and similar classes + enum {kDrawable, kParent, kOwnAttr} fKind{kDrawable}; ///fPrefix); // fullname = prnt->fPrefix + fullname - if (prnt->fDrawable) - return {&(prnt->fDrawable->fAttr), fullname, prnt->fDrawable}; - if (prnt->fOwnAttr) - return {prnt->fOwnAttr.get(), fullname, nullptr}; - prnt = prnt->fParent; + if (auto dr = prnt->GetDrawable()) + return { &dr->fAttr, fullname, dr }; + if (auto attr = prnt->GetOwnAttr()) + return { attr, fullname, nullptr }; + prnt = prnt->GetParent(); } return {nullptr, fullname, nullptr}; } @@ -104,13 +117,11 @@ protected: std::string fullname = name; while (prnt) { fullname.insert(0, prnt->fPrefix); // fullname = prnt->fPrefix + fullname - if (prnt->fDrawable) - return {&(prnt->fDrawable->fAttr), fullname, prnt->fDrawable}; - if (!prnt->fParent && !prnt->fOwnAttr) - prnt->fOwnAttr = std::make_unique(); - if (prnt->fOwnAttr) - return {prnt->fOwnAttr.get(), fullname, nullptr}; - prnt = prnt->fParent; + if (auto dr = prnt->GetDrawable()) + return { &dr->fAttr, fullname, dr }; + if (prnt->fKind != kParent) + return { prnt->CreateOwnAttr(), fullname, nullptr }; + prnt = prnt->GetParent(); } return {nullptr, fullname, nullptr}; } @@ -184,7 +195,7 @@ protected: public: RAttrBase() = default; - virtual ~RAttrBase() = default; + virtual ~RAttrBase() { ClearData(); } friend bool operator==(const RAttrBase& lhs, const RAttrBase& rhs) { return lhs.IsSame(rhs) && rhs.IsSame(lhs); } friend bool operator!=(const RAttrBase& lhs, const RAttrBase& rhs) { return !lhs.IsSame(rhs) || !rhs.IsSame(lhs); } diff --git a/graf2d/gpadv7/src/RAttrBase.cxx b/graf2d/gpadv7/src/RAttrBase.cxx index 99da328f7d55b..38545785b0cc8 100644 --- a/graf2d/gpadv7/src/RAttrBase.cxx +++ b/graf2d/gpadv7/src/RAttrBase.cxx @@ -16,15 +16,47 @@ #include "TClass.h" #include "TDataMember.h" -ROOT::Experimental::RLogChannel &ROOT::Experimental::GPadLog() { +using namespace ROOT::Experimental; + +RLogChannel &ROOT::Experimental::GPadLog() +{ static RLogChannel sLog("ROOT.GPad"); return sLog; } +/////////////////////////////////////////////////////////////////////////////// +/// Clear internal data + +void RAttrBase::ClearData() +{ + if ((fKind == kOwnAttr) && fD.ownattr) { + delete fD.ownattr; + fD.ownattr = nullptr; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// Creates own attribute - only if no drawable and no parent are assigned + +RAttrMap *RAttrBase::CreateOwnAttr() +{ + if (((fKind == kParent) && !fD.parent) || ((fKind == kDrawable) && !fD.drawable)) + fKind = kOwnAttr; + + if (fKind != kOwnAttr) + return nullptr; + + if (!fD.ownattr) + fD.ownattr = new RAttrMap(); + + return fD.ownattr; +} + + /////////////////////////////////////////////////////////////////////////////// /// Return default values for attributes, empty for base class -const ROOT::Experimental::RAttrMap &ROOT::Experimental::RAttrBase::GetDefaults() const +const RAttrMap &RAttrBase::GetDefaults() const { static RAttrMap empty; return empty; @@ -33,7 +65,7 @@ const ROOT::Experimental::RAttrMap &ROOT::Experimental::RAttrBase::GetDefaults() /////////////////////////////////////////////////////////////////////////////// /// Copy attributes from other object -bool ROOT::Experimental::RAttrBase::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) +bool RAttrBase::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) { if (check_type) { const auto *dvalue = GetDefaults().Find(name); @@ -52,7 +84,7 @@ bool ROOT::Experimental::RAttrBase::CopyValue(const std::string &name, const RAt /////////////////////////////////////////////////////////////////////////////// /// Check if provided value equal to attribute in the map -bool ROOT::Experimental::RAttrBase::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const +bool RAttrBase::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const { if (auto v = AccessValue(name, use_style)) return v.value->CanConvertFrom(value.Kind()) && v.value->IsEqual(value); @@ -63,7 +95,7 @@ bool ROOT::Experimental::RAttrBase::IsValueEqual(const std::string &name, const /////////////////////////////////////////////////////////////////////////////// /// Copy attributes into target object -void ROOT::Experimental::RAttrBase::CopyTo(RAttrBase &tgt, bool use_style) const +void RAttrBase::CopyTo(RAttrBase &tgt, bool use_style) const { for (const auto &entry : GetDefaults()) { if (auto v = AccessValue(entry.first, use_style)) @@ -74,18 +106,17 @@ void ROOT::Experimental::RAttrBase::CopyTo(RAttrBase &tgt, bool use_style) const /////////////////////////////////////////////////////////////////////////////// /// Move all fields into target object -void ROOT::Experimental::RAttrBase::MoveTo(RAttrBase &tgt) +void RAttrBase::MoveTo(RAttrBase &tgt) { - std::swap(fOwnAttr, tgt.fOwnAttr); + std::swap(fKind, tgt.fKind); + std::swap(fD, tgt.fD); std::swap(fPrefix, tgt.fPrefix); - std::swap(fDrawable, tgt.fDrawable); - std::swap(fParent, tgt.fParent); } /////////////////////////////////////////////////////////////////////////////// /// Check if all values which are evaluated in this object are exactly the same as in tgt object -bool ROOT::Experimental::RAttrBase::IsSame(const RAttrBase &tgt, bool use_style) const +bool RAttrBase::IsSame(const RAttrBase &tgt, bool use_style) const { for (const auto &entry : GetDefaults()) { if (auto v = AccessValue(entry.first, use_style)) @@ -97,33 +128,35 @@ bool ROOT::Experimental::RAttrBase::IsSame(const RAttrBase &tgt, bool use_style) } /////////////////////////////////////////////////////////////////////////////// -/// Return value from attributes container - no style or defaults are used +/// Assign drawable object for this RAttrBase -void ROOT::Experimental::RAttrBase::AssignDrawable(RDrawable *drawable, const std::string &prefix) +void RAttrBase::AssignDrawable(RDrawable *drawable, const std::string &prefix) { - fDrawable = drawable; - fOwnAttr.reset(); + ClearData(); + fKind = kDrawable; + fD.drawable = drawable; + fPrefix = prefix; if (!IsValue() && !fPrefix.empty()) fPrefix.append("_"); // naming convention - fParent = nullptr; } /////////////////////////////////////////////////////////////////////////////// /// Assign parent object for this RAttrBase -void ROOT::Experimental::RAttrBase::AssignParent(RAttrBase *parent, const std::string &prefix) +void RAttrBase::AssignParent(RAttrBase *parent, const std::string &prefix) { - fDrawable = nullptr; - fOwnAttr.reset(); + ClearData(); + fKind = kParent; + fD.parent = parent; + fPrefix = prefix; if (!IsValue() && !fPrefix.empty()) fPrefix.append("_"); // naming convention - fParent = parent; } /////////////////////////////////////////////////////////////////////////////// /// Clear value if any with specified name -void ROOT::Experimental::RAttrBase::ClearValue(const std::string &name) +void RAttrBase::ClearValue(const std::string &name) { if (auto access = AccessAttr(name)) access.attr->Clear(access.fullname); @@ -133,7 +166,7 @@ void ROOT::Experimental::RAttrBase::ClearValue(const std::string &name) /// Set for attribute. Ensure that value can not be configured via style - defaults will be used /// Equivalent to css syntax { attrname:; } -void ROOT::Experimental::RAttrBase::SetNoValue(const std::string &name) +void RAttrBase::SetNoValue(const std::string &name) { if (auto access = AccessAttr(name)) access.attr->AddNoValue(access.fullname); @@ -142,7 +175,7 @@ void ROOT::Experimental::RAttrBase::SetNoValue(const std::string &name) /////////////////////////////////////////////////////////////////////////////// /// Set boolean value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, bool value) +void RAttrBase::SetValue(const std::string &name, bool value) { if (auto access = EnsureAttr(name)) access.attr->AddBool(access.fullname, value); @@ -151,7 +184,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, bool value /////////////////////////////////////////////////////////////////////////////// /// Set integer value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, int value) +void RAttrBase::SetValue(const std::string &name, int value) { if (auto access = EnsureAttr(name)) access.attr->AddInt(access.fullname, value); @@ -160,7 +193,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, int value) /////////////////////////////////////////////////////////////////////////////// /// Set double value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, double value) +void RAttrBase::SetValue(const std::string &name, double value) { if (auto access = EnsureAttr(name)) access.attr->AddDouble(access.fullname, value); @@ -169,7 +202,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, double val /////////////////////////////////////////////////////////////////////////////// /// Set string value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const std::string &value) +void RAttrBase::SetValue(const std::string &name, const std::string &value) { if (auto access = EnsureAttr(name)) access.attr->AddString(access.fullname, value); @@ -178,7 +211,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const std: /////////////////////////////////////////////////////////////////////////////// /// Set PadLength value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const RPadLength &value) +void RAttrBase::SetValue(const std::string &name, const RPadLength &value) { if (value.Empty()) ClearValue(name); @@ -189,7 +222,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const RPad /////////////////////////////////////////////////////////////////////////////// /// Set RColor value -void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const RColor &value) +void RAttrBase::SetValue(const std::string &name, const RColor &value) { if (value.IsEmpty()) ClearValue(name); @@ -200,7 +233,7 @@ void ROOT::Experimental::RAttrBase::SetValue(const std::string &name, const RCol /////////////////////////////////////////////////////////////////////////////// /// Clear all respective values from drawable. Only defaults can be used -void ROOT::Experimental::RAttrBase::Clear() +void RAttrBase::Clear() { for (const auto &entry : GetDefaults()) ClearValue(entry.first); @@ -212,13 +245,13 @@ void ROOT::Experimental::RAttrBase::Clear() /// Works only if such class has dictionary. /// In special cases one has to provide special implementation directly -ROOT::Experimental::RAttrMap ROOT::Experimental::RAttrBase::CollectDefaults() const +RAttrMap RAttrBase::CollectDefaults() const { - ROOT::Experimental::RAttrMap res; + RAttrMap res; const std::type_info &info = typeid(*this); auto thisClass = TClass::GetClass(info); - auto baseClass = TClass::GetClass(); + auto baseClass = TClass::GetClass(); if (thisClass && baseClass) { for (auto data_member: TRangeDynCast(thisClass->GetListOfDataMembers())) { if (data_member && data_member->GetClass() && data_member->GetClass()->InheritsFrom(baseClass) && From 478e160d90f79194f75d881a95ebeeb15e6f6ef8 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 14:48:25 +0200 Subject: [PATCH 271/309] [rattr] split RAttrValue and RAttrAggregation class First used only for basic data type, last for aggregations. Simplify managing of defauls values for RAttrValue - no need for specialized container when just plain default value can be stored --- graf2d/gpadv7/inc/LinkDef.h | 1 + graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 110 ++++++++------- graf2d/gpadv7/inc/ROOT/RAttrFill.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrLine.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrMap.hxx | 2 + graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrText.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 55 ++++++-- graf2d/gpadv7/src/RAttrBase.cxx | 173 +++++++++++++----------- graf2d/gpadv7/src/RAttrMap.cxx | 12 +- graf2d/gpadv7/test/attribute.cxx | 6 +- 13 files changed, 220 insertions(+), 151 deletions(-) diff --git a/graf2d/gpadv7/inc/LinkDef.h b/graf2d/gpadv7/inc/LinkDef.h index e520af5753aa5..6d52ab8b6b45d 100644 --- a/graf2d/gpadv7/inc/LinkDef.h +++ b/graf2d/gpadv7/inc/LinkDef.h @@ -70,6 +70,7 @@ #pragma link C++ class ROOT::Experimental::RAttrMap::DoubleValue_t+; #pragma link C++ class ROOT::Experimental::RAttrMap::StringValue_t+; #pragma link C++ class ROOT::Experimental::RAttrBase+; +#pragma link C++ class ROOT::Experimental::RAttrAggregation+; #pragma link C++ class ROOT::Experimental::RAttrValue+; #pragma link C++ class ROOT::Experimental::RAttrValue+; #pragma link C++ class ROOT::Experimental::RAttrValue+; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx index 5d4b4c72fa7bc..10b386cd7c994 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx @@ -27,7 +27,7 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RAttrAxis : public RAttrBase { +class RAttrAxis : public RAttrAggregation { RAttrValue fMin{this, "min", 0.}; /// fMax{this, "max", 0.}; ///fPrefix); // fullname = prnt->fPrefix + fullname + if ((prnt != this) && !prnt->fPrefix.empty()) { + fullname.insert(0, "_"); // fullname = prnt->fPrefix + _ + fullname + fullname.insert(0, prnt->fPrefix); + } if (auto dr = prnt->GetDrawable()) return { &dr->fAttr, fullname, dr }; if (auto attr = prnt->GetOwnAttr()) @@ -116,7 +114,10 @@ protected: auto prnt = this; std::string fullname = name; while (prnt) { - fullname.insert(0, prnt->fPrefix); // fullname = prnt->fPrefix + fullname + if ((prnt != this) && !prnt->fPrefix.empty()) { + fullname.insert(0, "_"); // fullname = prnt->fPrefix + _ + fullname + fullname.insert(0, prnt->fPrefix); + } if (auto dr = prnt->GetDrawable()) return { &dr->fAttr, fullname, dr }; if (prnt->fKind != kParent) @@ -126,41 +127,10 @@ protected: return {nullptr, fullname, nullptr}; } - /// Evaluate attribute value - - template - auto Eval(const std::string &name, bool use_dflts = true) const - { - if (auto v = AccessValue(name, true)) - return RAttrMap::Value_t::GetValue(v.value); - - const RAttrMap::Value_t *rec = nullptr; - - if (use_dflts) - rec = GetDefaults().Find(name); - - return RAttrMap::Value_t::GetValue(rec); - } - - void CopyTo(RAttrBase &tgt, bool use_style = true) const; - - void MoveTo(RAttrBase &tgt); - - bool IsSame(const RAttrBase &src, bool use_style = true) const; - RAttrBase(RDrawable *drawable, const std::string &prefix) { AssignDrawable(drawable, prefix); } RAttrBase(RAttrBase *parent, const std::string &prefix) { AssignParent(parent, prefix); } - RAttrBase(const RAttrBase &src) { src.CopyTo(*this); } - - RAttrBase &operator=(const RAttrBase &src) - { - Clear(); - src.CopyTo(*this); - return *this; - } - void SetNoValue(const std::string &name); void SetValue(const std::string &name, bool value); void SetValue(const std::string &name, double value); @@ -173,7 +143,41 @@ protected: void ClearValue(const std::string &name); - void Clear(); + void MoveTo(RAttrBase &tgt); + +public: + RAttrBase() = default; + + virtual ~RAttrBase() { ClearData(); } + + virtual void Clear() = 0; + +}; + + +class RAttrAggregation : public RAttrBase { + +protected: + virtual const RAttrMap &GetDefaults() const; + + virtual RAttrMap CollectDefaults() const; + + void AddDefaultValues(RAttrMap &) const override; + + /// Evaluate attribute value + template + auto Eval(const std::string &name, bool use_dflts = true) const + { + if (auto v = AccessValue(name, true)) + return RAttrMap::Value_t::GetValue(v.value); + + const RAttrMap::Value_t *rec = nullptr; + + if (use_dflts) + rec = GetDefaults().Find(name); + + return RAttrMap::Value_t::GetValue(rec); + } template bool HasValue(const std::string &name, bool check_defaults = false) const @@ -188,18 +192,30 @@ protected: return Eval(name); } - virtual RAttrMap CollectDefaults() const; + void CopyTo(RAttrAggregation &tgt, bool use_style = true) const; - virtual bool IsValue() const { return false; } + bool CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type = true); + + bool IsSame(const RAttrAggregation &src, bool use_style = true) const; + + bool IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style = false) const; public: - RAttrBase() = default; + RAttrAggregation() = default; - virtual ~RAttrBase() { ClearData(); } + RAttrAggregation(const RAttrAggregation &src) : RAttrBase() { src.CopyTo(*this); } + + RAttrAggregation &operator=(const RAttrAggregation &src) + { + Clear(); + src.CopyTo(*this); + return *this; + } - friend bool operator==(const RAttrBase& lhs, const RAttrBase& rhs) { return lhs.IsSame(rhs) && rhs.IsSame(lhs); } - friend bool operator!=(const RAttrBase& lhs, const RAttrBase& rhs) { return !lhs.IsSame(rhs) || !rhs.IsSame(lhs); } + void Clear() override; + friend bool operator==(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return lhs.IsSame(rhs) && rhs.IsSame(lhs); } + friend bool operator!=(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return !lhs.IsSame(rhs) || !rhs.IsSame(lhs); } }; @@ -218,8 +234,6 @@ public: \ ClassName(RDrawable *drawable, const std::string &prefix = dflt_prefix) { AssignDrawable(drawable, prefix); } \ ClassName(RAttrBase *parent, const std::string &prefix = dflt_prefix) { AssignParent(parent, prefix); } \ ClassName(const ClassName &src) : ClassName() { src.CopyTo(*this); } \ - ClassName(ClassName &&src) : ClassName() { src.MoveTo(*this); } \ - ClassName &operator=(ClassName &&src) { src.MoveTo(*this); return *this; } \ ClassName &operator=(const ClassName &src) { Clear(); src.CopyTo(*this); return *this; } \ #endif diff --git a/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx b/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx index dc4faaba3b9c1..f1b5f26c26060 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx @@ -23,7 +23,7 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RAttrFill : public RAttrBase { +class RAttrFill : public RAttrAggregation { RAttrValue fColor{this, "color", RColor::kBlack}; /// fStyle{this, "style", 1}; /// fColor{this, "color", RColor::kBlack}; /// fWidth{this, "width", 1.}; /// fLeft{this, "left", 0._normal}; RAttrValue fRight{this, "right", 0._normal}; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx b/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx index ec1c635e24356..3835b6f6653d4 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx @@ -23,7 +23,7 @@ namespace Experimental { \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! */ -class RAttrMarker : public RAttrBase { +class RAttrMarker : public RAttrAggregation { RAttrValue fColor{this, "color", RColor::kBlack}; /// fSize{this, "size", 1.}; /// fColor{this, "color", RColor::kBlack}; /// fSize{this, "size", 12.}; /// class RAttrValue : public RAttrBase { protected: - RAttrMap fDefaults; ///(""); } - void Clear() { ClearValue(""); } - bool Has() const { return HasValue(""); } + RAttrValue(const RAttrValue& src) + { + Set(src.Get()); + } + + void Set(const T &v) + { + // todo - move all SetValue definitions here + SetValue(GetName(), v); + } + + T Get() const + { + if (auto v = AccessValue(GetName(), true)) + return RAttrMap::Value_t::GetValue(v.value); + + return fDefault; + } + + const std::string &GetName() const { return GetPrefix(); } + + void Clear() override { ClearValue(GetName()); } + + bool Has() const + { + if (auto v = AccessValue(GetName(), true)) { + auto res = RAttrMap::Value_t::GetValue(v.value); + return res ? (res->Kind() != RAttrMap::kNoValue) : false; + } + + return false; + } RAttrValue &operator=(const T &v) { Set(v); return *this; } + RAttrValue &operator=(const RAttrValue &v) { Set(v.Get()); return *this; } + operator T() const { return Get(); } + + friend bool operator==(const RAttrValue& lhs, const RAttrValue& rhs) { return lhs.Get() == rhs.Get(); } + friend bool operator!=(const RAttrValue& lhs, const RAttrValue& rhs) { return lhs.Get() != rhs.Get(); } + }; } // namespace Experimental diff --git a/graf2d/gpadv7/src/RAttrBase.cxx b/graf2d/gpadv7/src/RAttrBase.cxx index 38545785b0cc8..1e7948c1f1b98 100644 --- a/graf2d/gpadv7/src/RAttrBase.cxx +++ b/graf2d/gpadv7/src/RAttrBase.cxx @@ -52,81 +52,6 @@ RAttrMap *RAttrBase::CreateOwnAttr() return fD.ownattr; } - -/////////////////////////////////////////////////////////////////////////////// -/// Return default values for attributes, empty for base class - -const RAttrMap &RAttrBase::GetDefaults() const -{ - static RAttrMap empty; - return empty; -} - -/////////////////////////////////////////////////////////////////////////////// -/// Copy attributes from other object - -bool RAttrBase::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) -{ - if (check_type) { - const auto *dvalue = GetDefaults().Find(name); - if (!dvalue || !dvalue->CanConvertFrom(value.Kind())) - return false; - } - - if (auto access = EnsureAttr(name)) { - access.attr->Add(access.fullname, value.Copy()); - return true; - } - - return false; -} - -/////////////////////////////////////////////////////////////////////////////// -/// Check if provided value equal to attribute in the map - -bool RAttrBase::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const -{ - if (auto v = AccessValue(name, use_style)) - return v.value->CanConvertFrom(value.Kind()) && v.value->IsEqual(value); - - return value.Kind() == RAttrMap::kNoValue; -} - -/////////////////////////////////////////////////////////////////////////////// -/// Copy attributes into target object - -void RAttrBase::CopyTo(RAttrBase &tgt, bool use_style) const -{ - for (const auto &entry : GetDefaults()) { - if (auto v = AccessValue(entry.first, use_style)) - tgt.CopyValue(entry.first, *v.value); - } -} - -/////////////////////////////////////////////////////////////////////////////// -/// Move all fields into target object - -void RAttrBase::MoveTo(RAttrBase &tgt) -{ - std::swap(fKind, tgt.fKind); - std::swap(fD, tgt.fD); - std::swap(fPrefix, tgt.fPrefix); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Check if all values which are evaluated in this object are exactly the same as in tgt object - -bool RAttrBase::IsSame(const RAttrBase &tgt, bool use_style) const -{ - for (const auto &entry : GetDefaults()) { - if (auto v = AccessValue(entry.first, use_style)) - if (!tgt.IsValueEqual(entry.first, *v.value, use_style)) - return false; - } - - return true; -} - /////////////////////////////////////////////////////////////////////////////// /// Assign drawable object for this RAttrBase @@ -137,7 +62,6 @@ void RAttrBase::AssignDrawable(RDrawable *drawable, const std::string &prefix) fD.drawable = drawable; fPrefix = prefix; - if (!IsValue() && !fPrefix.empty()) fPrefix.append("_"); // naming convention } /////////////////////////////////////////////////////////////////////////////// @@ -150,7 +74,6 @@ void RAttrBase::AssignParent(RAttrBase *parent, const std::string &prefix) fD.parent = parent; fPrefix = prefix; - if (!IsValue() && !fPrefix.empty()) fPrefix.append("_"); // naming convention } /////////////////////////////////////////////////////////////////////////////// @@ -231,21 +154,31 @@ void RAttrBase::SetValue(const std::string &name, const RColor &value) } /////////////////////////////////////////////////////////////////////////////// -/// Clear all respective values from drawable. Only defaults can be used +/// Move all fields into target object -void RAttrBase::Clear() +void RAttrBase::MoveTo(RAttrBase &tgt) { - for (const auto &entry : GetDefaults()) - ClearValue(entry.first); + std::swap(fKind, tgt.fKind); + std::swap(fD, tgt.fD); + std::swap(fPrefix, tgt.fPrefix); } +/////////////////////////////////////////////////////////////////////////////// +/// Return default values for attributes, empty for base class + +const RAttrMap &RAttrAggregation::GetDefaults() const +{ + static RAttrMap empty; + return empty; +} + /////////////////////////////////////////////////////////////////////////////// /// Collect all attributes in derived class /// Works only if such class has dictionary. /// In special cases one has to provide special implementation directly -RAttrMap RAttrBase::CollectDefaults() const +RAttrMap RAttrAggregation::CollectDefaults() const { RAttrMap res; @@ -265,3 +198,79 @@ RAttrMap RAttrBase::CollectDefaults() const return res; } + +void RAttrAggregation::AddDefaultValues(RAttrMap &m) const +{ + std::string prefix = GetPrefix(); + if (!prefix.empty()) prefix.append("_"); + + m.AddValuesFrom(prefix, GetDefaults()); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Copy attributes into target object + +void RAttrAggregation::CopyTo(RAttrAggregation &tgt, bool use_style) const +{ + for (const auto &entry : GetDefaults()) { + if (auto v = AccessValue(entry.first, use_style)) + tgt.CopyValue(entry.first, *v.value); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// Copy attributes from other object + +bool RAttrAggregation::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) +{ + if (check_type) { + const auto *dvalue = GetDefaults().Find(name); + if (!dvalue || !dvalue->CanConvertFrom(value.Kind())) + return false; + } + + if (auto access = EnsureAttr(name)) { + access.attr->Add(access.fullname, value.Copy()); + return true; + } + + return false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/// Check if provided value equal to attribute in the map + +bool RAttrAggregation::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const +{ + if (auto v = AccessValue(name, use_style)) + return v.value->CanConvertFrom(value.Kind()) && v.value->IsEqual(value); + + return value.Kind() == RAttrMap::kNoValue; +} + + +/////////////////////////////////////////////////////////////////////////////// +/// Check if all values which are evaluated in this object are exactly the same as in tgt object + +bool RAttrAggregation::IsSame(const RAttrAggregation &tgt, bool use_style) const +{ + for (const auto &entry : GetDefaults()) { + // R__LOG_DEBUG(0, GPadLog()) << "Comparing entry " << entry.first; + if (auto v = AccessValue(entry.first, use_style)) + if (!tgt.IsValueEqual(entry.first, *v.value, use_style)) + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Clear all respective values from drawable. Only defaults can be used + +void RAttrAggregation::Clear() +{ + for (const auto &entry : GetDefaults()) + ClearValue(entry.first); +} + diff --git a/graf2d/gpadv7/src/RAttrMap.cxx b/graf2d/gpadv7/src/RAttrMap.cxx index 35bd8528e2742..a06d721504eba 100644 --- a/graf2d/gpadv7/src/RAttrMap.cxx +++ b/graf2d/gpadv7/src/RAttrMap.cxx @@ -47,14 +47,18 @@ template<> const RAttrMap::Value_t *RAttrMap::Value_t::GetValueCopy(); + vis.AddDefaultValues(*this); return *this; } +void RAttrMap::AddValuesFrom(const std::string &prefix, const RAttrMap &map) +{ + for (const auto &entry : map) + m[prefix+entry.first] = entry.second->Copy(); +} + + ///////////////////////////////////////////////////////////////////////////////////////////////// /// Add attribute, converting to best possible type /// Tested boolean, int, double. If none works - store as a string diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index e86280650cc47..a58adf8dac0da 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -1,12 +1,14 @@ #include "gtest/gtest.h" +#include "ROOT/RLogger.hxx" +#include "ROOT/RAttrBase.hxx" #include "ROOT/RAttrText.hxx" #include "ROOT/RAttrFill.hxx" #include "ROOT/RAttrLine.hxx" using namespace ROOT::Experimental; -class CustomAttrs : public RAttrBase { +class CustomAttrs : public RAttrAggregation { RAttrLine fAttrLine{this, "line"}; /// Date: Fri, 18 Jun 2021 15:19:34 +0200 Subject: [PATCH 272/309] [rattr] extract RAttrAggregation in separate incluse/source files --- graf2d/gpadv7/CMakeLists.txt | 2 + graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx | 107 ++++++++++++++++ graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx | 4 +- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 81 +----------- graf2d/gpadv7/inc/ROOT/RAttrFill.hxx | 4 +- graf2d/gpadv7/inc/ROOT/RAttrLine.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx | 4 +- graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx | 4 +- graf2d/gpadv7/inc/ROOT/RAttrText.hxx | 4 +- graf2d/gpadv7/src/RAttrAggregation.cxx | 131 ++++++++++++++++++++ graf2d/gpadv7/src/RAttrBase.cxx | 116 ----------------- graf2d/gpadv7/test/attribute.cxx | 2 +- 12 files changed, 253 insertions(+), 208 deletions(-) create mode 100644 graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx create mode 100644 graf2d/gpadv7/src/RAttrAggregation.cxx diff --git a/graf2d/gpadv7/CMakeLists.txt b/graf2d/gpadv7/CMakeLists.txt index 12144dd827cdc..8a680a2dd88bc 100644 --- a/graf2d/gpadv7/CMakeLists.txt +++ b/graf2d/gpadv7/CMakeLists.txt @@ -18,6 +18,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGpadv7 ROOT/RDisplayItem.hxx ROOT/RAttrMap.hxx ROOT/RAttrBase.hxx + ROOT/RAttrAggregation.hxx ROOT/RAttrAxis.hxx ROOT/RAttrBorder.hxx ROOT/RAttrLine.hxx @@ -52,6 +53,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(ROOTGpadv7 src/RDrawableRequest.cxx src/RAttrMap.cxx src/RAttrBase.cxx + src/RAttrAggregation.cxx src/RPalette.cxx src/RStyle.cxx src/RPadBase.cxx diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx new file mode 100644 index 0000000000000..dce951a699db4 --- /dev/null +++ b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT7_RAttrAggregation +#define ROOT7_RAttrAggregation + +#include + +namespace ROOT { +namespace Experimental { + +/** \class RAttrAggregation +\ingroup GpadROOT7 +\author Sergey Linev +\date 2021-06-18 +\brief Base class for attributes aggregations like lines or fill attributes +\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome! +*/ + + +class RAttrAggregation : public RAttrBase { + +protected: + virtual const RAttrMap &GetDefaults() const; + + virtual RAttrMap CollectDefaults() const; + + void AddDefaultValues(RAttrMap &) const override; + + /// Evaluate attribute value + template + auto Eval(const std::string &name, bool use_dflts = true) const + { + if (auto v = AccessValue(name, true)) + return RAttrMap::Value_t::GetValue(v.value); + + const RAttrMap::Value_t *rec = nullptr; + + if (use_dflts) + rec = GetDefaults().Find(name); + + return RAttrMap::Value_t::GetValue(rec); + } + + template + bool HasValue(const std::string &name, bool check_defaults = false) const + { + auto res = Eval(name, check_defaults); + return res ? (res->Kind() != RAttrMap::kNoValue) : false; + } + + template + T GetValue(const std::string &name) const + { + return Eval(name); + } + + void CopyTo(RAttrAggregation &tgt, bool use_style = true) const; + + bool CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type = true); + + bool IsSame(const RAttrAggregation &src, bool use_style = true) const; + + bool IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style = false) const; + +public: + RAttrAggregation() = default; + + RAttrAggregation(const RAttrAggregation &src) : RAttrBase() { src.CopyTo(*this); } + + RAttrAggregation &operator=(const RAttrAggregation &src) + { + Clear(); + src.CopyTo(*this); + return *this; + } + + void Clear() override; + + friend bool operator==(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return lhs.IsSame(rhs) && rhs.IsSame(lhs); } + friend bool operator!=(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return !lhs.IsSame(rhs) || !rhs.IsSame(lhs); } +}; + +} // namespace Experimental +} // namespace ROOT + +#define R__ATTR_CLASS(ClassName,dflt_prefix) \ +protected: \ +const RAttrMap &GetDefaults() const override \ +{ \ + static auto dflts = CollectDefaults(); \ + return dflts; \ +} \ +public: \ + ClassName() = default; \ + ClassName(RDrawable *drawable, const std::string &prefix = dflt_prefix) { AssignDrawable(drawable, prefix); } \ + ClassName(RAttrBase *parent, const std::string &prefix = dflt_prefix) { AssignParent(parent, prefix); } \ + ClassName(const ClassName &src) : ClassName() { src.CopyTo(*this); } \ + ClassName &operator=(const ClassName &src) { Clear(); src.CopyTo(*this); return *this; } \ + + +#endif diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx index 10b386cd7c994..c7b58b4d5192f 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAxis.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrAxis #define ROOT7_RAttrAxis -#include +#include #include #include #include diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index c27eba12b3492..67e914771de2e 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -154,86 +154,7 @@ public: }; - -class RAttrAggregation : public RAttrBase { - -protected: - virtual const RAttrMap &GetDefaults() const; - - virtual RAttrMap CollectDefaults() const; - - void AddDefaultValues(RAttrMap &) const override; - - /// Evaluate attribute value - template - auto Eval(const std::string &name, bool use_dflts = true) const - { - if (auto v = AccessValue(name, true)) - return RAttrMap::Value_t::GetValue(v.value); - - const RAttrMap::Value_t *rec = nullptr; - - if (use_dflts) - rec = GetDefaults().Find(name); - - return RAttrMap::Value_t::GetValue(rec); - } - - template - bool HasValue(const std::string &name, bool check_defaults = false) const - { - auto res = Eval(name, check_defaults); - return res ? (res->Kind() != RAttrMap::kNoValue) : false; - } - - template - T GetValue(const std::string &name) const - { - return Eval(name); - } - - void CopyTo(RAttrAggregation &tgt, bool use_style = true) const; - - bool CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type = true); - - bool IsSame(const RAttrAggregation &src, bool use_style = true) const; - - bool IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style = false) const; - -public: - RAttrAggregation() = default; - - RAttrAggregation(const RAttrAggregation &src) : RAttrBase() { src.CopyTo(*this); } - - RAttrAggregation &operator=(const RAttrAggregation &src) - { - Clear(); - src.CopyTo(*this); - return *this; - } - - void Clear() override; - - friend bool operator==(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return lhs.IsSame(rhs) && rhs.IsSame(lhs); } - friend bool operator!=(const RAttrAggregation& lhs, const RAttrAggregation& rhs) { return !lhs.IsSame(rhs) || !rhs.IsSame(lhs); } -}; - - } // namespace Experimental } // namespace ROOT -#define R__ATTR_CLASS(ClassName,dflt_prefix) \ -protected: \ -const RAttrMap &GetDefaults() const override \ -{ \ - static auto dflts = CollectDefaults(); \ - return dflts; \ -} \ -public: \ - ClassName() = default; \ - ClassName(RDrawable *drawable, const std::string &prefix = dflt_prefix) { AssignDrawable(drawable, prefix); } \ - ClassName(RAttrBase *parent, const std::string &prefix = dflt_prefix) { AssignParent(parent, prefix); } \ - ClassName(const ClassName &src) : ClassName() { src.CopyTo(*this); } \ - ClassName &operator=(const ClassName &src) { Clear(); src.CopyTo(*this); return *this; } \ - #endif diff --git a/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx b/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx index f1b5f26c26060..a0600ca03f700 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrFill.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrFill #define ROOT7_RAttrFill -#include +#include #include namespace ROOT { diff --git a/graf2d/gpadv7/inc/ROOT/RAttrLine.hxx b/graf2d/gpadv7/inc/ROOT/RAttrLine.hxx index b6892b8f306d2..4c33921dabe37 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrLine.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrLine.hxx @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrLine #define ROOT7_RAttrLine -#include +#include #include namespace ROOT { diff --git a/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx b/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx index b1335daba14bb..5add8af1bb024 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrMargins.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrMargins #define ROOT7_RAttrMargins -#include +#include #include #include diff --git a/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx b/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx index 3835b6f6653d4..20bea4000d402 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrMarker.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrMarker #define ROOT7_RAttrMarker -#include +#include #include namespace ROOT { diff --git a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx index c4009cd409675..13b3dc93e101c 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrText.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrText.hxx @@ -1,5 +1,5 @@ /************************************************************************* - * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -9,7 +9,7 @@ #ifndef ROOT7_RAttrText #define ROOT7_RAttrText -#include +#include #include namespace ROOT { diff --git a/graf2d/gpadv7/src/RAttrAggregation.cxx b/graf2d/gpadv7/src/RAttrAggregation.cxx new file mode 100644 index 0000000000000..1f6f70d5e2b82 --- /dev/null +++ b/graf2d/gpadv7/src/RAttrAggregation.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * Copyright (C) 1995-2021, 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 + +#include + +#include + +#include "TList.h" +#include "TClass.h" +#include "TDataMember.h" + +using namespace ROOT::Experimental; + + +/////////////////////////////////////////////////////////////////////////////// +/// Return default values for attributes, empty for base class + +const RAttrMap &RAttrAggregation::GetDefaults() const +{ + static RAttrMap empty; + return empty; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Collect all attributes in derived class +/// Works only if such class has dictionary. +/// In special cases one has to provide special implementation directly + +RAttrMap RAttrAggregation::CollectDefaults() const +{ + RAttrMap res; + + const std::type_info &info = typeid(*this); + auto thisClass = TClass::GetClass(info); + auto baseClass = TClass::GetClass(); + if (thisClass && baseClass) { + for (auto data_member: TRangeDynCast(thisClass->GetListOfDataMembers())) { + if (data_member && data_member->GetClass() && data_member->GetClass()->InheritsFrom(baseClass) && + (data_member->GetClass()->GetBaseClassOffset(baseClass) == 0)) { + res.AddDefaults(*((const RAttrBase *)((char*) this + data_member->GetOffset()))); + } + } + } else { + R__LOG_ERROR(GPadLog()) << "Missing dictionary for " << info.name() << " class"; + } + + return res; +} + +void RAttrAggregation::AddDefaultValues(RAttrMap &m) const +{ + std::string prefix = GetPrefix(); + if (!prefix.empty()) prefix.append("_"); + + m.AddValuesFrom(prefix, GetDefaults()); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Copy attributes into target object + +void RAttrAggregation::CopyTo(RAttrAggregation &tgt, bool use_style) const +{ + for (const auto &entry : GetDefaults()) { + if (auto v = AccessValue(entry.first, use_style)) + tgt.CopyValue(entry.first, *v.value); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// Copy attributes from other object + +bool RAttrAggregation::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) +{ + if (check_type) { + const auto *dvalue = GetDefaults().Find(name); + if (!dvalue || !dvalue->CanConvertFrom(value.Kind())) + return false; + } + + if (auto access = EnsureAttr(name)) { + access.attr->Add(access.fullname, value.Copy()); + return true; + } + + return false; +} + + +/////////////////////////////////////////////////////////////////////////////// +/// Check if provided value equal to attribute in the map + +bool RAttrAggregation::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const +{ + if (auto v = AccessValue(name, use_style)) + return v.value->CanConvertFrom(value.Kind()) && v.value->IsEqual(value); + + return value.Kind() == RAttrMap::kNoValue; +} + + +/////////////////////////////////////////////////////////////////////////////// +/// Check if all values which are evaluated in this object are exactly the same as in tgt object + +bool RAttrAggregation::IsSame(const RAttrAggregation &tgt, bool use_style) const +{ + for (const auto &entry : GetDefaults()) { + // R__LOG_DEBUG(0, GPadLog()) << "Comparing entry " << entry.first; + if (auto v = AccessValue(entry.first, use_style)) + if (!tgt.IsValueEqual(entry.first, *v.value, use_style)) + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Clear all respective values from drawable. Only defaults can be used + +void RAttrAggregation::Clear() +{ + for (const auto &entry : GetDefaults()) + ClearValue(entry.first); +} + diff --git a/graf2d/gpadv7/src/RAttrBase.cxx b/graf2d/gpadv7/src/RAttrBase.cxx index 1e7948c1f1b98..d4e01c159ed8c 100644 --- a/graf2d/gpadv7/src/RAttrBase.cxx +++ b/graf2d/gpadv7/src/RAttrBase.cxx @@ -12,10 +12,6 @@ #include -#include "TList.h" -#include "TClass.h" -#include "TDataMember.h" - using namespace ROOT::Experimental; RLogChannel &ROOT::Experimental::GPadLog() @@ -162,115 +158,3 @@ void RAttrBase::MoveTo(RAttrBase &tgt) std::swap(fD, tgt.fD); std::swap(fPrefix, tgt.fPrefix); } - - -/////////////////////////////////////////////////////////////////////////////// -/// Return default values for attributes, empty for base class - -const RAttrMap &RAttrAggregation::GetDefaults() const -{ - static RAttrMap empty; - return empty; -} - -/////////////////////////////////////////////////////////////////////////////// -/// Collect all attributes in derived class -/// Works only if such class has dictionary. -/// In special cases one has to provide special implementation directly - -RAttrMap RAttrAggregation::CollectDefaults() const -{ - RAttrMap res; - - const std::type_info &info = typeid(*this); - auto thisClass = TClass::GetClass(info); - auto baseClass = TClass::GetClass(); - if (thisClass && baseClass) { - for (auto data_member: TRangeDynCast(thisClass->GetListOfDataMembers())) { - if (data_member && data_member->GetClass() && data_member->GetClass()->InheritsFrom(baseClass) && - (data_member->GetClass()->GetBaseClassOffset(baseClass) == 0)) { - res.AddDefaults(*((const RAttrBase *)((char*) this + data_member->GetOffset()))); - } - } - } else { - R__LOG_ERROR(GPadLog()) << "Missing dictionary for " << info.name() << " class"; - } - - return res; -} - -void RAttrAggregation::AddDefaultValues(RAttrMap &m) const -{ - std::string prefix = GetPrefix(); - if (!prefix.empty()) prefix.append("_"); - - m.AddValuesFrom(prefix, GetDefaults()); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Copy attributes into target object - -void RAttrAggregation::CopyTo(RAttrAggregation &tgt, bool use_style) const -{ - for (const auto &entry : GetDefaults()) { - if (auto v = AccessValue(entry.first, use_style)) - tgt.CopyValue(entry.first, *v.value); - } -} - -/////////////////////////////////////////////////////////////////////////////// -/// Copy attributes from other object - -bool RAttrAggregation::CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type) -{ - if (check_type) { - const auto *dvalue = GetDefaults().Find(name); - if (!dvalue || !dvalue->CanConvertFrom(value.Kind())) - return false; - } - - if (auto access = EnsureAttr(name)) { - access.attr->Add(access.fullname, value.Copy()); - return true; - } - - return false; -} - - -/////////////////////////////////////////////////////////////////////////////// -/// Check if provided value equal to attribute in the map - -bool RAttrAggregation::IsValueEqual(const std::string &name, const RAttrMap::Value_t &value, bool use_style) const -{ - if (auto v = AccessValue(name, use_style)) - return v.value->CanConvertFrom(value.Kind()) && v.value->IsEqual(value); - - return value.Kind() == RAttrMap::kNoValue; -} - - -/////////////////////////////////////////////////////////////////////////////// -/// Check if all values which are evaluated in this object are exactly the same as in tgt object - -bool RAttrAggregation::IsSame(const RAttrAggregation &tgt, bool use_style) const -{ - for (const auto &entry : GetDefaults()) { - // R__LOG_DEBUG(0, GPadLog()) << "Comparing entry " << entry.first; - if (auto v = AccessValue(entry.first, use_style)) - if (!tgt.IsValueEqual(entry.first, *v.value, use_style)) - return false; - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -/// Clear all respective values from drawable. Only defaults can be used - -void RAttrAggregation::Clear() -{ - for (const auto &entry : GetDefaults()) - ClearValue(entry.first); -} - diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index a58adf8dac0da..cda8ad9463b16 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "ROOT/RLogger.hxx" -#include "ROOT/RAttrBase.hxx" +#include "ROOT/RAttrAggregation.hxx" #include "ROOT/RAttrText.hxx" #include "ROOT/RAttrFill.hxx" #include "ROOT/RAttrLine.hxx" From 398ec5671a3566c037dd745b1c6087a189481124 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 15:55:41 +0200 Subject: [PATCH 273/309] [rattr] remove unused RAttrBase::GetValue() methods Any access to basic data types should be performed via RAttrValue class --- graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx | 28 ---------- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 8 +-- graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 4 +- graf2d/gpadv7/src/RAttrBase.cxx | 58 --------------------- graf2d/gpadv7/test/attribute.cxx | 6 ++- 5 files changed, 8 insertions(+), 96 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx index dce951a699db4..efee96be09af5 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx @@ -32,34 +32,6 @@ protected: void AddDefaultValues(RAttrMap &) const override; - /// Evaluate attribute value - template - auto Eval(const std::string &name, bool use_dflts = true) const - { - if (auto v = AccessValue(name, true)) - return RAttrMap::Value_t::GetValue(v.value); - - const RAttrMap::Value_t *rec = nullptr; - - if (use_dflts) - rec = GetDefaults().Find(name); - - return RAttrMap::Value_t::GetValue(rec); - } - - template - bool HasValue(const std::string &name, bool check_defaults = false) const - { - auto res = Eval(name, check_defaults); - return res ? (res->Kind() != RAttrMap::kNoValue) : false; - } - - template - T GetValue(const std::string &name) const - { - return Eval(name); - } - void CopyTo(RAttrAggregation &tgt, bool use_style = true) const; bool CopyValue(const std::string &name, const RAttrMap::Value_t &value, bool check_type = true); diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index 67e914771de2e..2ef37ce71d9e6 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -40,7 +40,7 @@ class RAttrBase { RAttrMap *ownattr; // or just own container with values } fD{nullptr}; ///AddValue(access.fullname, v); } T Get() const diff --git a/graf2d/gpadv7/src/RAttrBase.cxx b/graf2d/gpadv7/src/RAttrBase.cxx index d4e01c159ed8c..c6aba9e5acd43 100644 --- a/graf2d/gpadv7/src/RAttrBase.cxx +++ b/graf2d/gpadv7/src/RAttrBase.cxx @@ -91,64 +91,6 @@ void RAttrBase::SetNoValue(const std::string &name) access.attr->AddNoValue(access.fullname); } -/////////////////////////////////////////////////////////////////////////////// -/// Set boolean value - -void RAttrBase::SetValue(const std::string &name, bool value) -{ - if (auto access = EnsureAttr(name)) - access.attr->AddBool(access.fullname, value); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Set integer value - -void RAttrBase::SetValue(const std::string &name, int value) -{ - if (auto access = EnsureAttr(name)) - access.attr->AddInt(access.fullname, value); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Set double value - -void RAttrBase::SetValue(const std::string &name, double value) -{ - if (auto access = EnsureAttr(name)) - access.attr->AddDouble(access.fullname, value); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Set string value - -void RAttrBase::SetValue(const std::string &name, const std::string &value) -{ - if (auto access = EnsureAttr(name)) - access.attr->AddString(access.fullname, value); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Set PadLength value - -void RAttrBase::SetValue(const std::string &name, const RPadLength &value) -{ - if (value.Empty()) - ClearValue(name); - else - SetValue(name, value.AsString()); -} - -/////////////////////////////////////////////////////////////////////////////// -/// Set RColor value - -void RAttrBase::SetValue(const std::string &name, const RColor &value) -{ - if (value.IsEmpty()) - ClearValue(name); - else - SetValue(name, value.AsString()); -} - /////////////////////////////////////////////////////////////////////////////// /// Move all fields into target object diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index cda8ad9463b16..16f0f99326733 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -28,7 +28,11 @@ class CustomAttrs : public RAttrAggregation { const RAttrText &AttrText() const { return fAttrText; } RAttrText &AttrText() { return fAttrText; } - double GetDirect(const std::string &name) const { return GetValue(name); } + double GetDirect(const std::string &name) + { + RAttrValue direct{this, name, 0.}; + return direct.Get(); + } }; From fb8efa4c11c9b91c311c47ac3f045bbb90cac614 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 16:40:36 +0200 Subject: [PATCH 274/309] [rattr] use const char* to keep name/prefix values Value is never changed and according to API one also can use constructor parameter. Significant size improvment compared to std::string. From 32 to 8 bytes --- graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx | 13 +++++++---- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 26 +++++++++++++-------- graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 14 +++-------- graf2d/gpadv7/src/RAttrBase.cxx | 24 ------------------- graf2d/gpadv7/test/attribute.cxx | 3 ++- 6 files changed, 31 insertions(+), 51 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx index efee96be09af5..1ce4467bb36a8 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx @@ -45,6 +45,9 @@ public: RAttrAggregation(const RAttrAggregation &src) : RAttrBase() { src.CopyTo(*this); } + RAttrAggregation(RDrawable *drawable, const char *prefix = nullptr) : RAttrBase(drawable, prefix) {} + RAttrAggregation(RAttrBase *parent, const char *prefix = nullptr) : RAttrBase(parent, prefix) {} + RAttrAggregation &operator=(const RAttrAggregation &src) { Clear(); @@ -61,7 +64,7 @@ public: } // namespace Experimental } // namespace ROOT -#define R__ATTR_CLASS(ClassName,dflt_prefix) \ +#define R__ATTR_CLASS_DERIVED(ClassName,dflt_prefix,BaseClass) \ protected: \ const RAttrMap &GetDefaults() const override \ { \ @@ -70,10 +73,12 @@ const RAttrMap &GetDefaults() const override \ } \ public: \ ClassName() = default; \ - ClassName(RDrawable *drawable, const std::string &prefix = dflt_prefix) { AssignDrawable(drawable, prefix); } \ - ClassName(RAttrBase *parent, const std::string &prefix = dflt_prefix) { AssignParent(parent, prefix); } \ + ClassName(RDrawable *drawable, const char *prefix = dflt_prefix) : BaseClass(drawable, prefix) {} \ + ClassName(RAttrBase *parent, const char *prefix = dflt_prefix) : BaseClass(parent, prefix) {} \ ClassName(const ClassName &src) : ClassName() { src.CopyTo(*this); } \ - ClassName &operator=(const ClassName &src) { Clear(); src.CopyTo(*this); return *this; } \ + ClassName &operator=(const ClassName &src) { Clear(); src.CopyTo(*this); return *this; } + +#define R__ATTR_CLASS(ClassName,dflt_prefix) R__ATTR_CLASS_DERIVED(ClassName,dflt_prefix,RAttrAggregation) #endif diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index 2ef37ce71d9e6..9d67b4065ed4b 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -40,7 +40,7 @@ class RAttrBase { RAttrMap *ownattr; // or just own container with values } fD{nullptr}; ///fPrefix.empty()) { + if ((prnt != this) && prnt->fPrefix) { fullname.insert(0, "_"); // fullname = prnt->fPrefix + _ + fullname fullname.insert(0, prnt->fPrefix); } @@ -114,7 +110,7 @@ protected: auto prnt = this; std::string fullname = name; while (prnt) { - if ((prnt != this) && !prnt->fPrefix.empty()) { + if ((prnt != this) && prnt->fPrefix) { fullname.insert(0, "_"); // fullname = prnt->fPrefix + _ + fullname fullname.insert(0, prnt->fPrefix); } @@ -127,13 +123,23 @@ protected: return {nullptr, fullname, nullptr}; } - RAttrBase(RDrawable *drawable, const std::string &prefix) { AssignDrawable(drawable, prefix); } + RAttrBase(RDrawable *drawable, const char *prefix = nullptr) + { + fKind = kDrawable; + fD.drawable = drawable; + fPrefix = prefix; + } - RAttrBase(RAttrBase *parent, const std::string &prefix) { AssignParent(parent, prefix); } + RAttrBase(RAttrBase *parent, const char *prefix = nullptr) + { + fKind = kParent; + fD.parent = parent; + fPrefix = prefix; + } void SetNoValue(const std::string &name); - const std::string &GetPrefix() const { return fPrefix; } + const char *GetPrefix() const { return fPrefix; } void ClearValue(const std::string &name); diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx index dc8459d9eef9b..4b2968c75e756 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBorder.hxx @@ -28,7 +28,7 @@ class RAttrBorder : public RAttrLine { RAttrValue fRx{this, "rx", 0}; /// fRy{this, "ry", 0}; /// direct{this, name, 0.}; + // CAUTION: name is not duplicated in RAttrValue + RAttrValue direct{this, name.c_str(), 0.}; return direct.Get(); } }; From 02f5188dd65de3ffa7e668242e120b0bfee9fd35 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 16:58:53 +0200 Subject: [PATCH 275/309] [rattr] add plain RAttrValue tests It should be possible (but not encouraged) to use class separately from drawable or aggregations --- graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 7 +++++-- graf2d/gpadv7/test/attribute.cxx | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx index 16574c0935dda..1c7c477213070 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx @@ -36,7 +36,7 @@ protected: public: - RAttrValue() = default; + RAttrValue() : RAttrBase(), fDefault() {}; RAttrValue(RDrawable *drawable, const char *name, const T &dflt = T()) : RAttrBase(drawable, name), fDefault(dflt) { } @@ -45,8 +45,11 @@ public: RAttrValue(const RAttrValue& src) { Set(src.Get()); + fDefault = src.Default(); } + T GetDefault() const { return fDefault; } + void Set(const T &v) { if (auto access = EnsureAttr(GetName())) @@ -61,7 +64,7 @@ public: return fDefault; } - const char *GetName() const { return GetPrefix(); } + const char *GetName() const { return GetPrefix() ? GetPrefix() : ""; } void Clear() override { ClearValue(GetName()); } diff --git a/graf2d/gpadv7/test/attribute.cxx b/graf2d/gpadv7/test/attribute.cxx index 953c6414765af..c0abe7d57b63d 100644 --- a/graf2d/gpadv7/test/attribute.cxx +++ b/graf2d/gpadv7/test/attribute.cxx @@ -154,3 +154,24 @@ TEST(OptsTest, AttribAssign) { EXPECT_FLOAT_EQ(attrs1.AttrLine().GetWidth(), 1.); EXPECT_FLOAT_EQ(attrs2.AttrLine().GetWidth(), 1.); } + +TEST(OptsTest, AttribValue) { + + RAttrValue value1; + + EXPECT_EQ(value1.GetDefault(), 0); + EXPECT_EQ(value1.Get(), 0); + + value1.Set(5); + EXPECT_EQ(value1.Get(), 5); + + RAttrValue value2; + EXPECT_NE(value1, value2); + EXPECT_NE(value2, value1); + + value2 = value1; + EXPECT_EQ(value1, value2); + EXPECT_EQ(value2, value1); + EXPECT_EQ(value2.Get(), 5); + +} From 5803fef9ed6005e892dc6efa4b796473aebaab9a Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 17:02:54 +0200 Subject: [PATCH 276/309] [rattr] always set prefix for RAttrValue Let avoid extra checks when using it --- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 7 +++++++ graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index 9d67b4065ed4b..1334f8a437d28 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -123,6 +123,13 @@ protected: return {nullptr, fullname, nullptr}; } + RAttrBase(const char *prefix) + { + fKind = kOwnAttr; + fD.ownattr = nullptr; + fPrefix = prefix; + } + RAttrBase(RDrawable *drawable, const char *prefix = nullptr) { fKind = kDrawable; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx index 1c7c477213070..3c8c3c1da1741 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx @@ -36,13 +36,13 @@ protected: public: - RAttrValue() : RAttrBase(), fDefault() {}; + RAttrValue() : RAttrBase(""), fDefault() {} - RAttrValue(RDrawable *drawable, const char *name, const T &dflt = T()) : RAttrBase(drawable, name), fDefault(dflt) { } + RAttrValue(RDrawable *drawable, const char *name, const T &dflt = T()) : RAttrBase(drawable, name ? name : ""), fDefault(dflt) { } - RAttrValue(RAttrBase *parent, const char *name, const T &dflt = T()) : RAttrBase(parent, name), fDefault(dflt) { } + RAttrValue(RAttrBase *parent, const char *name, const T &dflt = T()) : RAttrBase(parent, name ? name : ""), fDefault(dflt) { } - RAttrValue(const RAttrValue& src) + RAttrValue(const RAttrValue& src) : RAttrBase("") { Set(src.Get()); fDefault = src.Default(); @@ -64,7 +64,7 @@ public: return fDefault; } - const char *GetName() const { return GetPrefix() ? GetPrefix() : ""; } + const char *GetName() const { return GetPrefix(); } void Clear() override { ClearValue(GetName()); } From 68270d59ed08c5ea6e5bef755927f93ddb01c1cd Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 18 Jun 2021 18:13:03 +0200 Subject: [PATCH 277/309] [rattr] simplify default values collection and handling RAttrBase::CollectDefaults works for both aggregations and plain values --- graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx | 4 +--- graf2d/gpadv7/inc/ROOT/RAttrBase.hxx | 2 +- graf2d/gpadv7/inc/ROOT/RAttrMap.hxx | 2 -- graf2d/gpadv7/inc/ROOT/RAttrValue.hxx | 5 +++-- graf2d/gpadv7/src/RAttrAggregation.cxx | 11 +---------- graf2d/gpadv7/src/RAttrMap.cxx | 19 +++++++++++-------- 6 files changed, 17 insertions(+), 26 deletions(-) diff --git a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx index 1ce4467bb36a8..2450b927d4d15 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrAggregation.hxx @@ -28,9 +28,7 @@ class RAttrAggregation : public RAttrBase { protected: virtual const RAttrMap &GetDefaults() const; - virtual RAttrMap CollectDefaults() const; - - void AddDefaultValues(RAttrMap &) const override; + RAttrMap CollectDefaults() const override; void CopyTo(RAttrAggregation &tgt, bool use_style = true) const; diff --git a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx index 1334f8a437d28..5f5b576da1dbb 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrBase.hxx @@ -51,7 +51,7 @@ protected: RAttrBase *GetParent() const { return fKind == kParent ? fD.parent : nullptr; } RAttrMap *GetOwnAttr() const { return fKind == kOwnAttr ? fD.ownattr : nullptr; } - virtual void AddDefaultValues(RAttrMap &) const = 0; + virtual RAttrMap CollectDefaults() const = 0; /////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/gpadv7/inc/ROOT/RAttrMap.hxx b/graf2d/gpadv7/inc/ROOT/RAttrMap.hxx index 7fe616bd93eae..5650638ed2fcf 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrMap.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrMap.hxx @@ -163,8 +163,6 @@ public: } RAttrMap &AddDefaults(const RAttrBase &vis); - void AddValuesFrom(const std::string &prefix, const RAttrMap &map); - RAttrMap &AddValue(const std::string &name, bool value) { return AddBool(name, value); } RAttrMap &AddValue(const std::string &name, int value) { return AddInt(name, value); } RAttrMap &AddValue(const std::string &name, double value) { return AddDouble(name, value); } diff --git a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx index 3c8c3c1da1741..2b7700621135b 100644 --- a/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx +++ b/graf2d/gpadv7/inc/ROOT/RAttrValue.hxx @@ -29,11 +29,12 @@ protected: T fDefault; ///(thisClass->GetListOfDataMembers())) { if (data_member && data_member->GetClass() && data_member->GetClass()->InheritsFrom(baseClass) && - (data_member->GetClass()->GetBaseClassOffset(baseClass) == 0)) { + (data_member->GetClass()->GetBaseClassOffset(baseClass) == 0)) res.AddDefaults(*((const RAttrBase *)((char*) this + data_member->GetOffset()))); - } } } else { R__LOG_ERROR(GPadLog()) << "Missing dictionary for " << info.name() << " class"; @@ -54,14 +53,6 @@ RAttrMap RAttrAggregation::CollectDefaults() const return res; } -void RAttrAggregation::AddDefaultValues(RAttrMap &m) const -{ - std::string prefix = GetPrefix(); - if (!prefix.empty()) prefix.append("_"); - - m.AddValuesFrom(prefix, GetDefaults()); -} - /////////////////////////////////////////////////////////////////////////////// /// Copy attributes into target object diff --git a/graf2d/gpadv7/src/RAttrMap.cxx b/graf2d/gpadv7/src/RAttrMap.cxx index a06d721504eba..1ddd722eb2435 100644 --- a/graf2d/gpadv7/src/RAttrMap.cxx +++ b/graf2d/gpadv7/src/RAttrMap.cxx @@ -9,6 +9,7 @@ #include "ROOT/RAttrMap.hxx" #include "ROOT/RAttrBase.hxx" +#include "ROOT/RAttrAggregation.hxx" #include "ROOT/RLogger.hxx" #include @@ -47,17 +48,19 @@ template<> const RAttrMap::Value_t *RAttrMap::Value_t::GetValue(&vis) && vis.GetPrefix()) { + prefix = vis.GetPrefix(); + if (!prefix.empty()) prefix.append("_"); + } -void RAttrMap::AddValuesFrom(const std::string &prefix, const RAttrMap &map) -{ - for (const auto &entry : map) - m[prefix+entry.first] = entry.second->Copy(); -} + for (auto &entry : defaults.m) + m[prefix + entry.first] = std::move(entry.second); + return *this; +} ///////////////////////////////////////////////////////////////////////////////////////////////// /// Add attribute, converting to best possible type From 76fa2000a41ede1080650393f66f336f9baa8255 Mon Sep 17 00:00:00 2001 From: Enric Tejedor Saavedra Date: Fri, 18 Jun 2021 10:58:32 +0200 Subject: [PATCH 278/309] [PyROOT] Provide an explanatory error message when pickling cross-inheritance Python objects When a Python class derives from a C++ class, cppyy jits a C++ wrapper class that inherits from the base C++ class. Since I/O on jitted classes is not supported by ROOT, trying to pickle a cross-inheritance Python object fails. For this to work, dictionaries would need to be generated for the jitted class before serialization, and they would need to be carried along for deserialization too. Therefore, this commit replaces the previous segfault by an explanatory error message when the user tries to pickle a cross-inheritance Python object. It is suggested in the message to define a custom __reduce__ method for the derived Python class. That __reduce__ method can e.g. return a callable and some arguments with which the derived object can be constructed during deserialization, thus preventing any attempt to serialize the object itself. The old PyROOT did not jit any wrapper class during cross-inheritance (so it did not suffer from the problem described above), but serialization/deserialization of cross-inheritance Python objects was not properly supported anyway, since the class of the unpickled object was the base C++ class, not the derived Python class. --- bindings/pyroot/pythonizations/src/CPPInstancePyz.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/pyroot/pythonizations/src/CPPInstancePyz.cxx b/bindings/pyroot/pythonizations/src/CPPInstancePyz.cxx index 33fdc13cc16d6..d5acfe6035081 100644 --- a/bindings/pyroot/pythonizations/src/CPPInstancePyz.cxx +++ b/bindings/pyroot/pythonizations/src/CPPInstancePyz.cxx @@ -83,13 +83,20 @@ PyObject *op_reduce(CPPInstance *self, PyObject * /*args*/) if (s_bfClass == self->ObjectIsA()) { buff = (TBufferFile *)self->GetObject(); } else { + auto className = Cppyy::GetScopedFinalName(self->ObjectIsA()); + if (className.find("__cppyy_internal::Dispatcher") == 0) { + PyErr_Format(PyExc_IOError, "generic streaming of Python objects whose class derives from a C++ class is not supported. " + "Please refer to the Python pickle documentation for instructions on how to define " + "a custom __reduce__ method for the derived Python class"); + return 0; + } // no cast is needed, but WriteObject taking a TClass argument is protected, // so use WriteObjectAny() static TBufferFile s_buff(TBuffer::kWrite); s_buff.Reset(); // to delete if (s_buff.WriteObjectAny(self->GetObject(), - TClass::GetClass(Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str())) != 1) { + TClass::GetClass(className.c_str())) != 1) { PyErr_Format(PyExc_IOError, "could not stream object of type %s", Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str()); return 0; From 19929b63022af972f3fa78041026c047ee0e3fc8 Mon Sep 17 00:00:00 2001 From: chenxu <6235641+cxwx@users.noreply.github.com> Date: Mon, 21 Jun 2021 20:51:40 +0800 Subject: [PATCH 279/309] Update concurrentfill.cxx (#8492) error: reference to 'Experimental' is ambiguous Experimental::RH2D hist{{100, 0., 1.}, {{0., 1., 2., 3., 10.}}}; ^ ...root.../include/ROOT/RLogger.hxx:28:11: note: candidate found by name lookup is 'ROOT::Experimental' namespace Experimental { ^ ...root.../include/TMVA/RBDT.hxx:31:11: note: candidate found by name lookup is 'TMVA::Experimental' namespace Experimental { --- tutorials/v7/concurrentfill.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tutorials/v7/concurrentfill.cxx b/tutorials/v7/concurrentfill.cxx index 276d5e7d11dfd..409fb77c9eac3 100644 --- a/tutorials/v7/concurrentfill.cxx +++ b/tutorials/v7/concurrentfill.cxx @@ -23,7 +23,7 @@ #include #include -using namespace ROOT; +using namespace ROOT::Experimental; double wasteCPUTime(std::mt19937 &gen) { @@ -33,7 +33,7 @@ double wasteCPUTime(std::mt19937 &gen) std::generate_canonical(gen); } -using Filler_t = Experimental::RHistConcurrentFiller; +using Filler_t = RHistConcurrentFiller; /// This function is called within each thread: it spends some CPU time and then /// fills a number into the histogram, through the Filler_t. This is repeated @@ -47,7 +47,7 @@ void theTask(Filler_t filler) } /// This example fills a histogram concurrently, from several threads. -void concurrentHistFill(Experimental::RH2D &hist) +void concurrentHistFill(RH2D &hist) { // RHistConcurrentFillManager allows multiple threads to fill the histogram // concurrently. @@ -55,7 +55,7 @@ void concurrentHistFill(Experimental::RH2D &hist) // Details: each thread's Fill() calls are buffered. once the buffer is full, // the RHistConcurrentFillManager locks and flushes the buffer into the // histogram. - Experimental::RHistConcurrentFillManager fillMgr(hist); + RHistConcurrentFillManager fillMgr(hist); std::array threads; @@ -73,7 +73,7 @@ void concurrentHistFill(Experimental::RH2D &hist) void concurrentfill() { // This histogram will be filled from several threads. - Experimental::RH2D hist{{100, 0., 1.}, {{0., 1., 2., 3., 10.}}}; + RH2D hist{{100, 0., 1.}, {{0., 1., 2., 3., 10.}}}; concurrentHistFill(hist); From 7a2171255cfeb79976b7b1e4f922f1f57eb3bbec Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 21 Jun 2021 15:21:01 +0200 Subject: [PATCH 280/309] Revert "Update concurrentfill.cxx (#8492)" This reverts commit 19929b63022af972f3fa78041026c047ee0e3fc8. --- tutorials/v7/concurrentfill.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tutorials/v7/concurrentfill.cxx b/tutorials/v7/concurrentfill.cxx index 409fb77c9eac3..276d5e7d11dfd 100644 --- a/tutorials/v7/concurrentfill.cxx +++ b/tutorials/v7/concurrentfill.cxx @@ -23,7 +23,7 @@ #include #include -using namespace ROOT::Experimental; +using namespace ROOT; double wasteCPUTime(std::mt19937 &gen) { @@ -33,7 +33,7 @@ double wasteCPUTime(std::mt19937 &gen) std::generate_canonical(gen); } -using Filler_t = RHistConcurrentFiller; +using Filler_t = Experimental::RHistConcurrentFiller; /// This function is called within each thread: it spends some CPU time and then /// fills a number into the histogram, through the Filler_t. This is repeated @@ -47,7 +47,7 @@ void theTask(Filler_t filler) } /// This example fills a histogram concurrently, from several threads. -void concurrentHistFill(RH2D &hist) +void concurrentHistFill(Experimental::RH2D &hist) { // RHistConcurrentFillManager allows multiple threads to fill the histogram // concurrently. @@ -55,7 +55,7 @@ void concurrentHistFill(RH2D &hist) // Details: each thread's Fill() calls are buffered. once the buffer is full, // the RHistConcurrentFillManager locks and flushes the buffer into the // histogram. - RHistConcurrentFillManager fillMgr(hist); + Experimental::RHistConcurrentFillManager fillMgr(hist); std::array threads; @@ -73,7 +73,7 @@ void concurrentHistFill(RH2D &hist) void concurrentfill() { // This histogram will be filled from several threads. - RH2D hist{{100, 0., 1.}, {{0., 1., 2., 3., 10.}}}; + Experimental::RH2D hist{{100, 0., 1.}, {{0., 1., 2., 3., 10.}}}; concurrentHistFill(hist); From 4f0a53076d0c71859b619807ff20638f34bb1f37 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 18 Jun 2021 23:23:52 +0200 Subject: [PATCH 281/309] [RF] Add missing nullptr check to removeCommon helper in RooProdPdf This fixes a bug recently introduced by commit bdf75028147. --- roofit/roofitcore/src/RooProdPdf.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index c3287f79c23a5..8cc87cfd44948 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -565,7 +565,7 @@ void removeCommon(std::vector &v, std::span other for (auto const& arg : other) { auto namePtrMatch = [&arg](const RooAbsArg* elm) { - return elm->namePtr() == arg->namePtr(); + return elm != nullptr && elm->namePtr() == arg->namePtr(); }; auto found = std::find_if(v.begin(), v.end(), namePtrMatch); From 855fd44340e13161f88ca09a86e50abf5c1cd5a1 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 21 Jun 2021 11:32:11 +0200 Subject: [PATCH 282/309] [RF] Fix missing initializer warnings in MemPoolForRooSets.h (2nd try) This PR should finally fix the build warnings in the master nightlies, after the unsuccessful fix attempt in commit 4ed5ea3976743d1206a8f8c7579adeb1818a9695. I have checked that the missing field initializer warnings go away with this change by compiling the following example snippet under gcc48: ```C++ // compile with g++ -Wmissing-field-initializers -std=c++11 -o test test.cc struct A{ A() : arr_{{}} {} std::array arr_ = {{}}; }; int main() { A a{}; std::cout << a.arr_[0] << std::endl; return 0; } ``` The warnings are reproduced, and can successfully be suppressed by replacing `{}` with `{{}}`. --- roofit/roofitcore/src/MemPoolForRooSets.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roofit/roofitcore/src/MemPoolForRooSets.h b/roofit/roofitcore/src/MemPoolForRooSets.h index 16f853c491d39..694e68ce99002 100644 --- a/roofit/roofitcore/src/MemPoolForRooSets.h +++ b/roofit/roofitcore/src/MemPoolForRooSets.h @@ -64,7 +64,7 @@ class MemPoolForRooSets { : ownedMemory{static_cast(TStorage::ObjectAlloc(2 * POOLSIZE * sizeof(RooSet_t)))}, memBegin{ownedMemory}, nextItem{ownedMemory}, memEnd{memBegin + 2 * POOLSIZE}, - cycle{} + cycle{{}} {} Arena(const Arena &) = delete; @@ -74,7 +74,7 @@ class MemPoolForRooSets { refCount{other.refCount}, totCount{other.totCount}, assigned{other.assigned}, - cycle{} + cycle{{}} { // Needed for unique ownership other.ownedMemory = nullptr; @@ -197,7 +197,7 @@ class MemPoolForRooSets { std::size_t totCount = 0; std::bitset assigned = {}; - std::array cycle = {}; + std::array cycle = {{}}; }; From aa4efb77a607ed31efb19dbf956dc55fe5903794 Mon Sep 17 00:00:00 2001 From: Advait Dhingra <62119114+AdvaitDhingra@users.noreply.github.com> Date: Mon, 21 Jun 2021 18:37:43 +0200 Subject: [PATCH 283/309] TTree::GetEntry() entry parameter default value fix (#8425) Remove default value for the entry parameter in TTree::GetEntry and GetEvent. --- tree/tree/inc/TTree.h | 4 ++-- tree/tree/src/TTree.cxx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tree/tree/inc/TTree.h b/tree/tree/inc/TTree.h index 729210b151a09..e6d323f0e48da 100644 --- a/tree/tree/inc/TTree.h +++ b/tree/tree/inc/TTree.h @@ -460,8 +460,8 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker virtual Long64_t GetEntriesFast() const { return fEntries; } virtual Long64_t GetEntriesFriend() const; virtual Long64_t GetEstimate() const { return fEstimate; } - virtual Int_t GetEntry(Long64_t entry = 0, Int_t getall = 0); - Int_t GetEvent(Long64_t entry = 0, Int_t getall = 0) { return GetEntry(entry, getall); } + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0); + Int_t GetEvent(Long64_t entry, Int_t getall = 0) { return GetEntry(entry, getall); } virtual Int_t GetEntryWithIndex(Int_t major, Int_t minor = 0); virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor = 0) const; virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor = 0) const; diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 7af2c7b9b8e37..59c53f6b36236 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -5581,7 +5581,6 @@ Long64_t TTree::GetEntriesFriend() const Int_t TTree::GetEntry(Long64_t entry, Int_t getall) { - // We already have been visited while recursively looking // through the friends tree, let return if (kGetEntry & fFriendLockStatus) return 0; From 05bc521abea1b507928044316bba73dba0394d85 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 21 Jun 2021 13:47:49 +0200 Subject: [PATCH 284/309] [RF][Tutorials] Avoid race condition in RooFit python tutorials The rf503_wspaceread tutorial mus be run after the rf502_wspacewrite tutorial in the unit tests. This dependency was already defined for the C++ tutorial tests. The lines added to `tutorials/CMakeLists.txt` in this commit make the same definitions for the Python tutorials, and also indicate that the Python tests rf502 and rf503 should be run after the C++ tests to avoid a race condition on the output file. --- tutorials/CMakeLists.txt | 9 ++++++++- tutorials/roofit/rf503_wspaceread.C | 2 +- tutorials/roofit/rf503_wspaceread.py | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index ebfcc7fb50b2e..bd4c2b44c19a7 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -649,7 +649,14 @@ if(ROOT_pyroot_FOUND) tutorial-pyroot-ntuple1-py) set(pyroot-fit1-depends tutorial-pyroot-fillrandom-py) set(pyroot-na49view-depends tutorial-pyroot-geometry-py) - set(roofit-rf104_classfactory-depends tutorial-roofit-rf104_classfactory) #Race condition + + # Avoid a race condition: make sure Python tutorial is ran after C++ tutorial + set(roofit-rf104_classfactory-depends tutorial-roofit-rf104_classfactory) + + # The rf502 rf503 python tests should not be run at the same time as the C++ tests + # to avoid a race condidtionrf503_workspace.root file. + set(roofit-rf502_wspacewrite-depends tutorial-roofit-rf503_wspaceread) + set(roofit-rf503_wspaceread-depends tutorial-roofit-rf502_wspacewrite-py) #---------------------------------------------------------------------- # List requirements for python tutorials. diff --git a/tutorials/roofit/rf503_wspaceread.C b/tutorials/roofit/rf503_wspaceread.C index 1da06cb8a99fb..8c263cb34714a 100644 --- a/tutorials/roofit/rf503_wspaceread.C +++ b/tutorials/roofit/rf503_wspaceread.C @@ -31,7 +31,7 @@ void rf503_wspaceread() // R e a d w o r k s p a c e f r o m f i l e // ----------------------------------------------- - // Open input file with workspace (generated by rf14_wspacewrite) + // Open input file with workspace (generated by rf503_wspacewrite) TFile *f = new TFile("rf502_workspace.root"); // Retrieve workspace from file diff --git a/tutorials/roofit/rf503_wspaceread.py b/tutorials/roofit/rf503_wspaceread.py index 4a3d25fe790e7..6bc13f41fc285 100644 --- a/tutorials/roofit/rf503_wspaceread.py +++ b/tutorials/roofit/rf503_wspaceread.py @@ -20,7 +20,7 @@ # Read workspace from file # ----------------------------------------------- -# Open input file with workspace (generated by rf14_wspacewrite) +# Open input file with workspace (generated by rf503_wspacewrite) f = ROOT.TFile("rf502_workspace.root") # Retrieve workspace from file From d1b4256e9349ff54bf5c16029eadf91ba313332c Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Mon, 21 Jun 2021 18:58:37 +0200 Subject: [PATCH 285/309] [RF][Tutorials] Rename output file of rf502_wspacewrite_py Rename output file of rf502_wspacewrite Python tutorial to be different from output file name of the rf502_wspacewrite C++ version. This allows the tutorials in both languages to run concurrently. --- tutorials/CMakeLists.txt | 6 +----- tutorials/roofit/rf502_wspacewrite.py | 2 +- tutorials/roofit/rf503_wspaceread.py | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index bd4c2b44c19a7..c1b10ab9dabc1 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -649,15 +649,11 @@ if(ROOT_pyroot_FOUND) tutorial-pyroot-ntuple1-py) set(pyroot-fit1-depends tutorial-pyroot-fillrandom-py) set(pyroot-na49view-depends tutorial-pyroot-geometry-py) + set(roofit-rf503_wspaceread-depends tutorial-roofit-rf502_wspacewrite-py) # Avoid a race condition: make sure Python tutorial is ran after C++ tutorial set(roofit-rf104_classfactory-depends tutorial-roofit-rf104_classfactory) - # The rf502 rf503 python tests should not be run at the same time as the C++ tests - # to avoid a race condidtionrf503_workspace.root file. - set(roofit-rf502_wspacewrite-depends tutorial-roofit-rf503_wspaceread) - set(roofit-rf503_wspaceread-depends tutorial-roofit-rf502_wspacewrite-py) - #---------------------------------------------------------------------- # List requirements for python tutorials. # To add a new requirement, add a glob expression that's named requires_, diff --git a/tutorials/roofit/rf502_wspacewrite.py b/tutorials/roofit/rf502_wspacewrite.py index 3400f1968d93f..f495e1aef322b 100644 --- a/tutorials/roofit/rf502_wspacewrite.py +++ b/tutorials/roofit/rf502_wspacewrite.py @@ -61,4 +61,4 @@ # ------------------------------------------- # Save the workspace into a ROOT file -w.writeToFile("rf502_workspace.root") +w.writeToFile("rf502_workspace_py.root") diff --git a/tutorials/roofit/rf503_wspaceread.py b/tutorials/roofit/rf503_wspaceread.py index 6bc13f41fc285..d78a3318ad702 100644 --- a/tutorials/roofit/rf503_wspaceread.py +++ b/tutorials/roofit/rf503_wspaceread.py @@ -21,7 +21,7 @@ # ----------------------------------------------- # Open input file with workspace (generated by rf503_wspacewrite) -f = ROOT.TFile("rf502_workspace.root") +f = ROOT.TFile("rf502_workspace_py.root") # Retrieve workspace from file w = f.Get("w") From 498ad04d5a66486570598e0f625a33b4430e0208 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 22 Jun 2021 13:56:31 +0200 Subject: [PATCH 286/309] [cmake] update urls in windows installer --- cmake/modules/CMakeCPackOptions.cmake.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/modules/CMakeCPackOptions.cmake.in b/cmake/modules/CMakeCPackOptions.cmake.in index 84692d56cbd6f..3a08ac967cef5 100644 --- a/cmake/modules/CMakeCPackOptions.cmake.in +++ b/cmake/modules/CMakeCPackOptions.cmake.in @@ -38,9 +38,9 @@ if(CPACK_GENERATOR MATCHES "NSIS") set(CPACK_NSIS_MUI_UNIICON "@CMAKE_SOURCE_DIR@\\icons\\RootIcon.ico") set(CPACK_NSIS_DISPLAY_NAME "ROOT @ROOT_VERSION@") set(CPACK_NSIS_PACKAGE_NAME "ROOT @ROOT_VERSION@") - set(CPACK_NSIS_HELP_LINK "http:\\\\root.cern") - set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\root.cern\\about-root") - set(CPACK_NSIS_CONTACT "roottalk@cern.ch") + set(CPACK_NSIS_HELP_LINK "https:\\\\root.cern") + set(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\root.cern\\about") + set(CPACK_NSIS_CONTACT "root-dev@cern.ch") set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_NSIS_INSTALL_ROOT "C:") # Register .root file type From e1bdaf6163a34a65f86a8bc7f9c49a0255f85987 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Tue, 22 Jun 2021 14:24:12 +0200 Subject: [PATCH 287/309] Implement SetStats for TGraph. (#8498) As requested here: https://root-forum.cern.ch/t/remove-stats-box-from-fitted-tgraph/45490 --- README/ReleaseNotes/v626/index.md | 2 ++ hist/hist/inc/TGraph.h | 2 ++ hist/hist/src/TGraph.cxx | 24 ++++++++++++++++++++++++ hist/histpainter/src/TGraphPainter.cxx | 2 +- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/README/ReleaseNotes/v626/index.md b/README/ReleaseNotes/v626/index.md index b3176680f961c..1f921d8dffda1 100644 --- a/README/ReleaseNotes/v626/index.md +++ b/README/ReleaseNotes/v626/index.md @@ -63,6 +63,8 @@ The following people have contributed to this new version: ## Histogram Libraries +- Implement the `SetStats` method for `TGraph` to turn ON or OFF the statistics box display + for an individual `TGraph`. ## Math Libraries diff --git a/hist/hist/inc/TGraph.h b/hist/hist/inc/TGraph.h index e7e59efa7fae4..879b6266d930b 100644 --- a/hist/hist/inc/TGraph.h +++ b/hist/hist/inc/TGraph.h @@ -67,6 +67,7 @@ class TGraph : public TNamed, public TAttLine, public TAttFill, public TAttMarke public: // TGraph status bits enum EStatusBits { + kNoStats = BIT(9), ///< Don't draw stats box kClipFrame = BIT(10), ///< Clip to the frame boundary kResetHisto = BIT(17), ///< fHistogram must be reset in GetHistogram kNotEditable = BIT(18), ///< Bit set if graph is non editable @@ -182,6 +183,7 @@ class TGraph : public TNamed, public TAttLine, public TAttFill, public TAttMarke virtual void SetPointY(Int_t i, Double_t y); virtual void SetName(const char *name=""); // *MENU* virtual void SetNameTitle(const char *name="", const char *title=""); + virtual void SetStats(Bool_t stats=kTRUE); // *MENU* virtual void SetTitle(const char *title=""); // *MENU* virtual void Sort(Bool_t (*greater)(const TGraph*, Int_t, Int_t)=&TGraph::CompareX, Bool_t ascending=kTRUE, Int_t low=0, Int_t high=-1111); diff --git a/hist/hist/src/TGraph.cxx b/hist/hist/src/TGraph.cxx index 7eabb07dbaf17..269564cac1427 100644 --- a/hist/hist/src/TGraph.cxx +++ b/hist/hist/src/TGraph.cxx @@ -2362,6 +2362,30 @@ void TGraph::SetNameTitle(const char *name, const char *title) SetTitle(title); } +//////////////////////////////////////////////////////////////////////////////// +/// Set statistics option on/off. +/// +/// By default, the statistics box is drawn. +/// The paint options can be selected via gStyle->SetOptStats. +/// This function sets/resets the kNoStats bit in the graph object. +/// It has priority over the Style option. + +void TGraph::SetStats(Bool_t stats) +{ + ResetBit(kNoStats); + if (!stats) { + SetBit(kNoStats); + //remove the "stats" object from the list of functions + if (fFunctions) { + TObject *obj = fFunctions->FindObject("stats"); + if (obj) { + fFunctions->Remove(obj); + delete obj; + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// if size*2 <= fMaxSize allocate new arrays of size points, /// copy points [0,oend). diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx index 6912ea8937c66..7098ecfa4401e 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -1268,7 +1268,7 @@ void TGraphPainter::PaintHelper(TGraph *theGraph, Option_t *option) } } } - if (fit) PaintStats(theGraph, fit); + if (fit && !theGraph->TestBit(TGraph::kNoStats)) PaintStats(theGraph, fit); } } From 71e0b990b889ff292be5bfa79d1f85e15440eaa5 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 22 Jun 2021 16:03:46 -0500 Subject: [PATCH 288/309] Remove stray debug print out. It was inadvertently introduced in 82fad768c9a In TBranchElement::Print use the correct StreamerInfo in case of schema evolution --- tree/tree/src/TBranchElement.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx index ab171eee2ed72..ce1ff9e9b528b 100644 --- a/tree/tree/src/TBranchElement.cxx +++ b/tree/tree/src/TBranchElement.cxx @@ -3758,7 +3758,6 @@ static void PrintElements(const TStreamerInfo *info, const TStreamerInfoActions: Error("TBranchElement::Print", "Element for id #%d not found in StreamerInfo for %s", id, info->GetName()); info->ls(); - TClass::GetClass("PFTauWith")->GetStreamerInfos()->ls(); } } else if (cursor.fNestedIDs) { Printf(" Within subobject of type %s offset = %d", cursor.fNestedIDs->fInfo->GetName(), cursor.fNestedIDs->fOffset); From e1da585b10d780ef70e933e54347e135415a6016 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Wed, 23 Jun 2021 09:05:59 +0200 Subject: [PATCH 289/309] [skip-ci] Fix a few typos in roofit (#8508) --- roofit/roofit/src/Roo2DKeysPdf.cxx | 2 +- roofit/roofit/src/RooBukinPdf.cxx | 4 ++-- roofit/roofit/src/RooExponential.cxx | 3 +-- roofit/roofit/src/RooLagrangianMorphFunc.cxx | 22 ++++++++++---------- roofit/roofit/src/RooParamHistFunc.cxx | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/roofit/roofit/src/Roo2DKeysPdf.cxx b/roofit/roofit/src/Roo2DKeysPdf.cxx index e67195683ad68..5e23fa8dcef54 100644 --- a/roofit/roofit/src/Roo2DKeysPdf.cxx +++ b/roofit/roofit/src/Roo2DKeysPdf.cxx @@ -182,7 +182,7 @@ Int_t Roo2DKeysPdf::loadDataSet(RooDataSet& data, TString options) } if(bad) { - cout << "Roo2DKeysPdf::Roo2DKeysPdf Unable to initilize object; incompatible RooDataSet doesn't contain"< RooBukinPdf::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const { return RooBatchCompute::dispatch->computeBukin(this, evalData, x->getValues(evalData, normSet), Xp->getValues(evalData, normSet), sigp->getValues(evalData, normSet), xi->getValues(evalData, normSet), rho1->getValues(evalData, normSet), rho2->getValues(evalData, normSet)); } diff --git a/roofit/roofit/src/RooExponential.cxx b/roofit/roofit/src/RooExponential.cxx index ffb15893446d0..26bb2ea23a419 100644 --- a/roofit/roofit/src/RooExponential.cxx +++ b/roofit/roofit/src/RooExponential.cxx @@ -55,7 +55,6 @@ RooExponential::RooExponential(const RooExponential& other, const char* name) : } //////////////////////////////////////////////////////////////////////////////// -///cout << "exp(x=" << x << ",c=" << c << ")=" << exp(c*x) << endl ; Double_t RooExponential::evaluate() const{ return exp(c*x); @@ -88,7 +87,7 @@ Double_t RooExponential::analyticalIntegral(Int_t code, const char* rangeName) c } //////////////////////////////////////////////////////////////////////////////// -/// Compute multiple values of Exponential distribution. +/// Compute multiple values of Exponential distribution. RooSpan RooExponential::evaluateSpan(RooBatchCompute::RunContext& evalData, const RooArgSet* normSet) const { return RooBatchCompute::dispatch->computeExponential(this, evalData, x->getValues(evalData, normSet), c->getValues(evalData, normSet)); } diff --git a/roofit/roofit/src/RooLagrangianMorphFunc.cxx b/roofit/roofit/src/RooLagrangianMorphFunc.cxx index 3020be805feaf..45cd2ba9e573f 100644 --- a/roofit/roofit/src/RooLagrangianMorphFunc.cxx +++ b/roofit/roofit/src/RooLagrangianMorphFunc.cxx @@ -17,7 +17,7 @@ /** \class RooLagrangianMorphFunc \ingroup Roofit Class RooLagrangianMorphing is a implementation of the method of Effective -Lagrangian Morphing, descibed in ATL-PHYS-PUB-2015-047. +Lagrangian Morphing, described in ATL-PHYS-PUB-2015-047. Effective Lagrangian Morphing is a method to construct a continuous signal model in the coupling parameter space. Basic assumption is that shape and cross section of a physical distribution is proportional to it's @@ -233,7 +233,7 @@ inline SuperFloat invertMatrix(const Matrix &matrix, Matrix &inverse) { ::writeMatrixToStreamT(matrix, ss); cxcoutP(Eval) << ss.str << std::endl; } - // backsubstitute to get the inverse + // back-substitute to get the inverse lu_substitute(lu, pm, inverse); } catch (boost::numeric::ublas::internal_logic &error) { // coutE(Eval) << "boost::numberic::ublas error: matrix is not invertible!" @@ -461,7 +461,7 @@ void readValues(std::map & myMap, /////////////////////////////////////////////////////////////////////////////// /// retrieve the param_hists file and return a map of the parameter values /// by providing a list of names, only the param_hists of those subfolders are -/// read leaving the list empty is interpreted as meaning 'read everyting' +/// read leaving the list empty is interpreted as meaning 'read everything' template void readValues(std::map> & inputParameters, @@ -2050,7 +2050,7 @@ void RooLagrangianMorphFunc::Config::setVertices( //} //////////////////////////////////////////////////////////////////////////////// -/// set values to paramerter set (-?-) +/// set values to parameter set (-?-) void RooLagrangianMorphFunc::Config::append( RooLagrangianMorphFunc::ParamSet &set, const char *str, double val) { @@ -2121,7 +2121,7 @@ void RooLagrangianMorphFunc::printSamples() const { } //////////////////////////////////////////////////////////////////////////////// -/// print the current phyiscs values +/// print the current physics values void RooLagrangianMorphFunc::printPhysics() const { for (const auto &sample : this->_sampleMap) { @@ -3042,7 +3042,7 @@ int RooLagrangianMorphFunc::nPolynomials() const { } //////////////////////////////////////////////////////////////////////////////// -/// print the contributing smaples and their respective weights +/// print the contributing samples and their respective weights void RooLagrangianMorphFunc::printEvaluation() const { auto mf = std::make_unique(*(this->getFunc())); @@ -3194,7 +3194,7 @@ Double_t RooLagrangianMorphFunc::expectedEvents(const RooArgSet &nset) const { return createPdf()->expectedEvents(&nset); } //////////////////////////////////////////////////////////////////////////////// -/// return the expected uncertainity for the current parameter set +/// return the expected uncertainty for the current parameter set double RooLagrangianMorphFunc::expectedUncertainty() const { RooRealVar *observable = this->getObservable(); @@ -3266,7 +3266,7 @@ void RooLagrangianMorphFunc::printCouplings() const { } //////////////////////////////////////////////////////////////////////////////// -/// retrive the lsit of bin boundaries +/// retrieve the list of bin boundaries std::list * RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, Double_t xlo, @@ -3275,7 +3275,7 @@ RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, Double_t xlo, } //////////////////////////////////////////////////////////////////////////////// -/// retrive the sample Hint +/// retrieve the sample Hint std::list * RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, Double_t xlo, @@ -3302,7 +3302,7 @@ Double_t RooLagrangianMorphFunc::evaluate() const { if (pdf) return this->_scale * pdf->getVal(_curNormSet); else - std::cerr << "unable to aquire in-built function!" << std::endl; + std::cerr << "unable to acquire in-built function!" << std::endl; return 0.; } @@ -3388,7 +3388,7 @@ TMatrixD RooLagrangianMorphFunc::getInvertedMatrix() const { } //////////////////////////////////////////////////////////////////////////////// -/// Reterieve the condition of the coefficient matrix. If the condition number +/// Retrieve the condition of the coefficient matrix. If the condition number /// is very large, then the matrix is ill-conditioned and is almost singular. /// The computation of the inverse is prone to large numerical errors diff --git a/roofit/roofit/src/RooParamHistFunc.cxx b/roofit/roofit/src/RooParamHistFunc.cxx index ec6d3393e9647..ecdabd1dcf121 100644 --- a/roofit/roofit/src/RooParamHistFunc.cxx +++ b/roofit/roofit/src/RooParamHistFunc.cxx @@ -13,7 +13,7 @@ * \f] * * The \f$ \gamma_i \f$ can therefore be used to parametrise statistical uncertainties of the histogram - * template. In conjuction with a constraint term, this can be used to implement the Barlow-Beeston method. + * template. In conjunction with a constraint term, this can be used to implement the Barlow-Beeston method. * The constraint can be implemented using RooHistConstraint. * * See also the tutorial rf709_BarlowBeeston.C From d026b4918a696e6c8a5ef2c15985c8b9d98da2b2 Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Tue, 22 Jun 2021 15:04:10 +0200 Subject: [PATCH 290/309] [cling] Also fwd decl underlying type of using decls: Before, only the using decl itself was forward declared, causing undeclared identifiers in forward declaration code, as witnessed in https://github.com/root-project/root/issues/8499 Given the similarity of using and typedef, merge both into a single function, making sure both have the same featureset, and through that fixing this issue as a side-effect. --- .../lib/Interpreter/ForwardDeclPrinter.cpp | 57 +++++++++++-------- .../lib/Interpreter/ForwardDeclPrinter.h | 3 + 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.cpp b/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.cpp index 889eb585aea70..810cb4aa9572b 100644 --- a/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.cpp +++ b/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.cpp @@ -298,7 +298,7 @@ namespace cling { } } - void ForwardDeclPrinter::VisitTypedefDecl(TypedefDecl *D) { + void ForwardDeclPrinter::printTypedefOrAliasDecl(TypedefNameDecl *D) { QualType q = D->getTypeSourceInfo()->getType(); Visit(q); if (m_SkipFlag) { @@ -308,34 +308,45 @@ namespace cling { std::string closeBraces = PrintEnclosingDeclContexts(Out(), D->getDeclContext()); - if (!m_Policy.SuppressSpecifiers) - Out() << "typedef "; - if (D->isModulePrivate()) - Out() << "__module_private__ "; + auto printUnderying = [&]() { + QualType qNoRestrict = q; + if (qNoRestrict.isRestrictQualified()) + qNoRestrict.removeLocalRestrict(); + qNoRestrict.print(Out(), m_Policy); + }; + auto printDeclName = [&]() { + if (D->isModulePrivate()) + Out() << "__module_private__ "; - if (q.isRestrictQualified()){ - q.removeLocalRestrict(); - q.print(Out(), m_Policy, ""); - Out() << " __restrict " << D->getName(); //TODO: Find some policy that does this automatically - } - else { - q.print(Out(), m_Policy, D->getName()); + if (q.isRestrictQualified()) { + Out() << " __restrict "; // TODO: Find some policy that does this automatically + } + Out() << D->getName(); + prettyPrintAttributes(D); + }; + + if (llvm::isa(D)) { + Out() << "typedef "; + printUnderying(); + Out() << " "; + printDeclName(); + } else if (llvm::isa(D)) { + Out() << "using "; + printDeclName(); + Out() << " = "; + printUnderying(); + } else { + skipDecl(D, "Neither a typedef nor a type alias!"); } - prettyPrintAttributes(D); Out() << ';' << closeBraces << '\n'; + } + + void ForwardDeclPrinter::VisitTypedefDecl(TypedefDecl *D) { + printTypedefOrAliasDecl(D); } void ForwardDeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { - /*FIXME: Ugly Hack*/ -// if(!D->getLexicalDeclContext()->isNamespace() -// && !D->getLexicalDeclContext()->isFileContext()) -// return; - std::string closeBraces = PrintEnclosingDeclContexts(Out(), - D->getDeclContext()); - Out() << "using " << *D; - prettyPrintAttributes(D); - Out() << " = " << D->getTypeSourceInfo()->getType().getAsString(m_Policy) - << ';' << closeBraces << '\n'; + printTypedefOrAliasDecl(D); } void ForwardDeclPrinter::VisitEnumDecl(EnumDecl *D) { diff --git a/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.h b/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.h index 8311be287d813..a4b0c68c932ff 100644 --- a/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.h +++ b/interpreter/cling/lib/Interpreter/ForwardDeclPrinter.h @@ -79,6 +79,7 @@ namespace clang { class TranslationUnitDecl; class TypeAliasDecl; class TypedefDecl; + class TypedefNameDecl; class VarDecl; class UsingDirectiveDecl; } @@ -109,6 +110,8 @@ namespace cling { std::set m_BuiltinNames; IgnoreFilesFunc_t m_IgnoreFile; // Call back to ignore some top level files. + void printTypedefOrAliasDecl(clang::TypedefNameDecl* D); + public: ForwardDeclPrinter(llvm::raw_ostream& OutS, llvm::raw_ostream& LogS, From 4ccd20e11555290b4c0ab76486452aca7bb3c6c6 Mon Sep 17 00:00:00 2001 From: Enric Tejedor Saavedra Date: Wed, 23 Jun 2021 14:09:11 +0200 Subject: [PATCH 291/309] [JupyROOT][6974] Import get_ipython explicitly in JsMVA --- bindings/jsmva/python/JsMVA/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/jsmva/python/JsMVA/__init__.py b/bindings/jsmva/python/JsMVA/__init__.py index d227863decad7..92f9c0b185d23 100644 --- a/bindings/jsmva/python/JsMVA/__init__.py +++ b/bindings/jsmva/python/JsMVA/__init__.py @@ -3,6 +3,7 @@ # @package JsMVA # @author Attila Bagoly +from IPython import get_ipython from IPython.core.extensions import ExtensionManager ## This function will register JsMVAMagic class to ipython @@ -11,4 +12,4 @@ def loadExtensions(): extMgr = ExtensionManager(ip) extMgr.load_extension("JsMVA.JsMVAMagic") -loadExtensions() \ No newline at end of file +loadExtensions() From 86f17eba38ec97153328c459f1efade18fb9eafe Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Wed, 23 Jun 2021 17:43:38 +0200 Subject: [PATCH 292/309] RANLUX++: Add compatibility engines (#8383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These engines can be used to obtain the same sequences of numbers as RANLUX generators using recursive subtract-with-borrow steps, but with enhanced performance. Apart from the choice of parameters, the main difference between the various implementations is the way of seeding the initial state of the generator. This commit includes engines for compatibility with: * the original implementation by Fred James, with parameters for - luxury level 3 (p = 223), also matching gsl_rng_ranlux - luxury level 4 (p = 389), also matching gsl_rng_ranlux389 producing floating point numbers from 24 bits of randomness; * the family of generators using a second-generation version of the RANLUX algorithm as implemented in the GNU Scientific Library: - gsl_rng_ranlxs[012] using 24 bits per floating point number, and - gsl_rng_ranlxd[12] using 48 bits per floating point number; * the implementation by Martin Lüscher written in C that uses four states per generator; similar to GSL, there are ranlxs[012] with 24 bits per number and ranlxd[12] with 48 bits per number; and * the generators std::ranlux{24,48} defined by the C++ standard. The values in the tests were extracted directly from the mentioned implementations, showing that the LCG implementation is equivalent to the RANLUX algorithm. I am not adding compatibility engines for CLHEP because its semantics are very weird: While CLHEP::RanluxEngine::setSeed yields the same sequences as the original implementation by James, the seed is treated differently when passed as an argument to the constructor. --- math/mathcore/inc/Math/RanluxppEngine.h | 247 ++++++++- math/mathcore/src/RanluxppEngineImpl.cxx | 609 ++++++++++++++++++++++- math/mathcore/test/RanluxppEngine.cxx | 459 ++++++++++++++++- 3 files changed, 1300 insertions(+), 15 deletions(-) diff --git a/math/mathcore/inc/Math/RanluxppEngine.h b/math/mathcore/inc/Math/RanluxppEngine.h index bfef96bc7735c..d790f75027988 100644 --- a/math/mathcore/inc/Math/RanluxppEngine.h +++ b/math/mathcore/inc/Math/RanluxppEngine.h @@ -2,7 +2,7 @@ // Author: Jonas Hahnfeld 11/2020 /************************************************************************* - * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -20,14 +20,15 @@ namespace ROOT { namespace Math { -template +template class RanluxppEngineImpl; template class RanluxppEngine final : public TRandomEngine { private: - std::unique_ptr> fImpl; + using ImplType = RanluxppEngineImpl<48, p>; + std::unique_ptr fImpl; public: RanluxppEngine(uint64_t seed = 314159265); @@ -55,6 +56,246 @@ using RanluxppEngine2048 = RanluxppEngine<2048>; extern template class RanluxppEngine<24>; extern template class RanluxppEngine<2048>; + +template +class RanluxppCompatEngineJames final : public TRandomEngine { + +private: + using ImplType = RanluxppEngineImpl<24, p>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineJames(uint64_t seed = 314159265); + virtual ~RanluxppCompatEngineJames(); + + /// Generate a floating point random number with 24 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 24 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatJames"; } +}; + +/// Compatibility engine for original RANLUX implementation by James, luxury +/// level 3 (p = 223). The sequence of numbers also matches `gsl_rng_ranlux`. +using RanluxppCompatEngineJamesP3 = RanluxppCompatEngineJames<223>; +/// Compatibility engine for original RANLUX implementation by James, luxury +/// level 4 (p = 389). The sequence of numbers also matches `gsl_rng_ranlux389`. +using RanluxppCompatEngineJamesP4 = RanluxppCompatEngineJames<389>; + +extern template class RanluxppCompatEngineJames<223>; +extern template class RanluxppCompatEngineJames<389>; + + +/// Compatibility engine for `gsl_rng_ranlxs*` from the GNU Scientific Library. +template +class RanluxppCompatEngineGslRanlxs final : public TRandomEngine { + +private: + using ImplType = RanluxppEngineImpl<24, p>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineGslRanlxs(uint64_t seed = 1); + virtual ~RanluxppCompatEngineGslRanlxs(); + + /// Generate a floating point random number with 24 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 24 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatGslRanlxs"; } +}; + +using RanluxppCompatEngineGslRanlxs0 = RanluxppCompatEngineGslRanlxs<218>; +using RanluxppCompatEngineGslRanlxs1 = RanluxppCompatEngineGslRanlxs<404>; +using RanluxppCompatEngineGslRanlxs2 = RanluxppCompatEngineGslRanlxs<794>; + +extern template class RanluxppCompatEngineGslRanlxs<218>; +extern template class RanluxppCompatEngineGslRanlxs<404>; +extern template class RanluxppCompatEngineGslRanlxs<794>; + + +/// Compatibility engine for `gsl_rng_ranlxd*` from the GNU Scientific Library. +template +class RanluxppCompatEngineGslRanlxd final : public TRandomEngine { + +private: + using ImplType = RanluxppEngineImpl<48, p>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineGslRanlxd(uint64_t seed = 1); + virtual ~RanluxppCompatEngineGslRanlxd(); + + /// Generate a floating point random number with 48 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 48 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatGslRanlxd"; } +}; + +using RanluxppCompatEngineGslRanlxd1 = RanluxppCompatEngineGslRanlxd<404>; +using RanluxppCompatEngineGslRanlxd2 = RanluxppCompatEngineGslRanlxd<794>; + +extern template class RanluxppCompatEngineGslRanlxd<404>; +extern template class RanluxppCompatEngineGslRanlxd<794>; + + +template +class RanluxppCompatEngineLuescherImpl; + +/// Compatibility engine for Lüscher's ranlxs implementation written in C. +template +class RanluxppCompatEngineLuescherRanlxs final : public TRandomEngine { + +private: + using ImplType = RanluxppCompatEngineLuescherImpl<24, p>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineLuescherRanlxs(uint64_t seed = 314159265); + virtual ~RanluxppCompatEngineLuescherRanlxs(); + + /// Generate a floating point random number with 24 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 24 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatLuescherRanlxs"; } +}; + +using RanluxppCompatEngineLuescherRanlxs0 = RanluxppCompatEngineLuescherRanlxs<218>; +using RanluxppCompatEngineLuescherRanlxs1 = RanluxppCompatEngineLuescherRanlxs<404>; +using RanluxppCompatEngineLuescherRanlxs2 = RanluxppCompatEngineLuescherRanlxs<794>; + +extern template class RanluxppCompatEngineLuescherRanlxs<218>; +extern template class RanluxppCompatEngineLuescherRanlxs<404>; +extern template class RanluxppCompatEngineLuescherRanlxs<794>; + + +/// Compatibility engine for Lüscher's ranlxd implementation written in C. +template +class RanluxppCompatEngineLuescherRanlxd final : public TRandomEngine { + +private: + using ImplType = RanluxppCompatEngineLuescherImpl<48, p>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineLuescherRanlxd(uint64_t seed = 314159265); + virtual ~RanluxppCompatEngineLuescherRanlxd(); + + /// Generate a floating point random number with 48 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 48 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatLuescherRanlxd"; } +}; +using RanluxppCompatEngineLuescherRanlxd1 = RanluxppCompatEngineLuescherRanlxd<404>; +using RanluxppCompatEngineLuescherRanlxd2 = RanluxppCompatEngineLuescherRanlxd<794>; + +extern template class RanluxppCompatEngineLuescherRanlxd<404>; +extern template class RanluxppCompatEngineLuescherRanlxd<794>; + + +/// Compatibility engine for `std::ranlux24` from the C++ standard. +class RanluxppCompatEngineStdRanlux24 final : public TRandomEngine { + +private: + using ImplType = RanluxppEngineImpl<24, 223, 23>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineStdRanlux24(uint64_t seed = 19780503); + virtual ~RanluxppCompatEngineStdRanlux24(); + + /// Generate a floating point random number with 24 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 24 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatStdRanlux24"; } +}; + + +/// Compatibility engine for `std::ranlux48` from the C++ standard. +class RanluxppCompatEngineStdRanlux48 final : public TRandomEngine { + +private: + using ImplType = RanluxppEngineImpl<48, 2 * 389, 11>; + std::unique_ptr fImpl; + +public: + RanluxppCompatEngineStdRanlux48(uint64_t seed = 19780503); + virtual ~RanluxppCompatEngineStdRanlux48(); + + /// Generate a floating point random number with 48 bits of randomness + double Rndm() override; + /// Generate a floating point random number (non-virtual method) + double operator()(); + /// Generate a random integer value with 48 bits + uint64_t IntRndm(); + + /// Initialize and seed the state of the generator + void SetSeed(uint64_t seed); + /// Skip `n` random numbers without generating them + void Skip(uint64_t n); + + /// Get name of the generator + static const char *Name() { return "RanluxppCompatStdRanlux48"; } +}; + } // end namespace Math } // end namespace ROOT diff --git a/math/mathcore/src/RanluxppEngineImpl.cxx b/math/mathcore/src/RanluxppEngineImpl.cxx index 83ecbd7f576d3..100f8d8638765 100644 --- a/math/mathcore/src/RanluxppEngineImpl.cxx +++ b/math/mathcore/src/RanluxppEngineImpl.cxx @@ -2,7 +2,7 @@ // Author: Jonas Hahnfeld 11/2020 /************************************************************************* - * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -49,6 +49,18 @@ namespace { // Variable templates are a feature of C++14, use the older technique of having // a static member in a template class. +// The coefficients have been determined using Python, and in parts compared to the values given by Sibidanov. +// +// >>> def print_hex(a): +// ... while a > 0: +// ... print('{0:#018x}'.format(a & 0xffffffffffffffff)) +// ... a >>= 64 +// ... +// >>> m = 2 ** 576 - 2 ** 240 + 1 +// >>> a = m - (m - 1) // 2 ** 24 +// >>> kA = pow(a, , m) +// >>> print_hex(kA) + template struct RanluxppData; @@ -56,15 +68,73 @@ template <> struct RanluxppData<24> { static const uint64_t kA[9]; }; +// Also given by Sibidanov const uint64_t RanluxppData<24>::kA[] = { 0x0000000000000000, 0x0000000000000000, 0x0000000000010000, 0xfffe000000000000, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffeffffffff, 0xffffffffffffffff, }; +template <> +struct RanluxppData<218> { + static const uint64_t kA[9]; +}; +const uint64_t RanluxppData<218>::kA[] = { + 0xf445fffffffffd94, 0xfffffd74ffffffff, 0x000000000ba5ffff, 0xfc76000000000942, 0xfffffaaaffffffff, + 0x0000000000b0ffff, 0x027b0000000007d1, 0xfffff96000000000, 0xfffffffff8e4ffff, +}; + +template <> +struct RanluxppData<223> { + static const uint64_t kA[9]; +}; +// Also given by Sibidanov +const uint64_t RanluxppData<223>::kA[] = { + 0x0000000ba6000000, 0x0a00000000094200, 0xffeef0fffffffffa, 0xfffffffe25ffffff, 0x7b0000000007d0ff, + 0xfff9600000000002, 0xfffffff8e4ffffff, 0xba00000000026cff, 0x00028b000000000b, +}; + +template <> +struct RanluxppData<389> { + static const uint64_t kA[9]; +}; +// Also given by Sibidanov +const uint64_t RanluxppData<389>::kA[] = { + 0x00002ecac9000000, 0x740000002c389600, 0xb9c8a6ffffffe525, 0xfffff593cfffffff, 0xab0000001e93f2ff, + 0xe4ab160000000d92, 0xffffdf6604ffffff, 0x020000000b9242ff, 0x0df0600000002ee0, +}; + +template <> +struct RanluxppData<404> { + static const uint64_t kA[9]; +}; +const uint64_t RanluxppData<404>::kA[] = { + 0x2eabffffffc9d08b, 0x00012612ffffff99, 0x0000007c3ebe0000, 0x353600000047bba1, 0xffd3c769ffffffd1, + 0x0000001ada8bffff, 0x6c30000000463759, 0xffb2a1440000000a, 0xffffffc634beffff, +}; + +template <> +struct RanluxppData<778> { + static const uint64_t kA[9]; +}; +const uint64_t RanluxppData<778>::kA[] = { + 0x872de42d9dca512b, 0xdbf015ea1662f8a0, 0x01f48f0d28482e96, 0x392fca0b3be2ae04, 0xed00881af896ce54, + 0x14f0a768664013f3, 0x9489f52deb1f7f80, 0x72139804e09c0f37, 0x2146b0bb92a2f9a4, +}; + +template <> +struct RanluxppData<794> { + static const uint64_t kA[9]; +}; +const uint64_t RanluxppData<794>::kA[] = { + 0x428df7227a2ca7c9, 0xde32225faaa74b1a, 0x4b9d965ca1ebd668, 0x78d15f59e58e2aff, 0x240fea15e99d075f, + 0xfe0b70f2d7b7d169, 0x75a535f4c41d51fb, 0x1a5ef0b7233b93e1, 0xbc787ca783d5d5a9, +}; + template <> struct RanluxppData<2048> { static const uint64_t kA[9]; }; +// Also given by Sibidanov const uint64_t RanluxppData<2048>::kA[] = { 0xed7faa90747aaad9, 0x4cec2c78af55c101, 0xe64dcb31c48228ec, 0x6d8a15a13bee7cb0, 0x20b2ca60cb78c509, 0x256c3d3c662ea36c, 0xff74e54107684ed2, 0x492edfcc0cc8e753, 0xb48c187cf5b22097, @@ -75,8 +145,10 @@ const uint64_t RanluxppData<2048>::kA[] = { namespace ROOT { namespace Math { -template +template class RanluxppEngineImpl { + // Needs direct access to private members to initialize its four states. + friend class RanluxppCompatEngineLuescherImpl; private: uint64_t fState[9]; ///< RANLUX state of the generator @@ -84,18 +156,31 @@ class RanluxppEngineImpl { int fPosition = 0; ///< Current position in bits static constexpr const uint64_t *kA = RanluxppData

::kA; - static constexpr int kMaxPos = 9 * 64; + static constexpr int kMaxPos = (u == 0) ? 9 * 64 : u * w; + static_assert(kMaxPos <= 576, "maximum position larger than 576 bits"); - /// Produce next block of random bits - void Advance() + /// Advance with given multiplier + void Advance(const uint64_t *a) { uint64_t lcg[9]; to_lcg(fState, fCarry, lcg); - mulmod(kA, lcg); + mulmod(a, lcg); to_ranlux(lcg, fState, fCarry); fPosition = 0; } + /// Produce next block of random bits + void Advance() + { + Advance(kA); + } + + /// Skip 24 RANLUX numbers + void Skip24() + { + Advance(RanluxppData<24>::kA); + } + public: /// Return the next random bits, generate a new block if necessary uint64_t NextRandomBits() @@ -128,8 +213,84 @@ class RanluxppEngineImpl { return bits * div; } - /// Initialize and seed the state of the generator - void SetSeed(uint64_t s) + /// Initialize and seed the state of the generator as in James' implementation + void SetSeedJames(uint64_t s) + { + // Multiplicative Congruential generator using formula constants of L'Ecuyer + // as described in "A review of pseudorandom number generators" (Fred James) + // published in Computer Physics Communications 60 (1990) pages 329-344. + int64_t seed = s; + auto next = [&]() { + const int a = 0xd1a4, b = 0x9c4e, c = 0x2fb3, d = 0x7fffffab; + int64_t k = seed / a; + seed = b * (seed - k * a) - k * c ; + if (seed < 0) seed += d; + return seed & 0xffffff; + }; + + // Iteration is reversed because the first number from the MCG goes to the + // highest position. + for (int i = 6; i >= 0; i -= 3) { + uint64_t r[8]; + for (int j = 0; j < 8; j++) { + r[j] = next(); + } + + fState[i+0] = r[7] + (r[6] << 24) + (r[5] << 48); + fState[i+1] = (r[5] >> 16) + (r[4] << 8) + (r[3] << 32) + (r[2] << 56); + fState[i+2] = (r[2] >> 8) + (r[1] << 16) + (r[0] << 40); + } + fCarry = !seed; + + Skip24(); + } + + /// Initialize and seed the state of the generator as in gsl_rng_ranlx* + void SetSeedGsl(uint32_t s, bool ranlxd) + { + if (s == 0) { + // The default seed for gsl_rng_ranlx* is 1. + s = 1; + } + + uint32_t bits = s; + auto next_bit = [&]() { + int b13 = (bits >> 18) & 0x1; + int b31 = bits & 0x1; + uint32_t bn = b13 ^ b31; + bits = (bn << 30) + (bits >> 1); + return b31; + }; + auto next = [&]() { + uint64_t ix = 0; + for (int i = 0; i < 48; i++) { + int iy = next_bit(); + if (ranlxd) { + iy = (iy + 1) % 2; + } + ix = 2 * ix + iy; + } + return ix; + }; + + for (int i = 0; i < 9; i += 3) { + uint64_t r[4]; + for (int j = 0; j < 4; j++) { + r[j] = next(); + } + + fState[i+0] = r[0] + (r[1] << 48); + fState[i+1] = (r[1] >> 16) + (r[2] << 32); + fState[i+2] = (r[2] >> 32) + (r[3] << 16); + } + + fCarry = 0; + fPosition = 0; + Advance(); + } + + /// Initialize and seed the state of the generator as proposed by Sibidanov + void SetSeedSibidanov(uint64_t s) { uint64_t lcg[9]; lcg[0] = 1; @@ -149,6 +310,61 @@ class RanluxppEngineImpl { fPosition = 0; } + /// Initialize and seed the state of the generator as described by the C++ standard + void SetSeedStd24(uint64_t s) + { + // Seed LCG with given parameters. + uint64_t seed = s; + const uint64_t a = 40014, m = 2147483563; + auto next = [&]() { + seed = (a * seed) % m; + return seed & 0xffffff; + }; + + for (int i = 0; i < 9; i += 3) { + uint64_t r[8]; + for (int j = 0; j < 8; j++) { + r[j] = next(); + } + + fState[i+0] = r[0] + (r[1] << 24) + (r[2] << 48); + fState[i+1] = (r[2] >> 16) + (r[3] << 8) + (r[4] << 32) + (r[5] << 56); + fState[i+2] = (r[5] >> 8) + (r[6] << 16) + (r[7] << 40); + } + fCarry = !seed; + + Skip24(); + } + + /// Initialize and seed the state of the generator as described by the C++ standard + void SetSeedStd48(uint64_t s) + { + // Seed LCG with given parameters. + uint64_t seed = s; + const uint64_t a = 40014, m = 2147483563; + auto next = [&]() { + seed = (a * seed) % m; + uint64_t result = seed; + seed = (a * seed) % m; + result += seed << 32; + return result & 0xffffffffffff; + }; + + for (int i = 0; i < 9; i += 3) { + uint64_t r[4]; + for (int j = 0; j < 4; j++) { + r[j] = next(); + } + + fState[i+0] = r[0] + (r[1] << 48); + fState[i+1] = (r[1] >> 16) + (r[2] << 32); + fState[i+2] = (r[2] >> 32) + (r[3] << 16); + } + fCarry = !seed; + + Skip24(); + } + /// Skip `n` random numbers without generating them void Skip(uint64_t n) { @@ -183,9 +399,9 @@ class RanluxppEngineImpl { }; template -RanluxppEngine

::RanluxppEngine(uint64_t seed) : fImpl(new RanluxppEngineImpl<48, p>) +RanluxppEngine

::RanluxppEngine(uint64_t seed) : fImpl(new ImplType) { - fImpl->SetSeed(seed); + this->SetSeed(seed); } template @@ -212,7 +428,7 @@ uint64_t RanluxppEngine

::IntRndm() template void RanluxppEngine

::SetSeed(uint64_t seed) { - fImpl->SetSeed(seed); + fImpl->SetSeedSibidanov(seed); } template @@ -224,5 +440,376 @@ void RanluxppEngine

::Skip(uint64_t n) template class RanluxppEngine<24>; template class RanluxppEngine<2048>; + +template +RanluxppCompatEngineJames

::RanluxppCompatEngineJames(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +template +RanluxppCompatEngineJames

::~RanluxppCompatEngineJames() = default; + +template +double RanluxppCompatEngineJames

::Rndm() +{ + return (*this)(); +} + +template +double RanluxppCompatEngineJames

::operator()() +{ + return fImpl->NextRandomFloat(); +} + +template +uint64_t RanluxppCompatEngineJames

::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +template +void RanluxppCompatEngineJames

::SetSeed(uint64_t seed) +{ + fImpl->SetSeedJames(seed); +} + +template +void RanluxppCompatEngineJames

::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + +template class RanluxppCompatEngineJames<223>; +template class RanluxppCompatEngineJames<389>; + + +template +RanluxppCompatEngineGslRanlxs

::RanluxppCompatEngineGslRanlxs(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +template +RanluxppCompatEngineGslRanlxs

::~RanluxppCompatEngineGslRanlxs() = default; + +template +double RanluxppCompatEngineGslRanlxs

::Rndm() +{ + return (*this)(); +} + +template +double RanluxppCompatEngineGslRanlxs

::operator()() +{ + return fImpl->NextRandomFloat(); +} + +template +uint64_t RanluxppCompatEngineGslRanlxs

::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +template +void RanluxppCompatEngineGslRanlxs

::SetSeed(uint64_t seed) +{ + fImpl->SetSeedGsl(seed, /*ranlxd=*/false); +} + +template +void RanluxppCompatEngineGslRanlxs

::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + +template class RanluxppCompatEngineGslRanlxs<218>; +template class RanluxppCompatEngineGslRanlxs<404>; +template class RanluxppCompatEngineGslRanlxs<794>; + + +template +RanluxppCompatEngineGslRanlxd

::RanluxppCompatEngineGslRanlxd(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +template +RanluxppCompatEngineGslRanlxd

::~RanluxppCompatEngineGslRanlxd() = default; + +template +double RanluxppCompatEngineGslRanlxd

::Rndm() +{ + return (*this)(); +} + +template +double RanluxppCompatEngineGslRanlxd

::operator()() +{ + return fImpl->NextRandomFloat(); +} + +template +uint64_t RanluxppCompatEngineGslRanlxd

::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +template +void RanluxppCompatEngineGslRanlxd

::SetSeed(uint64_t seed) +{ + fImpl->SetSeedGsl(seed, /*ranlxd=*/true); +} + +template +void RanluxppCompatEngineGslRanlxd

::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + +template class RanluxppCompatEngineGslRanlxd<404>; +template class RanluxppCompatEngineGslRanlxd<794>; + + +template +class RanluxppCompatEngineLuescherImpl { + +private: + RanluxppEngineImpl fStates[4]; ///< The states of this generator + int fNextState = 0; ///< The index of the next state + +public: + /// Return the next random bits, generate a new block if necessary + uint64_t NextRandomBits() + { + uint64_t bits = fStates[fNextState].NextRandomBits(); + fNextState = (fNextState + 1) % 4; + return bits; + } + + /// Return a floating point number, converted from the next random bits. + double NextRandomFloat() + { + double number = fStates[fNextState].NextRandomFloat(); + fNextState = (fNextState + 1) % 4; + return number; + } + + /// Initialize and seed the state of the generator as in Lüscher's ranlxs + void SetSeed(uint32_t s, bool ranlxd) + { + uint32_t bits = s; + auto next_bit = [&]() { + int b13 = (bits >> 18) & 0x1; + int b31 = bits & 0x1; + uint32_t bn = b13 ^ b31; + bits = (bn << 30) + (bits >> 1); + return b31; + }; + auto next = [&]() { + uint64_t ix = 0; + for (int l = 0; l < 24; l++) { + ix = 2 * ix + next_bit(); + } + return ix; + }; + + for (int i = 0; i < 4; i++) { + auto &state = fStates[i]; + for (int j = 0; j < 9; j += 3) { + uint64_t r[8]; + for (int m = 0; m < 8; m++) { + uint64_t ix = next(); + // Lüscher's implementation uses k = (j / 3) * 8 + m, so only + // the value of m is important for (k % 4). + if ((!ranlxd && (m % 4) == i) || (ranlxd && (m % 4) != i)) { + ix = 16777215 - ix; + } + r[m] = ix; + } + + state.fState[j+0] = r[0] + (r[1] << 24) + (r[2] << 48); + state.fState[j+1] = (r[2] >> 16) + (r[3] << 8) + (r[4] << 32) + (r[5] << 56); + state.fState[j+2] = (r[5] >> 8) + (r[6] << 16) + (r[7] << 40); + } + + state.fCarry = 0; + state.fPosition = 0; + state.Advance(); + } + + fNextState = 0; + } + + /// Skip `n` random numbers without generating them + void Skip(uint64_t n) + { + uint64_t nPerState = n / 4; + int remainder = n % 4; + for (int i = 0; i < 4; i++) { + int idx = (fNextState + i) % 4; + uint64_t nForThisState = nPerState; + if (i < remainder) { + nForThisState++; + } + fStates[idx].Skip(nForThisState); + } + // Switch the next state according to the remainder. + fNextState = (fNextState + remainder) % 4; + } +}; + +template +RanluxppCompatEngineLuescherRanlxs

::RanluxppCompatEngineLuescherRanlxs(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +template +RanluxppCompatEngineLuescherRanlxs

::~RanluxppCompatEngineLuescherRanlxs() = default; + +template +double RanluxppCompatEngineLuescherRanlxs

::Rndm() +{ + return (*this)(); +} + +template +double RanluxppCompatEngineLuescherRanlxs

::operator()() +{ + return fImpl->NextRandomFloat(); +} + +template +uint64_t RanluxppCompatEngineLuescherRanlxs

::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +template +void RanluxppCompatEngineLuescherRanlxs

::SetSeed(uint64_t seed) +{ + fImpl->SetSeed(seed, /*ranlxd=*/false); +} + +template +void RanluxppCompatEngineLuescherRanlxs

::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + +template class RanluxppCompatEngineLuescherRanlxs<218>; +template class RanluxppCompatEngineLuescherRanlxs<404>; +template class RanluxppCompatEngineLuescherRanlxs<794>; + + +template +RanluxppCompatEngineLuescherRanlxd

::RanluxppCompatEngineLuescherRanlxd(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +template +RanluxppCompatEngineLuescherRanlxd

::~RanluxppCompatEngineLuescherRanlxd() = default; + +template +double RanluxppCompatEngineLuescherRanlxd

::Rndm() +{ + return (*this)(); +} + +template +double RanluxppCompatEngineLuescherRanlxd

::operator()() +{ + return fImpl->NextRandomFloat(); +} + +template +uint64_t RanluxppCompatEngineLuescherRanlxd

::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +template +void RanluxppCompatEngineLuescherRanlxd

::SetSeed(uint64_t seed) +{ + fImpl->SetSeed(seed, /*ranlxd=*/true); +} + +template +void RanluxppCompatEngineLuescherRanlxd

::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + +template class RanluxppCompatEngineLuescherRanlxd<404>; +template class RanluxppCompatEngineLuescherRanlxd<794>; + + +RanluxppCompatEngineStdRanlux24::RanluxppCompatEngineStdRanlux24(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +RanluxppCompatEngineStdRanlux24::~RanluxppCompatEngineStdRanlux24() = default; + +double RanluxppCompatEngineStdRanlux24::Rndm() +{ + return (*this)(); +} + +double RanluxppCompatEngineStdRanlux24::operator()() +{ + return fImpl->NextRandomFloat(); +} + +uint64_t RanluxppCompatEngineStdRanlux24::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +void RanluxppCompatEngineStdRanlux24::SetSeed(uint64_t seed) +{ + fImpl->SetSeedStd24(seed); +} + +void RanluxppCompatEngineStdRanlux24::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + + +RanluxppCompatEngineStdRanlux48::RanluxppCompatEngineStdRanlux48(uint64_t seed) : fImpl(new ImplType) +{ + this->SetSeed(seed); +} + +RanluxppCompatEngineStdRanlux48::~RanluxppCompatEngineStdRanlux48() = default; + +double RanluxppCompatEngineStdRanlux48::Rndm() +{ + return (*this)(); +} + +double RanluxppCompatEngineStdRanlux48::operator()() +{ + return fImpl->NextRandomFloat(); +} + +uint64_t RanluxppCompatEngineStdRanlux48::IntRndm() +{ + return fImpl->NextRandomBits(); +} + +void RanluxppCompatEngineStdRanlux48::SetSeed(uint64_t seed) +{ + fImpl->SetSeedStd48(seed); +} + +void RanluxppCompatEngineStdRanlux48::Skip(uint64_t n) +{ + fImpl->Skip(n); +} + } // end namespace Math } // end namespace ROOT diff --git a/math/mathcore/test/RanluxppEngine.cxx b/math/mathcore/test/RanluxppEngine.cxx index 258d90a055a7a..79c90237722e6 100644 --- a/math/mathcore/test/RanluxppEngine.cxx +++ b/math/mathcore/test/RanluxppEngine.cxx @@ -2,7 +2,7 @@ // Author: Jonas Hahnfeld 11/2020 /************************************************************************* - * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -46,3 +46,460 @@ TEST(RanluxppEngine, random2048) EXPECT_EQ(rng.IntRndm(), 49145148745150); EXPECT_EQ(rng.Rndm(), 0.74670661284082484599); } + +TEST(RanluxppCompatEngineJames, P3) +{ + RanluxppCompatEngineJamesP3 rng(314159265); + + // These values match: gsl_rng_ranlux, ranluxI_James, ranluxpp_James + EXPECT_EQ(rng.Rndm(), 0.53981816768646240234); + EXPECT_EQ(rng.Rndm(), 0.76155042648315429688); + EXPECT_EQ(rng.Rndm(), 0.06029939651489257812); + EXPECT_EQ(rng.Rndm(), 0.79600262641906738281); + EXPECT_EQ(rng.Rndm(), 0.30631220340728759766); + + // Skip to the 24th number, right before the LCG is used to advance the state. + rng.Skip(18); + EXPECT_EQ(rng.Rndm(), 0.20569473505020141602); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.76727509498596191406); + + // Skip to the 101st number. + rng.Skip(75); + EXPECT_EQ(rng.Rndm(), 0.43156743049621582031); + EXPECT_EQ(rng.Rndm(), 0.03774416446685791016); + EXPECT_EQ(rng.Rndm(), 0.24897110462188720703); + EXPECT_EQ(rng.Rndm(), 0.00147783756256103516); + EXPECT_EQ(rng.Rndm(), 0.90274453163146972656); +} + +TEST(RanluxppCompatEngineJames, P4) +{ + RanluxppCompatEngineJamesP4 rng(314159265); + + // These values match: gsl_rng_ranlux389 + EXPECT_EQ(rng.Rndm(), 0.53981816768646240234); + EXPECT_EQ(rng.Rndm(), 0.76155042648315429688); + EXPECT_EQ(rng.Rndm(), 0.06029939651489257812); + EXPECT_EQ(rng.Rndm(), 0.79600262641906738281); + EXPECT_EQ(rng.Rndm(), 0.30631220340728759766); + + // Skip to the 24th number, right before the LCG is used to advance the state. + rng.Skip(18); + EXPECT_EQ(rng.Rndm(), 0.20569473505020141602); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.84534603357315063477); + + // Skip to the 101st number. + rng.Skip(75); + EXPECT_EQ(rng.Rndm(), 0.67576026916503906250); + EXPECT_EQ(rng.Rndm(), 0.90395343303680419922); + EXPECT_EQ(rng.Rndm(), 0.31414842605590820312); + EXPECT_EQ(rng.Rndm(), 0.98801732063293457031); + EXPECT_EQ(rng.Rndm(), 0.93221199512481689453); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs0) +{ + RanluxppCompatEngineGslRanlxs0 rng(314159265); + + // These values match: gsl_rng_ranlxs0 + EXPECT_EQ(rng.Rndm(), 0.95476531982421875000); + EXPECT_EQ(rng.Rndm(), 0.10175001621246337891); + EXPECT_EQ(rng.Rndm(), 0.03923547267913818359); + EXPECT_EQ(rng.Rndm(), 0.23141473531723022461); + EXPECT_EQ(rng.Rndm(), 0.56545680761337280273); + + // Skip to the 24th number, right before the LCG is used to advance the state. + rng.Skip(18); + EXPECT_EQ(rng.Rndm(), 0.66594201326370239258); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.08081126213073730469); + + // Skip to the 101st number. + rng.Skip(75); + EXPECT_EQ(rng.Rndm(), 0.74328583478927612305); + EXPECT_EQ(rng.Rndm(), 0.79350239038467407227); + EXPECT_EQ(rng.Rndm(), 0.09384918212890625000); + EXPECT_EQ(rng.Rndm(), 0.00877797603607177734); + EXPECT_EQ(rng.Rndm(), 0.81286895275115966797); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs0_default) +{ + RanluxppCompatEngineGslRanlxs0 rng; + EXPECT_EQ(rng.Rndm(), 0.32085895538330078125); + + rng.SetSeed(0); + EXPECT_EQ(rng.Rndm(), 0.32085895538330078125); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs1) +{ + RanluxppCompatEngineGslRanlxs1 rng(314159265); + + // These values match: gsl_rng_ranlxs1 + EXPECT_EQ(rng.Rndm(), 0.64368855953216552734); + EXPECT_EQ(rng.Rndm(), 0.67669576406478881836); + EXPECT_EQ(rng.Rndm(), 0.21001303195953369141); + EXPECT_EQ(rng.Rndm(), 0.27618223428726196289); + EXPECT_EQ(rng.Rndm(), 0.04699170589447021484); + + // Skip to the 24th number, right before the LCG is used to advance the state. + rng.Skip(18); + EXPECT_EQ(rng.Rndm(), 0.81624960899353027344); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.52857619524002075195); + + // Skip to the 101st number. + rng.Skip(75); + EXPECT_EQ(rng.Rndm(), 0.76676791906356811523); + EXPECT_EQ(rng.Rndm(), 0.28538894653320312500); + EXPECT_EQ(rng.Rndm(), 0.30258500576019287109); + EXPECT_EQ(rng.Rndm(), 0.38395434617996215820); + EXPECT_EQ(rng.Rndm(), 0.50305640697479248047); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs1_default) +{ + RanluxppCompatEngineGslRanlxs1 rng; + EXPECT_EQ(rng.Rndm(), 0.06963491439819335938); + + rng.SetSeed(0); + EXPECT_EQ(rng.Rndm(), 0.06963491439819335938); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs2) +{ + RanluxppCompatEngineGslRanlxs2 rng(314159265); + + // These values match: gsl_rng_ranlxs2 + EXPECT_EQ(rng.Rndm(), 0.84824979305267333984); + EXPECT_EQ(rng.Rndm(), 0.75232243537902832031); + EXPECT_EQ(rng.Rndm(), 0.12018418312072753906); + EXPECT_EQ(rng.Rndm(), 0.05532860755920410156); + EXPECT_EQ(rng.Rndm(), 0.05795300006866455078); + + // Skip to the 24th number, right before the LCG is used to advance the state. + rng.Skip(18); + EXPECT_EQ(rng.Rndm(), 0.13871461153030395508); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.97801673412322998047); + + // Skip to the 101st number. + rng.Skip(75); + EXPECT_EQ(rng.Rndm(), 0.92746645212173461914); + EXPECT_EQ(rng.Rndm(), 0.82626664638519287109); + EXPECT_EQ(rng.Rndm(), 0.77763950824737548828); + EXPECT_EQ(rng.Rndm(), 0.49001514911651611328); + EXPECT_EQ(rng.Rndm(), 0.88770687580108642578); +} + +TEST(RanluxppCompatEngineGslRanlxs, ranlxs2_default) +{ + RanluxppCompatEngineGslRanlxs2 rng; + EXPECT_EQ(rng.Rndm(), 0.53008824586868286133); + + rng.SetSeed(0); + EXPECT_EQ(rng.Rndm(), 0.53008824586868286133); +} + +TEST(RanluxppCompatEngineGslRanlxd, ranlxd1) +{ + RanluxppCompatEngineGslRanlxd1 rng(314159265); + + // These values match: gsl_rng_ranlxd1 + EXPECT_EQ(rng.Rndm(), 0.32330420393203596063); + EXPECT_EQ(rng.Rndm(), 0.72381776078560733367); + EXPECT_EQ(rng.Rndm(), 0.88817512439535306612); + EXPECT_EQ(rng.Rndm(), 0.04598644245910676887); + EXPECT_EQ(rng.Rndm(), 0.76110447268111158792); + + // Skip to the 12th number, right before the LCG is used to advance the state. + rng.Skip(6); + EXPECT_EQ(rng.Rndm(), 0.18375035143688478456); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.83312931792853106572); + + // Skip to the 101st number. + rng.Skip(87); + EXPECT_EQ(rng.Rndm(), 0.49329437415119770094); + EXPECT_EQ(rng.Rndm(), 0.37550852748539753634); + EXPECT_EQ(rng.Rndm(), 0.93543254436396239271); + EXPECT_EQ(rng.Rndm(), 0.43517686324045001811); + EXPECT_EQ(rng.Rndm(), 0.77751776122982363404); +} + +TEST(RanluxppCompatEngineGslRanlxd, ranlxd1_default) +{ + RanluxppCompatEngineGslRanlxd1 rng; + EXPECT_EQ(rng.Rndm(), 0.83451879245814453157); + + rng.SetSeed(0); + EXPECT_EQ(rng.Rndm(), 0.83451879245814453157); +} + +TEST(RanluxppCompatEngineGslRanlxd, ranlxd2) +{ + RanluxppCompatEngineGslRanlxd2 rng(314159265); + + // These values match: gsl_rng_ranlxd2 + EXPECT_EQ(rng.Rndm(), 0.28994560412829528673); + EXPECT_EQ(rng.Rndm(), 0.06729010717305428102); + EXPECT_EQ(rng.Rndm(), 0.69404482039860582177); + EXPECT_EQ(rng.Rndm(), 0.56285566362747729841); + EXPECT_EQ(rng.Rndm(), 0.34655505440137091000); + + // Skip to the 12th number, right before the LCG is used to advance the state. + rng.Skip(6); + EXPECT_EQ(rng.Rndm(), 0.12507187350916737500); + // The LCG advances for the next call: + EXPECT_EQ(rng.Rndm(), 0.97552452698574398937); + + // Skip to the 101st number. + rng.Skip(87); + EXPECT_EQ(rng.Rndm(), 0.85118391727546338643); + EXPECT_EQ(rng.Rndm(), 0.94509863457767551154); + EXPECT_EQ(rng.Rndm(), 0.29384155017066149185); + EXPECT_EQ(rng.Rndm(), 0.48683495244473462549); + EXPECT_EQ(rng.Rndm(), 0.70125558306756730076); +} + +TEST(RanluxppCompatEngineGslRanlxd, ranlxd2_default) +{ + RanluxppCompatEngineGslRanlxd2 rng; + EXPECT_EQ(rng.Rndm(), 0.07725383918716843823); + + rng.SetSeed(0); + EXPECT_EQ(rng.Rndm(), 0.07725383918716843823); +} + +TEST(RanluxppCompatEngineLuescherRanlxs, ranlxs0) +{ + RanluxppCompatEngineLuescherRanlxs0 rng(314159265); + + // These values match: ranlxs0 + EXPECT_EQ(rng.Rndm(), 0.65404480695724487305); + EXPECT_EQ(rng.Rndm(), 0.08226150274276733398); + EXPECT_EQ(rng.Rndm(), 0.29213166236877441406); + EXPECT_EQ(rng.Rndm(), 0.50535500049591064453); + EXPECT_EQ(rng.Rndm(), 0.95475935935974121094); + + // Skip to the 92nd number, right before the LCG is used to advance the state. + rng.Skip(87); + EXPECT_EQ(rng.Rndm(), 0.63037145137786865234); + EXPECT_EQ(rng.Rndm(), 0.82800912857055664062); + EXPECT_EQ(rng.Rndm(), 0.31651723384857177734); + EXPECT_EQ(rng.Rndm(), 0.09057545661926269531); + // The LCG advances for the next calls: + EXPECT_EQ(rng.Rndm(), 0.06262010335922241211); + EXPECT_EQ(rng.Rndm(), 0.39436388015747070312); + EXPECT_EQ(rng.Rndm(), 0.61765056848526000977); + EXPECT_EQ(rng.Rndm(), 0.14016568660736083984); + + // Skip to the 401st number. + rng.Skip(300); + EXPECT_EQ(rng.Rndm(), 0.21224951744079589844); + EXPECT_EQ(rng.Rndm(), 0.28637069463729858398); + EXPECT_EQ(rng.Rndm(), 0.01129972934722900391); + EXPECT_EQ(rng.Rndm(), 0.62236660718917846680); + EXPECT_EQ(rng.Rndm(), 0.11493819952011108398); +} + +TEST(RanluxppCompatEngineLuescherRanlxs, ranlxs1) +{ + RanluxppCompatEngineLuescherRanlxs1 rng(314159265); + + // These values match: ranlxs1 + EXPECT_EQ(rng.Rndm(), 0.90099400281906127930); + EXPECT_EQ(rng.Rndm(), 0.76765865087509155273); + EXPECT_EQ(rng.Rndm(), 0.22530400753021240234); + EXPECT_EQ(rng.Rndm(), 0.83992105722427368164); + EXPECT_EQ(rng.Rndm(), 0.59816044569015502930); + + // Skip to the 92nd number, right before the LCG is used to advance the state. + rng.Skip(87); + EXPECT_EQ(rng.Rndm(), 0.64669114351272583008); + EXPECT_EQ(rng.Rndm(), 0.46657902002334594727); + EXPECT_EQ(rng.Rndm(), 0.12610912322998046875); + EXPECT_EQ(rng.Rndm(), 0.10862994194030761719); + // The LCG advances for the next calls: + EXPECT_EQ(rng.Rndm(), 0.01416563987731933594); + EXPECT_EQ(rng.Rndm(), 0.58082711696624755859); + EXPECT_EQ(rng.Rndm(), 0.38216590881347656250); + EXPECT_EQ(rng.Rndm(), 0.91653412580490112305); + + // Skip to the 401st number. + rng.Skip(300); + EXPECT_EQ(rng.Rndm(), 0.76539427042007446289); + EXPECT_EQ(rng.Rndm(), 0.11502689123153686523); + EXPECT_EQ(rng.Rndm(), 0.40491354465484619141); + EXPECT_EQ(rng.Rndm(), 0.96093446016311645508); + EXPECT_EQ(rng.Rndm(), 0.38819086551666259766); +} + +TEST(RanluxppCompatEngineLuescherRanlxs, ranlxs2) +{ + RanluxppCompatEngineLuescherRanlxs2 rng(314159265); + + // These values match: ranlxs2 + EXPECT_EQ(rng.Rndm(), 0.60732543468475341797); + EXPECT_EQ(rng.Rndm(), 0.74212568998336791992); + EXPECT_EQ(rng.Rndm(), 0.76778668165206909180); + EXPECT_EQ(rng.Rndm(), 0.56459045410156250000); + EXPECT_EQ(rng.Rndm(), 0.51524215936660766602); + + // Skip to the 92nd number, right before the LCG is used to advance the state. + rng.Skip(87); + EXPECT_EQ(rng.Rndm(), 0.07774782180786132812); + EXPECT_EQ(rng.Rndm(), 0.12600058317184448242); + EXPECT_EQ(rng.Rndm(), 0.56134593486785888672); + EXPECT_EQ(rng.Rndm(), 0.36321890354156494141); + // The LCG advances for the next calls: + EXPECT_EQ(rng.Rndm(), 0.23446798324584960938); + EXPECT_EQ(rng.Rndm(), 0.42847990989685058594); + EXPECT_EQ(rng.Rndm(), 0.21235740184783935547); + EXPECT_EQ(rng.Rndm(), 0.30497443675994873047); + + // Skip to the 401st number. + rng.Skip(300); + EXPECT_EQ(rng.Rndm(), 0.17799735069274902344); + EXPECT_EQ(rng.Rndm(), 0.23861807584762573242); + EXPECT_EQ(rng.Rndm(), 0.65686619281768798828); + EXPECT_EQ(rng.Rndm(), 0.39222949743270874023); + EXPECT_EQ(rng.Rndm(), 0.45217937231063842773); +} + +TEST(RanluxppCompatEngineLuescherRanlxd, ranlxd1) +{ + RanluxppCompatEngineLuescherRanlxd1 rng(314159265); + + // These values match: ranlxd1 + EXPECT_EQ(rng.Rndm(), 0.40183950697007020381); + EXPECT_EQ(rng.Rndm(), 0.75729181403551848462); + EXPECT_EQ(rng.Rndm(), 0.44293039330603889425); + EXPECT_EQ(rng.Rndm(), 0.27412463825007193918); + EXPECT_EQ(rng.Rndm(), 0.90543407471131232001); + + // Skip to the 44th number, right before the LCG is used to advance the state. + rng.Skip(39); + EXPECT_EQ(rng.Rndm(), 0.35330884918042571030); + EXPECT_EQ(rng.Rndm(), 0.53342096246839787455); + EXPECT_EQ(rng.Rndm(), 0.87389084649229076263); + EXPECT_EQ(rng.Rndm(), 0.89137004735275837675); + // The LCG advances for the next calls: + EXPECT_EQ(rng.Rndm(), 0.92005646450699529737); + EXPECT_EQ(rng.Rndm(), 0.83437278691344118897); + EXPECT_EQ(rng.Rndm(), 0.96002403910338784954); + EXPECT_EQ(rng.Rndm(), 0.19537819235692666098); + + // Skip to the 401st number. + rng.Skip(348); + EXPECT_EQ(rng.Rndm(), 0.74482704516052322674); + EXPECT_EQ(rng.Rndm(), 0.36930523933338221809); + EXPECT_EQ(rng.Rndm(), 0.36572707642276824913); + EXPECT_EQ(rng.Rndm(), 0.91548098968585378543); + EXPECT_EQ(rng.Rndm(), 0.55814623941527585771); +} + +TEST(RanluxppCompatEngineLuescherRanlxd, ranlxd2) +{ + RanluxppCompatEngineLuescherRanlxd2 rng(314159265); + + // These values match: ranlxd2 + EXPECT_EQ(rng.Rndm(), 0.52702589450092673928); + EXPECT_EQ(rng.Rndm(), 0.14545363991469173470); + EXPECT_EQ(rng.Rndm(), 0.79180414135301191436); + EXPECT_EQ(rng.Rndm(), 0.07733853533090595533); + EXPECT_EQ(rng.Rndm(), 0.14180497711929263005); + + // Skip to the 44th number, right before the LCG is used to advance the state. + rng.Skip(39); + EXPECT_EQ(rng.Rndm(), 0.18603867668678475411); + EXPECT_EQ(rng.Rndm(), 0.13778587858302770996); + EXPECT_EQ(rng.Rndm(), 0.70244055389935411426); + EXPECT_EQ(rng.Rndm(), 0.90056757149901045523); + // The LCG advances for the next calls: + EXPECT_EQ(rng.Rndm(), 0.93044152534523050235); + EXPECT_EQ(rng.Rndm(), 0.99330367160287025285); + EXPECT_EQ(rng.Rndm(), 0.63528838564139178402); + EXPECT_EQ(rng.Rndm(), 0.61276861283659656010); + + // Skip to the 401st number. + rng.Skip(348); + EXPECT_EQ(rng.Rndm(), 0.37774257837078550892); + EXPECT_EQ(rng.Rndm(), 0.20167640311612444748); + EXPECT_EQ(rng.Rndm(), 0.34101141228811471251); + EXPECT_EQ(rng.Rndm(), 0.35947589472738883387); + EXPECT_EQ(rng.Rndm(), 0.51160837322844798791); +} + +TEST(RanluxppCompatEngineStdRanlux24, compare) +{ + RanluxppCompatEngineStdRanlux24 rng(314159265); + + // These values match: std::ranlux24 + EXPECT_EQ(rng.IntRndm(), 6389521); + EXPECT_EQ(rng.IntRndm(), 1245860); + EXPECT_EQ(rng.IntRndm(), 9047089); + EXPECT_EQ(rng.IntRndm(), 5613314); + EXPECT_EQ(rng.IntRndm(), 15388463); + + // Skip to the 23rd number, right before the LCG is used to advance the state. + rng.Skip(17); + EXPECT_EQ(rng.IntRndm(), 14135596); + // The LCG advances for the next call: + EXPECT_EQ(rng.IntRndm(), 1842057); + + // Skip to the 101st number. + rng.Skip(76); + EXPECT_EQ(rng.IntRndm(), 7894321); + EXPECT_EQ(rng.IntRndm(), 2634015); + EXPECT_EQ(rng.IntRndm(), 12134196); + EXPECT_EQ(rng.IntRndm(), 15231589); + EXPECT_EQ(rng.IntRndm(), 11032869); +} + +TEST(RanluxppCompatEngineStdRanlux24, default) +{ + RanluxppCompatEngineStdRanlux24 rng; + + // Skip to the 10000th number, which is specified by the standard. + rng.Skip(9999); + EXPECT_EQ(rng.IntRndm(), 9901578); +} + +TEST(RanluxppCompatEngineStdRanlux48, compare) +{ + RanluxppCompatEngineStdRanlux48 rng(314159265); + + // These values match: std::ranlux48 + EXPECT_EQ(rng.IntRndm(), 2902733192977); + EXPECT_EQ(rng.IntRndm(), 183625379875889); + EXPECT_EQ(rng.IntRndm(), 164401649471280); + EXPECT_EQ(rng.IntRndm(), 158572192479531); + EXPECT_EQ(rng.IntRndm(), 227024878504710); + + // Skip to the 11th number, right before the LCG is used to advance the state. + rng.Skip(5); + EXPECT_EQ(rng.IntRndm(), 137631957902972); + // The LCG advances for the next call: + EXPECT_EQ(rng.IntRndm(), 122438241205867); + + // Skip to the 101st number. + rng.Skip(88); + EXPECT_EQ(rng.IntRndm(), 155713325118081); + EXPECT_EQ(rng.IntRndm(), 75203262258561); + EXPECT_EQ(rng.IntRndm(), 164155826303104); + EXPECT_EQ(rng.IntRndm(), 58159697115827); + EXPECT_EQ(rng.IntRndm(), 89006261856016); +} + +TEST(RanluxppCompatEngineStdRanlux48, default) +{ + RanluxppCompatEngineStdRanlux48 rng; + + // Skip to the 10000th number, which is specified by the standard. + rng.Skip(9999); + EXPECT_EQ(rng.IntRndm(), 249142670248501); +} From 00b136828adff3108f39b9e443cf8307b5d7d0b5 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 4 Jun 2021 12:33:36 +0200 Subject: [PATCH 293/309] [RF] Fix warning about sigma parameter shadowing RooCrystalBall member This fixes warnings in the CentOS 7 build in the nightlies. --- roofit/roofit/inc/RooCrystalBall.h | 4 ++-- roofit/roofit/src/RooCrystalBall.cxx | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/roofit/roofit/inc/RooCrystalBall.h b/roofit/roofit/inc/RooCrystalBall.h index 07fab298385cf..e95b282af67f0 100644 --- a/roofit/roofit/inc/RooCrystalBall.h +++ b/roofit/roofit/inc/RooCrystalBall.h @@ -17,9 +17,9 @@ class RooCrystalBall final : public RooAbsPdf { RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigmaL, RooAbsReal &sigmaR, RooAbsReal &alphaL, RooAbsReal &nL, RooAbsReal &alphaR, RooAbsReal &nR); - RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigma, + RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigmaLR, RooAbsReal &alphaL, RooAbsReal &nL, RooAbsReal &alphaR, RooAbsReal &nR); - RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigma, + RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigmaLR, RooAbsReal &alpha, RooAbsReal &n, bool doubleSided = false); RooCrystalBall(const RooCrystalBall &other, const char *name = 0); diff --git a/roofit/roofit/src/RooCrystalBall.cxx b/roofit/roofit/src/RooCrystalBall.cxx index ea080e5fdff20..2885ae652b285 100644 --- a/roofit/roofit/src/RooCrystalBall.cxx +++ b/roofit/roofit/src/RooCrystalBall.cxx @@ -101,15 +101,15 @@ RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal & /// \param nL Exponent of power-law tail on the left. /// \param alphaR Location of transition to a power law on the right, in standard deviations away from the mean. /// \param nR Exponent of power-law tail on the right. -RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigma, +RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigmaLR, RooAbsReal &alphaL, RooAbsReal &nL, RooAbsReal &alphaR, RooAbsReal &nR) : RooAbsPdf(name, title), x_("x", "Dependent", this, x), x0_("x0", "X0", this, x0), - sigmaL_("sigmaL", "Left Sigma", this, sigma), sigmaR_("sigmaR", "Right Sigma", this, sigma), + sigmaL_("sigmaL", "Left Sigma", this, sigmaLR), sigmaR_("sigmaR", "Right Sigma", this, sigmaLR), alphaL_{"alphaL", "Left Alpha", this, alphaL}, nL_{"nL", "Left Order", this, nL}, alphaR_{std::make_unique("alphaR", "Right Alpha", this, alphaR)}, nR_{std::make_unique("nR", "Right Order", this, nR)} { - RooHelpers::checkRangeOfParameters(this, {&sigma}, 0.0); + RooHelpers::checkRangeOfParameters(this, {&sigmaLR}, 0.0); RooHelpers::checkRangeOfParameters(this, {&alphaL}, 0.0); RooHelpers::checkRangeOfParameters(this, {&alphaR}, 0.0); RooHelpers::checkRangeOfParameters(this, {&nL}, 0.0); @@ -128,10 +128,10 @@ RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal & /// \param alpha Location of transition to a power law, in standard deviations away from the mean. /// \param n Exponent of power-law tail. /// \param doubleSided Whether the tail is only on one side or on both sides -RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigma, +RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal &x, RooAbsReal &x0, RooAbsReal &sigmaLR, RooAbsReal &alpha, RooAbsReal &n, bool doubleSided) : RooAbsPdf(name, title), x_("x", "Dependent", this, x), x0_("x0", "X0", this, x0), - sigmaL_{"sigmaL", "Left Sigma", this, sigma}, sigmaR_{"sigmaR", "Right Sigma", this, sigma}, + sigmaL_{"sigmaL", "Left Sigma", this, sigmaLR}, sigmaR_{"sigmaR", "Right Sigma", this, sigmaLR}, alphaL_{"alphaL", "Left Alpha", this, alpha}, nL_{"nL", "Left Order", this, n} { @@ -140,7 +140,7 @@ RooCrystalBall::RooCrystalBall(const char *name, const char *title, RooAbsReal & nR_ = std::make_unique("nR", "Right Order", this, n); } - RooHelpers::checkRangeOfParameters(this, {&sigma}, 0.0); + RooHelpers::checkRangeOfParameters(this, {&sigmaLR}, 0.0); RooHelpers::checkRangeOfParameters(this, {&n}, 0.0); if (doubleSided) { RooHelpers::checkRangeOfParameters(this, {&alpha}, 0.0); From f1098624ae54d68a2625b40b9317a5615d652971 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sat, 19 Jun 2021 14:33:35 +0200 Subject: [PATCH 294/309] [RF] Fix warning about getObservables member shadowing in RooProdPdf This fixes warnings in the CentOS 7 build in the nightlies. --- roofit/roofitcore/src/RooProdPdf.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 8cc87cfd44948..6d0aa27be2c63 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -633,7 +633,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // once and use it in a lambda function. RooArgSet pdfLeafList("leafNodeServerList") ; pdf->treeNodeServerList(&pdfLeafList,0,kFALSE,kTRUE,true) ; - auto getObservables = [&pdfLeafList]( + auto getObservablesOfCurrentPdf = [&pdfLeafList]( std::vector & out, const RooArgSet& dataList) { for (const auto arg : pdfLeafList) { @@ -645,14 +645,14 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // Reduce pdfNSet to actual dependents if (0 == strcmp("nset", pdfNSetOrig->GetName())) { - getObservables(pdfNSet, *pdfNSetOrig); + getObservablesOfCurrentPdf(pdfNSet, *pdfNSetOrig); } else if (0 == strcmp("cset", pdfNSetOrig->GetName())) { - getObservables(pdfNSet, normSet); + getObservablesOfCurrentPdf(pdfNSet, normSet); removeCommon(pdfNSet, pdfNSetOrig->get()); pdfCSet = pdfNSetOrig->get(); } else { // Legacy mode. Interpret at NSet for backward compatibility - getObservables(pdfNSet, *pdfNSetOrig); + getObservablesOfCurrentPdf(pdfNSet, *pdfNSetOrig); } @@ -660,7 +660,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int pdfAllDeps.clear(); // Make list of all dependents of this PDF - getObservables(pdfAllDeps, normSet); + getObservablesOfCurrentPdf(pdfAllDeps, normSet); // cout << GetName() << ": pdf = " << pdf->GetName() << " pdfAllDeps = " << pdfAllDeps << " pdfNSet = " << *pdfNSet << " pdfCSet = " << *pdfCSet << endl; @@ -677,7 +677,7 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int // cout << GetName() << ": pdfNormDeps for " << pdf->GetName() << " = " << pdfNormDeps << endl; pdfIntSet.clear(); - getObservables(pdfIntSet, intSet) ; + getObservablesOfCurrentPdf(pdfIntSet, intSet) ; // WVE if we have no norm deps, conditional observables should be taken out of pdfIntSet if (pdfNormDeps.empty() && !pdfCSet.empty()) { From 8ed10cbcf4adb641f4fcd486cb0ec284d76f3218 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Fri, 18 Jun 2021 10:11:59 +0200 Subject: [PATCH 295/309] [RRawFileDavix] Silence 'maybe uninitialized' warning --- net/davix/src/RRawFileDavix.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/davix/src/RRawFileDavix.cxx b/net/davix/src/RRawFileDavix.cxx index 426c2b7e09ab1..1a90948364caf 100644 --- a/net/davix/src/RRawFileDavix.cxx +++ b/net/davix/src/RRawFileDavix.cxx @@ -14,6 +14,7 @@ #include +#include // for memset #include #include @@ -94,6 +95,7 @@ void ROOT::Internal::RRawFileDavix::ReadVImpl(RIOVec *ioVec, unsigned int nReq) Davix::DavIOVecInput in[nReq]; Davix::DavIOVecOuput out[nReq]; + memset(in, 0, sizeof(Davix::DavIOVecInput) * nReq); for (unsigned int i = 0; i < nReq; ++i) { in[i].diov_buffer = ioVec[i].fBuffer; in[i].diov_offset = ioVec[i].fOffset; From d8e3ac51d93dc4afd5bdac841965e69af179a957 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Fri, 18 Jun 2021 15:18:17 +0200 Subject: [PATCH 296/309] [RRawFileDavix] Use C++ native initialization of Davix struct --- net/davix/src/RRawFileDavix.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/davix/src/RRawFileDavix.cxx b/net/davix/src/RRawFileDavix.cxx index 1a90948364caf..5cfa7100cbe68 100644 --- a/net/davix/src/RRawFileDavix.cxx +++ b/net/davix/src/RRawFileDavix.cxx @@ -14,7 +14,6 @@ #include -#include // for memset #include #include @@ -92,10 +91,9 @@ size_t ROOT::Internal::RRawFileDavix::ReadAtImpl(void *buffer, size_t nbytes, st void ROOT::Internal::RRawFileDavix::ReadVImpl(RIOVec *ioVec, unsigned int nReq) { Davix::DavixError *davixErr = NULL; - Davix::DavIOVecInput in[nReq]; + Davix::DavIOVecInput in[nReq] {}; Davix::DavIOVecOuput out[nReq]; - memset(in, 0, sizeof(Davix::DavIOVecInput) * nReq); for (unsigned int i = 0; i < nReq; ++i) { in[i].diov_buffer = ioVec[i].fBuffer; in[i].diov_offset = ioVec[i].fOffset; From 2c0f22e78c0ff80de3cbf59571ba811a99f22848 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Wed, 23 Jun 2021 14:32:02 +0200 Subject: [PATCH 297/309] [RRawFileDavix] Use vector for RRawFileDavix::ReadVImpl I/O structs --- net/davix/src/RRawFileDavix.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/davix/src/RRawFileDavix.cxx b/net/davix/src/RRawFileDavix.cxx index 5cfa7100cbe68..3dde675c22610 100644 --- a/net/davix/src/RRawFileDavix.cxx +++ b/net/davix/src/RRawFileDavix.cxx @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -91,8 +92,8 @@ size_t ROOT::Internal::RRawFileDavix::ReadAtImpl(void *buffer, size_t nbytes, st void ROOT::Internal::RRawFileDavix::ReadVImpl(RIOVec *ioVec, unsigned int nReq) { Davix::DavixError *davixErr = NULL; - Davix::DavIOVecInput in[nReq] {}; - Davix::DavIOVecOuput out[nReq]; + std::vector in(nReq); + std::vector out(nReq); for (unsigned int i = 0; i < nReq; ++i) { in[i].diov_buffer = ioVec[i].fBuffer; @@ -101,7 +102,7 @@ void ROOT::Internal::RRawFileDavix::ReadVImpl(RIOVec *ioVec, unsigned int nReq) R__ASSERT(ioVec[i].fSize > 0); } - auto ret = fFileDes->pos.preadVec(fFileDes->fd, in, out, nReq, &davixErr); + auto ret = fFileDes->pos.preadVec(fFileDes->fd, in.data(), out.data(), nReq, &davixErr); if (ret < 0) { throw std::runtime_error("Cannot do vector read from '" + fUrl + "', error: " + davixErr->getErrMsg()); } From d5e2aa0b579f74a73ce0d1430d67f4099a803158 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Wed, 23 Jun 2021 21:16:48 +0200 Subject: [PATCH 298/309] add clang-format job --- .github/workflows/code_analysis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/code_analysis.yml diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml new file mode 100644 index 0000000000000..7adf996e83898 --- /dev/null +++ b/.github/workflows/code_analysis.yml @@ -0,0 +1,18 @@ +name: clang-tools code analysis + +on: + # push: + # branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +jobs: + clang-format: + runs-on: ubuntu-latest + env: + TRAVIS_BRANCH: ${{ github.base_ref }} + TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} + steps: + - uses: actions/checkout@v2 + - name: run clang-format script + run: .ci/format_script.sh From 303f586e79b2dc20bfcc0380b32d5a0cd3328496 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Wed, 23 Jun 2021 21:23:15 +0200 Subject: [PATCH 299/309] trigger on pull_request without branch specified --- .github/workflows/code_analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 7adf996e83898..359dde110a43f 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -1,10 +1,10 @@ name: clang-tools code analysis -on: +on: pull_request # push: # branches: [ $default-branch ] - pull_request: - branches: [ $default-branch ] + # pull_request: + # branches: [ $default-branch ] jobs: clang-format: From 3f604f618c77d57216c9d13322a66910081e607f Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Wed, 23 Jun 2021 21:44:50 +0200 Subject: [PATCH 300/309] fetch all history and tags so we can compare for clang-format --- .github/workflows/code_analysis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 359dde110a43f..966c87962b4e7 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -14,5 +14,7 @@ jobs: TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: run clang-format script run: .ci/format_script.sh From 8bcd2c1a3332e7e5364435f0014bbe16c3c01196 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Wed, 23 Jun 2021 21:51:25 +0200 Subject: [PATCH 301/309] try to separately pull in master --- .github/workflows/code_analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 966c87962b4e7..d7b93067fda69 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -14,7 +14,7 @@ jobs: TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} steps: - uses: actions/checkout@v2 - with: - fetch-depth: 0 + - name: also pull base branch + run: git pull origin $TRAVIS_BRANCH - name: run clang-format script run: .ci/format_script.sh From 036272ebb3f86d90675b077411f186d0c0f6f127 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Wed, 23 Jun 2021 21:54:56 +0200 Subject: [PATCH 302/309] change to fetch --- .github/workflows/code_analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index d7b93067fda69..d7662bad61362 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -14,7 +14,7 @@ jobs: TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} steps: - uses: actions/checkout@v2 - - name: also pull base branch - run: git pull origin $TRAVIS_BRANCH + - name: fetch base branch + run: git fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 origin $TRAVIS_BRANCH - name: run clang-format script run: .ci/format_script.sh From 8221f2f27fac25f8c4ea979c5c16a7e8f00148c0 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 13:29:52 +0200 Subject: [PATCH 303/309] pass in BASE_COMMIT using a github actions variable --- .ci/format_script.sh | 2 +- .github/workflows/code_analysis.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.ci/format_script.sh b/.ci/format_script.sh index 6bb51fa51291c..cca8627b89d46 100755 --- a/.ci/format_script.sh +++ b/.ci/format_script.sh @@ -2,7 +2,7 @@ set -ex -BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) +# BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) echo "Running clang-format against branch $TRAVIS_BRANCH, with hash $BASE_COMMIT" COMMIT_FILES=$(git diff --name-only $BASE_COMMIT | grep -i -v LinkDef) RESULT_OUTPUT="$(git-clang-format --commit $BASE_COMMIT --diff --binary `which clang-format` $COMMIT_FILES)" diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index d7662bad61362..acadc419df7ab 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -12,9 +12,8 @@ jobs: env: TRAVIS_BRANCH: ${{ github.base_ref }} TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} + BASE_COMMIT: ${{ github.event.pull_request.head.sha }} steps: - uses: actions/checkout@v2 - - name: fetch base branch - run: git fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 origin $TRAVIS_BRANCH - name: run clang-format script run: .ci/format_script.sh From c0f2291c02411231d5bfdb3513e0f51cce6e8c38 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 13:32:42 +0200 Subject: [PATCH 304/309] actually point to base SHA instead of head SHA --- .github/workflows/code_analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index acadc419df7ab..47e875fe44dae 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -12,7 +12,7 @@ jobs: env: TRAVIS_BRANCH: ${{ github.base_ref }} TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} - BASE_COMMIT: ${{ github.event.pull_request.head.sha }} + BASE_COMMIT: ${{ github.event.pull_request.base.sha }} steps: - uses: actions/checkout@v2 - name: run clang-format script From 170826ec168fb9b856abe9c18822797cc8056d04 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 13:42:35 +0200 Subject: [PATCH 305/309] fetch base ref Uses example in as of yet unmerged PR https://github.com/actions/checkout/pull/213 --- .github/workflows/code_analysis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 47e875fe44dae..9fb2671981cd5 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -15,5 +15,7 @@ jobs: BASE_COMMIT: ${{ github.event.pull_request.base.sha }} steps: - uses: actions/checkout@v2 + - name: Fetch base_ref HEAD + run: git fetch --depth=1 origin +refs/heads/${{github.base_ref}}:refs/remotes/origin/${{github.base_ref}} - name: run clang-format script run: .ci/format_script.sh From bd2d0729f1c9d3e785fa6e893318fe953d6ebbad Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 13:51:51 +0200 Subject: [PATCH 306/309] install clang tools to also get git-clang-format --- .github/workflows/code_analysis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 9fb2671981cd5..18a96006824aa 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -17,5 +17,7 @@ jobs: - uses: actions/checkout@v2 - name: Fetch base_ref HEAD run: git fetch --depth=1 origin +refs/heads/${{github.base_ref}}:refs/remotes/origin/${{github.base_ref}} + - name: install clang-tools + run: sudo apt-get install -y clang-tools - name: run clang-format script run: .ci/format_script.sh From 88fd75139401ec7804b66ae990e44db3eb1f3420 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 13:56:13 +0200 Subject: [PATCH 307/309] install clang-format instead I thought clang-tools would include clang-format, but apparently not. --- .github/workflows/code_analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 18a96006824aa..4b36e6597d9c4 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v2 - name: Fetch base_ref HEAD run: git fetch --depth=1 origin +refs/heads/${{github.base_ref}}:refs/remotes/origin/${{github.base_ref}} - - name: install clang-tools - run: sudo apt-get install -y clang-tools + - name: install clang-format + run: sudo apt-get install -y clang-format - name: run clang-format script run: .ci/format_script.sh From d424b5d60220b8356568e1a4c8237df7ce82e433 Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 14:01:07 +0200 Subject: [PATCH 308/309] revert format_script.sh change Now that we correctly fetch the base_ref, we can put the format_script back into Travis-compatible state. --- .ci/format_script.sh | 2 +- .github/workflows/code_analysis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/format_script.sh b/.ci/format_script.sh index cca8627b89d46..6bb51fa51291c 100755 --- a/.ci/format_script.sh +++ b/.ci/format_script.sh @@ -2,7 +2,7 @@ set -ex -# BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) +BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) echo "Running clang-format against branch $TRAVIS_BRANCH, with hash $BASE_COMMIT" COMMIT_FILES=$(git diff --name-only $BASE_COMMIT | grep -i -v LinkDef) RESULT_OUTPUT="$(git-clang-format --commit $BASE_COMMIT --diff --binary `which clang-format` $COMMIT_FILES)" diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 4b36e6597d9c4..03a4907b26194 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -12,7 +12,7 @@ jobs: env: TRAVIS_BRANCH: ${{ github.base_ref }} TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} - BASE_COMMIT: ${{ github.event.pull_request.base.sha }} + # BASE_COMMIT: ${{ github.event.pull_request.base.sha }} steps: - uses: actions/checkout@v2 - name: Fetch base_ref HEAD From f4dcfe1dbcae777776855e051e3c850cf8d70b6f Mon Sep 17 00:00:00 2001 From: "E. G. Patrick Bos" Date: Thu, 24 Jun 2021 14:06:13 +0200 Subject: [PATCH 309/309] pass BASE_COMMIT to format_script.sh It is not possible to use the base branch name in the GitHub Actions workflow to get the base SHA hash, because the branch name is not known there. To keep the format_script.sh universal, we just pass the SHA hash in from both the Travis and the GH Actions configurations instead. --- .ci/format_script.sh | 1 - .github/workflows/code_analysis.yml | 2 +- .travis.yml | 6 +++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.ci/format_script.sh b/.ci/format_script.sh index 6bb51fa51291c..67503dd8710de 100755 --- a/.ci/format_script.sh +++ b/.ci/format_script.sh @@ -2,7 +2,6 @@ set -ex -BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) echo "Running clang-format against branch $TRAVIS_BRANCH, with hash $BASE_COMMIT" COMMIT_FILES=$(git diff --name-only $BASE_COMMIT | grep -i -v LinkDef) RESULT_OUTPUT="$(git-clang-format --commit $BASE_COMMIT --diff --binary `which clang-format` $COMMIT_FILES)" diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index 03a4907b26194..4b36e6597d9c4 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -12,7 +12,7 @@ jobs: env: TRAVIS_BRANCH: ${{ github.base_ref }} TRAVIS_PULL_REQUEST_BRANCH: ${{ github.head_ref }} - # BASE_COMMIT: ${{ github.event.pull_request.base.sha }} + BASE_COMMIT: ${{ github.event.pull_request.base.sha }} steps: - uses: actions/checkout@v2 - name: Fetch base_ref HEAD diff --git a/.travis.yml b/.travis.yml index 8041119e0bef9..180f5304daec9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,11 @@ matrix: include: - env: TOOL=clang-format script: &format_script - - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then .ci/format_script.sh; fi + - | + if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then + export BASE_COMMIT=$(git rev-parse $TRAVIS_BRANCH) + .ci/format_script.sh + fi - env: TOOL=clang-tidy-analyzer before_script: ©_headers