!> !> @file pex10.f90 !> !> @brief Parallel write/read of 2d and 3d arrays partionned on 2d processor grid !> !> @copyright !> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) !> SPC (Swiss Plasma Center) !> !> futils is free software: you can redistribute it and/or modify it under !> the terms of the GNU Lesser General Public License as published by the Free !> Software Foundation, either version 3 of the License, or (at your option) !> any later version. !> !> futils is distributed in the hope that it will be useful, but WITHOUT ANY !> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS !> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. !> !> You should have received a copy of the GNU Lesser General Public License !> along with this program. If not, see . !> !> @authors !> (in alphabetical order) !> @author Trach-Minh Tran !> PROGRAM main ! ! Parallel write/read of 2d and 3d arrays partionned on ! 2d processor grid ! USE futils IMPLICIT NONE INCLUDE "mpif.h" CHARACTER(len=32) :: file='para.h5' INTEGER :: ierr, fid, me, npes, comm=MPI_COMM_WORLD ! INTEGER, PARAMETER :: ndims=2 INTEGER, DIMENSION(ndims) :: dims, coords LOGICAL :: periods(ndims), reorder INTEGER :: cart, cartcol, cartrow ! INTEGER, DIMENSION(ndims) :: offsets, np INTEGER :: n1=7, n2=9, n3=8 INTEGER :: i, j, k, iglob, jglob, kglob DOUBLE PRECISION, ALLOCATABLE :: array2(:,:), array3(:,:,:), brray3(:,:,:) DOUBLE COMPLEX, ALLOCATABLE :: carray2(:,:), carray3(:,:,:), cbrray3(:,:,:) DOUBLE PRECISION :: a DOUBLE COMPLEX :: za INTEGER :: nerrors !=========================================================================== ! 1. Prologue ! Init MPI CALL mpi_init(ierr) CALL mpi_comm_size(MPI_COMM_WORLD, npes, ierr) CALL mpi_comm_rank(MPI_COMM_WORLD, me, ierr) ! ! Create cartesian topololy ! dims(1) = 3; dims(2:ndims) = 0; periods = (/.FALSE., .FALSE./) reorder = .FALSE. CALL mpi_dims_create(npes, ndims, dims, ierr) CALL mpi_cart_create(comm, ndims, dims, periods, reorder, cart, ierr) CALL mpi_cart_coords(cart, me, ndims, coords, ierr) CALL mpi_cart_sub(cart, (/.TRUE., .FALSE. /), cartcol, ierr) CALL mpi_cart_sub(cart, (/.FALSE., .TRUE. /), cartrow, ierr) IF( me .EQ. 0 ) WRITE(*,'(a,i2,i2)') 'Processor grid', dims(1), dims(2) ! ! Create file collectively ! CALL creatf(file, fid, & & desc="A parallel file", & & real_prec='s', & & mpiposix=.FALSE., & & mpicomm=cart) !=========================================================================== ! 2. Parallel write file ! ! Define local 2d array ! CALL dist1d(cartcol, 0, n1, offsets(1), np(1)) CALL dist1d(cartrow, 0, n2, offsets(2), np(2)) ! WRITE(*,'(a,i3.3,a,10i5)') 'PE', me, ': coords, offsets, np', & & coords, offsets, np ! ALLOCATE(array2(np(1),np(2))) ALLOCATE(carray2(np(1),np(2))) DO i=1,np(1) iglob = offsets(1)+i DO j=1,np(2) jglob = offsets(2)+j array2(i,j) = 10*iglob + jglob END DO END DO carray2 = CMPLX(array2, -array2, KIND(array2)) ! ! Define local 3d array A(n1, n2/P1, n3/P2) ! CALL dist1d(cartcol, 0, n2, offsets(1), np(1)) CALL dist1d(cartrow, 0, n3, offsets(2), np(2)) ! WRITE(*,'(a,i3.3,a,10i5)') 'PE', me, ': coords, offsets, np', & & coords, offsets, np ! ALLOCATE(array3(n1,np(1),np(2))) ALLOCATE(carray3(n1,np(1),np(2))) DO i=1,n1 DO j=1,np(1) jglob = offsets(1)+j DO k=1,np(2) kglob = offsets(2)+k array3(i,j,k) = 100*i + 10*jglob + kglob END DO END DO END DO carray3 = CMPLX(-array3/10.0d0, array3, KIND(array3)) ! ! Define local 3d array B(n1/P1, n2, n3/P2) ! CALL dist1d(cartcol, 0, n1, offsets(1), np(1)) CALL dist1d(cartrow, 0, n3, offsets(2), np(2)) ! WRITE(*,'(a,i3.3,a,10i5)') 'PE', me, ': coords, offsets, np', & & coords, offsets, np ! ALLOCATE(brray3(np(1),n2,np(2))) ALLOCATE(cbrray3(np(1),n2,np(2))) DO i=1,np(1) iglob = offsets(1)+i DO j=1,n2 DO k=1,np(2) kglob = offsets(2)+k brray3(i,j,k) = 100*iglob + 10*j + kglob END DO END DO END DO cbrray3 = CMPLX(-brray3/10.0, brray3) ! ! Write to file ! CALL putarrnd(fid, "/parray2", array2, (/1,2/)) CALL putarrnd(fid, "/pcarray2", carray2, (/1,2/)) ! CALL putarrnd(fid, "/parray3", array3, (/2,3/)) CALL putarrnd(fid, "/pcarray3", carray3, (/2,3/)) ! CALL putarrnd(fid, "/parray3b", brray3, (/1,3/)) CALL putarrnd(fid, "/pcarray3b", cbrray3, (/1,3/)) WRITE(*,'(a,i3.3,a)') 'PE', me, ': All write ok!' !=========================================================================== ! 3. Parallel read file ! ! Close and reopen file CALL closef(fid) CALL openf(file, fid, mpicomm=cart) ! ! Read file array2 = 0.0d0 array3 = 0.0d0 carray2 = (0.0d0, 0.0d0) carray3 = (0.0d0, 0.0d0) CALL getarrnd(fid, "/parray2", array2, (/1,2/)) CALL getarrnd(fid, "/pcarray2", carray2, (/1,2/)) CALL getarrnd(fid, "/parray3", array3, (/2,3/)) CALL getarrnd(fid, "/pcarray3", carray3, (/2,3/)) ! ! Check read arrays CALL dist1d(cartcol, 0, n1, offsets(1), np(1)) CALL dist1d(cartrow, 0, n2, offsets(2), np(2)) nerrors = 0 DO i=1,np(1) iglob = offsets(1)+i DO j=1,np(2) jglob = offsets(2)+j a = 10*iglob + jglob IF( a .NE. array2(i,j) ) nerrors = nerrors+1 END DO END DO WRITE(*,'(a25,i5)') 'nerrors reading /parray2', nerrors ! nerrors = 0 DO i=1,np(1) iglob = offsets(1)+i DO j=1,np(2) jglob = offsets(2)+j za = CMPLX(array2(i,j), -array2(i,j)) IF( za .NE. carray2(i,j) ) nerrors = nerrors+1 END DO END DO WRITE(*,'(a25,i5)') 'nerrors reading /pcarray2', nerrors ! CALL dist1d(cartcol, 0, n2, offsets(1), np(1)) CALL dist1d(cartrow, 0, n3, offsets(2), np(2)) nerrors = 0 DO i=1,n1 DO j=1,np(1) jglob = offsets(1)+j DO k=1,np(2) kglob = offsets(2)+k a = 100*i + 10*jglob + kglob IF( a .NE. array3(i,j,k) ) nerrors = nerrors+1 END DO END DO END DO WRITE(*,'(a25,i5)') 'nerrors reading /parray3', nerrors ! nerrors = 0 DO i=1,n1 DO j=1,np(1) jglob = offsets(1)+j DO k=1,np(2) kglob = offsets(2)+k za = CMPLX(-array3(i,j,k)/10.0, array3(i,j,k)) IF( za .NE. carray3(i,j,k) ) nerrors = nerrors+1 END DO END DO END DO WRITE(*,'(a25,i5)') 'nerrors reading /pcarray3', nerrors !=========================================================================== ! 9. Epilogue ! DEALLOCATE(array2, array3, brray3) DEALLOCATE(carray2, carray3, cbrray3) ! CALL closef(fid) CALL mpi_finalize(ierr) END PROGRAM main SUBROUTINE dist1d(comm, s0, ntot, s, nloc) IMPLICIT NONE INCLUDE 'mpif.h' INTEGER, INTENT(in) :: s0, ntot INTEGER, INTENT(out) :: s, nloc INTEGER :: comm, me, npes, ierr, naver, rem ! CALL MPI_COMM_SIZE(comm, npes, ierr) CALL MPI_COMM_RANK(comm, me, ierr) naver = ntot/npes rem = MODULO(ntot,npes) s = s0 + MIN(rem,me) + me*naver nloc = naver IF( me.LT.rem ) nloc = nloc+1 ! END SUBROUTINE dist1d