使用main.f90模块调用特定的.f文件运行f2py时出现问题?(未知的子程序?)

2024-09-19 23:36:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用f2py将fortran函数与我的主要python代码集成。但是,当我试图包含一个特定的“.f”文件时,f2py会引发一个错误(但可以很好地处理其他“.f”文件)。我为我的主“.f90”文件创建了以下最小工作示例:

module min_example
  implicit none

  public :: calc_min

contains

  subroutine calc_min
    print*, 'test'
  return
  end subroutine calc_min

end module min_example

引起我问题的“.f”文件是“qromb.f”,如下所示:https://github.com/david-deboer/cosmo/blob/master/Komatsu/mf_jenkins/qromb.f

^{pr2}$

我用的是:

gfortran -c min_example.f90
gfortran -c qromb.f
f2py -c qromb.f min_example.f90 -m min_example

任何帮助都将不胜感激!谢谢您!在

最新消息:我一直在四处搜寻,发现的线索很少。有人认为f2py有内联注释的问题,但是删除它们并没有帮助。我读到的另一个答案建议将“.f”文件转换为“.f90”文件,但说实话,我不知道这两者之间的区别(我对fortran非常陌生)。所以我不知道该怎么做(我不太清楚.f文件的结构),也不知道它是否会减慢速度。在

另一个更新:使用“f2py-m min_example min_example.f90 qromb.f”进行编译时,将得到以下输出:

Reading fortran codes...
    Reading file 'min_example.f90' (format:free)
    Reading file 'qromb.f' (format:fix,strict)
Post-processing...
    Block: min_example
            Block: min_example
                Block: calc_min
            Block: qromb
            Block: trapzd
                    Block: func
            Block: polint
Post-processing (stage 2)...
    Block: min_example
        Block: unknown_interface
            Block: min_example
                Block: calc_min
            Block: qromb
            Block: trapzd
            Block: polint
Building modules...
    Constructing call-back function "cb_func_in_trapzd__user__routines"
      def func(x,q): return sum
    Building module "min_example"...
        Constructing wrapper function "qromb"...
routsign2map: Confused: function qromb has externals ['func'] but no "use" statement.
sign2map: Confused: external func is not in lcb_map[].
append_needs: unknown need 'func'
append_needs: unknown need 'func'
          qromb(func,a,b,ss,q,[func_extra_args])
        Constructing wrapper function "trapzd"...
          trapzd(func,a,b,s,n,q,[func_extra_args])
        Constructing wrapper function "polint"...
          polint(xa,ya,x,y,dy,[n])
        Constructing F90 module support for "min_example"...
            Constructing wrapper function "min_example.calc_min"...
              calc_min()
    Wrote C/API module "min_example" to file "./min_examplemodule.c"
    Fortran 90 wrappers are saved to "./min_example-f2pywrappers2.f90"

并生成以下文件:

min_example-f2pywrappers2.f90
min_example.mod
min_example.o
qromb.o
min_examplemodule.c 

这看起来很有前途,但是当我进入python时,我不能导入函数。在


Tags: 文件examplecalcfunctionminwrapperblockmodule
1条回答
网友
1楼 · 发布于 2024-09-19 23:36:19

为了让F2PY为Fortran过程创建包装器,它需要完全标识Fortran过程参数的类型和意图,即参数是否为整数/实数、标量/向量、输入/输出/二者等等。这个Fortran接口在F2PY中被称为过程的签名。如果函数作为参数传递(例如,trapzd中的func和链接文件qromb.f中的qromb),F2PY还需要为该传递函数的参数标识此信息。与Fortran 90及更高版本不同,Fortran 77(似乎是用qromb.f编写的方言)不提供任何语言直接在Fortran代码中明确定义此信息。在

因此,在您的例子中,F2PY未能使用手头的信息自动识别过程签名(因此未知的子程序输出)。在

但是,F2PY可以通过多种方式成功包装代码:

  1. 通过创建和 手动修改qromb.f的过程签名文件。在
  2. 定义接口并在 min_example模块,并将Fortran 77代码作为 预编译对象到F2PY。例如,见第一部分 answer。在
  3. 用更现代的Fortran方言重写qromb.f, 显式定义所有接口(您的代码似乎被修改了 fortran77中的数值公式 版本存在,这可能会有帮助)。在

您提到您是Fortran初学者,因此可能不想直接修改源代码。考虑到这一点,我将更详细地描述上面列出的第一种解决方案,并将其应用到您的示例中:

第一步是通过执行以下命令创建签名文件(请参见F2PY documentation中的smart-way):

f2py -m min_example -h min_example.pyf min_example.f90 qromb.f

这将创建一个名为min_example.pyf的签名文件,打开该文件,您会注意到,trapzdqromb之间的Fortran接口(F2PYsignatures)只显示为unknown_subroutine。此外,polint的接口需要修改。在

然后,您的第二步是修改min_example.pyf,使其只包含以下文本(也可参考F2Py documentation on call-back functions):

^{pr2}$

第三步也是最后一步是使用F2PY和手动更正的签名文件编译源代码,方法是执行以下命令:

f2py -c min_example.pyf min_example.f90 qromb.f

您的示例没有显示如何使用Python中的Fortran代码,但下面是一个Python脚本示例,展示了刚刚编译的模块的用法:

import numpy as np
from scipy.integrate import romberg
import min_example

print(min_example.__doc__)
print(min_example.qromb.__doc__)

def func(x, q):
    return q*np.sin(x)

a = 0.0
b = np.pi
q = 1.0

f_f2py = min_example.qromb(func, a, b, q)
f_scipy = romberg(func, a, b, args=(q,))

print("f2py:  {:0.7g}".format(f_f2py))
print("scipy: {:0.7g}".format(f_scipy))

得到了以下输出:

<auto-generated documentation strings>

f2py:  2
scipy: 2

相关问题 更多 >