Getting a TF1 pointer from a ROOT.TF1 class

Hi,
I have a pretty complex library, which contains a class Func1 which derives from TF1, and which can be instantiated like this:

Func1(const &TF1)

I have built a python wrapper of the library with SWIG, so I can access its classes from python.

Then, I have a python function which cannot be easily re-written in C, and I can use it to get a ROOT.TF1 object from pyROOT:

tf1 = ROOT.TF1(“test”,someCrazyPythonFunction,-10,10,1)

Then, from python, I need to get a Func1 object which uses the ROOT.TF1 class I just created. Of course, doing:

Func1(tf1)

does not work, because tf1 is not a TF1 class, but a ROOT.TF1 class.

Is there a way to get the underlying TF1 C-class from a ROOT.TF1 class?

Hi Giacomo,

a question to understand better your setup before actually debugging this particular problem: why did you decide for swig instead of ROOT dictionaries?
This problem could be solved as follows:
Func1 class

#include "TF1.h"
class Func1:public TF1 {
public:
	Func1(TF1& f){};

ClassDef(Func1, 1)
};

Selection xml

<lcgdict>
<class name="Func1" />
</lcgdict>

Dictionary generation and compilation of the library (ROOT6, ~identical for ROOT5)

genreflex Func1.h -s sel.xml --rootmap al.rootmap 
g++ -o libFunc1.so -shared -fPIC `root-config --cflags --libs` Func1_rflx.cpp 

The rootmap file is used by ROOT to dynamically load a library when a symbol is missing. Libraries can be of course also loaded manually via gSystem->Load(“libname”).
In Python

>>> import ROOT
>>> f = ROOT.TF1()
>>> func1 = ROOT.Func1(f)
>>> func1
<ROOT.Func1 object at 0x7fe15e5128c0>

Thanks for the reply!

Unfortunately the library I am using is very complex, with a lot of external third-party libraries being imported and used, among which boost.

I tried to get a dictionary of everything I need and to import the library in ROOT but, after spending a day inserting #ifndef CINT and similar, I gave up. rootcint cannot parse most of the headers of my library…

Basically I reached the point you reached (having a ROOT.Func1 instance), but then I need to pass that class to other classes of the library, and the problem presents itself again: they want a Func1 class, not a ROOT.Func1 class…

Hi,

[quote=“giacomov”]Is there a way to get the underlying TF1 C-class from a ROOT.TF1 class?[/quote]yes, PyROOT and SWIG can talk CObjects with each other. My SWIG is rusty, but the two calls you need from PyROOT are:ROOT.AsCObject( tf1 ) # produces PyCObject from TF1 ROOT.BindObject( cobj_from_swig, ROOT.TF1 ) # produces TF1 from PyCObject
HTH,
Wim

Thanks!

Unfortunately as far as I can tell, ROOT.BindObject support only objects which are known to ROOT, and it returns again a ROOT.* object. In my case I would have to generate a dictionary for Func1 (which is easy), load the library (.so) with gSystem.Load(), and then use BindObject, but I will end up again with a ROOT.Func1 class, instead of a Func1 class.

I now realize that this might not be the right place for this, since I guess the real issue here is how to get a Func1 class from a void pointer, in SWIG.

Anyway, if anyone has any more advice, it would be much appreciated.

Hi,

yes, of course, that is the point.

You extract the CObject from ROOT, bind it to SWIG, do all the SWIG thingies, re-extract a CObject from SWIG, then bind it back to ROOT to do ROOT thingies. (Of course, if the object address stays the same, rebinding is not necessary: just keep a reference alive to the old python object.)

Not following this … you said in your first post that you had SWIG bindings?

Cheers,
Wim

sorry, I didn’t make myself very clear…

This is what I need to do:

tf1 = ROOT.TF1(…)
f1 = mySwigWrapper.Func1(tf1)
oc = mySwigWrapper.OtherClass(f1)

(and then many other classes from mySwigWrapper)

So, I need f1 to be of type Func1, not ROOT.Func1, otherwise I cannot create the instance of OtherClass.

I cannot use rootcint on all classes of the library because it cannot parse them.

I have written a SWIG interface so that I can do this:

tf1 = ROOT.TF1(…)
f1 = mySwigWrapper.Func1(ROOT.AsCObject(tf1))

as you suggested, but now f1 is of type CObject, and I need to “cast it back” to Func1, and I don’t know how to do it…

Hi,

okay, that’s up to SWIG then. A cast or typemap, or whatever the things were called (sorry, too long ago). Use the Python C-API “PyCObject_AsVoidPtr” to extract the pointer value on the SWIG side (in the .i).

Cheers,
WIm

Thanks!

Yes, I have been playing with that all day (and the night, I just finished and it’s 1am…), but I was missing a small key part, i.e., the (TF1 *) casting in the constructor of Func1.

Just for reference, this is some relevant snipplets:

[code]class Func1: public TF1 {

public:

Func1() : TF1() {};

//This constructor is primarily for the Python wrapper, so that Func1
//can be created starting from an arbitrary ROOT.TF1 object, casted to void*
//by using ROOT.AsCObject and the appropriate SWIG typemap
Func1(const char* name,void* mfcn, Double_t xmin, Double_t xmax, Int_t npar) : 
  TF1(name,(TF1 *)mfcn,xmin,xmax,npar) {};

Func1(const char* name, const char* formula, double xmin = 0, double xmax = 1):
  TF1(name, formula, xmin, xmax) {};

}[/code]

I added this in the interface file (.i):

[code]%typemap(in) void *mfcn {
$1 = PyCObject_AsVoidPtr($input);
}

%rename (Func1_fromVoid) Func1(const char* name, void* mfcn, Double_t xmin, Double_t xmax, Int_t npar);[/code]

And this is how I can use it now:

import ROOT
import mySwigWrapper
tf1 = ROOT.TF1("test","[0]*x+[1]")
myfunc1 = mySwigWrapper.Func1_fromVoid("testFunc1",ROOT.AsCObject(tf1),-10,10,2)
print(myfunc1)
<mySwigWrapper.Func1; proxy of <Swig Object of type 'Func1 *' at 0x7fd5e33d6b40> >

In the Func1 header, note the (TF1 *) casting when initializing the base class TF1: it took me a long time to realize that I had to add that…

Now I can go on and use myfunc1 with all the other classes of the library.

Thanks for the help!