经过一些在线挖掘和试错后,我仍然想知道如何通过f2py将字符串数组从Python传递给Fortran。
我在string.f90
中有Fortran子例程:
SUBROUTINE FOO(A)
CHARACTER*5,dimension(10),intent(inout):: A
PRINT*, "A=",A
END
然后我跑f2py -m mystring -c string.f90
。
编译成功。
python会话位于test.py
:
import mystring
import numpy as np
nobstot=10
xstring=np.empty(nobstot,dtype='S5')
xstring[0]="ABCDE"
mystring.foo(xstring)
运行python test.py
,我收到错误消息:
1-th dimension must be 5 but got 0 (not defined).
Traceback (most recent call last) :
File "test.py", line 6, in <module>
mystring.foo(xstring)
mystring.error: failed in converting 1st argument `a' of mystring.foo to C/Fortran array
在f2py编译步骤中,调用了gfortran和gcc编译器。
在>>> print mystring.foo.__doc__
之后,有:
foo(a)
Wrapper for ``foo``.
Parameters
---------
a : in/output rank-2 array('S') with bounds (10,5)
所以,我尝试了test.py
:
import mystring
import numpy as np
nobstot=10
xstring=np.empty((nobstot,5),dtype='S1')
print xstring.shape
xstring[0]="ABCDE"
mystring.foo(xstring)
然后运行python test.py
,错误消息为:
Traceback (most recent call last):
File "test.py", line 7, in <module>
mystring.foo(xstring)
ValueError: failed to initialize intent(inout) array -- input 'S' not compatible to 'c'
答案 0 :(得分:2)
首先,要将字符串数组传递给Fortran,在Python中,必须创建一个形状为(<number of strings>, <string length>)
的字符数组,填充其内容,然后将char数组传递给f2py生成的函数。使用您的示例:
xstring = np.empty((nobstot, 5), dtype='c')
xstring[0] = "ABCDE"
xstring[1] = "FGHIJ"
mystring.foo(xstring)
为了实现这一点,您还需要更改Fortran代码:
subroutine foo(A)
character*5, dimension(10), intent(in) :: A
print*, "A(1)=",A(1)
print*, "A(2)=",A(2)
end
请注意,intent(inout)
已替换为intent(in)
。这是因为Python中的字符串以及numpy字符串数组中的字符串是不可变的,但在Fortran中它们可能不是。因此,Python字符串的内存布局不能简单地传递给Fortran函数,用户必须重新组织字符串数据,如上所述。
其次,如果您的Fortran代码更改了字符串,正如intent(inout)
的用法所示,您需要将此类字符串参数声明为intent(in, out)
,例如,使用f2py指令。以下是一个完整的例子:
subroutine foo(A)
character*5, dimension(10), intent(inout) :: A
!f2py intent(in, out) A
print*, "A(1)=",A(1)
print*, "A(2)=",A(2)
A(1)="QWERT"
end
F2py致电:
f2py -m mystring -c string.f90
Python测试脚本:
import mystring
import numpy as np
nobstot = 10
xstring = np.empty((nobstot, 5), dtype='c')
xstring[0] = "ABCDE"
xstring[1] = "FGHIJ"
xstring = mystring.foo(xstring)
print("xstring[0]=",string[0].tostring())
print("xstring[1]=",string[1].tostring())
控制台输出:
A(1)=ABCDE
A(2)=FGHIJ
xstring[0]= QWERT
xstring[1]= FGHIJ
答案 1 :(得分:0)
与fortran之间传递字符串有点棘手。
通过这一行你建立了一个实用的二维字符数组10 * 5
CHARACTER*5,dimension(10),intent(inout):: A
尝试将其更改为
CHARACTER*10,intent(inout):: A
使它成为一个10个字符的一维数组。 如果它工作,但输出是垃圾,检查两者是否是相同的字符格式(ascii / multibyte或unicode)。
答案 2 :(得分:0)
这会起作用吗@Pearu?
用 ord
转换 ASCII -> int 并直接发送一个 numpy 数组
xstring = np.zeros((10, 5)).astype(int)
strings = ["ABCDE","FGHIJ"]
for istring,string in enumerate(strings):
for ichar,char in enumerate(string):
xstring[istring,ichar] = ord(char)
mystring.foo(xstring)