文件名长度问题很容易解决:您制作文件名:character(len_filename):: filename
,将len_filename
其作为 fortran 函数的参数,并使用 将f2py intent(hide)
其隐藏在 Python 界面中(参见下面的代码)。
您不想传入nx
的ny
问题更复杂,本质上是如何从 f2py 返回可分配数组的问题。我可以看到两种方法,这两种方法都需要一个(小而非常轻的)Python 包装器来为您提供一个漂亮的界面。
我还没有真正解决如何读取 csv 文件的问题——我刚刚生成并返回了一些虚拟数据。我假设你有一个很好的实现。
方法一:模块级可分配数组
这似乎是一种相当标准的方法——我发现至少有一篇新闻组帖子推荐了这种方法。你基本上有一个可分配的全局变量,将它初始化为正确的大小,然后写入它。
module mod
real, allocatable, dimension(:,:) :: genfromtxt_output
contains
subroutine genfromtxt_v1(filename, len_filename)
implicit none
character(len_filename), intent(in):: filename
integer, intent(in) :: len_filename
!f2py intent(hide) :: len_filename
integer :: row, col
! for the sake of a quick demo, assume 5*6
! and make it all 2
if (allocated(genfromtxt_output)) deallocate(genfromtxt_output)
allocate(genfromtxt_output(1:5,1:6))
do row = 1,5
do col = 1,6
genfromtxt_output(row,col) = 2
end do
end do
end subroutine genfromtxt_v1
end module mod
简短的 Python 包装器如下所示:
import _genfromtxt
def genfromtxt_v1(filename):
_genfromtxt.mod.genfromtxt_v1(filename)
return _genfromtxt.mod.genfromtxt_output.copy()
# copy is needed, otherwise subsequent calls overwrite the data
这样做的主要问题是它不是线程安全的:如果两个 Python 线程genfromtxt_v1
在非常相似的时间调用,则数据可能会在您进行更改以将其复制出来之前被覆盖。
方法2:保存数据的Python回调函数
这稍微复杂一些,也是我自己发明的一个可怕的黑客攻击。您将数组传递给回调函数,然后将其保存。Fortran 代码如下所示:
subroutine genfromtxt_v2(filename,len_filename,callable)
implicit none
character(len_filename), intent(in):: filename
integer, intent(in) :: len_filename
!f2py intent(hide) :: len_filename
external callable
real, allocatable, dimension(:,:) :: result
integer :: row, col
integer :: rows,cols
! for the sake of a quick demo, assume 5*6
! and make it all 2
rows = 5
cols = 6
allocate(result(1:rows,1:cols))
do row = 1,rows
do col = 1,cols
result(row,col) = 2
end do
end do
call callable(result,rows,cols)
deallocate(result)
end subroutine genfromtxt_v2
然后,您需要使用f2py -m _genfromtxt -h _genfromtxt.pyf genfromtxt.f90
(假设genfromtxt.f90
是带有您的 Fortran 代码的文件)生成“签名文件”。然后修改“用户例程块”以阐明回调的签名:
python module genfromtxt_v2__user__routines
interface genfromtxt_v2_user_interface
subroutine callable(result,rows,cols)
real, dimension(rows,cols) :: result
integer :: rows
integer :: cols
end subroutine callable
end interface genfromtxt_v2_user_interface
end python module genfromtxt_v2__user__routines
(即您指定尺寸)。文件的其余部分保持不变。编译f2py -c genfromtxt.f90 _genfromtxt.pyf
小的 Python 包装器是
import _genfromtxt
def genfromtxt_v2(filename):
class SaveArrayCallable(object):
def __call__(self,array):
self.array = array.copy() # needed to avoid data corruption
f = SaveArrayCallable()
_genfromtxt.genfromtxt_v2(filename,f)
return f.array
我认为这应该是线程安全的:虽然我认为 Python 回调函数是作为全局变量实现的,但默认 f2py 不会释放 GIL,因此在设置的全局和正在运行的回调之间不能运行 Python 代码。我怀疑您是否关心此应用程序的线程安全性...