Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran MPI按顺序写入文件_Fortran_Mpi_Paraview_Mpi Io - Fatal编程技术网

Fortran MPI按顺序写入文件

Fortran MPI按顺序写入文件,fortran,mpi,paraview,mpi-io,Fortran,Mpi,Paraview,Mpi Io,我正在用fortran CFD解算器编写一个并行VTK文件(pvti)。该文件实际上只是每个数据段的所有单个文件的列表。运行MPI,如果我让每个进程将其单个文件的名称写入标准输出 print *, name 然后我得到了每个文件的一个很好的列表,即 block0.vti block1.vti block2.vti 这正是我想要的那种名单。但是如果我写一个文件 write(9,*) name 然后我在文件中只得到一个输出。有没有一种简单的方法可以在不传输数据的情况下复制此文件的标准输出版本?

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

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

block0.vti
block1.vti
block2.vti
这正是我想要的那种名单。但是如果我写一个文件

write(9,*) name

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

您可以尝试采用以下使用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

另外,请注意,您只是幸运地获得了标准输出“解决方案”,您不一定能很好地对其进行排序。

您可以尝试调整以下使用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

另外,请注意,您只是幸运地获得了标准输出“解决方案”,您不一定能将其很好地排序。

如果您不着急,您可以强制将不同任务的输出按顺序排列:

! 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文件,而无需传递数据。

如果您不着急,可以强制不同任务的输出按顺序进行:

! 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文件,而无需传递数据。

除了将不同级别的写入很好地混合在一起之外,您的问题是Fortran
OPEN
语句可能会将文件截断为零长度,从而删除以前的内容,而不是附加到文件中。我和Vladimir F在这件事上是一致的,我只会写0级的文件。以下列出了几种可能的情况:

  • 每个列组写入一个单独的VTK文件,顺序跟随列组,或者实际顺序不重要。在这种情况下,您可以简单地使用秩0中从
    0
    #ranks-1
    DO
    循环来生成整个列表

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

  • 有些列组写入VTK文件,有些不写入,并且块顺序不跟随列组。这与前一种情况类似-只需让不写入块的列组发送一个负的块号,然后列组0将跳过负的数组元素

  • 块编号遵循列组顺序,但并非所有列组都写入块。在这种情况下,您可以使用
    MPI\u-GATHER
    从每个列组中收集一个
    逻辑
    值,以指示它是否写入了块


除了将来自不同级别的写入很好地混合在一起之外,您的问题是Fortran
OPEN
语句可能会将文件长度截断为零,从而删除以前的内容,而不是附加到文件中。我和Vladimir F在这件事上是一致的,我只会写0级的文件。以下列出了几种可能的情况:

  • 每个列组写入一个单独的VTK文件,顺序跟随列组,或者实际顺序不重要。在这种情况下,您可以简单地使用秩0中从
    0
    #ranks-1
    DO
    循环来生成整个列表

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

  • 有些列组写入VTK文件,有些不写入,并且块顺序不跟随列组。这与前一种情况类似-只需让不写入块的列组发送一个负的块号,然后列组0将跳过负的数组元素

  • 块编号遵循列组顺序,但并非所有列组都写入块。在这种情况下,您可以使用
    MPI\u-GATHER
    从每个列组中收集一个
    逻辑
    值,以指示它是否写入了块


谢谢。在我检查这个之前,你知道为什么打印功能对我有效,但并不总是有效吗?引擎盖下发生了什么?没什么特别的,只是所有的事情都是异步发生的。不仅是程序,还有程序与正在写入的屏幕或文件之间的I/O层。因此,即使您同步以确保程序中的顺序,您也无法同步下面的所有层,因此顺序可能会丢失。MPI-I/O是管理这一点的唯一明智的方法。因此答案是“不,使用MPI-IO没有简单的方法。”在我的例子中,只需重新计算秩0 a上的“名称”就容易得多