使用f2py从fortran向python返回0长度数组
我正在使用使用f2py从fortran向python返回0长度数组,python,numpy,fortran,f2py,Python,Numpy,Fortran,F2py,我正在使用f2py为用fortran编写的基于MPI的库生成包装器。由于我正在使用的阵列分区方案,在给定足够的MPI进程的情况下,一个进程有可能拥有一个长度为0的本地阵列。这会在我有权访问的Cray系统上触发以下错误: ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (0,) 我的桌面上没有收到相同的错误。这可能与我安装的python和n
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,)
[2.2]
[ 1.]
回溯(最近一次呼叫最后一次):
文件“pytest.py”,第11行,在
a=fortran_sub.sub(0)
ValueError:未能创建意图(缓存|隐藏)|可选数组--必须已定义维度,但已获取(0,)
自从我了解Python Fortran接口的ctypes
以来,我已经很久没有使用f2py了。这是一个基于ctypes
的解决方案,它还可以处理零大小的阵列(从技术上讲,它也可以与MPI一起工作)
使用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 = []
它给出了以下结果:
#!/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 = []
谢谢你详细的回答。然而,具有讽刺意味的是,在我确信f2py是一种更有效的做事方式后,几个月前我实际上从ctypes转换过来了。我想我将来会坚持使用ctypes,我更喜欢知道到底发生了什么。然而,就目前而言,我希望有人有一个f2py特定的解决方案。