在Python中调用Fortran子例程会返回“ NoneType”

时间:2019-07-17 07:20:12

标签: python r fortran fortran77 f2py

我想编写一个Python包,其中包含Brian Ripley维护的R的KernSmooth包的基本功能。 R的KernSmooth的大多数代码都是用Fortran77语法编写的。因此,基本上是模仿Brian Ripley在R中所做的事情,我的计划是将Fortran subroutines导入Python并编写相应的用户界面。首先,我想将Fortran77子例程 rlbin.f (下面的代码)放入Python函数中。

c  Part of R package KernSmooth
c  Copyright (C) 1995  M. P. Wand
c
c  Unlimited use and distribution (see LICENCE).

cccccccccc FORTRAN subroutine rlbin.f cccccccccc

c Obtains bin counts for univariate regression data
c via the linear binning strategy. If "trun=0" then
c weight from end observations is given to corresponding
c end grid points. If "trun=1" then end observations
c are truncated.

c Last changed: 26 MAR 2009

      subroutine rlbin(X,Y,n,a,b,M,trun,xcnts,ycnts)
      double precision X(*),Y(*),a,b,xcnts(*),ycnts(*),lxi,delta,rem
      integer n,M,i,li,trun

c     Initialize grid counts to zero

      do 10 i=1,M
         xcnts(i) = dble(0)
         ycnts(i) = dble(0)
10    continue

      delta = (b-a)/(M-1)
      do 20 i=1,n
         lxi = ((X(i)-a)/delta) + 1

c        Find integer part of "lxi"

         li = int(lxi) 
         rem = lxi - li
         if (li.ge.1.and.li.lt.M) then
            xcnts(li) = xcnts(li) + (1-rem)
            xcnts(li+1) = xcnts(li+1) + rem
            ycnts(li) = ycnts(li) + (1-rem)*y(i)
            ycnts(li+1) = ycnts(li+1) + rem*y(i)
         endif

         if (li.lt.1.and.trun.eq.0) then
            xcnts(1) = xcnts(1) + 1
            ycnts(1) = ycnts(1) + y(i)
         endif      

         if (li.ge.M.and.trun.eq.0) then 
               xcnts(M) = xcnts(M) + 1
               ycnts(M) = ycnts(M) + y(i)
         endif

20    continue

      return
      end

cccccccccc End of rlbin.f cccccccccc

我已经成功编译了Fortran代码并将其导入Python。

在Unix shell中,我键入

f2py -c -m rlbin rlbin.f

创建一个共享库 rlbin.so ,我将其导入Python:

import rlbin
print(rlbin.__doc__)

输出:

This module 'rlbin' is auto-generated with f2py (version:2).
Functions:
  rlbin(x,y,n,a,b,m,trun,xcnts,ycnts)
.
print(rlbin.rlbin.__doc__)

输出:

rlbin(x,y,n,a,b,m,trun,xcnts,ycnts)

Wrapper for ``rlbin``.

Parameters
----------
x : input rank-1 array('d') with bounds (*)
y : input rank-1 array('d') with bounds (*)
n : input int
a : input float
b : input float
m : input int
trun : input int
xcnts : input rank-1 array('d') with bounds (*)
ycnts : input rank-1 array('d') with bounds (*)

我指定了以下输入参数:

import numpy as np

# create random x and y arrays
x = np.ndarray(shape=(2000,), dtype=float, order='F')
y = np.ndarray(shape=(2000,), dtype=float, order='F')

n = len(x)
a = 0.05
b = 0.995
M = 500
trun = 1

xcents = np.zeros(M)
ycnts = np.zeros(M)

我检查了数据类型: a b 确实是浮点型; n M trun 是整数; x y xcnst ycnts 是numpy数组。

并称为Fortran子例程

out = rlbin.rlbin(x, y, n, a, b, M, trun, xcnts, ycnts)

它执行没有错误。同样,调用 out 不会引发错误,但也不返回任何内容。

type(out)无论如何都会返回NoneTypeprint(out)返回None

我在R中尝试了相同的过程(编译,导入,调用),但没有任何问题。

对于感兴趣的人,相应的R调用将是(摘自all.R脚本,第713-724行):

out <- .Fortran("rlbin", as.double(x), as.double(y), as.integer(n),
                  as.double(a), as.double(b), as.integer(M),  as.integer(trun), double(M), double(M))

我已经按照一些教程来检查我的f2py环境是否设置正确,是的,我在用Python调用其他Fortran子例程时没有问题:

所以让我感到恼火的是,使用完全相同的输入参数在R中调用完全相同的Fortran子例程可以完美地工作。也许Python处理输入参数的方式与R处理方式不同,但是我目前还不了解。

感谢您的帮助!

0 个答案:

没有答案