Fortran无格式输出,每个MPI进程写入数组的一部分

Fortran无格式输出,每个MPI进程写入数组的一部分,fortran,mpi,binaryfiles,Fortran,Mpi,Binaryfiles,在我的并行程序中,有一个大矩阵。每个进程计算并存储其中的一部分。然后程序通过让每个进程以正确的顺序写入矩阵中自己的部分,将矩阵写入文件。输出文件为“未格式化”格式。但是,当我试图读取串行代码中的文件时(我分配了正确大小的大矩阵),我得到了一个我不理解的错误 我的问题是:在MPI程序中,如何获得二进制文件作为由不同进程存储的大型矩阵的串行版本输出 以下是我的尝试: if(ThisProcs == RootProcs) then open(unit = file_restar

在我的并行程序中,有一个大矩阵。每个进程计算并存储其中的一部分。然后程序通过让每个进程以正确的顺序写入矩阵中自己的部分,将矩阵写入文件。输出文件为“未格式化”格式。但是,当我试图读取串行代码中的文件时(我分配了正确大小的大矩阵),我得到了一个我不理解的错误

我的问题是:在MPI程序中,如何获得二进制文件作为由不同进程存储的大型矩阵的串行版本输出

以下是我的尝试:

    if(ThisProcs == RootProcs) then
        open(unit = file_restart%unit, file = file_restart%file, form = 'unformatted')
        write(file_restart%unit)psi
        close(file_restart%unit)
    endif
#ifdef USEMPI
    call mpi_barrier(mpi_comm_world,MPIerr)
#endif
    do i = 1, NProcs - 1
        if(ThisProcs == i) then
            open(unit = file_restart%unit, file = file_restart%file, form = 'unformatted', status = 'old', position = 'append')
            write(file_restart%unit)psi
            close(file_restart%unit)
        endif
#ifdef USEMPI
        call mpi_barrier(mpi_comm_world,MPIerr)
#endif
    enddo
Psi是一个大矩阵,其分配如下:

Psi(N_lattice_points, NPsiStart:NPsiEnd)
但当我试图以串行代码加载文件时:

open(2,file=File1,form="unformatted")
read(2)psi

如何修复并行部分以使二进制文件对串行代码可读?当然可以在MPI程序中将它们组合成一个大矩阵,但是有更简单的方法吗

编辑1


这两个答案真的很好。我将使用
access=“stream”
来解决我的问题。我只是想我可以使用inquire来检查文件是“顺序”还是“流”。

记录文件中的Fortran无格式顺序写入并不是完全的原始数据。每次写入都将以处理器相关的形式在记录前后提供数据。读取的大小不能超过写入的记录大小。这意味着如果在两次写入中写入了
psi
,则需要在两次读取中读回,而不能同时读入

也许最直接的选择是使用
stream
access而不是
sequential
。流文件通常按字节索引,不包含记录开始和结束信息。使用此访问方法,您可以拆分写入,但同时读取所有内容。流访问是Fortran 2003的一项功能


如果您坚持顺序访问,则需要知道有多少MPI列写入了文件,并在适当大小的记录上循环,以便在写入数据时读取数据。您可以让用户指定列组数或将其存储为文件中的第一条记录,然后首先读取该列组数,以确定如何读取其余数据。

这不是MPI特有的问题,但在串行程序中也会发生,该程序采用相同的逐段写入数据块的方法

忽略每个进程的开始和结束,查看整个连接和传输语句。您的连接是使用顺序访问的未格式化文件。它是无格式的,因为你明确要求它,而顺序的,因为你没有要求任何其他东西

顺序文件访问基于记录。每个write语句都会输出一条由矩阵块组成的记录。相反,您的输入语句尝试从单个记录读取数据

您的问题是,当您尝试从文件的第一条记录读取整个矩阵时,该记录并不包含整个矩阵。它包含的数据量不正确。最终结果:“输入语句需要太多数据”

因此,您需要基于相同的记录结构读入数据,或者远离记录文件

后者很简单,使用流访问

open(unit = file_restart%unit, file = file_restart%file,  &
     form = 'unformatted', access='stream')
或者,使用类似的循环结构读取:

do i=1, NPROCS
  ! read statement with a slice
end do
这当然需要理解正确的切片


可选地,可以考虑使用MPI-IO进行输出,这与使用流输出非常相似。使用流访问将此内容读回。你可以在其他地方找到这个概念。

如果你在写MPI,为什么不写MPI-IO?每个进程将调用MPI_File_set_view来设置文件的子数组视图,然后每个进程都可以使用MPI_File_write_ALL来集体写入数据。这种方法很可能在大型计算机上扩展得非常好(尽管您的方法最多可以扩展到100个处理器)。

错误表明文件大于
psi
。文件的大小和psi的大小是多少?@CareyGregory在我的测试用例中,文件是8.03 MB。在同一测试案例中,Psi分为两个过程的两部分。我已经检查了这个文件,如果你在序列代码中这样做,你会得到同样大小的文件。当每个进程都将它写入到一个记录中。然后尝试从单个记录读取整个矩阵。您可能需要阅读有关记录定向和流输出的内容。@CareyGregory complex(8)Psi(4096,16,8)。我忘了提到文件是8.03MB,其中包括Psi和另一个数组d(4096)。@francescalus你的意思是我应该写一个循环,按照写文件过程的相同顺序将文件读到矩阵的相应部分,对吗?完美!我将使用'stream',我使用的是windows版本MPICH2。但网站上的版本是1.4.1p。我记得(也许我错了),那里的IO功能不够好。所以我没有学习MPI-IO部分。另外,我认为物理上只有一个进程可以将数据写入硬盘。所以我会坚持我的方法,因为它也不是那么复杂。谢谢你提出来。
do i=1, NPROCS
  ! read statement with a slice
end do