Combining RooDatasets using std::map in PyROOT

I am using PyROOT (from ROOT v5.34/09) and RooFit (v3.56). I am trying to do a simultaneous fit, following the example, here:
root.cern.ch/root/html/tutorials … pdf.C.html

I have come to this step, but instead of 2 datasets (like in the example), I have 21 datasets that I want to combine. The example code snippet is here:

RooDataSet combData("combData","combined data",x,Index(sample),Import("physics",*data),Import("control",*data_ctl)) ;

Since the constructor is limited to 8 RooCmdArg arguments, I guess I have to use this same constructor:

RooDataSet(const char* name, const char* title, const RooArgSet& vars, const RooCmdArg& arg1, const RooCmdArg& arg2 = RooCmdArg(), const RooCmdArg& arg3 = RooCmdArg(), const RooCmdArg& arg4 = RooCmdArg(), const RooCmdArg& arg5 = RooCmdArg(), const RooCmdArg& arg6 = RooCmdArg(), const RooCmdArg& arg7 = RooCmdArg(), const RooCmdArg& arg8 = RooCmdArg())

… but with these two RooCmdArg arguments instead:

 Index(RooCategory&)
 Import(map<string,RooDataSet*>&)

The problem is that when I try to use map<string,RooDataSet*> in PyROOT, I get a seg fault. This seems to be a problem with std::maps and RooFit objects in PyROOT in general:

Do the RooFit experts know how to either (a) import 21 datasets into a RooDataSet in some other way, or (b) make std::maps work with RooFit variables?

Thanks very much,
Edmund

Edmund,

sorry for the late reply, but I’m traveling (and will be for a couple more weeks).

In the other topic, you use:gInterpreter.GenerateDictionary("std::map<std::string, RooDataSet>", "map;string;RooDataSet.h")
but have you tried (I haven’t :slight_smile: ):gInterpreter.GenerateDictionary("std::map<std::string, RooDataSet*>", "map;string;RooDataSet.h")
as that appears what you need here?

Cheers,
Wim

Hi,

I tried to use:
Root.gInterpreter.GenerateDictionary(“std::map<std::string, RooDataSet*>”, “map;string;RooDataSet.h”)

But I got the error message:
terminate called after throwing an instance of 'Reflex::RuntimeError’
what(): REFLEX: Attempt to change the size of the class RooEffResModel
Abort

Do you have an idea what’s wrong?

Thanks very much in advance!
Cheers,
Walaa

Hi,

which version and, more importantly, in what environment are you running? There should be no Reflex involved in GenerateDictionary().

Also, what is this “Root.” is? Just a misspelling?

Cheers,
Wim

Hi,

Sorry for the late reply. I’m writing a python script where I import ROOT.
I’m working in /cvmfs/lhcb.cern.ch/lib/lhcb/URANIA/ with ROOTVERS=5.34.10 and PythonVERS=2.7.3.

Thanks in advance !
Cheers,
Walaa

More precisely, cvmfs (x86_64-slc5-gcc43-opt).

Thanks in advance!
Cheers,
Walaa

Hi,

so target “x86_64-slc5-gcc43-opt” only exists in URANIA_v1r1 and URANIA_v1r0, and both are about half a year older than 5.34.10 …

For that matter, I don’t see a “x86_64-slc5-gcc43-opt” target for 5.34.10? Not on /afs anyway?

Might be best to start with getting a consistent environment?

Cheers,
Wim

Hi,

I’m working on a local machine in Marseille where cvmfs is installed and using Urania-v2r1.

what would you suggest?

Many thanks!
Cheers,
Walaa

Hi,

sorry, I don’t follow … the /cvmfs at CERN does not have a x86_64-slc5-gcc43-opt target for Urania-v2r1.

Anyway, looking in Urania-v2r1, I see 2 different RooEffResModel.h files: one for PVV2 and one for B2DXFitters. I also see two dictionary files, one for each. Both contain RooEffResModel, and they are for a fact different.

So my guess is then that both dictionaries are loaded, resulting in the error of different class sizes.

Could you set the LD_DEBUG envar to ‘files’ and see whether indeed both dicts are loaded?

If they are, the only solution I see is to explicitly use gSystem.Load(“one_or_the_other_dict.so”) to select the one that you want, rather than relying on the auto-loader.

Cheers,
Wim

Hi,

Sorry, I was mistaken. I’m working with x86_64-slc5-gcc46-opt not gcc43!
I set LD_DEBUG and I see that both dicts are loaded. So when I try:

  1. gSystem.Load(“one_or_the_other_dict.so”)
    Both dicts are still loaded and the error message (Reflex …) is still here.

  2. I downloaded the package P2VV hoping that the code will only use the local P2VV/RooEffResModel.h
    but I doesn’t work either! B2DXFitters is still used and I got the same error.

Please find in attachment an output of the code.

Thank you very much for your help!
Walaa
10_output.txt (384 KB)

Hi,

[quote=“kanso”]1) gSystem.Load(“one_or_the_other_dict.so”)
Both dicts are still loaded and the error message (Reflex …) is still here.[/quote]
did you try each dict? And which one was used for the output posted? AFAICS, both are still auto-loaded there?

Also, the .rootmap file in Urania-v2r1x86_64-slc5-gcc46-opt/lib contains a duplicate set for the classes is both dicts. I.e. any auto-loading will pull them both in. I don’t see how that could ever work. Who installed that?

Cheers,
Wim

Hi,

Yes, I tried each dict. I got the same error and the same output with both of them.
I contacted the package maintainers and I use now a version of Urania without P2VV and B2DXFitters. It works!

Thank you very much for your help!
Cheers,
Walaa

Sorry for rising up old topic, but I tried to do the same:

R.gInterpreter.GenerateDictionary("std::map<std::string, RooDataSet*>", "map;string;RooDataSet.h") m = R.std.map('string, RooDataSet*')() ... m["sample"] = R.RooDataSet("SignalDataSet",\ "SignalDataSet",\ tree,\ w.set("dataset_args"),\ cut)
Unfortunately, i catch an error:

TypeError: none of the 2 overloaded methods succeeded. Full details:
  no __setitem__ handler for return type (RooDataSet*&)
  no __setitem__ handler for return type (RooDataSet*&)

When type definition from RooDatSet to RooDataSet* is performed (I assume)

Since this topic is quite old and this question has not been discussed yet, I assume that there is very simple solution of this. Can anyone please help me?

Ilya,

that indeed does not work, as setitem as-is only works for by-value assignments (so that there’s no difficulty with ownership semantics). Instead, use insert (and make sure that the set is kept alive). For example:[code]# create a dictionary for the std::pair to use with insert
R.gInterpreter.GenerateDictionary(“std::pair<std::string, RooDataSet*>”, “map;string;RooDataSet.h”)

data set to insert

r = R.RooDataSet(“SignalDataSet”, “SignalDataSet”, tree, w.set(“dataset_args”), cut)

make sure a reference count is kept

m.keepalive = list()
keepalive.append®

actual insertion into the map,

m.insert(m.begin(), R.std.pair(‘string, RooDataSet*’)(“sample”, r))[/code]
HTH,
Wim

Wim, thank you very much. Worked for me.

Hi,

I stumbled across this topic as I was also looking for a way to import at the moment 9 data sets from different detectors. But for me the code given by Wim at the end doesn’t work with ROOT 6.04 and Python 2.7.6. I made a small running code example that stops with an error at the first insert call:

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

import ROOT

x = ROOT.RooRealVar(‘x’, ‘x’, 0, 100)

data_det1 = ROOT.RooDataSet(“data_det1”, “data_det1”, ROOT.RooArgSet(x))
data_det2 = ROOT.RooDataSet(“data_det2”, “data_det2”, ROOT.RooArgSet(x))

detector = ROOT.RooCategory(“detector”, “detector”)
detector.defineType(“det1”)
detector.defineType(“det2”)

ROOT.gInterpreter.GenerateDictionary(“std::pair<std::string, RooDataSet*>”, “map;string;RooDataSet.h”)
m = ROOT.std.map(‘string, RooDataSet*’)()

keepalive = list()
keepalive.append(data_det1)
keepalive.append(data_det2)

m.insert(m.begin(), ROOT.std.pair(“string,RooDataSet*”)(“det1”, data_det1))
m.insert(m.begin(), ROOT.std.pair(“string,RooDataSet*”)(“det2”, data_det2))

data_comb = ROOT.RooDataSet(“data_comb”, “data_comb”, ROOT.RooArgSet(x), RF.Index(detector), RF.Import(m))[/code]

the error message shows problems with the arguments, but I have no idea, what to change.

[quote]TypeError: none of the 3 overloaded methods succeeded. Full details:
pair<_Rb_tree_iterator<pair<const string,RooDataSet*> >,bool> map<string,RooDataSet*>::insert(const pair<const string,RooDataSet*>& __x) =>
takes at most 1 arguments (2 given)
void map<string,RooDataSet*>::insert(initializer_list<pair<const string,RooDataSet*> > __list) =>
takes at most 1 arguments (2 given)
_Rb_tree_iterator<pair<const string,RooDataSet*> > map<string,RooDataSet*>::insert(_Rb_tree_const_iterator<pair<const string,RooDataSet*> > __position, const pair<const string,RooDataSet*>& __x) =>
could not convert argument 1[/quote]

It would be great if anyone has a solution.
Thanks!
Lukas

Hi Lukas,

Lately I have struggled with similar problem, so I corrected your example and I think it should work. First issue was with dictionary generation, second with omitting m before keepalive = list(). It should be m.keepalive = list().
Below working example:

#!/usr/bin/env python

import ROOT 
from ROOT import RooFit as RF

x = ROOT.RooRealVar('x', 'x', 0, 100)

data_det1 = ROOT.RooDataSet("data_det1", "data_det1", ROOT.RooArgSet(x))
data_det2 = ROOT.RooDataSet("data_det2", "data_det2", ROOT.RooArgSet(x))

detector = ROOT.RooCategory("detector", "detector")
detector.defineType("det1")
detector.defineType("det2")

ROOT.gInterpreter.GenerateDictionary("std::pair<std::string, RooDataSet*>", "map;string;RooDataSet.h")
ROOT.gInterpreter.GenerateDictionary("std::map<std::string, RooDataSet*>", "map;string;RooDataSet.h")
ROOT.gInterpreter.GenerateDictionary("std::pair<std::map<string,RooDataSet*>::iterator, bool>", "map;string;RooDataSet.h")

print 'for diagnostic purposes: '
p0 = ROOT.std.pair('string, RooDataSet*')()
print 'p0 = ', p0
m0 = ROOT.std.map('string, RooDataSet*')()
print 'm0 = ', m0
b0 = ROOT.std.pair('map<string,RooDataSet*>::iterator, bool')()
print 'b0 = ', b0

m = ROOT.std.map('string, RooDataSet*')()

m.keepalive = list()
m.keepalive.append(data_det1)
m.keepalive.append(data_det2)

m.insert(m.begin(), ROOT.std.pair("string,RooDataSet*")("det1", data_det1))
m.insert(m.begin(), ROOT.std.pair("string,RooDataSet*")("det2", data_det2))

data_comb = ROOT.RooDataSet("data_comb", "data_comb", ROOT.RooArgSet(x), RF.Index(detector), RF.Import(m))

data_comb.Print()

Cheers,
Karol

Hi Karol,

thanks for your example! The code seems to work with ROOT 5.34.30, but unfortunately I get an error message with ROOT 6. As I just switched to ROOT 6 I would prefer not to go back to the older version. Do you have any idea, what could be changed to run in under ROOT 6?
Running the code quickly in ipython with pyROOT 6 I get an error message when first using the dictionary:

Thanks a lot,

Lukas

Hi Lukas,
I confirm, it works with ROOT v5-34-30, but I have got the same error while I have used ROOT6.

 m.insert(m.begin(),ROOT.std.pair("string,RooDataSet*")("det1", data_det1))
TypeError: none of the 3 overloaded methods succeeded. Full details:
  pair<_Rb_tree_iterator<pair<const string,RooDataSet*> >,bool> map<string,RooDataSet*>::insert(const pair<const string,RooDataSet*>& __x) =>
    takes at most 1 arguments (2 given)
  void map<string,RooDataSet*>::insert(initializer_list<pair<const string,RooDataSet*> > __list) =>
    takes at most 1 arguments (2 given)
  _Rb_tree_iterator<pair<const string,RooDataSet*> > map<string,RooDataSet*>::insert(_Rb_tree_const_iterator<pair<const string,RooDataSet*> > __position, const pair<const string,RooDataSet*>& __x) =>
    could not convert argument 1

Now I have no idea how to fix it. It is probably matter of c++ compiler or library version.

Cheers,
Karol

Rather, the bindings seem to play fast and loose with ‘const’. This works:m.insert(m.cbegin(), ROOT.std.pair("const string,RooDataSet*")("det1", data_det1))Note the ‘cbegin’ and addition of ‘const’ to the type name of the pair. Looks like a bug to me: the bindings should simply ignore ‘const’ and allow the conversions.

-Dom

1 Like