Deb*_*asu 8 python fortran ctypes gfortran fortran90
经验:
fortran大约3个月
python - 中间:在此之前从未在python中使用过ctypes模块
我正在寻找一种方法来在python中使用fortran代码进行我的博士工作 - 随后使用matplotlib即时使用可视化计算进行可视化.
这个帖子有帮助(这告诉我可以使用ctypes模块在python中使用/调用fortran代码 - 并且鉴于fortran函数具有绑定到它们的备用名称 - 这在逻辑上对我有意义,尽管我不知道它是如何工作的细节,但我们不要选择我们的战斗明智的!).
然后这个SO帖子也处理从python调用fortran函数.
下一个合乎逻辑的步骤是查找python模块ctypes的文档.这里讨论了如何在API级别使用python访问共享库.
我把所有的部分都做成了一个最小的工作示例,另一个答案已经完成了.但我想看看涉及真实浮点数的输出机制和数学运算.这是我做的测试用例.
function prnt(s)
character(80):: s
logical :: prnt
print*, s
prnt = .true.
end function prnt
function sin_2(r)
real:: r,sin_2
sin_2 = sin(r)**2
end function sin_2
Run Code Online (Sandbox Code Playgroud)
$gfortran -shared -g -o test.so test.f90
Run Code Online (Sandbox Code Playgroud)
编辑:由于某种原因,我的工作计算机需要-fPIC选项进行编译
为了确保我的两个功能prnt
,sin_2
并在那里,我检查nm
:
$ nm test.so | tail -3
0000067f T prnt_
0000065c T sin_2_
U sinf@@GLIBC_2.0
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.我的功能prnt
和sin_2
已映射到prnt_
和sin_2_
存储库中.
这是所有这一切都有点潮湿的地方.使用python-ctypes文档中的表,我输入以下内容 -
>>> from ctypes import byref, cdll, c_float,c_char_p
>>> t = cdll.LoadLibrary('./test.so')
>>> c = c_char_p("Mary had a little lamb")
>>> t.prnt_('Mary had a little lamb')
Mary had a little lambe
1
>>> t.prnt_("Mary had a little lamb")
Mary had a little lambe
1
>>> t.prnt_(c)
Mary had a little lambe[? .prnt_(c)
1
Run Code Online (Sandbox Code Playgroud)
我想在每个输出结尾打印的1是python让我知道布尔输出为的t.prnt_
方式.true.
.当我切换到字符串的正确数据类型时,我
有点担心情况会变得更糟t.prnt_
.文字打印好,只有e
最后一个.这是EOL角色吗?
然后是t.sin_2_
功能.我决定用它来计算罪(4.56)**2.这是怎么回事 -
>>> f = c_float(4.56)
>>> t.sin_2_(4.56)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1
>>> t.sin_2_(f)
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)
我在哪里错了?我试图解释我是如何处理这个问题的,这样如果我在某个地方做出明显的失误就会很明显.
与其他SO帖子的大量链接是为了帮助其他人提出与我现在相同的问题.
在Fortran中,参数通过引用传递.Fortran字符数组不以null结尾; 长度作为隐式long int
参数通过值传递.此外,Python的float
类型是a double
,因此您可能希望使用Fortran real(8)
来保持一致性.
test.f90:
function prnt(s) ! byref(s), byval(length) [long int, implicit]
character(len=*):: s ! variable length input
logical :: prnt
write(*, "(A)") s ! formatted, to remove initial space
prnt = .true.
end function prnt
function sin_2(r) ! byref(r)
real:: r, sin_2 ! float; use real(8) for double
sin_2 = sin(r)**2
end function sin_2
Run Code Online (Sandbox Code Playgroud)
请记住argtypes
为函数设置ctypes ,并restype
在适当的位置.在这种情况下,sin_2
采用浮点指针并返回一个浮点数.
ctypes示例:
>>> from ctypes import *
>>> test = CDLL('./test.so')
>>> test.prnt_.argtypes = [c_char_p, c_long]
>>> test.sin_2_.argtypes = [POINTER(c_float)]
>>> test.sin_2_.restype = c_float
>>> s = 'Mary had a little lamb'
>>> test.prnt_(s, len(s))
Mary had a little lamb
1
>>> x = c_float(4.56)
>>> test.sin_2_(byref(x))
0.9769567847251892
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4791 次 |
最近记录: |