美文网首页PythonPython/Go开发
Python与Fortran混合编程

Python与Fortran混合编程

作者: 地学小哥 | 来源:发表于2020-05-10 13:34 被阅读0次

    简介:Fortran程序在地球物理学中并不少见,90年代Fortran十分流行,386时代计算机时很珍贵,Fortran作为当时的高级语言,具有运行速度快,语法简单等诸多优点。现在虽然Fortran已经成为小众游戏,但过去曾经的那些基础计算程序还是有价值的,如果全要重新改写,不但耗时耗力还容易出错。因此,今天我们讨论一下如何在Python里面调用Fortran的函数。

    1、认识f2py

    混合编程方法有很多,但是f2py可以作为众多方法的首选。f2py是NumPy的一部分,不需要独立安装配置。f2py简单来说就是 Fortran to Python的接口生成器。使用它可以实现Python和Fortran语言之间提供的连接。

    在安装了NumPy之后,它还可以作为独立的命令行工具f2py使用,它可以方便地创建/构建Python C/API扩展模块。支持调用Fortran 77/90/95外部子程序和Fortran 90/95模块子程序以及C函数; 支持访问Fortran 77通用块和Fortran 90/95模块数据,包括可分配数组。

    f2py通过创建一个可在Python中使用import关键字导入的扩展模块来工作。该模块包含可以从Python调用的自动生成的包装器函数,充当Python和编译后的Fortran例程之间的接口。

    编译后的fortran程序依据平台的不同,在磁盘上会产生一个以pyd为扩展名的文件,可以在python程序中被import。

    MATLAB和Python这样的脚本语言虽然容易上手,但是对于大规模的循环和数值计算速度还是逊色于C/ c++和Fortran这样的编译语言。要实现两全其美,混合编程是一个好的选择,而Numpy这种大型的python包,其底层也是要通过混合编程来加速的。

    2、Fortran的函数接口设计

    我们从一个简单的例子开始,Fortran代码保存在fortran.f95中。一般作为接口函数的代码都放到一个subroutine中,这里面在fortran代码里面通过intent关键字来定义输入/输出变量和类型。

    下面是fortran代码中的subroutine的典型写法:

    subroutine logical_to_integer(prime_numbers, is_prime, num_primes, n)
    ! =====================================================
    ! Translates the logical array from sieve to an array
    ! of size num_primes of prime numbers.
    ! =====================================================
        integer                 :: i, j=0
        integer, intent(in)     :: n
        logical, intent(in)     :: is_prime(n)
        integer, intent(in)     :: num_primes
        integer, intent(out)    :: prime_numbers(num_primes)
        do i = 1, size(is_prime)
            if (is_prime(i)) then
                j = j + 1
                prime_numbers(j) = i
            end if
        end do
    end subroutine
    

    需要注意的是在接口函数中不要使用动态数组,与python交换数据一定要指定数组大小。

    3、Python的函数调用方法

    Python要调用fortran的函数,必须对fortran函数进行编译。
    可以在虚拟环境中,使用下面的命令:

    f2py -c fortran.f95 -m fortran
    

    或者:

    python -m numpy.f2py -c fortran.f95 -m fortran
    

    在Python中,可以直接import上面的函数名

    import fortran
    print(fortran.__doc__)
    print(fortran.logical_to_integer.__doc__)
    

    注意上面的__doc __是f2py自动生成的,可以看到fortran模块里面包含几个函数,每个函数里面还可以再调用doc看到接口参数类型。

    在实践中更常见的做法是在python中在设计一个与fortran函数同名的wrapper函数,并设计新的docstring,这样用起来更像一个python函数。

    4、Setup.py中的编译

    如果您在程序包里面用到了混合编程方法,还需要编写setup.py,这样软件包安装后,自动会完成fortran代码的编译。方法如下:

    # Fortran extension
    from numpy.distutils.core import Extension 
    from numpy.distutils.core import setup 
    ext_for1 = Extension(name='geoist.name.for1',
                    sources=['geoist/name/for1.f90'])
    setup(
      ext_modules         = [ext_for1],
    )
    

    上面代码在setup.py中添加后,当geoist这个软件包安装时,for1.f90就会被自动的根据平台类型进行编译。

    5、什么时候使用混合编程

    如果想问什么时候要用到混合编程,我想这永远不会有没有明确的答案。然而,一个好的经验法则是,当在(嵌套的)循环中执行多个操作/-计算时,可以使用f2py或编译语言。最典型的例子可能是对多维矩阵中的元素进行操作。也就是一般的线性代数。其他好的例子可以是计算积分的程序或进行蒙特卡罗模拟。此时,您可能想知道是否已经有人为您的特定问题制作了免费的模块。

    答案很可能是肯定的!

    NumPy和SciPy中的大多数函数和例程实际上都是用Fortran(或C/ c++)例程编译的,它们为解决多个问题提供了高效和快速的解决方案。

    一句话总结:如果您是从fortran阵营转到python来的,并且希望使用更多python生态工具,或者您期望通过fortran来加速python程序运行速度,我想这篇文章是有帮助的。对于一些经典的数值计算算法,我们建议您经常检查这Numpy和Scipy这两个包中是否已经提供了解决方案。如果没有,您可以尝试通过混合编程的方法,继承原来的程序框架,而f2py可能会为您的问题提供最佳解决方案。

    相关文章

      网友评论

        本文标题:Python与Fortran混合编程

        本文链接:https://www.haomeiwen.com/subject/iuxjnhtx.html