TTree.Draw() with custom function

Hi,

I’m using pyroot, with root v5.34/01, python v2.7.3 and gcc v4.7.2,

I’m trying to use a custom function for weights in the selection field of TTree.Draw(). My custom function is defined as a C-style root macro:

#include <TH1F.h> TH1F *h = 0; double myfunction(double val = 0) { if (!h) return 0.; return h->GetBinContent(h->FindBin(val)); }

In the main program (below) I load the macro and use it in TTree.Draw(). This works fine (output reweighted.png looks fine), but (as far as I can judge) at the closing of my main function the program segfaults. My main concern is making this run cleanly, but maybe you can give me other suggestions to improve the method.

a) Why am I getting a segmentation fault and how do I solve it. Output is attached, but I don’t understand where the error is coming from.

b) Is it possible to define my custom function in python, e.g. “def myfunction(): …” syntax, in the main file? If so, how do I load it such that it is known to TTree.Draw().

Main (test) program:

[code]#!/usr/bin/env python

import ROOT

def main():
f0 = ROOT.TFile(“extra.root”,“read”)
f1 = ROOT.TFile(“data.root”,“read”)

ROOT.gROOT.ProcessLineSync('.x myfunction.C+')

f0.cd()
h = f0.Get("inputdir/inputhist;1")
h.SetName("h")
ROOT.gDirectory.cd("inputdir")
ROOT.gROOT.ProcessLineSync('TH1F *h = (TH1F*)gDirectory->Get("h")')

canvas = ROOT.TCanvas("c","c")
canvas.cd()

t1 = f1.Get("mytree")
t1.Draw("var","","",10000)
t1.Draw("var","(myfunction(var))*1.0","same",10000)

canvas.SaveAs("reweighted.png")
canvas.Close()

f0.Close()
f1.Close()

if name == “main”:
main()
[/code]

Thanks,
Sara
out.txt (6.13 KB)

Hi again,

Testing a bit I can see the error appears when I try to Close f0, after I have used it in TTree.Draw(). If I try to Close before the Draw() but after the ProcessLineSync()'s, I don’t get a segmentation fault.

I believe the problem is related to where the h histogram is loaded in memory. Currently it’s loaded under f0, if I try to load it under f1, the segmentation fault appears when closing f1 instead. Actively deleting the histogram before closing doesn’t help.

Cheers,
Sara

Adding to my confusion, on lxplus this script runs fine, no segfault.

Any suggestions?

Sara

I’m problably starting to look a bit ridiculous, four updates without any input from someone else, but I really want to solve this issue. Is there no-one around with some pyroot/gdb experience to help point me in the right direction for a solution?

Meanwhile:
Reorganizing a bit to get rid of the extra cd()'s:

[code]#!/usr/bin/env python

import ROOT

def main():
f0 = ROOT.TFile(“extra.root”,“read”)

ROOT.gROOT.ProcessLineSync(’.x myfunction.C+’)

h = f0.Get(“inputdir/inputhist;1”).Clone(“h”)
ROOT.gROOT.ProcessLineSync(‘TH1F h = (TH1F)gDirectory->Get(“h”)’)

canvas = ROOT.TCanvas(“c”,“c”)
canvas.cd()

f1 = ROOT.TFile(“data.root”,“read”)
t1 = f1.Get(“mytree”)
t1.Draw(“var”,"","",10000)
t1.Draw(“var”,"(myfunction(var))*1.0",“same”,10000)

canvas.SaveAs(“reweighted.png”)
canvas.Close()

f0.Close()
f1.Close()

if name == “main”:
main()
[/code]

Locally on my laptop I still get the segmentation fault, and attached is a more elaborate backtrace. Hopefully someone can help me fish the issue from that.

Sara
out.txt (35.4 KB)

Sara,

sorry, I had too much on my plate; trying to catch up now.

I expect that the problem is that PyROOT tries to figure out where ownership should be and typically this works well when variables are passed around through normal function interfaces. This call, however:ROOT.gROOT.ProcessLineSync('TH1F *h = (TH1F*)gDirectory->Get("h")')goes around the back of everything and so both python and C++ (b/c of the file ownership) think they own “h”.

If that is indeed the problem, thenROOT.SetOwnership(h, False)should solve the problem.

Cheers,
Wim

No problem Wim.

A colleague suggested the same SetOwnership, but this does not solve the problem. If I add it, syntax like you wrote, I still get the segfault and the backtrace remains exactly the same.

Since the problem only appears on my local machine I suspect it has something to do either with the version of root/gcc I’m running, or with the way everything is linked. If you know which things to check there I can have a look.

Thanks,
Sara

Sara,

does it help if you change the close order (i.e. close files in reverse order of opening them)?

One thing that will certainly help is if you use ROOT.SetOwnership(f0, False) ROOT.SetOwnership(f1, False)but that just doesn’t seem right: I’m not certain whether the problem is deleting a TFile that has already gone dodo-bird, or whether the problem is in the objects it is holding, but not calling their dtors at all seems rather drastic.

Cheers,
Wim

The order of closing doesn’t change the error. The segfault always happens when you try to close the tfile under which th1f h is loaded.

With the code like I put it here first, h is in memory under tfile f0 (from which it was read too), and subsequently closing f0 gives the segfault. If I do some extra cd’s and load the histogram to memory under f1, the segfault comes when closing f1.

Setting the ownership to False for both files I still get a segfault, but the bactrace is different. I attached it again.

Cheers,
Sara
out2.txt (4.18 KB)

Sara,

then it looks like it’s not PyROOT related, but rather ROOT’s internal cleanup on program shutdown. There’s a similar discussion (very similar stack trace) going on at the roottalk mailing list (started by Chris Jones). Philippe can reproduce it and is looking into it.

Cheers,
Wim

Hi,

and according to Philippe, a fix has just gone in. Any chance you can try v5-34-00-patches?

Cheers,
Wim

Hi Wim,

I just upgraded to the patched version and the segmentation fault is gone :slight_smile:. Thanks for pointing me to the fix.

Cheers,
Sara