为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Cython 将 np.ndarray 传递给 Fortran

使用 Cython 将 np.ndarray 传递给 Fortran

肥皂起泡泡 2022-12-20 16:17:30
我正在用 Python 包装 Fortran 模块。我选择使用 Cython 来做到这一点。我的问题是将 a 传递np.ndarray给 Fortran。我能够np.ndarray从 Fortran 收到一个,但我所有传递给 Fortran 的尝试都没有奏效。我发现,问题直接出在 Cython - Fortran 接口上,因为我的 Fotran 子例程工作正常(尽可能在没有数据的情况下工作)。Cython 端似乎也能正常工作,我可以在那里操作变量。我的最低工作示例:PATTERN_wrap.f90module PATTERN_wrap    use iso_c_binding, only: c_float, c_double, c_short, c_int    implicit noneCONTAINS    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 subroutineend module PATTERN_wrap注意:对实际执行某些操作的子程序的调用DO_PATTERN已被注释掉,因为此时它不相关。我只是想指出上面的代码是一个包装器。pattern.pyx#cython: language_level=3import cythonimport numpy as npcimport numpy as npcdef 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
查看完整描述

1 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

我设法找到了解决方案。代码没问题。问题是我的配置。


如上所述,我测试了 gcc/gfortran 的不同配置,看它是否影响 Cythonizing。它不是。因此,我继续反汇编我的 Dockerfile,以找到导致代码中断的步骤。原来是conda安装了numpy。


我上面使用 pip 进行的所有 ggc 图像测试:


$ python -m pip install numpy

Collecting numpy

  Downloading numpy-1.18.4-cp38-cp38-manylinux1_x86_64.whl (20.7 MB)

     |████████████████████████████████| 20.7 MB 18.9 MB/s

Installing collected packages: numpy

Successfully installed numpy-1.18.4

一包一轮,快速简单。但是,我在“生产”图像中使用了 conda。


如果你通过 conda 安装 numpy:


$ conda install numpy

Collecting package metadata (current_repodata.json): done

Solving environment: done


## Package Plan ##


  environment location: /opt/conda


  added / updated specs:

    - numpy



The 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 --inplace

running build_ext

cythoning pattern.pyx to pattern.c

building 'pattern' extension

creating build

creating build/temp.linux-x86_64-3.8

gcc -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.o

In 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.so

libgfortran.so.4

libgfortran.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 包的编译后,一切正常。


无论如何,当心康达。



查看完整回答
反对 回复 2022-12-20
  • 1 回答
  • 0 关注
  • 110 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信