go-hep / hep

hep is the mono repository holding all of go-hep.org/x/hep packages and tools
https://go-hep.org
BSD 3-Clause "New" or "Revised" License
231 stars 37 forks source link

groot: finding child object (multilevel TDirectory) in a ROOT file and conversion of plots to JSON #982

Closed mrceyhun closed 1 year ago

mrceyhun commented 1 year ago

I have 2 questions which are related with each other. I have a local root file, let's say dqm.root, and it includes so many objects/plots.

Q-1 How can I get the object using goroot?

In PyROOT, we can get it like:

f = ROOT.TFile.Open("dqm.root")
h = f.Get("DQMData/Run 366713/EcalPreshower/Run summary/ESRecoSummary/recHits_ES_energyMax")

In goroot, I could not find an easy way and write my function like below. I think that there should be a better way. And I am open your suggestions for type casting for ROOT objects.

func findObj(filePath, objPath string) any {
    var obj any
    f, err := groot.Open(filePath)
    if err != nil {
        log.Fatal(err)
    }
    defer func(f *groot.File) {
        err := f.Close()
        if err != nil {
            log.Println("ROOT file could not close successfully!")
        }
    }(f)

    // Get object path list via splitting by slash
    pathList := strings.Split(objPath, "/")
    obj, err = f.Get(pathList[0])
    if err != nil {
        log.Fatal(err)
    }

    for _, objDir := range pathList[1:] {
        obj, err = obj.(riofs.Directory).Get(objDir)
        if err != nil {
            log.Fatal(err)
        }
    }
    return obj
}

func main() {
    histObj := findObj("dqm.root", "DQMData/Run 366713/EcalPreshower/Run summary/ESRecoSummary/recHits_ES_energyMax")
    h := histObj.(rhist.H1)
    fmt.Printf("name= %v\n", h.GetName())
}

Q-2 How can I convert or save a plot/object as a JSON?

In PyROOT, there is a SaveAs functionality and saves a plot as JSON. However, I searched almost all go-hep and could not find any hint.

What I want to do is finding a plot inside many ROOT files and run a Go web server as a backend to serve them. I cannot use root-srv (AFAIU) because I am only interested with a couple of plots from different big ROOT files instead of plots of a single ROOT file.

P.s.: Sorry for my ROOT Jargon which I'm not that familiar.

Many thanks in advance!

sbinet commented 1 year ago

hi,

(apologies for the belated answer)

wrt question 1, in groot we have riofs.Dir that returns a recursive-able riofs.Directory value: https://pkg.go.dev/go-hep.org/x/hep@v0.33.0/groot/riofs#Dir

f, err := groot.Open("dqm.root")
handle(err)
o, err := riofs.Dir(f).Get("DQMData/Run 366713/EcalPreshower/Run summary/ESRecoSummary/recHits_ES_energyMax")
handle(err)
h, ok := o.(rhist.H1)

or, using Go generics (w/ Go>=1.18):

f, err := groot.Open("dqm.root")
handle(err)
h, err := riofs.Get[rhist.H1].Get(riofs.Dir(f), "DQMData/Run 366713/EcalPreshower/Run summary/ESRecoSummary/recHits_ES_energyMax")
handle(err)

As for question 2, groot doesn't have such a thing (yet?). if all you want is to be able to plot a couple of histograms from a couple of ROOT files, you could perhaps reuse some of the functions used by root-srv: https://pkg.go.dev/go-hep.org/x/hep@v0.33.0/groot/rsrv

let me know if you need more guidance.

sbinet commented 1 year ago

is it for integration with a CMS monitoring tool (K8s-based ?)

one could perhaps implement a ROOT-TH{1,2}x to JSON facility

mrceyhun commented 1 year ago

Very life saving info of riofs.Dir feature.

This is not for CMS monitoring actually. I am evaluating Go option for a project of CMS PPD, not a big project. PyROOT and C++ options are working fine but since I'll run it in K8s , I wanted to give it a try to go-hep libs.

If I can find free time, I can try to convert ROOT-TH{1,2}x to JSON. If I it works, I can open an issue to discuss it.

Because this is a question issue and I don't have any further questions, issue is closable. Thanks a lot @sbinet !

sbinet commented 1 year ago

the rhist.H{1,2}x code is heavily generated (as you may have guessed). but once you get, say, rhist.H1D implemented, we can port it to the generation code scaffolding. I'd suggest to implement this as a MarshalJSON/UnmarshalJSON pair of methods. (but that would only tackle the histogram part. not the styles, colors, points, plot title, etc...)

alternatively, one could address the problem one level down: at the gonum/plot layer. there is a "canvas recorder" tool that can record canvas in "ASCII" form:

one could use a similar implementation (say, vgjson or something) to save the whole thing in JSON. (this could be tucked under go-hep.org/x/hep/hplot)

sbinet commented 1 year ago

closing in favour of https://github.com/go-hep/hep/issues/982