将fortran转换为python:用于从文本文件生成矩阵的等效命令

时间:2016-03-16 18:20:02

标签: python arrays matrix fortran equivalence

我正在尝试复制旧的fortran代码,以便我可以在python中使用它。最难的部分是导入以相当复杂的形状存储的数据。

我有一个文本文件,其中有14500个数据点存储在5列中,以逗号分隔:

 9.832e-06, 2.121e-16, 3.862e-21, 2.677e-23, 1.099e-22,
 5.314e-23, 1.366e-23, 6.504e-23, 3.936e-23, 1.175e-22,
 1.033e-23, 5.262e-23, 3.457e-23, 9.673e-23, 1.903e-22,
 3.153e-10, 2.572e-21, 5.350e-23, 4.522e-22, 1.468e-22,
 2.195e-23, 2.493e-22, 1.075e-22, 3.525e-22, 1.541e-23,
 1.935e-22, 9.220e-23, ...,       ...,       ...,

fortran代码声明了两个变量来存储这些数据: pg ping 。第一个是4D矩阵,第二个是1D数组,数据点数组长度(14500)

  parameter(NSIZ=29)
  parameter(NTg=5)
  parameter(NDg=5)
  parameter(NTAUg=20)
  real pg(NSIZ,NDg,NTg,NTAUg)
  real ping(NSIZ*NDg*NTg*NTAUg)

到目前为止一切顺利,但现在我有一个等价命令:

  equivalence(pg,ping)

据我所知,它将pg矩阵指向ping数组。最后一部分是一个循环,它从数据文件中读取行并将它们分配给ping数组:

  NCOLs=5
  NROWS=NTg*NDg*NTAUg*NSIZ / NCOLs

  irow=1
  do i=1,NROWS
    read(nat,*) (ping((irow-1)*NCOLs+k),k=1,NCOLs)
    print *, ping(irow)
    irow=irow+1
  enddo

我想在python中复制这段代码,但我不明白read命令如何将数据分配给4D矩阵。有人可以提供任何建议吗?

2 个答案:

答案 0 :(得分:4)

首先,Fortran equivalence和内存布局。我们首先需要查看内存布局。为简单起见,我将描述2D情况。这种概括不应该太难以找出任意维度。

fortran数组始终是连续的内存块 1 。最左边的索引变化最快(称为列主要顺序)。所以:

a(i, j)
a(i+1, j)

1 几乎总是。在某些情况下,数组切片和F90 +指针可能会使该语句不真实。即使这样,那些“数组”也会被分配给程序的连续内存块支持......

在内存中相邻。现在,假设我们有一个长度为a(N, M)的数组。从内存的角度来看,这与数组a(N*M)没什么不同,其中索引的映射是:

memory_index = i*(N-1) + j
a(memory_index)

N-1是因为fortran在索引中默认为从1开始。)

最终,当您拥有2D数组时,编译器会将您的语句a(i, j)转换为a(i*(N-1) + j)可能也会做一些检查的边界(例如,确保i介于1N之间,但通常必须将其打开带有编译器标志,因为它会略微影响性能,当程序运行速度减慢时,Fortran人群真的不喜欢它; - )

好的,我们在哪儿? 我所说的几乎所有内容都是对编译器而言,N维数组实际上只是一个带有索引重新映射的一维数组。

现在我们可以开始处理equivalence了。 C中的类似构造将是指针 - 有点像。您的Equivalence语句表示ping中的第一个元素与pg中的第一个元素的内存位置相同。这允许用户将数据读入ping这是一个扁平数组,但让它填充n维数组(因为最终,它们共享相同的存储位置)。值得注意的是,现代Fortran有指针。它们并不完全像C指针,但我认为大多数Fortran爱好者会建议你在新代码中使用它们而不是等价。

现在,我如何在python中读取这些数据?我可能会做一些真的简单的事情:

def yield_values(filename):
    with open(filename) as f_input:
        for line in f_input:
            for val in line.split(','):
                yield float(val)

然后你可以将它打包成一个numpy数组:

import numpy as np
arr = np.array(list(yield_values('data.dat')))

最后,您可以重塑数组:

# Account for python's Row-major ordering.
arr = arr.reshape((NTAUg, NTg, NDg, NSIZ))

如果您更喜欢fortran的专栏主要订购:

arr = arr.reshape((NSIZ, NDg, NTg, NTAUg), order='F')

答案 1 :(得分:1)

由于equivalence语句,ping中存储的所有数据也存储在pg中,因为它们指向内存中的相同位置。因此,当read命令读入值并将其存储在ping中时,可通过使用4D表示法读取pg来获取该值。这是一个捣蛋"用于将数据读入其中的数组。

在Python中,你可以做类似的事情,但这实际上取决于你打算如何使用数组。