使用f2py公开子程序的“in,out”和“inplace”版本

时间:2015-02-07 21:33:21

标签: python f2py

我正在使用f2py将一些Fortran77例程集成到我的python模块中,但无法解决以下问题。我的Fortran例程在计算过程中销毁所有输入数组。我想为用户提供使用内存效率的选项" inplace"这些例程的行为以及在不破坏Python端数据的情况下执行例程的选项。

我可以想到两种方法:

  1. 如果用户不希望输入被破坏,请在调用我的Fortran例程之前用Python备份所有输入数组。使用" intent(inplace)"编译Fortran例程我签名中的声明。退出时,我可以使用备份副本恢复输入。
  2. 针对两个不同的签名文件编译相同的Fortran例程,一个使用" intent(inplace)"和#34;意图(in,out)" (或者只是"意图(in)"取决于具体情况)。然后在python中,我可以将两种程序的例程导入到我的模块中。
  3. 我不喜欢任何一种方法,因为它们都看似非pythonic。有没有更好的方法来解决这个问题?是否有更简单的方法来实施方法2,例如我可以将具有两个不同签名的相同例程编译到一个共享对象模块中吗?

    以下是一个示例(基于此documentation)。

    Fortran例程fib.f:

    C FILE: FIB.F
          SUBROUTINE FIB(A,N)
    C
    C     CALCULATE FIRST N FIBONACCI NUMBERS
    C
          INTEGER N
          REAL*8 A(N)
          DO I=1,N
             IF (I.EQ.1) THEN
                A(I) = 0.0D0
             ELSEIF (I.EQ.2) THEN
                A(I) = 1.0D0
             ELSE 
                A(I) = A(I-1) + A(I-2)
             ENDIF
          ENDDO
          END
    C END FILE FIB.F
    

    我使用f2py fib.f -m fib.pyf生成我的签名文件,然后添加一些意图声明:

    !    -*- f90 -*-
    ! Note: the context of this file is case sensitive.
    
    python module fib ! in
        interface  ! in :fib
            subroutine fib(a,n) ! in :fib:fib.f
                real*8 dimension(n), intent(inout) :: a
                integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
            end subroutine fib
        end interface
    end python module fib
    
    ! This file was auto-generated with f2py (version:2).
    ! See http://cens.ioc.ee/projects/f2py2e/
    

    我使用f2py -c fib.pyf fib.f编译,然后我可以运行我的例程:

    >>> import numpy as np
    >>> from fib import fib
    >>> A = np.zeros(10, dtype=float)
    >>> fib(A)
    >>> print(A)
    [  0.   1.   1.   2.   3.   5.   8.  13.  21.  34.]
    

    要将此示例更改为输入/输出模式,我只需在" fib.pyf"中更改我的意图声明。到intent(in,out)

1 个答案:

答案 0 :(得分:1)

我最终在签名文件中使用fortranname声明来生成相同子例程的inplace和in,out of flavor。这是签名文件:

    !    -*- f90 -*-
    ! Note: the context of this file is case sensitive.

    python module fib ! in
            interface  ! in :fib
                subroutine fib_inplace(a,n) ! in :fib:fib.f
                    fortranname fib
                    real*8 dimension(n), intent(inout) :: a
                    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
                end subroutine fib
                subroutine fib(a,n) ! in :fib:fib.f
                    fortranname fib
                    real*8 dimension(n), intent(copy, in,out) :: a
                    integer, optional,check(len(a)>=n),depend(a) :: n=len(a)
                end subroutine fib
            end interface
    end python module fib

注意:要实际阻止第二个例程修改Python输入,我还必须将copy添加到intent指令中。