Sernight
Sernight

Reputation: 5

List of pointers of ctypes.Structures in Python and C++ function

I've checked countless posts and I can't find solution. I have the same classes in the Python and c++.

C++

__host__ __device__ class Vector3f {
    public:
        float x;
        float y;
        float z;
};

__host__ __device__ class Point3f {
    public:
        float x;
        float y;
        float z;
};

struct Values {
    Point3f position;
    Vector3f velocity;
};

struct Orb {
    std::string name;
    float mass;
    float radius;
    float density;
    Values values;
    float distance;
};

Python

class Point3f(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("z", c_float)]


class Vector3f(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("z", c_float)]


class Values(Structure):
    _fields_ = [("position", Point3f),
                ("velocity", Vector3f)]

    def __init__(self, p, v):
        Structure.__init__(self, p, v)


class Orb(Structure):
    _fields_ = [("name", c_char_p),
                       ("mass", c_float),
                       ("radius", c_float),
                       ("density", c_float),
                       ("values", Values),
                       ("distance", c_float)]

    def __init__(self, n, m, r, d, p, v, dd):
        n = c_char_p(n.encode('utf-8'))
        val = Values(p, v)
        super(Orb, self).__init__(n, m, r, d, val, dd)


class PyOrb():
    def __init__(self, n, m, r, d, p, v, dd, c=(0, 0, 0)):
        self.orb = Orb(n, m, r, d, p, v, dd)
        self.pr = pointer(self.orb)


class SolarSystem:
    def __init__(self):
        self.objects = []   #array of PyOrbs
        self.pointers = []
        self.time = None

    def fill_pointers(self):
        prs = []
        for i in range(len(self.objects)):
            prs.append(self.objects[i].pr)
        self.pointers = (POINTER(Orb) * len(self.objects))(*prs)

In Python I have array of PyOrbs that have orb(ctype structure) I am trying to get array of pointers to C++ function:

extern "C" void update(Orb **obj, int length) {
    std::cout << "Length: " << length << '\n';
    for (int i = 0; i < length; i++) {
        std::cout << obj[i] << '\n';
        std::cout << obj[i]->mass << '\n';
    }
    obj[0]->mass /= 1000;
};

I call it in Python:

gpu = cdll.LoadLibrary('./libKernel.so')

    ss = SolarSystem()
    ss.add_orbs()

    for i, p in enumerate(ss.pointers):
        print(ss.pointers[i], ss.objects[i].pr)

    print(ss.pointers[0].contents.mass, ss.objects[0].pr.contents.mass)
    ss.pointers[0].contents.mass /= 1000
    print(ss.pointers[0].contents.mass, ss.objects[0].pr.contents.mass, ss.objects[0].orb.mass)

    gpu.update(ss.pointers, len(ss.pointers))

    print(ss.objects[0].orb.mass)

In terminal my print and cout doesn't match. When i try read mass of orb[0] i get different number. Also i get wrong adresses in Python, but if i change one of them, rest change. I guess that the problem is in calling C++ function. I compile '.so':

nvcc --ptxas-options=-v --compiler-options '-fPIC' -o libKernel.so --shared project.cu

In addition the terminal:

<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd2200c0>
<__main__.LP_Orb object at 0x7f05dd220dc0> <__main__.LP_Orb object at 0x7f05dd220640>
<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd2205c0>
<__main__.LP_Orb object at 0x7f05dd220dc0> <__main__.LP_Orb object at 0x7f05dd2209c0>
<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd220840>
<__main__.LP_Orb object at 0x7f05dd220dc0> <__main__.LP_Orb object at 0x7f05dd2207c0>
<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd220140>
<__main__.LP_Orb object at 0x7f05dd220dc0> <__main__.LP_Orb object at 0x7f05dd220a40>
<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd2204c0>
<__main__.LP_Orb object at 0x7f05dd220dc0> <__main__.LP_Orb object at 0x7f05dd220c40>
<__main__.LP_Orb object at 0x7f05dd220ec0> <__main__.LP_Orb object at 0x7f05dd220d40>
1.9899999468308077e+30 1.9899999468308077e+30
1.9899999232189753e+27 1.9899999232189753e+27 1.9899999232189753e+27
Length: 11
0x7f05d00e8de0
-0.00587
0x7f05d00e8f30
6.82
0x7f05d0086750
-35.1
0x7f05d0086f90
-30.1
0x7f05d009d810
20.5
0x7f05d009df30
4.6
0x7f05d00ac7b0
6.36
0x7f05d00acfc0
-4.7
0x7f05d00376c0
0.709
0x7f05d0037f00
5.01
0x7f05d0047780
-29.5
1.9899999232189753e+27

Process finished with exit code 0

I know that code isn't great and it's a lot of to read, but i really hope for some help. Thank you!

Upvotes: 0

Views: 83

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177891

It's ctypes, not cpptypes. ctypes doesn't understand C++ classes like std::string. c_char_p represents a char* in the Orb structure. Change std::string to an char[MAX_NAME_LEN] array and use type c_char * MAX_NAME_LEN in Python.

Upvotes: 1

Related Questions