f2py,返回数组的Python函数(向量值函数)

Sau*_*tro 5 python numpy cython numerical-integration f2py

在下面的Python中,我有五个函数包含在func我必须集成的数组中.代码调用使用f2py以下代码生成的外部Fortran模块:

import numpy as np
from numpy import cos, sin , exp
from trapzdv import trapzdv
def func(x):
    return np.array([x**2, x**3, cos(x), sin(x), exp(x)])

if __name__ == '__main__':
    xs = np.linspace(0.,20.,100)
    ans =  trapzdv(func,xs,5)
    print 'from Fortran:', ans
    print 'exact:', np.array([20**3/3., 20**4/4., sin(20.), -cos(20.), exp(20.)])
Run Code Online (Sandbox Code Playgroud)

Fortran例程是:

      subroutine trapzdv(f,xs,nf,nxs,result)
          integer :: I
          double precision :: x1,x2
          integer, intent(in) :: nf, nxs
          double precision, dimension(nf) :: fx1,fx2
          double precision, intent(in), dimension(nxs) :: xs
          double precision, intent(out), dimension(nf) :: result
          external :: f 
          result = 0.0
          do I = 2,nxs
            x1 = xs(I-1)
            x2 = xs(I)
            fx1 = f(x1)
            fx2 = f(x2)
            result = result + (fx1+fx2)*(x2-x1)/2
          enddo
          return
      end 
Run Code Online (Sandbox Code Playgroud)

问题是Fortran只集成了第一个函数func(x).查看打印结果:

from Fortran: [ 2666.80270721  2666.80270721  2666.80270721  2666.80270721  2666.80270721]
exact: [  2.66666667e+03   4.00000000e+04   9.12945251e-01  -4.08082062e-01 4.85165195e+08]
Run Code Online (Sandbox Code Playgroud)

workarond的一种方法是修改func(x)以返回函数数组中给定位置的值:

def func(x,i):
    return np.array([x**2, x**3, cos(x), sin(x), exp(x)])[i-1]
Run Code Online (Sandbox Code Playgroud)

然后更改Fortran例程以使用两个参数调用该函数:

      subroutine trapzdv(f,xs,nf,nxs,result)
          integer :: I
          double precision :: x1,x2,fx1,fx2
          integer, intent(in) :: nf, nxs
          double precision, intent(in), dimension(nxs) :: xs
          double precision, intent(out), dimension(nf) :: result
          external :: f 
          result = 0.0
          do I = 2,nxs
            x1 = xs(I-1)
            x2 = xs(I)
            do J = 1,nf
                fx1 = f(x1,J)
                fx2 = f(x2,J)
                result(J) = result(J) + (fx1+fx2)*(x2-x1)/2
            enddo
          enddo
          return
      end 
Run Code Online (Sandbox Code Playgroud)

哪个有效:

from Fortran: [  2.66680271e+03   4.00040812e+04   9.09838195e-01   5.89903440e-01 4.86814128e+08]
exact: [  2.66666667e+03   4.00000000e+04   9.12945251e-01  -4.08082062e-01 4.85165195e+08]
Run Code Online (Sandbox Code Playgroud)

但这里func被称为超过必要的5倍(在实际情况下func 有超过300个函数,所以它将被称为超过必要的300倍).

  • 有谁知道更好的解决方案让Fortran识别返回的所有数组func(x)?换句话说,将Fortran构建fx1 = f(x1)为一个数组,其中包含5个与其中的函数对应的元素func(x).

OBS:我正在编译使用 f2py -c --compiler=mingw32 -m trapzdv trapzdv.f90

Set*_*ton 2

不幸的是,您无法将数组从 python 函数返回到 Fortran 中。您需要一个子例程(这意味着它是用call语句调用的),而这是f2py不允许您这样做的。

在 Fortran 90 中,您可以创建返回数组的函数,但这又不是f2py可以做的事情,特别是因为您的函数不是 Fortran 函数。

您唯一的选择是使用循环解决方法,或者重新设计您希望 python 和 Fortran 交互的方式。