4

我的问题是使用 f2py 编译时,模块中定义的函数无法识别某些模块变量。在声明传递给函数的变量类型的参数(例如描述类型的变量real或维度元素)时会引发错误。使用 gfortran 编译时我没有收到此错误。使用 f2py 编译时有什么区别以及如何纠正这些错误?

我的示例文件moddata.f90包含以下代码:

module mod

  implicit none

  integer, parameter :: dp = selected_real_kind(15)
  integer, parameter :: nelem = 3
  real(kind=dp), dimension(nelem) :: b

  parameter (b=(/3,1,2/))

contains
  function foo(x,y) result(z)
!  dp, nelem are defined in module above
    real(kind=dp), intent(in) :: x !scalar
    integer, dimension(nelem), intent(in) :: y
!  local variable
    real(kind=dp) :: z

    z = sum(b*y*x)

  end function foo
end module mod

我编译

f2py -c -m moddata moddata.f90

我得到这些错误:

  y_Dims[0]=(nelem);
             ^
1 warning and 1 error generated.reduce to a constant expression

如果我integer, parameter :: nelem=3之前重新定义integer, dimension(nelem), intent(in) :: y并重新编译,我会得到

      real(kind=dp) foof2pywrap
                1
Error: Parameter 'dp' at (1) has not been declared or is a variable, which does not reduce to a constant expression

每个real(kind=dp)声明都有相同的错误,并且

      foof2pywrap = foo(x, y)
                    1
Warning: Possible change of value in conversion from REAL(8) to REAL(4) at (1)

所以我必须在函数中重新定义dpby 。integer, parameter :: dp = selected_real_kind(15)然后它就起作用了。

当我使用 fortran 包装器编译此模块时,我没有收到这些错误。我想知道为什么nelemdp在函数中没有正确限定 f2py 的范围?

4

1 回答 1

4

也许我错了,但我不认为 f2py 可以处理 Fortran 90 的module+contains功能。如果你把你的代码变成

function foo(x,y) result(z)
   integer, parameter :: dp = selected_real_kind(15)
   real(kind=dp), intent(in) :: x
   integer, parameter :: nelem = 3
   integer, dimension(3), parameter :  = (/3, 1, 2/)
   integer, dimension(nelem), intent(in) :: y
   real(kind=dp) :: z

   z = sum(b*y*x)
end function

并像以前一样编译它,它可以工作:

 >>> x = 1.0000000000
 >>> y = [2, 3, 4]
 >>> moddata.foo(x,y)
 17.0

编辑

SO上这个问题的答案说 f2py不明白如何将 Fortran 函数转换为 python 函数。所以我将其更改function foosubroutine foo2然后编译为f2py moddata.f90 -m moddata并作为输出

Reading fortran codes...
        Reading file 'moddata.f90' (format:free)
Post-processing...
        Block: moddata
                        Block: moddata
In: :moddata:moddata.f90:moddata
get_parameters: got "invalid syntax (<string>, line 1)" on '(/3, 1, 2/)'
                                Block: foo2
Post-processing (stage 2)...
        Block: moddata
                Block: unknown_interface
                    Block: moddata
                            Block: foo2
Building modules...
        Building module "moddata"...
                Constructing F90 module support for "moddata"...
                    Variables: nelem b dp
                    Constructing wrapper function "moddata.foo2"...
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /home/jdwood/Documents/Physics/Fortran/tests/f2py/.f2py_f2cmap file).
                          z = foo2(x,y)
Wrote C/API module "moddata" to file "./moddatamodule.c"
Fortran 90 wrappers are saved to "./moddata-f2pywrappers2.f90"

所以看起来双精度确实丢失了,所以按照建议编辑一个名为. 的文件.f2py_f2cmap,我这样做了,在dp. 但是,它仍然给出错误nelem,所以我可以想到两种解决方案:

  1. 坚持使用3代替nelem
  2. nelem将和b作为变量传递给子例程

我还发现,在使用这parameter(b = (/3.d0, 1.d0, 2.d0/) )条线时,我收到一条警告,内容为

analyzeline: Failed to evaluate '/3.e0+1j*( 1.e0+1j*( 2.e0/)'. Ignoring: invalid syntax (<string>, line 1)

我不知道该怎么做。x=1.0但是,当我使用and y=(/ 3, 6, 2/)(使用 python 和在 Fortran 程序中使用模块)时,我确实得到了 18 作为答案。

简而言之,在使用 f2py 时完全避免使用函数。

于 2013-09-09T13:22:25.840 回答