Richard Taylor
Richard Taylor

Reputation: 2742

Writing to files with MPI

I'm writing to a file as follows. The order does not necessarily matter (though it would be nice if I could get it ordered by K, as would be inherently in serial code)

            CALL MPI_BARRIER(MPI_COMM_WORLD, IERR)
            OPEN(EIGENVALUES_UP_IO, FILE=EIGENVALUES_UP_PATH, ACCESS='APPEND')
            WRITE(EIGENVALUES_UP_IO, *) K * 0.0001_DP * PI, (EIGENVALUES(J), J = 1, ATOM_COUNT)
            CLOSE(EIGENVALUES_UP_IO)

I'm aware this is likely to be the worst option.

I've taken a look at MPI_FILE_WRITE_AT etc. but I'm not sure they (directly) take data in the form that I have?

The file must be in the same format as this, which comes out as a line per K, with ATOM_COUNT + 1 columns. The values are REAL(8)

I've hunted over and over, and can't find any simple references on achieving this. Any help? :)

Similar code in C (assuming it's basically the same as FORTRAN) is just as useful

Thanks!

Upvotes: 1

Views: 3483

Answers (2)

Phil Miller
Phil Miller

Reputation: 38108

If you can determine how long each rank's write will be, you can call MPI_SCAN(size, offset, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD) to compute the offset that each rank should start at, and then they can all call MPI_FILE_WRITE_AT. This is probably more suitable if you have a lot of data, and you are confident that your MPI implementation does the write efficiently (doesn't serialize internally, or the like).

Upvotes: 0

Jonathan Dursi
Jonathan Dursi

Reputation: 50927

So determining the right IO strategy depends on a lot of factors. If you are just sending back a handful of eigenvalues, and you're stuck writing out ASCII, you might be best off just sending all the data back to process 0 to write. This is not normally a winning strategy, as it obviously doesn't scale; but if the amount of data is very small, it could well be better than the contention involved in trying to write out to a shared file (which is, again, harder with ASCII).

Some code is below which will schlep the amount of data back to proc 0, assuming everyone has the same amount of data.

Another approach would just be to have everyone write out their own ks and eigenvalues, and then as a postprocessing step once the program is finished, cat them all together. That avoids the MPI step, and (with the right filesystem) can scale up quite a ways, and is easy; whether that's better is fairly easily testable, and will depend on the amount of data, number of processors, and underlying file system.

   program testio
    use mpi
    implicit none

    integer, parameter :: atom_count = 5
    integer, parameter :: kpertask   = 2
    integer, parameter :: fileunit   = 7
    integer, parameter :: io_master  = 0
    double precision, parameter :: pi = 3.14159

    integer :: totalk
    integer :: ierr
    integer :: rank, nprocs

    integer :: handle
    integer(kind=MPI_OFFSET_KIND) :: offset
    integer :: filetype

    integer :: j,k
    double precision, dimension(atom_count, kpertask) :: eigenvalues
    double precision, dimension(kpertask) :: ks

    double precision, allocatable, dimension(:,:):: alleigenvals
    double precision, allocatable, dimension(:)  :: allks

    call MPI_INIT(ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, nprocs, ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)

    totalk   = nprocs*kpertask

    !! setup test data

    do k=1,kpertask
        ks(k) = (rank*kpertask+k)*1.d-4*PI
        do j=1,atom_count
            eigenvalues(j,k) = rank*100+j
        enddo
    enddo

    !! Everyone sends proc 0 their data

    if (rank == 0) then
        allocate(allks(totalk))
        allocate(alleigenvals(atom_count, totalk))
    endif

    call MPI_GATHER(ks, kpertask, MPI_DOUBLE_PRECISION,    &
                    allks, kpertask, MPI_DOUBLE_PRECISION, &
                    io_master, MPI_COMM_WORLD, ierr)

    call MPI_GATHER(eigenvalues, kpertask*atom_count, MPI_DOUBLE_PRECISION,  &
                    alleigenvals, kpertask*atom_count, MPI_DOUBLE_PRECISION, &
                    io_master, MPI_COMM_WORLD, ierr)

    if (rank == 0) then 
        open(unit=fileunit, file='output.txt')
        do k=1,totalk
            WRITE(fileunit, *) allks(k), (alleigenvals(j,k), j = 1, atom_count)
        enddo
        close(unit=fileunit)

        deallocate(allks)
        deallocate(alleigenvals)
    endif
    call MPI_FINALIZE(ierr)
end program testio

Upvotes: 2

Related Questions