Skip to content

Commit

Permalink
Improved the Get method used to retrieve objects of any type from a T…
Browse files Browse the repository at this point in the history
…File.

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 <[email protected]>
  • Loading branch information
peremato and grasph committed Jul 28, 2024
1 parent 7d0a95b commit 1fbf9a5
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 49 deletions.
2 changes: 1 addition & 1 deletion deps/src/JlClasses_003.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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<TObject * (TDirectory::*)(const char *) >(&TDirectory::Get));
t.method("Get_", static_cast<TObject * (TDirectory::*)(const char *) >(&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 *)
Expand Down
2 changes: 1 addition & 1 deletion deps/src/JlClasses_004.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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<TObject * (TDirectoryFile::*)(const char *) >(&TDirectoryFile::Get));
t.method("Get_", static_cast<TObject * (TDirectoryFile::*)(const char *) >(&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 *)
Expand Down
9 changes: 4 additions & 5 deletions examples/TTree_examples/read_tree1.jl
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
19 changes: 9 additions & 10 deletions examples/TTree_examples/read_tree3.jl
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
7 changes: 3 additions & 4 deletions examples/TTree_examples/write_tree1.jl
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 2 additions & 3 deletions examples/TTree_examples/write_tree3.jl
Original file line number Diff line number Diff line change
@@ -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}()
Expand Down
6 changes: 4 additions & 2 deletions misc/ROOT.wit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 17 additions & 17 deletions src/ROOT-export.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
120 changes: 118 additions & 2 deletions src/ROOTex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
# 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

#---TGraph extensions------------------------------------------------------------------------------
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) ---------------------------------------------------------------------------
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/demo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 1fbf9a5

Please sign in to comment.