c -在Python中使用ctypes访问数组



我正在用C编写一个代码求解器,导出到Windows DLL和DLL的Python包装器。我非常习惯Python,但我也是C和ctypes的完全初学者。

受此公认答案启发的修改解决方案如下:

c代码

/* my_clib.c */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct data {
  int nr_steps;
  double dt;
  double* t;
  double* x;
  double t0, x0;
 };
double fun_to_integrate(double t, double y){
    return (y - t);
 }
double rk4(double t, double y, double dt){
    double  k1 = dt * fun_to_integrate(t, y),
            k2 = dt * fun_to_integrate(t + dt / 2, y + k1 / 2),
            k3 = dt * fun_to_integrate(t + dt / 2, y + k2 / 2),
            k4 = dt * fun_to_integrate(t + dt, y + k3);
    return y + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
}
__declspec(dllexport) void my_fun(struct data* pointer){
    int i;
    double dt;
    dt = pointer->dt;
    pointer->t[0] = pointer->t0;
    pointer->x[0] = pointer->x0;
    for(i = 1; i < pointer->nr_steps; i++){
        pointer->t[i] = dt*i + pointer->t0;
        pointer->x[i] = rk4(pointer->t[i-1], pointer->x[i-1], dt);
    }
 }

与对应的Python文件

# my_python.py
import ctypes
import numpy as np
class DATA(ctypes.Structure):
    _fields_ = [
                ('nr_steps', ctypes.c_int),
                ('dt', ctypes.c_double),
                ('t', ctypes.POINTER(ctypes.c_double)),
                ('x', ctypes.POINTER(ctypes.c_double)),
                ('t0', ctypes.c_double),
                ('x0', ctypes.c_double)]
    def __init__(self):
        self.nr_steps = 1000
        self.dt = 0.00001
        self.t0 = 0.
        self.x0 = 2./3
        self.t = (ctypes.c_double * self.nr_steps)()
        self.x = (ctypes.c_double * self.nr_steps)()
class SOLVER(object):
    def __init__(self):
        self.clib = ctypes.CDLL('rk4.dll')
        self.clib.my_fun.argtypes = [ctypes.POINTER(DATA)]
        self.clib.my_fun.restype = None
    def func(self, data_struc):
        self.clib.my_fun(ctypes.byref(data_struc))
solver = SOLVER()
data = DATA()
solver.func(data)

在Windows 8下使用MinGW编译gcc -o -c my_clib.o my_clib.c + gcc -o rk4.dll -shared my_clib.o

一切运行正常,在最后一行solver.func()之后,时间数据和溶液数据存储在data.tdata.x中。现在我需要从指针中访问计算出来的数据。这似乎不能直接做到。如果你访问type(data.x),你得到<class '__main__.LP_c_double'>,但如果你试图访问type(data.x[i]),你得到一个标准的double

每次我尝试例如plot(data.t, data.x)或将其转换为np.array(data.t)时,Python文件崩溃并且cmd冻结。然而,我认为x_python = [data.x[i] for x i in range(*number_of_elements*)]工作,但它是非常慢的,如果数组很长。

我的问题是:访问c求解器中计算的数据的正确/最佳方法是什么?

同样,如果这不是从C传递数组到Python的最佳方式,还有什么其他替代方法适合这种应用程序?即,对于每一个时间步骤,或者可能在达到一些最终时间后,将解决方案(t, x)(元组或两个数组)从C传递到Python?

从ctypes对象中访问int、long等类型的值,使用:

x = ctypes.c_int(123)
print x.value

所以,你可以遍历它们并创建你的数组。

同样,你可以传递一个清晰的C静态数组给Python,而不是使用结构体,并使用numpy的ctypes支持来获得numpy。

但是,我用这个结构明白你的意思。

您可以使用numpy.ctypeslib.as_array

从ctypes数组或ctypes指针创建numpy数组。numpy数组与ctypes对象共享内存。

numpy.ctypeslib.as_array(data.x, (data.nr_steps,)

使用不同形状的指针会有一个小问题。

相关内容

  • 没有找到相关文章

最新更新