【发布时间】:2016-02-26 13:01:35
【问题描述】:
我正在尝试在 Python 中使用 Fortran 模块。我在 Python 中有几个数组——数字和字符串。我在 Fortran 和 Python 中定义了数组,但我认为我为数值数组使用了错误的类型。我收到一个错误,即转换第一个参数(数字数组)失败。我应该使用哪些类型?
错误:
Traceback (most recent call last):
File "py_try.py", line 66, in <module>
writelittler.write_obs(p,z,t,td,spd,wdir,slp,ter,xlat,xlon,date_char,num_met,num_lev,kx,dd_strvar,station_strvar,synop,string4, bogus, iseq_num, iunit)
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1
Fortran:
subroutine write_obs(p, z, t, td, spd, wdir, xlon, kx, slp, ter, xlat, date_char, dd, station, num_met, num_lev, synop, string4, bogus, iseq_num, iunit) bind(C, name='write_obs')
use iso_c_binding
implicit none
integer(c_int) k, kx, num_met, num_lev, iseq_num, iunit, ierr
real(kind=c_float) p(kx), slp(kx), z(kx), t(kx), td(kx)
real(kind=c_float) spd(kx), ter(kx), xlat(kx), xlon(kx), wdir(kx)
character(len=1,kind=c_char) date_char
character(len=1,kind=c_char) synop, string4
character(len=1,kind=c_char), intent(in) :: dd(kx)
character(len=1,kind=c_char), intent(in) :: station(kx)
logical(c_bool) bogus
character(len=84,kind=c_char) rpt_format
character(len=22,kind=c_char) meas_format
character(len=14,kind=c_char) end_format
rpt_format = ' ( 2f20.5 , 2a40 , '&
&' 2a40 , 1f20.5 , 5i10 , 3L10 , '&
&' 2i10 , a20 , 13( f13.5 , i7 ) )'
meas_format = ' ( 10( f13.5 , i7 ) ) '
end_format = ' ( 3 ( i7 ) )'
do 100 k=1 , kx
write ( UNIT = iunit , iostat = ierr , FMT = rpt_format ) &
& xlat(k), xlon(k), dd(k), station(k), &
& synop , string4, ter(k), num_met, 0, 0, iseq_num, 0, &
& .true., bogus, .false., &
& -888888, -888888, date_char, slp(k), 0, &
& -888888., 0, -888888., 0, -888888., 0, &
& -888888., 0, -888888., 0, -888888., 0, -888888., 0, &
& -888888., 0, -888888., 0, -888888., 0, -888888., 0, &
& -888888., 0
write ( UNIT = iunit , iostat = ierr , FMT = meas_format ) &
& p(k), 0, z(k), 0, t(k), 0, td(k), 0, &
& spd(k), 0, wdir(k), 0, &
& -888888., 0, -888888., 0, -888888., 0, -888888., 0
write ( UNIT = iunit , iostat = ierr, FMT = meas_format ) &
& -777777., 0, -777777., 0, float(num_lev), 0, &
& -888888., 0, -888888., 0, -888888., 0, &
& -888888., 0, -888888., 0, -888888., 0, &
& -888888., 0
write ( UNIT = iunit, iostat = ierr, FMT = end_format ) &
& num_lev, 0, 0
if (ierr .NE. 0 ) then
print '(A,I5,A)','Troubles writing a sounding.Error #', ierr
stop 'writing_error'
endif
100 continue
return
end subroutine write_obs
Python:
import numpy as np
import ctypes
from ctypes import c_int, c_char
writelittler=ctypes.CDLL("/writelittler.so")
p = np.asarray([ 982.6, 999.7 ], dtype="float64")
p_strvar=ctypes.c_void_p(p.ctypes.data)
# [other numerical arrays omitted]
bogus = 0
kx=2
iseq_num = 0
iunit=2
date_char = ' 20160128060000'
dt=np.dtype('a40')
dd = np.asarray([ '1111111111111111111111111111111111111111', '6666666666666666666666666666666666666666', '9999999999999999999999999999999999999999' ], dtype=dt)
station = np.asarray([ 'V111111111111111111111111111111111111111','M111111111111111111111111111111111111111' ], dtype=dt)
dd_strvar=ctypes.c_void_p(dd.ctypes.data)
station_strvar=ctypes.c_void_p(station.ctypes.data)
num_met=6
num_lev=1
synop='FM-12 SYNOP '
string4=' '
writelittler.write_obs(p,z,t,td,spd,wdir,slp,ter,xlat, xlon,date_char,num_met,num_lev,kx,dd_strvar, station_strvar,synop,string4, bogus, iseq_num, iunit)
【问题讨论】:
-
当传递一个numpy数组时,使用它的
ctypes属性,例如x.ctypes而不是c_void_p(x.ctypes.data)。对于第一个参数,您错误地传递了 numpy 数组p而不是p.ctypes。确保数字类型匹配(例如c_floatfloat32、c_doublefloat64)。 -
对于按值传递,Fortran 的 C 绑定不要求您像
value那样显式声明一个参数吗?否则参数通过引用传递。例如,integer(c_int), intent(in), value :: k, kx。 -
@eryksun 确实如此。但我建议将 argtypes 明确声明为
POINTER(c_float)等。 -
@Palina 您在哪里指定
z、t以及 Python 代码中的所有其他变量?您正在 Fortran 中访问它们!