使用f2py将0长度的数组从fortran返回到python

2024-06-16 04:58:09 发布

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

我使用f2py为用fortran编写的基于MPI的库生成一个包装器。由于我正在使用的数组分区方案,在给定足够的MPI进程的情况下,一个进程有可能拥有一个长度为0的本地数组。这会在我可以访问的Cray系统上触发以下错误:

ValueError: failed to create intent(cache|hide)|optional array-- 
must have defined dimensions but got (0,)

我的桌面上没有收到相同的错误。这可能与我安装的python和numpy版本有关。在我的桌面上它们是numpyversion1.16.4和python2.7.15+,在集群上它们是numpy1.13.3和python2.7.14。由于我无法升级集群上的包,我想知道是否存在一个简单的解决方法。以下代码再现错误:

文件“fortran\u sub.f90”:

subroutine sub(a_size, a)                                                       

    integer, intent(in) :: a_size                                               
    real, dimension(a_size), intent(out) :: a                                   

    if (size(a) > 0) then                                                       
        a = size(a)                                                             
    endif                                                                       

end subroutine sub  

使用f2py进行包装和编译,如下所示:

python2 -m numpy.f2py -h --overwrite-signature fortran_sub.pyf -m 
fortran_sub fortran_sub.f90

python2 -m numpy.f2py --f90exec="ftn" -c fortran_sub.pyf -m 
fortran_sub fortran_sub.f90

生成的.pyf是:

!    -*- f90 -*-
! Note: the context of this file is case sensitive.

python module fortran_sub ! in 
    interface  ! in :fortran_sub
        subroutine sub(a_size,a) ! in :fortran_sub:fortran_sub.f90
            integer intent(in) :: a_size
            real dimension(a_size),intent(out),depend(a_size) :: a
        end subroutine sub
     end interface 
end python module fortran_sub

! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/

运行以下python程序'pytest.py测试“用Python2pytest.py测试地址:

import fortran_sub

a = fortran_sub.sub(2)
print(a)

a = fortran_sub.sub(1)
print(a)

a = fortran_sub.sub(0)
print(a)

我得到以下输出:

[ 2.  2.]
[ 1.]
Traceback (most recent call last):
  File "pytest.py", line 11, in <module>
   a = fortran_sub.sub(0)
ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (0,)

Tags: inpynumpysize错误endmoduleprint
1条回答
网友
1楼 · 发布于 2024-06-16 04:58:09

自从我了解了pythonfortran接口的ctypes之后,我已经很久没有使用f2py了。这是一个基于ctypes的解决方案,它还可以处理零大小的数组(从技术上讲,它也可以与MPI一起工作)

module sub_mod
contains
    subroutine sub(a_size, a) bind(C,name="sub")
        !DEC$ ATTRIBUTES DLLEXPORT :: sub
        use iso_c_binding, only: c_size_t, c_double
        integer(c_size_t), intent(in) :: a_size
        real(c_double), intent(inout) :: a(a_size)
        if (size(a) > 0) then
            a = size(a)
        endif
    end subroutine sub
end module sub_mod

使用Intel或(其他编译器)编译以创建DLL库

ifort /dll main.f90

使用来自ifort的如下输出消息

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.4.245 Build 20190417
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.22.27905.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:main.dll
-dll
-implib:main.lib
main.obj
   Creating library main.lib and object main.exp

然后可以通过如下ctypes从Python调用

#!/usr/bin/env python

import ctypes as ct
import numpy as np

# import Fortran DLL
lib = ct.CDLL("main.dll")
lib.sub.restype = None    # define subroutine result type

# define subroutine argument type
lib.sub.argtypes =  [ ct.POINTER(ct.c_size_t)        # a_size
                    , ct.POINTER(ct.c_double)       # a array
                    ]
# all Fortran DLL
for i in [2,1,0]:
    a_size = i
    a = np.zeros(shape=[a_size])
    lib.sub ( ct.byref( ct.c_size_t(a_size) ) # Fortran passes everything around by reference
            , np.ctypeslib.as_ctypes( a ) # pointer to numpy array
            )
    print("a_size = {}, a = {}".format(a_size, a))

由此得出如下结论:

a_size = 2, a = [2. 2.]
a_size = 1, a = [1.]
a_size = 0, a = []

相关问题 更多 >