Combining RooDatasets using std::map in PyROOT

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

Now it works! Thanks!

Karol

Also works here, great. Thanks to both of you for the code. :slight_smile:

Hi,

I also tried:

>>> import ROOT
>>> 
>>> mp1=ROOT.std.map("int, int")()
>>> mp1.insert( ROOT.std.pair("int, int")(4,8) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: none of the 3 overloaded methods succeeded. Full details:
  pair<_Rb_tree_iterator<pair<const int,int> >,bool> map<int,int>::insert(const pair<const int,int>& __x) =>
    could not convert argument 1
  void map<int,int>::insert(initializer_list<pair<const int,int> > __list) =>
    could not convert argument 1
  _Rb_tree_iterator<pair<const int,int> > map<int,int>::insert(_Rb_tree_const_iterator<pair<const int,int> > __position, const pair<const int,int>& __x) =>
    takes at least 2 arguments (1 given)
>>> 
>>> 

Which did not work, but:

>>> import ROOT
>>> 
>>> 
>>> mp1=ROOT.std.map("const int, const int")()
>>> mp1.insert( ROOT.std.pair("const int, const int")(4,8) )
<ROOT.pair<_Rb_tree_iterator<pair<const int,const int> >,bool> object at 0x7809640>
>>> 
>>> 

works. As was already said, we should not have to use const. Therefore this is likely a bug, which just costed me an hour. Hopefully It will someday be fixed. I am using the latest available ROOT version from CVMFS:

root 6.06.06-x86_64-slc6-gcc49-opt

Cheers.

Chiming in to say that we still need const in ROOT6.16/00. Thanks all for the detailed instructions!

Hello,

With the new PyROOT (likely ROOT 6.22), these problems will hopefully be gone. In the mean time, if somebody wants to test, adding the datasets explicitly could work:
https://root.cern.ch/doc/master/classRooAbsData.html#a900e7778e6b09912764747a94723ebb7

It requires to give the correct category label, and from python it’s dangerous because both C++ and python might think that they own the object, but I can imagine that this works:

dataobjects = []
cat1Data = ROOT.RooDataSet(...)
[...]
dataobjects.append(cat1Data) # this is necessary so that python doesn't delete the dataset
dataset.addOwnedComponent("cat1", cat1Data)
dataset.addOwnedComponent("cat2", cat2Data)
[...]

I confirm this issue does not happen anymore in experimental PyROOT.

Hi,
I tried your example in LCG_101/ROOT/6.24.06/x86_64-centos7-gcc11-opt and can’t make it work. The test script is attached.
test_dd.py (940 Bytes)
Any thing wrong in the script? Thanks.

I think this one is for @jonas or @moneta ?

Hi @Dongliang, sorry for the late reply!

With ROOT 6.26 that will be released in the next days, there will be many new Pythonizations for RooFit! On of them is that you can just pass a Python dictionary to these functions that take a std::map like RooFit::Import:

    comData = RooDataSet('comData','comb data', obs, RooFit.Index(c),
       RooFit.Import({"s1" : data1, "s2" : data2, "s3" : data3})
    )

Before ROOT 6.26, e.g. with 6.24, you can either follow the recommendation by @StephanH, or you just take the pythonization code for RooFit::Import() from 6.26 like I demonstrate in this updated script:
test_dd_jonasedit.py (4.4 KB)

I hope that this helps!

Cheers,
Jonas

Hi Jonas, thanks a lot for taking care of this. I’m currently using the std.map workaround discussed above, which works fine in 6.24.

Ok, thanks for letting me know! I will mark the std::map workaround as the solution for this thread then and close it, so this zombie doesn’t get resurrected over and over :slight_smile: Feel free to open a new thread if needed!