Piotr Benedysiuk
Piotr Benedysiuk

Reputation: 197

Cython self defined data types ndarray

I've created a dtype for my np.ndarrays:

particle_t = np.dtype([
    ('position', float, 2),
    ('momentum', float, 2),
    ('velocity', float, 2),
    ('force', float, 2),
    ('charge', int, 1),
])

According to the official examples one can call:

def my_func(np.ndarray[dtype, dim] particles):

but when I try to compile:

def tester(np.ndarray[particle_t, ndim = 1] particles):

I get the Invalid type error. Another possibility of usage I've seen is with the memory view like int[:]. Trying def tester(particle_t[:] particles): results in: 'particle_t' is not a type identifier.

How can I fix this?

Upvotes: 3

Views: 508

Answers (1)

ead
ead

Reputation: 34316

Obviously, particle_t is not a type but a Python-object as far as Cython is concerned.

It is similar to np.int32 being a Python-object and thus

def tester(np.ndarray[np.int32] particles):     #doesn't work!
       pass

won't work, you need to use the corresponding type, i.e. np.int32_t:

 def tester(np.ndarray[np.int32_t] particles):  #works!
      pass

But what is the corresponding type for particle_t? You need to create a packed struct, which would mirror your numpy-type. Here is a simplified version:

#Python code:
particle_t = np.dtype([
    ('position', np.float64, 2), #It is better to specify the number of bytes exactly!
    ('charge', np.int32, 1),  #otherwise you might be surprised...
])

and corresponding Cython code:

%%cython
import numpy as np
cimport numpy as np

cdef packed struct cy_particle_t:
    np.float64_t position_x[2]
    np.int32_t   charge

def tester(np.ndarray[cy_particle_t, ndim = 1] particles):
    print(particles[0])

Not only does it compile and load, it also works as advertised:

>>> t=np.zeros(2, dtype=particle_t)
>>> t[:]=42
>>> tester(t)
{'charge': 42, 'position_x': [42.0, 42.0]}

Upvotes: 4

Related Questions