【问题标题】:when using f2py, function scope within fortran module different than when compiled for fortran program?使用 f2py 时,fortran 模块中的函数范围与为 fortran 程序编译时不同?
【发布时间】:2013-09-07 04:46:27
【问题描述】:

我的问题是使用 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, dimension(nelem), intent(in) :: y 之前重新定义integer, parameter :: nelem=3 并重新编译,我会得到

      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)

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

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

【问题讨论】:

    标签: python fortran90 gfortran f2py


    【解决方案1】:

    也许我错了,但我不认为 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
    

    编辑

    this question on SO 的答案说 f2py 不了解如何将 Fortran 函数转换为 python 函数。所以我把function foo改成subroutine 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. nelemb 作为变量传递给子程序

    我还发现,在使用 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.0y=(/ 3, 6, 2/) (都使用 python 和在 Fortran 程序中使用模块)时,我确实得到 18 作为答案。

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

    【讨论】:

    • 我不认为这是正确的。这里有使用模块的例子:stackoverflow.com/questions/12523524/…cens.ioc.ee/projects/f2py2e/usersguide/#fortran-90-module-data。我还只包含了一个小示例,但我需要从许多函数和子例程中访问模块参数,而不仅仅是我在简化示例中所示的foo
    • 另外,我已经编辑了文本以更清楚地表明,如果我在函数中为dpnelem 添加额外的声明,那么它可以工作,所以模块+包含表单确实工作。
    • @crippledlambda 就像我说的,“也许我错了”,但我可能已经找到了一些东西。暂时更新我的​​答案。
    • 不,没关系,什么都不是。不过我会再挖一点。
    • 感谢您挖掘这些信息。只要我在函数中定义了nelemdp,我实际上就能够运行我的函数,而无需将其转换为子例程。我能够访问b,而无需重新定义它。充其量,这种行为是不可预测的。好吧,f2py 结果有点令人失望。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多