f2py, Python function that returns an array (vector-valued function)

醉酒当歌 提交于 2019-11-28 13:43:42

Unfortunately, you cannot return the array from the python function into Fortran. You would need a subroutine for that (meaning it is called with the call statement), and this is something that f2py does not let you do.

In Fortran 90 you can create functions that return arrays, but again this is not something that f2py can do, especially since your function is not a Fortran function.

Your only option is to use your looping workaround, or a redesign of how you want python and Fortran to interact.

Despite this answer does not solve the question, it is a workaround doing the same in Cython. Here the trapezoidal rule and a polynomial integrator are implemented for a vector-valued function. The code below I put in a integratev.pyx:

import numpy as np
from numpy.linalg import inv
cimport numpy as np
FLOAT = np.float32
ctypedef np.float_t FLOAT_t

def trapzv(f, np.ndarray xs, int nf):
    cdef int nxs = xs.shape[0]
    cdef np.ndarray ans = np.zeros(nf, dtype=FLOAT)
    cdef double x1, x2
    for i in range(1,nxs):
        x1 = xs[i-1]
        x2 = xs[i]
        ans += (f(x2)+f(x1))*(x2-x1)/2.
    return ans

def poly(f, np.ndarray xs, int nf, int order=2):
    cdef int nxs = xs.shape[0]
    cdef np.ndarray ans = np.zeros(nf, dtype=FLOAT)
    cdef np.ndarray xis = np.zeros(order+1, dtype=FLOAT)
    cdef np.ndarray ais
    if nxs % (order+1) != 0:
        raise ValueError("poly: The size of xs must be a multiple of 'order+1'")
    for i in range(order,nxs,order):
        xis = xs[i-order:i+1]
        X = np.concatenate([(xis**i)[:,None] for i in range(order+1)], axis=1)
        ais = np.dot( inv(X), f(xis).transpose() )
        for k in range(1,order+2):
            ans += ais[k-1,:]/k * (xis[-1]**k - xis[0]**k)
    return ans

The following test was used:

import numpy as np
from numpy import cos, sin , exp
import pyximport; pyximport.install()
import integratev
from subprocess import Popen
def func(x):
    return np.array([x**2, x**3, cos(x), sin(x), exp(x)])

if __name__ == '__main__':
    xs = np.linspace(0.,20.,33)
    print 'exact:', np.array([20**3/3., 20**4/4., sin(20.), -cos(20.)+1, exp(20.)-1])
    ans =  integratev.trapzv(func,xs,5)
    print 'trapzv:', ans
    ans =  integratev.poly(func,xs,5,2)
    print 'poly:', ans

Giving:

exact: [  2.66666667e+03   4.00000000e+04   9.12945251e-01   5.91917938e-01 4.85165194e+08]
trapzv: [  2.66796875e+03   4.00390625e+04   8.83031547e-01   5.72522998e-01 5.00856448e+08]
poly: [  2.66666675e+03   4.00000000e+04   9.13748980e-01   5.92435718e-01 4.85562144e+08]

The poly can be of any order, which will probably give better results for most of the cases...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!