使用 Cython 将 np.ndarray 传递给 Fortran

我正在用 Python 包装 Fortran 模块。我选择使用 Cython 来做到这一点。我的问题是将 a 传递np.ndarray给 Fortran。我能够np.ndarray从 Fortran 收到一个,但我所有传递给 Fortran 的尝试都没有奏效。


我发现,问题直接出在 Cython - Fortran 接口上,因为我的 Fotran 子例程工作正常(尽可能在没有数据的情况下工作)。Cython 端似乎也能正常工作,我可以在那里操作变量。


我的最低工作示例:


PATTERN_wrap.f90


module PATTERN_wrap

    use iso_c_binding, only: c_float, c_double, c_short, c_int

    implicit none


CONTAINS

    subroutine c_pattern(scalar_variable, array_variable, return_array) bind(c)

        implicit NONE


        INTEGER(c_int), intent(in) :: scalar_variable

        INTEGER(c_int), intent(in), DIMENSION(10, 15) :: array_variable


        REAL(c_float), INTENT(OUT), DIMENSION(10) :: return_array


        write(*,*) "start fortran"

        write(*,*) "scalar_variable"

        write(*,*) scalar_variable

        write(*,*) "array_variable"

        write(*,*) array_variable


        return_array = 3

        write(*,*) "end fortran"



!        call DO_PATTERN(&

!                scalar_variable=scalar_variable, &

!                array_variable=array_variable, &

!                return_array=return_array)

!

    end subroutine


end module PATTERN_wrap

注意:对实际执行某些操作的子程序的调用DO_PATTERN已被注释掉,因为此时它不相关。我只是想指出上面的代码是一个包装器。


pattern.pyx


#cython: language_level=3

import cython

import numpy as np

cimport numpy as np


cdef extern:

    void c_pattern(

            int *scalar_variable,

            int *array_variable,

            float *return_array

    )


def run_pattern(

        int scalar_variable,

):

    cdef:

        np.ndarray[int, ndim=2, mode="fortran"] array_variable = np.ones((10,15), dtype=np.int32, order='F')

        np.ndarray[float, ndim=1, mode="fortran"] return_array = np.zeros(10, dtype=np.float32, order='F')


    c_pattern(

        &scalar_variable,

        &array_variable[0,0],

        &return_array[0],

    )


    print('Cython side')

    print(return_array)


    return return_array


肥皂起泡泡
浏览 111回答 1
1回答

婷婷同学_

我设法找到了解决方案。代码没问题。问题是我的配置。如上所述,我测试了 gcc/gfortran 的不同配置,看它是否影响 Cythonizing。它不是。因此,我继续反汇编我的 Dockerfile,以找到导致代码中断的步骤。原来是conda安装了numpy。我上面使用 pip 进行的所有 ggc 图像测试:$ python -m pip install numpyCollecting numpy  Downloading numpy-1.18.4-cp38-cp38-manylinux1_x86_64.whl (20.7 MB)     |████████████████████████████████| 20.7 MB 18.9 MB/sInstalling collected packages: numpySuccessfully installed numpy-1.18.4一包一轮,快速简单。但是,我在“生产”图像中使用了 conda。如果你通过 conda 安装 numpy:$ conda install numpyCollecting package metadata (current_repodata.json): doneSolving environment: done## Package Plan ##  environment location: /opt/conda  added / updated specs:    - numpyThe following packages will be downloaded:    package                    |            build    ---------------------------|-----------------    blas-1.0                   |              mkl           6 KB    intel-openmp-2020.1        |              217         780 KB    libgfortran-ng-7.3.0       |       hdf63c60_0        1006 KB    mkl-2020.1                 |              217       129.0 MB    mkl-service-2.3.0          |   py38he904b0f_0          62 KB    mkl_fft-1.0.15             |   py38ha843d7b_0         159 KB    mkl_random-1.1.1           |   py38h0573a6f_0         341 KB    numpy-1.18.1               |   py38h4f9e942_0           5 KB    numpy-base-1.18.1          |   py38hde5b4d6_1         4.2 MB    ------------------------------------------------------------                                           Total:       135.5 MB...这里需要注意的重要一点是,除了 numpy 之外,conda 也在安装libgfortran-ng-7.3.0. 在我正在处理的图像中,安装了 gcc/gfortran 8.5.0。为什么这很重要?当你运行 cython 编译时:$ python setup.py build_ext --inplacerunning build_extcythoning pattern.pyx to pattern.cbuilding 'pattern' extensioncreating buildcreating build/temp.linux-x86_64-3.8gcc -pthread -B /opt/conda/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/opt/conda/lib/python3.8/site-packages/numpy/core/include -I/opt/conda/include/python3.8 -c pattern.c -o build/temp.linux-x86_64-3.8/pattern.oIn file included from /opt/conda/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1832,                 from /opt/conda/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,                 from /opt/conda/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:4,                 from pattern.c:599:/opt/conda/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning "Using deprecated NumPy API, disable it with " "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp] #warning "Using deprecated NumPy API, disable it with " \  ^~~~~~~gcc -pthread -shared -B /opt/conda/compiler_compat -L/opt/conda/lib -Wl,-rpath=/opt/conda/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.8/pattern.o -lgfortran -o /mwe/pattern.cpython-38-x86_64-linux-gnu.so PATTERN_wrap.o正如您在列表行中看到的,传递给 gcc 的包含是/opt/conda/lib.$ ls /opt/conda/lib | grep "fortran"libgfortran.solibgfortran.so.4libgfortran.so.4.0.0          这是libgfortran我最初编译代码时使用的不同版本。解决方案是:$ conda install -c conda-forge libgfortran-ng==8.2.0注意:使用 conda-forge 通道是必要的,在我的例子中,conda 无法解决仅来自基本通道的包的依赖关系。此外,此版本的 libgfortran-ng 还需要将 libblas 从 openblas 版本更改为 mkl,如果您担心的话。通过这种方式,我在 conda 中安装了一个 libgfortran,它与我在系统中使用的主版本相同。重新运行 Cythonized 包的编译后,一切正常。无论如何,当心康达。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python