Question about how to cast in pyROOT

That example works.

Our case would be more as follows:

import ROOT

ROOT.gInterpreter.Declare("""
    struct A { virtual void abstractmethod() = 0; };
    struct B: public A {
        void abstractmethod() final {}
    };
    struct C{
        int methodC(A *a) { return 42; }
    };
""")


b = ROOT.B()

c = ROOT.C()

print(c.methodC(b))

which also works.

In our case we have the following classes which inherit from TObject.

A= TRestEvent. It contains only one abstract method void Initialize() = 0
B = TRestRawSignalEvent
C = TRestRun

abstractmethod = TRestEvent::Initialize()
methodC = TRestRun::SetInputEvent (TRestEvent *ev).

It is compiled code, not interpreted. Not sure if that would make a difference.

Thanks!!

But if I change the struct keyword by class, I get an error

>>> import ROOT
>>> 
>>> ROOT.gInterpreter.Declare("""
...     class A { virtual void abstractmethod() = 0; };
...     class B: public A {
...         void abstractmethod() final {}
...     };
...     class C{
...         int methodC(A *a) { return 42; }
...     };
... """)
True
>>> 
>>> 
>>> b = ROOT.B()
>>> 
>>> c = ROOT.C()
>>> 
>>> print(c.methodC(b))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'methodC'

Ok, glad the examples work! For your last case, the error is due to the fact that changing to class makes the methodC private in that class. You need to make it public.
Cheers,
Vincenzo

Ok that solves the problem with the example, however this does not solve our problem with our compiled class, which is the main topic for this post.

There must be something I don’t understand. Why do you expect to be able to use a private method of a class from outside that class?

Hi @Javier_Galan,

I find it weird that it works for code injected into the interpreter, but not for compiled classes. Could you please attach a minimal reproducer so that we can better diagnose (or debug) the issue?

As a (hacky) workaround, maybe you could define an inline member function on the C++ side that returns a pointer to the base object, as in

class TRestRawSignalEvent : public TRestEvent {
public:
   // ...
   TRestEvent *AsTRestEvent() { return static_cast<TRestEvent *>(this); }
};

and, obviously, on the Python side

rawEv = ROOT.TRestRawSignalEvent
rn.SetInputEvent(rawEv.AsTRestEvent())

In any case, looking forward to your reproducer.

Cheers,
J.

I can provide the following

git clone git@github.com:rest-for-physics/framework.git
cd framework
python3 pull-submodules.py --onlylibs
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../install -DRESTLIB_RAW=ON ..
make -j install
source ../install/thisREST.sh

Then I added the method you suggested into TRestRawSignalEvent and tested in python3

>>> import ROOT
>>> import REST
>>> rn = ROOT.TRestRun()
>>> rawEv = ROOT.TRestRawSignalEvent()
>>> rn.SetInputEvent( rawEv.AsTRestEvent() )

and the error output

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: TRestEvent* TRestRawSignalEvent::AsTRestEvent() =>
    TypeError: unbound method TRestRawSignalEvent::AsTRestEvent must be called with a TRestRawSignalEvent instance as first argument

This snippet should be equivalent to what you are doing (based on your previous examples, corrected class names and also adding the latest AsTRestEvent method). But all the classes feature their methods in the public section in your own repository, so I still don’t understand what was your previous issue with using the private methods.

import ROOT

ROOT.gInterpreter.Declare("""
    class TRestEvent {
    public:
        virtual void Initialize() = 0;
    };
    class TRestRawSignalEvent: public TRestEvent {
    public:
        void Initialize() final {}
        TRestEvent *AsTRestEvent() { return static_cast<TRestEvent *>(this); }
    };
    class TRestRun{
    public:
        void SetInputEvent(TRestEvent *) {}
    };
""")

rn = ROOT.TRestRun()
rawEv = ROOT.TRestRawSignalEvent()
rn.SetInputEvent(rawEv)
rn.SetInputEvent(rawEv.AsTRestEvent())

This fails as it is, what are the requirements to build the project? I’ve hit a couple issues, first I didn’t have a ROOT installation before running the cmake command and it complained. Then I sourced ROOT and now it complains that it can’t find TEveArrow.h.

It requires ROOT 6.26/10, then, as your ROOT seems to be not compiled with Eve libraries, just disable it.

Add the following option

cmake -DREST_EVE=OFF ..

I cannot build on ArchLinux due to notable changes in the GNU mpfr headers (using version 4.1.1). Could you provide us additional information about your build environment?

@jalopezg Try (if it fails, use “-DREST_MPFR=OFF”):

REST_MPFR=OFF should be the default option.

So just compiling with:

cmake -DCMAKE_INSTALL_PREFIX=../install -DRESTLIB_RAW=ON -DREST_EVE=OFF ..

should do the job.

Both of the following commands lead to the same error when building

cmake -DREST_MPFR=OFF -DCMAKE_INSTALL_PREFIX=../install -DRESTLIB_RAW=ON -DREST_EVE=OFF ..
cmake -DCMAKE_INSTALL_PREFIX=../install -DRESTLIB_RAW=ON -DREST_EVE=OFF ..

Error:

make -j install
[...]
[ 17%] generating: /home/vpadulan/Programs/framework/build/rootdict/CINT_TRestTask.cxx with /home/vpadulan/Programs/framework/source/framework/core/inc/TRestTask.h;/home/vpadulan/Programs/framework/build/rootdict/TRestTask_Linkdef.h
In file included from input_line_9:3:
In file included from /home/vpadulan/Programs/framework/source/framework/tools/inc/TRestComplex.h:27:
/home/vpadulan/Programs/framework/source/framework/tools/inc/mpreal.h:121:10: fatal error: 'mpfr.h' file not found
#include <mpfr.h>
         ^~~~~~~~

TRestComplex should not be in the compilation targets, as it is written in out main CMakeLists.txt.

#####  MPFR  #####
if (NOT DEFINED REST_MPFR)
    set(REST_MPFR OFF)
endif ()
if (${REST_MPFR} MATCHES "ON")
    find_path(MPFR_INCLUDE mpfr.h HINTS ${MPFR_PATH} ${MPFR_PATH}/include) # path to include directory
    find_path(MPFR_LIB_PATH libmpfr.so HINTS ${MPFR_PATH} ${MPFR_PATH}/lib)
    find_library(MPFR_LIB mpfr HINTS ${MPFR_PATH} ${MPFR_PATH}/lib) # path to .so file
    if (NOT MPFR_INCLUDE MATCHES "MPFR_INCLUDE-NOTFOUND" AND NOT MPFR_LIB MATCHES "MPFR_LIB-NOTFOUND")
        # MPFR is found
        list(APPEND rest_features "MPFR")
        add_compile_definitions(USE_MPFR)
        set(external_include_dirs ${external_include_dirs} ${MPFR_INCLUDE})
        set(external_libs "${external_libs};${MPFR_LIB}")
        link_directories(${MPFR_LIB})
        message(STATUS "MPFR library : ${MPFR_LIB}")
    else ()
        message(ERROR "MPFR library was not found. Adding the location to the installation path may solve this problem.\n Use -DMPFR_PATH=/path/to/mpfr/")
    endif ()
else ()
    set(REST_MPFR OFF)
    set(excludes ${excludes} TRestComplex)
endif (${REST_MPFR} MATCHES "ON")

It could be related to the version of cmake. I am using cmake version 3.20.0-rc1

I’m using cmake 3.25

Ok, I looked a bit in to the problem and I think I found a quick fix that is now at a pending PR

It will be soon merged to master

I am also investigating the errors you got about the Eve libraries. If I disable REST_EVE I also get into troubles, the point is that we never got into this error because it seems that in our systems Eve libraries in ROOT are always active.

In the code as written, you are trying to pass a class through a pointer. Instead, an instance should be created from the class. E.g. rawEv = ROOT.TRestRawSignalEvent() if the class has a default constructor.

1 Like

Ok, I was trying to create the rawEv instance without parenthesis. I.e. rawEv = ROOT.TRestRawSignalEvent, instead, using rawEv = ROOT.TRestRawSignalEvent() solved the problem!

Thanks!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.