MPI按顺序写入文件

时间:2014-04-29 09:49:59

标签: fortran mpi paraview mpi-io

我正在从我的fortran CFD求解器中编写并行VTK文件(pvti)。该文件实际上只是每个数据的所有单个文件的列表。运行MPI,如果我有每个进程将其单个文件的名称写入标准输出

print *, name

然后我得到一个很好的每个文件列表,即

block0.vti
block1.vti
block2.vti

这正是我想要的那种列表。但是如果我写一个文件

write(9,*) name

然后我只在文件中输出一个输出。是否有一种简单的方法可以在不传输数据的情况下复制此标准输出版本?

3 个答案:

答案 0 :(得分:2)

您可以尝试调整使用MPI-IO的以下内容,这实际上是确保来自多个进程的有序文件的唯一方法。它假设一个行尾字符,并且所有行都是相同的长度(如果需要,用空格填充)但我认为这是关于它。

Program ascii_mpiio

  ! simple example to show MPI-IO "emulating" Fortran 
  ! formatted direct access files. Note can not use the latter
  ! in parallel with multiple processes writing to one file
  ! is behaviour is not defined (and DOES go wrong on certain
  ! machines)

  Use mpi

  Implicit None

  ! All the "lines" in the file will be this length
  Integer, Parameter :: max_line_length = 30

  ! We also need to explicitly write a carriage return. 
  ! here I am assuming  ASCII
  Character, Parameter :: lf = Achar( 10 )

  ! Buffer to hold a line
  Character( Len = max_line_length + 1 ) :: line

  Integer :: me, nproc
  Integer :: fh
  Integer :: record
  Integer :: error
  Integer :: i

  ! Initialise MPI
  Call mpi_init( error )
  Call mpi_comm_rank( mpi_comm_world, me   , error )
  Call mpi_comm_size( mpi_comm_world, nproc, error )

  ! Create a MPI derived type that will contain a line of the final
  ! output just before we write it using MPI-IO. Note this also
  ! includes the carriage return at the end of the line.
  Call mpi_type_contiguous( max_line_length + 1, mpi_character, record, error )
  Call mpi_type_commit( record, error )

  ! Open the file. prob want to change the path and name
  Call mpi_file_open( mpi_comm_world, '/home/ian/test/mpiio/stuff.dat', &
       mpi_mode_wronly + mpi_mode_create, &
       mpi_info_null, fh, error )

  ! Set the view for the file. Note the etype and ftype are both RECORD,
  ! the derived type used to represent a whole line, and the displacement
  ! is zero. Thus
  ! a) Each process can "see" all of the file
  ! b) The unit of displacement in subsequent calls is a line. 
  !    Thus if we have a displacement of zero we write to the first line,
  !    1 means we write to the second line, and in general i means
  !    we write to the (i+1)th line
  Call mpi_file_set_view( fh, 0_mpi_offset_kind, record, record, &
       'native', mpi_info_null, error )

  ! Make each process write to a different part of the file
  Do i = me, 50, nproc
     ! Use an internal write to transfer the data into the
     ! character buffer
     Write( line, '( "This is line ", i0, " from ", i0 )' ) i, me
     !Remember the line feed at the end of the line
     line( Len( line ):Len( line ) ) = lf
     ! Write with a displacement of i, and thus to line i+1
     ! in the file
     Call mpi_file_write_at( fh, Int( i, mpi_offset_kind ), &
          line, 1, record, mpi_status_ignore, error )
  End Do

  ! Close the file
  Call mpi_file_close( fh, error )

  ! Tidy up
  Call mpi_type_free( record, error )

  Call mpi_finalize( error )

End Program ascii_mpii

另外请注意,您只是很幸运,您的标准输出“解决方案”,您无法保证将其整齐排序。

答案 1 :(得分:1)

如果您不赶时间,可以强制执行不同任务的输出:

! Loop over processes in order
DO n = 0,numProcesses-1

  ! Write to file if it is my turn
  IF(nproc == n)THEN 
    ! Write output here
  ENDIF

  ! This call ensures that all processes wait for each other
#ifdef MPI
  CALL MPI_Barrier(mpi_comm_world,ierr)
#endif

ENDDO

此解决方案很简单,但对于非常大的输出效率不高。这似乎不是你的情况。确保在每次写入后刷新输出缓冲区。如果使用此方法,请确保在实施之前进行测试,因为并非所有体系结构都能保证成功。这种方法适用于输出大型NetCDF文件而无需传递数据。

答案 2 :(得分:1)

除了让不同级别的写入混合好之外,你的问题是Fortran OPEN语句可能会将文件截断为零长度,从而删除以前的内容而不是附加到它。我和弗拉基米尔F在一起,并且只会在0级写这个文件。有几种可能的情况,其中一些列在这里:

  • 每个等级写一个单独的VTK文件,顺序跟随排名或实际顺序不重要。在这种情况下,您只需使用DO0等级0的#ranks-1循环即可生成整个列表。

  • 每个等级写一个单独的VTK文件,但订单不遵循等级,例如等级0写入block3.vti,等级1写入block12.vti等等。在这种情况下,您可以使用MPI_GATHER将每个进程的块编号收集到等级0的数组中,然后循环遍历数组的元素。

  • 某些等级写入VTK文件,有些则不写,并且块顺序不符合等级。它与前一种情况类似 - 只是让不写块的行发送一个负数块然后排名0会跳过负数组元素。

  • 块编号遵循排序顺序,但并非所有排名都写入块。在这种情况下,您可以使用MPI_GATHER从每个排名中收集一个LOGICAL值,以表明它是否已写入块。