python fortran混编 ctypes_python fortran集成:f2py和ctypes的回调比较

良好的编程风格要求我们永远不要使用单字符变量名。Fortran子例程的现代Fortran-2008实现类似于以下内容:

module foo_mod

use iso_c_binding, only: RK => c_double, IK => c_int32_t

implicit none

abstract interface

function getFunVal_proc(inputInteger) result(funVal) bind(C)

import :: RK, IK

implicit none

integer(IK), intent(in), value :: inputInteger

real(RK) :: funVal

end function getFunVal_proc

end interface

contains

subroutine getFoo(getFunValFromC,outputReal) bind(C,name="getFoo")

!DEC$ ATTRIBUTES DLLEXPORT :: getFoo

use, intrinsic :: iso_c_binding, only: c_funptr, c_f_procpointer

implicit none

type(c_funptr), intent(in), value :: getFunValFromC

procedure(getFunVal_proc), pointer :: getFunVal

real(RK), intent(out) :: outputReal

integer(IK) :: indx

! associate the input C procedure pointer to a Fortran procedure pointer

call c_f_procpointer(cptr=getFunValFromC, fptr=getFunVal)

outputReal = 0._RK

do indx = -5,5

write(*,"(*(g0,:,' '))") "value of indx from inside Fortran: ", indx

outputReal = outputReal + getFunVal(indx)

end do

write(*,"(*(g0,:,' '))") "value of outputReal from inside Fortran: ", outputReal

! nullify the Fortran pointer

nullify(getFunVal)

end subroutine getFoo

end module foo_mod

这看起来相当冗长,但它远远好于F77。毕竟,我们生活在21世纪。然后通过Intel ifort编译这个Fortran代码,例如,

ifort /dll /threads /libs:static foo_mod.f90 /exe:foo.dll

然后,你会打电话给

getFoo()

从生成的DLL

foo.dll

就像下面的Python脚本一样,

import ctypes as ct

import numpy as np

# This is the Python callback function to be passed to Fortran

def getSquare(inputInteger):

print("value of indx received by getSquare() inside Python: ",inputInteger)

return np.double(inputInteger**2)

# define ctypes wrapper function, with the proper result and argument types

getFunVal_proc = ct.CFUNCTYPE( ct.c_double # callback (python) function result

, ct.c_int32 # callback (python) function input integer argument

)

getSquare_pntr = getFunVal_proc(getSquare)

libpath = "foo.dll"

try:

# open DLL

foolib = ct.CDLL(libpath)

except Exception as e:

import logging

logger = logging.Logger("catch_all")

logger.error(e, exc_info=True)

# define getFoo's interface from Fortran dll

foolib.getFoo.restype = None # return type of the Fortran subroutine/function

foolib.getFoo.argtypes = [ getFunVal_proc # procedure

, ct.POINTER(ct.c_double) # real64 return value

, ]

outputReal = ct.c_double(0.)

foolib.getFoo ( getSquare_pntr

, ct.byref(outputReal)

)

print("value of outputReal received in Python: ", np.double(outputReal))

运行这个脚本会产生如下结果:,

In [1]: run main.py

value of indx from inside Fortran: -5

value of indx received by getSquare() inside Python: -5

value of indx from inside Fortran: -4

value of indx received by getSquare() inside Python: -4

value of indx from inside Fortran: -3

value of indx received by getSquare() inside Python: -3

value of indx from inside Fortran: -2

value of indx received by getSquare() inside Python: -2

value of indx from inside Fortran: -1

value of indx received by getSquare() inside Python: -1

value of indx from inside Fortran: 0

value of indx received by getSquare() inside Python: 0

value of indx from inside Fortran: 1

value of indx received by getSquare() inside Python: 1

value of indx from inside Fortran: 2

value of indx received by getSquare() inside Python: 2

value of indx from inside Fortran: 3

value of indx received by getSquare() inside Python: 3

value of indx from inside Fortran: 4

value of indx received by getSquare() inside Python: 4

value of indx from inside Fortran: 5

value of indx received by getSquare() inside Python: 5

value of outputReal from inside Fortran: 110.0000000000000

value of outputReal received in Python: 110.0

与您的F2PY代码相比,上面的Python脚本可能看起来更加冗长。但它比您的实现更专业、更现代、更符合标准,无论是使用Python还是Fortran标准。

脚注:“英特尔ifort”在Windows、Linux和Mac平台上向所有学生、教师和开源开发人员免费提供。这并不意味着格佛兰不好。但在我看来,在Windows操作系统上使用gcc总的来说并不比永无休止的噩梦好多少(我与英特尔没有任何关系,只是一个用户)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PythonFortran的混合编程可以通过使用F2PYFortran to Python)工具来实现。F2PY是一个用于将Fortran代码转换为Python可调用模块的工具,它可以将Fortran代码编译成Python模块,使得Python代码可以调用Fortran代码。 以下是Python封装Fortran的步骤: 1. 编写Fortran代码,并创建一个Fortran模块文件。例如,假设我们有一个Fortran程序文件`test.f90`,其中包含一个名为`add`的子程序,它可以计算两个整数的和。我们可以使用以下命令编译Fortran代码,生成一个名为`test_module.so`的共享库文件: ``` f2py -c -m test_module test.f90 ``` 2. 在Python中导入创建的Fortran模块。可以使用以下代码: ```python import numpy as np from test_module import add a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) c = add(a, b) print(c) ``` 在上述代码中,我们首先导入了Numpy库和我们创建的Fortran模块`test_module`中的`add`子程序。然后,我们使用Numpy创建了两个数组`a`和`b`,并将它们作为参数传递给`add`子程序。最后,我们打印输出结果。 注意,在使用F2PY封装Fortran代码时,需要将Fortran代码中的变量类型和Python中的变量类型进行匹配。同时,还需要考虑Fortran代码中的数组是按列存储还是按行存储的,以及是否使用了Fortran特有的数组下标从1开始的特性。 除了使用F2PY进行Python封装Fortran外,还可以使用Cython、SWIG等工具进行混合编程。这些工具都可以将Fortran代码编译成Python可调用模块,使得Python代码可以调用Fortran代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值