Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Fortran-Cython工作流_Python_Fortran_Cython_Fortran Iso C Binding - Fatal编程技术网

Python Fortran-Cython工作流

Python Fortran-Cython工作流,python,fortran,cython,fortran-iso-c-binding,Python,Fortran,Cython,Fortran Iso C Binding,我想建立一个工作流,在Windows机器上使用Cython从Python访问fortran例程 经过一番搜索,我发现: 及 还有一些代码图片: Fortran端: pygfunc.h: void c_gfunc(double x, int n, int m, double *a, double *b, double *c); pygfunc.f90 module gfunc1_interface use iso_c_binding use gfunc_module i

我想建立一个工作流,在Windows机器上使用Cython从Python访问fortran例程

经过一番搜索,我发现: 及

还有一些代码图片:

Fortran端:

pygfunc.h:

void c_gfunc(double x, int n, int m, double *a, double *b, double *c);
pygfunc.f90

module gfunc1_interface
    use iso_c_binding
    use gfunc_module

    implicit none

contains
    subroutine c_gfunc(x, n, m, a, b, c) bind(c)
        real(C_FLOAT), intent(in), value :: x
        integer(C_INT), intent(in), value ::  n, m
        type(C_PTR),    intent(in), value :: a, b
        type(C_PTR),                value :: c

        real(C_FLOAT), dimension(:), pointer :: fa, fb
        real(C_FLOAT), dimension(:,:), pointer :: fc

        call c_f_pointer(a, fa, (/ n /))
        call c_f_pointer(b, fb, (/ m /))
        call c_f_pointer(c, fc, (/ n, m /))
        call gfunc(x, fa, fb, fc)
     end subroutine

end module
gfunc.f90

module gfunc_module

use iso_c_binding

    implicit none
    contains
        subroutine gfunc(x, a, b, c)
            real,                 intent(in) :: x
            real, dimension(:),   intent(in) :: a, b
            real, dimension(:,:), intent(out) :: c

            integer :: i, j, n, m
            n = size(a)
            m = size(b)
            do j=1,m
                do i=1,n
                     c(i,j) = exp(-x * (a(i)**2 + b(j)**2))
                end do
            end do
        end subroutine
end module
赛顿方面:

pygfunc.pyx

cimport numpy as cnp
import numpy as np

cdef extern from "./pygfunc.h":
    void c_gfunc(double, int, int, double *, double *, double *)

cdef extern from "./pygfunc.h":
    pass

def f(float x, a=-10.0, b=10.0, n=100):
    cdef cnp.ndarray ax, c
    ax = np.arange(a, b, (b-a)/float(n))
    n = ax.shape[0]
    c = np.ndarray((n,n), dtype=np.float64, order='F')
    c_gfunc(x, n, n, <double *> ax.data, <double *> ax.data, <double *> c.data)
    return c
所有文件都在一个目录中

fortran文件编译(使用NAG fortran Builder)pygfunc编译

但将它们联系起来会带来一个问题:

错误LNK2019:引用了未解析的外部符号_c_gfunc 在函数中

当然:

致命错误LNK1120:1个未解析的外部

我错过了什么?或者,这种在Python和Fortran之间建立工作流的方式从一开始就糟糕透了吗

THX
Martin

这里有一个最基本的工作示例。 我使用gfortran并将编译命令直接写入安装文件

gfunc.f90

module gfunc_module
implicit none
contains
subroutine gfunc(x, n, m, a, b, c)
    double precision, intent(in) :: x
    integer, intent(in) :: n, m
    double precision, dimension(n), intent(in) :: a
    double precision, dimension(m), intent(in) :: b
    double precision, dimension(n, m), intent(out) :: c
    integer :: i, j
    do j=1,m
        do i=1,n
             c(i,j) = exp(-x * (a(i)**2 + b(j)**2))
        end do
    end do
end subroutine
end module
module gfunc1_interface
use iso_c_binding, only: c_double, c_int
use gfunc_module, only: gfunc
implicit none
contains
subroutine c_gfunc(x, n, m, a, b, c) bind(c)
    real(c_double), intent(in) :: x
    integer(c_int), intent(in) ::  n, m
    real(c_double), dimension(n), intent(in) :: a
    real(c_double), dimension(m), intent(in) :: b
    real(c_double), dimension(n, m), intent(out) :: c
    call gfunc(x, n, m, a, b, c)
end subroutine
end module
pygfunc.f90

module gfunc_module
implicit none
contains
subroutine gfunc(x, n, m, a, b, c)
    double precision, intent(in) :: x
    integer, intent(in) :: n, m
    double precision, dimension(n), intent(in) :: a
    double precision, dimension(m), intent(in) :: b
    double precision, dimension(n, m), intent(out) :: c
    integer :: i, j
    do j=1,m
        do i=1,n
             c(i,j) = exp(-x * (a(i)**2 + b(j)**2))
        end do
    end do
end subroutine
end module
module gfunc1_interface
use iso_c_binding, only: c_double, c_int
use gfunc_module, only: gfunc
implicit none
contains
subroutine c_gfunc(x, n, m, a, b, c) bind(c)
    real(c_double), intent(in) :: x
    integer(c_int), intent(in) ::  n, m
    real(c_double), dimension(n), intent(in) :: a
    real(c_double), dimension(m), intent(in) :: b
    real(c_double), dimension(n, m), intent(out) :: c
    call gfunc(x, n, m, a, b, c)
end subroutine
end module
pygfunc.h

extern void c_gfunc(double* x, int* n, int* m, double* a, double* b, double* c);
pygfunc.pyx

from numpy import linspace, empty
from numpy cimport ndarray as ar

cdef extern from "pygfunc.h":
    void c_gfunc(double* a, int* n, int* m, double* a, double* b, double* c)

def f(double x, double a=-10.0, double b=10.0, int n=100):
    cdef:
        ar[double] ax = linspace(a, b, n)
        ar[double,ndim=2] c = empty((n, n), order='F')
    c_gfunc(&x, &n, &n, <double*> ax.data, <double*> ax.data, <double*> c.data)
    return c
test.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
# This line only needed if building with NumPy in Cython file.
from numpy import get_include
from os import system

# compile the fortran modules without linking
fortran_mod_comp = 'gfortran gfunc.f90 -c -o gfunc.o -O3 -fPIC'
print fortran_mod_comp
system(fortran_mod_comp)
shared_obj_comp = 'gfortran pygfunc.f90 -c -o pygfunc.o -O3 -fPIC'
print shared_obj_comp
system(shared_obj_comp)

ext_modules = [Extension(# module name:
                         'pygfunc',
                         # source file:
                         ['pygfunc.pyx'],
                         # other compile args for gcc
                         extra_compile_args=['-fPIC', '-O3'],
                         # other files to link to
                         extra_link_args=['gfunc.o', 'pygfunc.o'])]

setup(name = 'pygfunc',
      cmdclass = {'build_ext': build_ext},
      # Needed if building with NumPy.
      # This includes the NumPy headers when compiling.
      include_dirs = [get_include()],
      ext_modules = ext_modules)
# A script to verify correctness
from pygfunc import f
print f(1., a=-1., b=1., n=4)

import numpy as np
a = np.linspace(-1, 1, 4)**2
A, B = np.meshgrid(a, a, copy=False)
print np.exp(-(A + B))
我所做的大多数改变都不是很基本。这里是重要的

  • 您混合了双精度和单精度浮点数。不要那样做。同时使用real(Fortran)、float(Cython)和float32(NumPy),并同时使用双精度(Fortran)、double(Cyton)和float64(NumPy)。尽量不要无意中把它们混在一起。在我的例子中,我假设你想要双打

  • 您应该将所有变量作为指针传递给Fortran。在这方面,它不符合C调用约定。Fortran中的iso_c_绑定模块仅与c命名约定匹配。将数组作为指针传递,其大小作为单独的值。可能还有其他方法,但我不知道

我还在安装文件中添加了一些内容,以显示在构建时可以在何处添加一些更有用的额外参数

要编译,请运行
python setup.py build\u ext--inplace
。要验证它是否有效,请运行测试脚本

以下是fortran90.org上显示的示例:

这是我不久前整理的另外两个:,
我当然不是这方面的专家,但这些例子可能是一个很好的起点。

这很奇怪。你不是在没有显式接口的情况下从Fortran调用
cgfunc
,或者以其他方式作为Fortran过程调用,而不是c过程吗?对不起,我不明白这个问题不能解决你的问题,但如果你不知道还有一个可供选择的方法:f2py。没关系,它不会导致任何结果。显然Cython根本没有使用您的Fortran对象文件。我对Cython了解不够,帮不了你。我可以使用
ctypes
@steabert运行代码,但我认为
ctypes
是一种更接近
Cython
的方法。Fortran代码可以保持原样。THX,explicit setup.py是一个让人大开眼界的工具,您可以提供一些见解。