繁体   English   中英

如何使用 f2py 将字符串数组传递给 Fortran 子程序

[英]How to pass array of strings to Fortran subroutine using f2py

经过一些在线挖掘和试错后,我仍然想知道如何通过 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'

首先,要将字符串数组传递给 Fortran,在 Python 中,您必须创建一个形状为(<number of strings>, <string length>)的字符数组,填充其内容,然后将字符数组传递给 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

与 fortran 通信字符串有点棘手。

用这一行,你建立了一个实用的二维字符数组 10 * 5

CHARACTER*5,dimension(10),intent(inout):: A

尝试将其更改为

CHARACTER*10,intent(inout):: A

这使它成为一个包含 10 个字符的一维数组。 如果它有效,但输出是垃圾,请检查两者是否是相同的字符格式(ascii/multibyte 或 unicode)。

这会在@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)

按照这里的评论,我试图在我的 Fortran/python 代码中重现这种方法,但我没有任何成功。 在我的代码中,我需要传递一个未知大小的字符串数组和未知长度的字符串。 例如,在我的 Fortran 代码中,我有:

   character(len=*), dimension(:), intent(in)  :: string

按照这个主题,这对我不起作用。

所以我做了一些修改,找到了一种对我有用的方法,在这里分享。 我知道这是一个老话题,但我相信其他人可以使用它。

当我将字符串数组从 python 传递到 Fortran 时,f2py 将字符串数组转换为类似 string(:,:) 的字符串,其中第一维是字符串长度,第二维是数组长度。 考虑到这一点,我以这种方式修改了 Fortran:

subroutine foo(A)
   character, dimension(:,:), intent(in) :: A
   character(len=25), allocatable :: B(:)
   integer :: strLen
   integer :: arrLen

   strLen = size(A,1)
   arrLen = size(A,2)
   allocate(B(arrLen))
   do i = 1, arrLen
      B(i) = transfer(A(:,i),B(i)(1:strLen))
   enddo
   
   do i=1, arrLen
      print*,trim(B(i))
   enddo

end

Python 测试脚本,具有不同的字符串和数组长度:

import mystring
import numpy as np

print('strings for test 1:')
xstring = np.array(['ABCDE','FGHIJ'],dtype='c').T
mystring.foo(xstring)

print('strings for test 2:')
isisList = ['amsua_n15    ', 'amsua_n18    ', 'amsua_n19    ', 'amsua_metop-a']
xstring = np.array(isisList,dtype='c').T
mystring.foo(xstring)

控制台结果:

strings for test 1:
 ABCDE
 FGHIJ
strings for test 2:
 amsua_n15
 amsua_n18
 amsua_n19
 amsua_metop-a

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM