Я пытаюсь передать и получить доступ к структурированному массиву 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.