使用f2py将numpy字符串格式数组传递给fortran
我的目标是从一个Python的numpy数组中打印第二个字符串,但我总是只打印出第一个字符,而且这个字符不一定是正确的字符串。
有没有人能告诉我,正确地将完整的字符串数组传递给Fortran的方法是什么?
代码如下:
testpy.py
import numpy as np
import testa4
strvar = np.asarray(['aa','bb','cc'], dtype = np.dtype('a2'))
testa4.testa4(strvar)
testa4.f90
subroutine testa4(strvar)
implicit none
character(len=2), intent(in) :: strvar(3)
!character*2 does not work here - why?
print *, strvar(2)
end subroutine testa4
编译命令是
f2py -c -m testa4 testa4.f90
上面代码的输出
c
期望的输出
bb
3 个回答
这不是一个真正的答案,但评论太长了:也许这对你有帮助..
在你的第一个例子中,传给Fortran的原因是每个字符串的第一个字符:
'abc'
在Fortran中,这些字符最终会变成长度为2的数组,内容是'ab'和'c'。如果你只用长度为1的字符串数组,那就没问题了。我想。不过不幸的是,你不能在Python中伪装系统,把它拆分成单个字符的数组,比如 ['a','a','b','b'..
- 如果数组长度不匹配,它会报错。
关于你的第二个问题,如果你用
character*2
这种写法声明,它实际上可以直接传递一个普通的Python字符串列表:
testa4.testa4(['aa','bb','cc'])
(如果你尝试使用numpy字符串数组,它会报错。)这些字符串必须是完全正确的长度,否则这里也会报错。
根据文档,f2py希望字符串数组以dtype='c'的形式传递(也就是'|S1')。这样做可以解决一部分问题,不过在后台还有一些奇怪的数组形状问题(例如,在我的很多测试中,我发现Fortran会保持2个字符的长度,但把6个字符解释为一个2x6的数组,这样输出时就会得到一些随机的内存数据)。据我所知,这要求你把Fortran数组当作一个二维字符数组来处理,而不是一维的“字符串”数组。不幸的是,我没能让它接受假定的形状,最后只能把字符串的数量作为一个参数传入。
我很确定我遗漏了一些比较明显的东西,但目前这样应该可以工作。至于为什么CHARACTER*2不起作用……我真的不知道。
MODULE char_test
CONTAINS
SUBROUTINE print_strings(strings, n_strs)
IMPLICIT NONE
! Inputs
INTEGER, INTENT(IN) :: n_strs
CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
!f2py INTEGER, INTENT(IN) :: n_strs
!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
! Misc.
INTEGER*4 :: j
DO j=1, n_strs
WRITE(*,*) strings(:,j)
END DO
END SUBROUTINE print_strings
END MODULE char_test
----------------
import numpy as np
import char_test as ct
strings = np.array(['aa', 'bb', 'cc'], dtype='c').T
ct.char_test.print_strings(strings, strings.shape[1])
strings = np.array(['ab', 'cd', 'ef'], dtype='c').T
ct.char_test.print_strings(strings, strings.shape[1])
-->python run_char_test.py
aa
bb
cc
ab
cd
ef
我不知道怎么用 f2py
来做到这一点。不过可以用 ctypes
来实现。你会得到一个字符数组,但你可以很简单地把它转换成字符串。
subroutine testa4(strvar) bind(C, name='testa4')
use iso_c_binding
implicit none
character(len=1,kind=c_char), intent(in) :: strvar(2,3)
print *, strvar(:,2)
end subroutine testa4
编译命令是: gfortran -shared -fPIC testa4.f90 -o testa4.so
import numpy as np
import ctypes
testa4 = ctypes.CDLL("./testa4.so")
strvar = np.asarray(['aa','bb','cc'], dtype = np.dtype('a2'))
strvar_p = ctypes.c_void_p(strvar.ctypes.data)
testa4.testa4(strvar_p)
运行命令:
> python testpy.f90
bb