From 0999b73090259c5aaa6f953148057bf69b1a1e21 Mon Sep 17 00:00:00 2001 From: Pere Mato Date: Fri, 7 Jun 2024 12:02:48 +0200 Subject: [PATCH] Improved the Get method used to retrieve objects of any type from a TFile. The methods returns now an instance of the object, of proper type, instead of a Ptr{TObjet}. getproperty is also implemented with the same effect as the Get method, to provide object access with the dot notation, `file.objet`. Code from commit c10c8e028cc29837f765aeeb4cb717c8c45392e4 of ROOT.jl-generator Co-authored-by: Philippe Gras --- deps/src/JlClasses_003.cxx | 2 +- deps/src/JlClasses_004.cxx | 2 +- examples/TTree_examples/read_tree1.jl | 9 +- examples/TTree_examples/read_tree3.jl | 19 ++-- examples/TTree_examples/write_tree1.jl | 7 +- examples/TTree_examples/write_tree3.jl | 5 +- misc/ROOT.wit | 6 +- src/ROOT-export.jl | 34 +++---- src/ROOTex.jl | 120 ++++++++++++++++++++++++- src/demo.jl | 8 +- 10 files changed, 163 insertions(+), 49 deletions(-) diff --git a/deps/src/JlClasses_003.cxx b/deps/src/JlClasses_003.cxx index 23b69cc..87ace02 100644 --- a/deps/src/JlClasses_003.cxx +++ b/deps/src/JlClasses_003.cxx @@ -236,7 +236,7 @@ struct JlTDirectory: public Wrapper { DEBUG_MSG("Adding wrapper for TObject * TDirectory::Get(const char *) (" __HERE__ ")"); // signature to use in the veto list: TObject * TDirectory::Get(const char *) // defined in /home/pgras/.julia/conda/3/include/TDirectory.h:203:24 - t.method("Get", static_cast(&TDirectory::Get)); + t.method("Get_", static_cast(&TDirectory::Get)); DEBUG_MSG("Adding wrapper for TDirectory * TDirectory::GetDirectory(const char *, Bool_t, const char *) (" __HERE__ ")"); // signature to use in the veto list: TDirectory * TDirectory::GetDirectory(const char *, Bool_t, const char *) diff --git a/deps/src/JlClasses_004.cxx b/deps/src/JlClasses_004.cxx index 5921982..e56816c 100644 --- a/deps/src/JlClasses_004.cxx +++ b/deps/src/JlClasses_004.cxx @@ -494,7 +494,7 @@ struct JlTDirectoryFile: public Wrapper { DEBUG_MSG("Adding wrapper for TObject * TDirectoryFile::Get(const char *) (" __HERE__ ")"); // signature to use in the veto list: TObject * TDirectoryFile::Get(const char *) // defined in /home/pgras/.julia/conda/3/include/TDirectoryFile.h:80:23 - t.method("Get", static_cast(&TDirectoryFile::Get)); + t.method("Get_", static_cast(&TDirectoryFile::Get)); DEBUG_MSG("Adding wrapper for TDirectory * TDirectoryFile::GetDirectory(const char *, Bool_t, const char *) (" __HERE__ ")"); // signature to use in the veto list: TDirectory * TDirectoryFile::GetDirectory(const char *, Bool_t, const char *) diff --git a/examples/TTree_examples/read_tree1.jl b/examples/TTree_examples/read_tree1.jl index d89e182..54eb89d 100644 --- a/examples/TTree_examples/read_tree1.jl +++ b/examples/TTree_examples/read_tree1.jl @@ -1,16 +1,15 @@ using ROOT -const R = ROOT println("Reading back the file created with write_tree1.jl using TTree::GetEntry.\n") -f = R.TFile!Open("test1.root") +f = ROOT.TFile!Open("test1.root") f != C_NULL || error("File not found.") -t = R.GetTTree(f[], "tree") +t = Get(f, "tree") t != C_NULL || error("Tree not found!") -a = fill(0) -SetBranchAddress(t[], "a", a) +a = Ref{Int32}(0) +SetBranchAddress(t, "a", a) nevts = GetEntries(t) for i in 1:nevts GetEntry(t, i-1) diff --git a/examples/TTree_examples/read_tree3.jl b/examples/TTree_examples/read_tree3.jl index 11aec38..a016732 100644 --- a/examples/TTree_examples/read_tree3.jl +++ b/examples/TTree_examples/read_tree3.jl @@ -1,30 +1,29 @@ using ROOT -const R = ROOT println("Reading back the file created with write_tree3.jl using TTreeReader.\n") -f = R.TFile!Open("test3.root") +f = ROOT.TFile!Open("test3.root") f != C_NULL || error("File not found.") -reader = R.TTreeReader("tree", f) -Muon_pt_ = R.TTreeReaderArray{Float32}(reader, "Muon_pt") -Muon_eta_ = R.TTreeReaderArray{Float32}(reader, "Muon_eta") -Muon_phi_ = R.TTreeReaderArray{Float32}(reader, "Muon_phi") +reader = ROOT.TTreeReader("tree", f) +Muon_pt_ = ROOT.TTreeReaderArray{Float32}(reader, "Muon_pt") +Muon_eta_ = ROOT.TTreeReaderArray{Float32}(reader, "Muon_eta") +Muon_phi_ = ROOT.TTreeReaderArray{Float32}(reader, "Muon_phi") ievt = 0 while Next(reader) global ievt += 1 println("Event ", ievt) - println("Muon multiplicity: ", R.length(Muon_pt_)) + println("Muon multiplicity: ", ROOT.length(Muon_pt_)) - Muon_pt::Vector{Float32} = [ Muon_pt_[i-1] for i in 1:R.length(Muon_pt_)] + Muon_pt::Vector{Float32} = [ Muon_pt_[i-1] for i in 1:ROOT.length(Muon_pt_)] println("Muon pt: ", Muon_pt) - Muon_eta::Vector{Float32} = [ Muon_eta_[i-1] for i in 1:R.length(Muon_eta_)] + Muon_eta::Vector{Float32} = [ Muon_eta_[i-1] for i in 1:ROOT.length(Muon_eta_)] println("Muon eta: ", Muon_eta) - Muon_phi::Vector{Float32} = [ Muon_phi_[i-1] for i in 1:R.length(Muon_phi_)] + Muon_phi::Vector{Float32} = [ Muon_phi_[i-1] for i in 1:ROOT.length(Muon_phi_)] println("Muon phi: ", Muon_phi) println() diff --git a/examples/TTree_examples/write_tree1.jl b/examples/TTree_examples/write_tree1.jl index 7746ab6..f38a492 100644 --- a/examples/TTree_examples/write_tree1.jl +++ b/examples/TTree_examples/write_tree1.jl @@ -1,12 +1,11 @@ using ROOT -const R = ROOT println("Creating a ROOT file with a TTree filled with scalars.\n") nevts = 10 -f = R.TFile!Open("test1.root", "RECREATE") -t = R.TTree("tree", "tree") -a = fill(0) +f = ROOT.TFile!Open("test1.root", "RECREATE") +t = ROOT.TTree("tree", "tree") +a = Ref{Int32}(0) Branch(t, "a", a, Int32(32000), Int32(99)) for i in 1:nevts a[] = i diff --git a/examples/TTree_examples/write_tree3.jl b/examples/TTree_examples/write_tree3.jl index ad875a5..c3b6da3 100644 --- a/examples/TTree_examples/write_tree3.jl +++ b/examples/TTree_examples/write_tree3.jl @@ -1,11 +1,10 @@ using ROOT -const R = ROOT using CxxWrap println("Creating a ROOT file with a TTree filled with std vectors.\n") -f = R.TFile!Open("test3.root", "RECREATE") -tree = R.TTree("tree", "tree") +f = ROOT.TFile!Open("test3.root", "RECREATE") +tree = ROOT.TTree("tree", "tree") Muon_pt = StdVector{Float32}() Muon_eta = StdVector{Float32}() diff --git a/misc/ROOT.wit b/misc/ROOT.wit index f03c3b6..b8d0fa0 100644 --- a/misc/ROOT.wit +++ b/misc/ROOT.wit @@ -9,12 +9,14 @@ out_cxx_dir = "ROOT/deps/src" include_dirs = [ "/home/pgras/.julia/conda/3/include", "src" ] -input = [ "TROOT.h", "TBrowser.h", "TTree.h", "TBranchPtr.h", "TLeaf.h", "TBranch.h", "TSystem.h", "TCanvas.h", "TH1.h", "TH2.h", "TProfile.h", "TProfile2D.h","TRandom.h", "TAxis.h", "TApplication.h", "TDirectory.h", "TDirectoryFile.h", "TFile.h", "TNamed.h", "TObject.h", "TGraph.h", "TF1.h", "TTreeReader.h", "TTreeReaderValue.h", "TTreeReaderArray.h", "Templates.h", "TEntryList.h", "TKey.h", "TVectorT.h", "TVectorDfwd.h", "TVectorFfwd.h", "Extra.h" ] -#input = [ "TTreeReader.h", "TTreeReaderValue.h", "TTreeReaderArray.h" ] +input = [ "TROOT.h", "TBrowser.h", "TTree.h", "TBranchPtr.h", "TLeaf.h", "TBranch.h", "TSystem.h", "TCanvas.h", "TH1.h", "TH2.h", "TProfile.h", "TProfile2D.h","TRandom.h", "TAxis.h", "TApplication.h", "TDirectory.h", "TDirectoryFile.h", "TFile.h", "TNamed.h", "TObject.h", "TGraph.h", "TF1.h", "TTreeReader.h", "TTreeReaderValue.h", "TTreeReaderArray.h", "Templates.h", "TEntryList.h", "TKey.h", "TVectorT.h", "TVectorDfwd.h", "TVectorFfwd.h", "Extra.h" ] + extra_headers = [ "TVectorT.h" ] veto_list = "src/jlROOT-veto.h" +julia_names = [ "TDirectoryFile::Get -> Get_", "TDirectory::Get -> Get_" ] + fields_and_variables = true # Currently not working with CxxWrap 0.15+, use 0.14.x diff --git a/src/ROOT-export.jl b/src/ROOT-export.jl index 72f88a4..ca2e4d2 100644 --- a/src/ROOT-export.jl +++ b/src/ROOT-export.jl @@ -77,23 +77,23 @@ export GetTreeNumber, GetType, GetTypeName, GetUUID, GetUid, GetUniqueID, GetUpd export GetValue, GetValueLong64, GetValuePointer, GetVariable, GetVersion, GetVersionCode, GetVersionDate, GetVersionInt export GetVersionTime, GetVolumes, GetW, GetWebDisplay, GetWeight, GetWh, GetWindowHeight, GetWindowTopX, GetWindowTopY export GetWindowWidth, GetWorkingDirectory, GetWriteBasket, GetWw, GetX, GetXaxis, GetXbins, GetXmax, GetXmin, GetXsizeReal -export GetXsizeUser, GetY, GetYaxis, GetYmax, GetYmin, GetYsizeReal, GetYsizeUser, GetZaxis, GetZipBytes, GetZmax, GetZmin, Getenv -export GradientPar, HandleException, HandleIdleTimer, HandleInput, HandleTermInput, HandleTimer, HasInconsistentHash, HasMenuBar -export Hash, Hide, HighlightConnect, Highlighted, HomeDirectory, HostName, Iconify, Idle, IgnoreInclude, IgnoreInterrupt -export IgnoreSignal, Import, ImportAttributes, InControl, InPlaceClone, IncludeRange, IncrementPidOffset, IncrementProcessIDs -export IncrementTotalBuffers, InheritsFrom, Init, InitArgs, InitExpo, InitGaus, InitPolynom, InitializeGraphics, InnerLoop, InputFiles -export InsertPoint, InsertPointBefore, Inspect, Integral, IntegralAndError, IntegralError, IntegralFast, IntegralMultiple -export IntegralOneDim, Interpolate, InvertBit, IsA, IsAbsoluteFileName, IsAlphanumeric, IsArchive, IsAutoDelete, IsBatch -export IsBinOverflow, IsBinUnderflow, IsBinary, IsBuilt, IsChain, IsCmdThread, IsDestructed, IsDrawn, IsEditable, IsEqual, IsEscaped -export IsEvalNormalized, IsExecutingMacro, IsFileInIncludePath, IsFolder, IsGrayscale, IsHighlight, IsInside, IsInterrupted, IsInvalid -export IsLineProcessing, IsLinear, IsModified, IsOnHeap, IsOnTerminalBranch, IsOpen, IsPathLocal, IsProofServ, IsRange, IsRaw -export IsRetained, IsRootFile, IsRunning, IsSortable, IsUnsigned, IsUpdated, IsValid, IsVariableBinSize, IsVectorized, IsWeb -export IsWebDisplay, IsWebDisplayBatch, IsWritable, IsZombie, Keep, KeepCircular, KeyPressed, KolmogorovTest, LabelsDeflate -export LabelsInflate, LabelsOption, Landau, LeastSquareFit, LeastSquareLinearFit, LineProcessed, Link, ListLibraries, ListSymbols -export Load, LoadAllLibraries, LoadBaskets, LoadClass, LoadMacro, LoadTree, LoadTreeFriend, Lower, Macro, MakeClass -export MakeCode, MakeDefCanvas, MakeDirectory, MakeFree, MakeProject, MakeProxy, MakeSelector, Map, Matches, MayNotUse, Mean -export MemoryFull, Merge, Message, Moment, MoveOpaque, MovePoints, Multiply, MustClean, MustFlush, Next, NextTimeOut, NoLogOpt -export NoLogoOpt, Notify, NotifyApplicationCreated, Now, Obsolete, OpaqueMoving, OpaqueResizing, Open, OpenConnection +export GetXsizeUser, GetY, GetYaxis, GetYmax, GetYmin, GetYsizeReal, GetYsizeUser, GetZaxis, GetZipBytes, GetZmax, GetZmin, Get_ +export Getenv, GradientPar, HandleException, HandleIdleTimer, HandleInput, HandleTermInput, HandleTimer, HasInconsistentHash +export HasMenuBar, Hash, Hide, HighlightConnect, Highlighted, HomeDirectory, HostName, Iconify, Idle, IgnoreInclude +export IgnoreInterrupt, IgnoreSignal, Import, ImportAttributes, InControl, InPlaceClone, IncludeRange, IncrementPidOffset +export IncrementProcessIDs, IncrementTotalBuffers, InheritsFrom, Init, InitArgs, InitExpo, InitGaus, InitPolynom, InitializeGraphics +export InnerLoop, InputFiles, InsertPoint, InsertPointBefore, Inspect, Integral, IntegralAndError, IntegralError, IntegralFast +export IntegralMultiple, IntegralOneDim, Interpolate, InvertBit, IsA, IsAbsoluteFileName, IsAlphanumeric, IsArchive, IsAutoDelete +export IsBatch, IsBinOverflow, IsBinUnderflow, IsBinary, IsBuilt, IsChain, IsCmdThread, IsDestructed, IsDrawn, IsEditable +export IsEqual, IsEscaped, IsEvalNormalized, IsExecutingMacro, IsFileInIncludePath, IsFolder, IsGrayscale, IsHighlight +export IsInside, IsInterrupted, IsInvalid, IsLineProcessing, IsLinear, IsModified, IsOnHeap, IsOnTerminalBranch, IsOpen +export IsPathLocal, IsProofServ, IsRange, IsRaw, IsRetained, IsRootFile, IsRunning, IsSortable, IsUnsigned, IsUpdated, IsValid +export IsVariableBinSize, IsVectorized, IsWeb, IsWebDisplay, IsWebDisplayBatch, IsWritable, IsZombie, Keep, KeepCircular, KeyPressed +export KolmogorovTest, LabelsDeflate, LabelsInflate, LabelsOption, Landau, LeastSquareFit, LeastSquareLinearFit, LineProcessed, Link +export ListLibraries, ListSymbols, Load, LoadAllLibraries, LoadBaskets, LoadClass, LoadMacro, LoadTree, LoadTreeFriend, Lower, Macro +export MakeClass, MakeCode, MakeDefCanvas, MakeDirectory, MakeFree, MakeProject, MakeProxy, MakeSelector, Map, Matches, MayNotUse +export Mean, MemoryFull, Merge, Message, Moment, MoveOpaque, MovePoints, Multiply, MustClean, MustFlush, Next, NextTimeOut +export NoLogOpt, NoLogoOpt, Notify, NotifyApplicationCreated, Now, Obsolete, OpaqueMoving, OpaqueResizing, Open, OpenConnection export OpenDirectory, OpenFile, OpenForumTopic, OpenGitHubIssue, OpenInBrowser, OpenPipe, OpenReferenceGuideFor, Openlog export OptimizeBaskets, OptimizeStorage, Paint, PaintGrapHist, PaintGraph, PaintStats, ParamsVec, Pick, Picked, Poisson, PoissonD, Pop export PrependPathName, Previous, Print, PrintCacheInfo, PrintCacheStats, PrintValue, Process, ProcessEvents, ProcessFile, ProcessLine diff --git a/src/ROOTex.jl b/src/ROOTex.jl index 1f47aec..434adc4 100644 --- a/src/ROOTex.jl +++ b/src/ROOTex.jl @@ -3,7 +3,7 @@ # demo_fit_with_jl_func.jl for an example of such a fit without this module. # -export TF1W, TGraphW +export TF1W, TGraphW, Get import Base.convert @@ -11,7 +11,7 @@ import Base.convert function TGraph(x::AbstractVector{T}, y::AbstractVector{T}) where T TGraph(Base.length(x), x isa AbstractRange ? collect(x) : x, - y isa AbstractRange ? collect(y) : y) + y isa AbstractRange ? collect(y) : y) end #----Global vector (GC) --------------------------------------------------------------------------- @@ -45,6 +45,122 @@ function Fit(g::TGraph, tf1::TF1, option::String = "", goption::String = "", rxm Fit(g, CxxPtr(tf1), option, goption, rxmin, rxmax) end +# helper function used by the Get methods +function _GetHelper(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name; throwexcept = true) + obj = Get_(file, name) # Get object from file (TObject*) + if obj == C_NULL + if throwexcept + fname = GetName(file) + throw(KeyError("No object with name $name found in file $fname")) + else + return (Nothing, C_NULL) + end + end + + #Gets the type from the key, which works for any object including + #for class that does not derive from a TObject. + #Note: we used above Get_ to retrieve the object instead of ReadObj(key) + #because it handles cases, where the object is already in memory. + k = GetKey(file, TDirectory!DecodeNameCycle(name)...) + typename = GetClassName(k) + type = getproperty(ROOT, Symbol(typename)) + (type, obj) +end + +#---TFile extensions------------------------------------------------------------------------------- +""" + `Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name)` + + Retrieves an object from a `TFile`. If the object is not found, an `KeyError` exception is thrown. + + Note that this function is type instable. Use instead `Get(file, name, type)` is type stability is required. + + See also [`Get(file, name, type)`](@ref) and [`Get(file, name, default)`](@ref) +""" +function Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name) + (type, obj) = _GetHelper(file, name) + return CxxWrap.CxxPtr{type}(obj)[] # Cast to the proper type +end + +""" + `Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name, type)` + + Retrieves an object of type `type` from a `TFile`. If the object is not found, + an `KeyError` exception is thrown. The object data type is specified to + ensure type stability and can be omitted if type stability is not required. + + See also [`Get(file, name)`](@ref) and [`Get(file, name, default)`](@ref) +""" +function Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name, type) + (actualtype, obj) = _GetHelper(file, name) + + if ! (actualtype <: type) + fname = GetName(file) + #throw(ArgumentError("Type of the object $name found in $fname, $actualtype, does not match with the type argument, $type.")) + throw(TypeError(:get, "Type mismatch between retrieved object and provided type information.", type, actualtype)) + end + + return CxxWrap.CxxPtr{type}(obj)[] +end + +""" + `Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name, type::DataType, default::T)` + + Retrieves an object named `name` from a `TFile`. Returns `default` is the object is not found. The type of the object needs to be of the `type` specified in the 4th argument. If it is not, an `TypeError` exception is thrown. + + The function type stability can be ensured by providing as `default` the value `nothing` or another value of type `type`. + + See also [`Get(file, name)`](@ref) and [`Get(file, name)`](@ref) +""" +function Get(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name, type, default::T)::Union{type, T} where {T} + (actualtype, obj) = _GetHelper(file, name; throwexcept = false) + if obj == C_NULL + return default + elseif !(actualtype <: type) + fname = GetName(file) + #throw(ArgumentError("Type mismatch between the object $name found in $fname and the passed default value") + throw(TypeError(:get, "Type mismatch between retrieved object and default value", type, T)) + else + return CxxWrap.CxxPtr{actualtype}(obj)[] + end +end + +#See https://root.cern/doc/v632/TDirectory_8cxx.html#a942917eb21a84f137c08b7d4185f1b44 +const TDirectory!kMaxLen = 2056 + +function TDirectory!DecodeNameCycle(name) + cycle = zeros(Int16) + basename_ = Base.Vector{Int8}(undef, ROOT.TDirectory!kMaxLen) + TDirectory!DecodeNameCycle(name, basename_, cycle, ROOT.TDirectory!kMaxLen) + GC.@preserve basename = unsafe_string(pointer(basename_)) + (basename, cycle[]) +end + +""" + `getindex(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name)` + + Retrieves an object named `name` from a `TFile`. It is usually called with the syntax file[name]. + Throws an `KeyError` exception is the object is not found. + + See also [`Get(file, name)`](@ref), [`Get(file, name)`](@ref) and [`Get(file, name, type)`](@ref) +""" +Base.getindex(file::Union{TDirectoryFile, CxxPtr{<:TDirectoryFile}}, name) = Get(file, name) + +""" + `getproperty(file::T, sym::Symbol) + + Retrieves an object named `sym` (provided as a symbol) from a `TFile`. It is usually called with the syntax file.name. + Throws an `KeyError` exception is the object is not found. + + See also [`getindex(file, name)`](), [`Get(file, name)`](@ref), [`Get(file, name)`](@ref) and [`Get(file, name, type)`](@ref) +""" +function Base.getproperty(file::T, sym::Symbol) where {T<:Union{ROOT.TDirectoryFile, CxxPtr{<:ROOT.TDirectoryFile}}} + if sym ∈ fieldnames(T) + return getfield(file, sym) + else + return Get(file, String(sym)) + end +end # Wrapper for TF1 that holds references to julia objects struct TF1W <: TF1 diff --git a/src/demo.jl b/src/demo.jl index 0213a94..a3c96c5 100644 --- a/src/demo.jl +++ b/src/demo.jl @@ -4,14 +4,14 @@ function demo() println("""Executing: h = $(@__MODULE__).TH1D("h", "Normal distribution", 100, -5, 5) - $(@__MODULE__).FillRandom(h, "gaus") + FillRandom(h, "gaus") c = $(@__MODULE__).TCanvas() - $(@__MODULE__).Fit(h, "gaus") + Fit(h, "gaus") """) - h = TH1D("h", "Normal distribution", 100, -5, 5) + h = ROOT.TH1D("h", "Normal distribution", 100, -5, 5) FillRandom(h, "gaus") - c = TCanvas() + c = ROOT.TCanvas() Fit(h, "gaus") c end