gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 04:02:26 24 4
gpt4 key购买 nike

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

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

我的桌面上没有收到同样的错误。这个估计和我安装的python和numpy的版本有关。在我的桌面上,它们是 numpy 版本 1.16.4 和 python 2.7.15+,在集群上它们是 numpy 1.13.3 和 python 2.7.14。由于我无法升级集群上的软件包,我想知道是否存在简单的解决方法。以下代码重现错误:

文件“fortran_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/

使用 python2 pytest.py 运行以下 python 程序“pytest.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,)

最佳答案

自从我了解用于 Python-Fortran 接口(interface)的 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 = []

关于python - 使用 f2py 将 0 长度数组从 fortran 返回到 python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57968189/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com