我正在用C编写一个ode-solver,导出到一个Windows DLL和一个DLL的Python包装器。我很习惯Python,但我也是C和ctypes的初学者。
受接受的答案here启发的修改后的解决方案如下:
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.t
和data.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-solver中计算的数据的正确/最佳方式是什么?
另外,如果这不是将数组从C传递到Python的最佳方法,那么还有哪些其他选择适合这种应用程序?即对于每个时间步,或者可能在达到某个最后时间之后,将解决方案(t, x)
(元组或两个数组)从C传递给Python?
答案 0 :(得分:0)
要访问行为int,long等的ctypes对象的值,请使用:
x = ctypes.c_int(123)
print x.value
所以,你可以迭代它们并制作你的数组。
另外,你可以将一个清晰的C静态数组传递给Python而不是使用结构,并使用numpy的ctypes支持来获取numpy.ndarray,或者使用Python的数组模块。
但是,我明白了你的观点。这些都是简单而干净的方法。
答案 1 :(得分:0)
您可以使用numpy.ctypeslib.as_array
。
从ctypes数组或ctypes POINTER创建一个numpy数组。 numpy数组与ctypes对象共享内存。
numpy.ctypeslib.as_array(data.x, (data.nr_steps,)
只有一点issue重复使用不同形状的相同指针。