Приведение Numpy структурированного массива к массиву C структур - PullRequest
0 голосов
/ 11 июня 2019

Я пытаюсь передать и получить доступ к структурированному массиву Numpy, созданному на Python, из части C приложения. Я хочу использовать такой массив для создания массива со стороны Python, использовать его по своему усмотрению (все еще из Python), а затем для этапов тяжелых вычислений передавать массив в модуль C (без копий, используя указатели). так что данные могут быть доступны и изменены на стороне C.

Со стороны Python я создаю структурированный массив Numpy с пользовательским dtype , например следующим, и передаю его функции, расположенной в простом расширении C:

Python

import numpy
import cmodule

blocksize=10
numblocks=5

particle_struct_dtype = numpy.dtype([
    ('position_x', 'f4', (blocksize,)),
    ('position_y', 'f4', (blocksize,)),
    ('position_z', 'f4', (blocksize,))
])

particles = numpy.empty(numblocks, dtype=particle_struct_dtype)

cmodule.compute(particles, blocksize, numblocks) 

Как показано, я создаю массив значений ключей, где каждый ключ представляет собой "поле" структуры C, а каждое значение такого поля представляет собой массив с плавающей точкой. Затем на стороне C я пытаюсь получить массив следующим образом:
- Сначала используйте функцию PyArg_ParseTuple для получения ссылки на массив
- Затем с помощью фиктивного PyObject, созданного Py_BuildValue, получить представление dtype массива (типа структуры), чтобы затем привести его к PyArray_AsCArray

C

static PyObject *compute(PyObject *self, PyObject *args)
{
    PyArrayObject *particles;
    int numblocks, blocksize;

    // Parse arguments
    if (!PyArg_ParseTuple(args, "O!ii", &PyArray_Type, &particles, &blocksize, &numblocks)) {
        Py_RETURN_NONE;
    }
    PyArray_Descr* arrayDescr;
    PyObject* dummy;

    dummy = Py_BuildValue("[(s, O), (s, O), (s, O)]", "position_x", (blocksize), "position_y", (blocksize), "position_z", (blocksize));
    PyArray_DescrConverter(dummy, &arrayDescr);

    struct particles_t *castedParticles;
    npy_intp dims[1];
    dims[0] = blocksize;
    PyArray_AsCArray((PyObject **)&particles, (struct particles_t**)&castedParticles, dims, 1, arrayDescr);
    ...
}

Тем не менее, я продолжаю получать ошибки SEGFAULT при доступе к данным. Покопавшись в ошибках, я обнаружил, что данные не приводятся так, как я думал (преобразование выполняется неправильно).
Я попытался упростить пример, передав массив простых кортежей вместо массива кортежей с большим количеством массивов внутри:

dummy = Py_BuildValue("[(s, s), (s, s), (s, s)]", "position_x", "f4", "position_y", "f4", "position_z", "f4");
PyArray_DescrConverter(dummy, &arrayDescr);

struct simple_particles_t *castedParticles;
npy_intp dims[1];
dims[0] = blocksize;
PyArray_AsCArray((PyObject **)&particles, (struct simple_particles_t**)&castedParticles, dims, 1, arrayDescr);

И, похоже, это работает, я получаю массив упрощенных структур, каждая из которых содержит только 3 поплавка (по одному на поле) вместо 3 массивов поплавков.

Мои сомнения:
- Я что-то пропустил? Можно ли даже привести структурированный массив NumPy, где каждое поле имеет массив с плавающей точкой, в массив структур C, чтобы каждое поле Python отображалось в поле структуры C? Например, доступ к particles[0].position_x[0] из C был бы похож на доступ к particles[0]['position_x'][0] со стороны Python.
- Это собирается создать какие-либо копии? Я пытаюсь получить доступ и изменить память, выделенную Python из C.

...