MPI запись в файл последовательно


Я пишу параллельный файл VTK (pvti)из моего решателя Fortran CFD. Файл на самом деле представляет собой просто список всех отдельных файлов для каждой части данных. Запуск MPI, если у меня есть каждый процесс, запишите имя его отдельного файла в стандартный вывод

print *, name

Затем я получаю хороший список каждого файла, т. е.

block0.vti
block1.vti
block2.vti
Это именно тот список, который мне нужен. Но если я пишу в файл
write(9,*) name

Тогда я получаю только один вывод в файле. Есть ли простой способ повторить стандартная выходная версия этого без передачи данных?

3 2

3 ответа:

Помимо того, что записи из разных рангов хорошо перемешаны, ваша проблема заключается в том, что оператор Fortran OPEN, вероятно, усекает файл до нулевой длины, тем самым стирая предыдущее содержимое вместо добавления к нему. Я с Владимиром Ф по этому поводу и написал бы этот файл только в ранге 0. Существует несколько возможных случаев, некоторые из которых перечислены здесь:

  • Каждый ранг записывает отдельный файл VTK, и порядок следует за рангами или фактический порядок не имеет значения. В этом случае вы можете просто использовать цикл DO в ранге 0 от 0 до #ranks-1, чтобы сгенерировать весь список.

  • Каждый ранг записывает отдельный файл VTK, но порядок не следует за рангами, например, ранг 0 записывает block3.vti, ранг 1 записывает block12.vti и т. д. В этом случае вы можете использовать MPI_GATHER, чтобы собрать номер блока из каждого процесса в массив ранга 0, а затем выполнить цикл по элементам массива.

  • Некоторые ранги пишут файл VTK, некоторые-нет, а порядок блоков-нет. следуйте за рядами. Это похоже на предыдущий случай - просто есть ранги, которые не пишут блок, посылают отрицательный номер блока, а затем ранг 0 пропустит отрицательные элементы массива.

  • Нумерация блоков следует порядку рангов, но не все ранги пишут блок. В этом случае вы можете использовать MPI_GATHER для сбора одного значения LOGICAL из каждого ранга, которое указывает, записал ли он блок или нет.

Вы можете попробовать адаптировать следующий, который использует 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 без необходимости передавать данные вокруг.