使用Python调用Fortran程序

Washy
2023-05-27 / 0 评论 / 171 阅读 / 正在检测是否收录...

1 前言

网上关于Python调用Fortran程序的方法通常分为三种:1)基于f2py;2)生成动态链接库;3)生成可执行文件。

其中第1种方法在涉及到“祖传”代码时,通常会出现各种报错;第3种方法在进行数据传递时基本只能通过操作文件的方式,很不方便。

由于涉及Fortran程序时,一般都逃不开“祖传”代码,因此本文将介绍最为稳定可靠的第2种方法。

2 方法详情

2.1 示例代码

  • 新建test01.f90文件,创建子例程sub_test01以及函数func_test01,详细内容如下
subroutine sub_test01(x,y,z) bind(C,name="sub_test01")
    use iso_c_binding
    real(c_double), intent(in), value :: x,y
    real(c_double), intent(out) ::  z(2)

    z(1) = x + x
    z(2) = y*y
end subroutine sub_test01

function func_test01(x,y) result(z) bind(c,name="func_test01")
    use iso_c_binding
    real(c_double), intent(in), value :: x,y
    real(c_double) :: z

    z = x + y
end function func_test01
  • bind:用于声明外部调用时子例程/函数名称
  • iso_c_binding:Fortran自带的模组,必须引用
  • intent:声明变量属性,输入为in,输出为out,即是输入也是输出为inout
  • c_double:变量类型,real对应c_doubleinteger对应c_int
  • value:输入变量为单个值时,需添加此标记

2.2 生成动态链接库

  • 与正常编译相比增加-shared,生成后缀为.so的文件,如下
gfortran -shared test01.f90 -o test01.so

如果此步骤报错recompile with -fPIC,则在-shared后加上-fPIC

2.3 使用Python调用

  • 调用sub_test01子例程,需要引用ctypesnumpy,示例代码如下
import ctypes as ct
import numpy as np

# 加载动态链接库
fortlib = ct.CDLL('test01.so') 
# 引用sub_test01子例程
f_sub = fortlib.sub_test01
# 声明变量类型
f_sub.argtypes = [ct.c_double, ct.c_double, ct.POINTER(ct.c_double)]

# 输入变量赋值
x = ct.c_double(3)
y = ct.c_double(4)
# 输出变量初始化
z = np.ones(2)
z_p = z.ctypes.data_as(ct.POINTER(ct.c_double))

# 调用sub_test01子例程
f_sub(x,y,z_p)
print(z)
  • 使用ctypes.CDLL(<so name>)加载动态链接库,其中<so name>为上一节生成的动态链接库名称
  • 子例程的引用名称为上一节bindname定义的名称
  • argtypes用于声明变量类型,其中ctypes.POINTER表示指针。当变量为单个值(Fortran代码中value)时,声明为相应类型;当变量为数组(或输出变量,即intent(out))时,声明为指针
  • ctypes.c_double(<value>),其中<value>为变量的值
  • 打印结果为[6. 16.]
  • 调用func_test01函数,与子例程调用方式基本相同,示例代码如下
import ctypes as ct

# 加载动态链接库
fortlib = ct.CDLL('test01.so') 
# 引用sub_test01子例程
f_sub = fortlib.func_test01
# 声明变量类型
f_sub.argtypes = [ct.c_double, ct.c_double]
# 声明结果类型
f_sub.restype = ct.c_double

# 输入变量赋值
x = ct.c_double(3)
y = ct.c_double(4)

# 调用sub_test01子例程
z = f_sub(x,y)
print(z)
  • restype声明返回值的类型
  • 打印结果为7.0

参考

0

评论 (0)

昵称
邮箱
网址
取消