Open MPI logo

Open MPI User's Mailing List Archives

  |   Home   |   Support   |   FAQ   |   all Open MPI User's mailing list

Subject: [OMPI users] try to understand heat equation 2D mpi solving version
From: christophe petit (christophe.petit09_at_[hidden])
Date: 2010-10-26 01:46:58


Hello,

i am still trying to understand the parallelized version of the heat
equation 2D solving that we saw at school. In order to explain my problem, i
need to list the main code :

  9 program heat
 10
!**************************************************************************
 11 !
 12 ! This program solves the heat equation on the unit square [0,1]x[0,1]
 13 ! | du/dt - Delta(u) = 0
 14 ! | u/gamma = cste
 15 ! by implementing a explicit scheme.
 16 ! The discretization is done using a 5 point finite difference scheme
 17 ! and the domain is decomposed into sub-domains.
 18 ! The PDE is discretized using a 5 point finite difference scheme
 19 ! over a (x_dim+2)*(x_dim+2) grid including the end points
 20 ! correspond to the boundary points that are stored.
 21 !
 22 ! The data on the whole domain are stored in
 23 ! the following way :
 24 !
 25 ! y
 26 ! ------------------------------------
 27 ! d | |
 28 ! i | |
 29 ! r | |
 30 ! e | |
 31 ! c | |
 32 ! t | |
 33 ! i | x20 |
 34 ! o /\ | |
 35 ! n | | x10 |
 36 ! | | |
 37 ! | | x00 x01 x02 ... |
 38 ! | ------------------------------------
 39 ! -------> x direction x(*,j)
 40 !
 41 ! The boundary conditions are stored in the following submatrices
 42 !
 43 !
 44 ! x(1:x_dim, 0) ---> left temperature
 45 ! x(1:x_dim, x_dim+1) ---> right temperature
 46 ! x(0, 1:x_dim) ---> top temperature
 47 ! x(x_dim+1, 1:x_dim) ---> bottom temperature
 48 !
 49
!**************************************************************************
 50 implicit none
 51 include 'mpif.h'
 52 ! size of the discretization
 53 integer :: x_dim, nb_iter
 54 double precision, allocatable :: x(:,:),b(:,:),x0(:,:)
 55 double precision :: dt, h, epsilon
 56 double precision :: resLoc, result, t, tstart, tend
 57 !
 58 integer :: i,j
 59 integer :: step, maxStep
 60 integer :: size_x, size_y, me, x_domains,y_domains
 61 integer :: iconf(5), size_x_glo
 62 double precision conf(2)
 63 !
 64 ! MPI variables
 65 integer :: nproc, infompi, comm, comm2d, lda, ndims
 66 INTEGER, DIMENSION(2) :: dims
 67 LOGICAL, DIMENSION(2) :: periods
 68 LOGICAL, PARAMETER :: reorganisation = .false.
 69 integer :: row_type
 70 integer, parameter :: nbvi=4
 71 integer, parameter :: S=1, E=2, N=3, W=4
 72 integer, dimension(4) :: neighBor
 73
 74 !
 75 intrinsic abs
 76 !
 77 !
 78 call MPI_INIT(infompi)
 79 comm = MPI_COMM_WORLD
 80 call MPI_COMM_SIZE(comm,nproc,infompi)
 81 call MPI_COMM_RANK(comm,me,infompi)
 82 !
 83 !
 84 if (me.eq.0) then
 85 call readparam(iconf, conf)
 86 endif
 87 call MPI_BCAST(iconf,5,MPI_INTEGER,0,comm,infompi)
 88 call MPI_BCAST(conf,2,MPI_DOUBLE_PRECISION,0,comm,infompi)
 89 !
 90 size_x = iconf(1)
 91 size_y = iconf(1)
 92 x_domains = iconf(3)
 93 y_domains = iconf(4)
 94 maxStep = iconf(5)
 95 dt = conf(1)
 96 epsilon = conf(2)
 97 !
 98 size_x_glo = x_domains*size_x+2
 99 h = 1.0d0/dble(size_x_glo)
100 dt = 0.25*h*h
101 !
102 !
103 lda = size_y+2
104 allocate(x(0:size_y+1,0:size_x+1))
105 allocate(x0(0:size_y+1,0:size_x+1))
106 allocate(b(0:size_y+1,0:size_x+1))
107 !
108 ! Create 2D cartesian grid
109 periods(:) = .false.
110
111 ndims = 2
112 dims(1)=x_domains
113 dims(2)=y_domains
114 CALL MPI_CART_CREATE(MPI_COMM_WORLD, ndims, dims, periods, &
115 reorganisation,comm2d,infompi)
116 !
117 ! Identify neighbors
118 !
119 NeighBor(:) = MPI_PROC_NULL
120 ! Left/West and right/Est neigbors
121 CALL MPI_CART_SHIFT(comm2d,0,1,NeighBor(W),NeighBor(E),infompi)
122
123 print *,'mpi_proc_null=', MPI_PROC_NULL
124 print *,'rang=', me
125 print *, 'ici premier mpi_cart_shift : neighbor(w)=',NeighBor(W)
126 print *, 'ici premier mpi_cart_shift : neighbor(e)=',NeighBor(E)
127
128 ! Bottom/South and Upper/North neigbors
129 CALL MPI_CART_SHIFT(comm2d,1,1,NeighBor(S),NeighBor(N),infompi)
130
131
132 print *, 'ici deuxieme mpi_cart_shift : neighbor(s)=',NeighBor(S)
133 print *, 'ici deuxieme mpi_cart_shift : neighbor(n)=',NeighBor(N)
134
135
136
137 !
138 ! Create row data type to coimmunicate with South and North neighbors
139 !
140 CALL MPI_TYPE_VECTOR(size_x, 1, size_y+2, MPI_DOUBLE_PRECISION,
row_type,infompi)
141 CALL MPI_TYPE_COMMIT(row_type, infompi)
142 !
143 ! initialization
144 !
145 call initvalues(x0, b, size_x+1, size_x )
146 !
147 ! Update the boundaries
148 !
149 call updateBound(x0,size_x,size_x, NeighBor, comm2d, row_type)
150
151 step = 0
152 t = 0.0
153 !
154 tstart = MPI_Wtime()
155 ! REPEAT
156 10 continue
157 !
158 step = step + 1
159 t = t + dt
160 ! perform one step of the explicit scheme
161 call Explicit(x0,x,b, size_x+1, size_x, size_x, dt, h, resLoc)
162 ! update the partial solution along the interface
163 call updateBound(x0,size_x,size_x, NeighBor, comm2d, row_type)
164 ! Check the distance between two iterates
165 call MPI_ALLREDUCE(resLoc,result,1, MPI_DOUBLE_PRECISION,
MPI_SUM,comm,infompi)
166 result= sqrt(result)
167 !
168 if (me.eq.0) write(*,1002) t,result
169 !
170 if ((result.gt.epsilon).and.(step.lt.maxStep)) goto 10
171 !
172 ! UNTIL "Convergence"
173 !
174 tend = MPI_Wtime()
175 if (me.eq.0) then
176 write(*,*)
177 write(*,*) ' Convergence after ', step,' steps '
178 write(*,*) ' Problem size ',
size_x*x_domains*size_y*y_domains
179 write(*,*) ' Wall Clock ', tend-tstart
180
181 !
182 ! Print the solution at each point of the grid
183 !
184 write(*,*)
185 write(*,*) ' Computed solution '
186 write(*,*)
187 do 30, j=size_x+1,0,-1
188 write(*,1000)(x0(j,i),i=0,size_x+1)
189 30 continue
190 endif
191 !
192 call MPI_FINALIZE(infompi)
193 !
194 deallocate(x)
195 deallocate(x0)
196 deallocate(b)
197 !
198 ! Formats available to display the computed values on the grid
199 !
200 1000 format(100(1x, f7.3))
201 1001 format(100(1x, e7.3))
202 1002 format(' At time ',E8.2,' Norm ', E8.2)
203
204 !
205 stop
206 end
207 !
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The routine "Explicit" at line 161 allows to compute the domain 2D ( the
values of Temperature are stocked in vector "x" : x(1:size_x,1:size_y)) with
the following scheme :

! The stencil of the explicit operator for the heat equation
! on a regular rectangular grid using a five point finite difference
! scheme in space is
!
! | + 1
     |
! |
    |
!dt/(h*h) * | +1 -4 + h*h/dt + 1 |
! |
     |
! | + 1
  |
!
      diag = - 4.0 + h*h/dt
      weight = dt/(h*h)
!
! perform an explicit update on the points within the domain
        do 20, j=1,size_x
          do 30, i=1,size_y
             x(i,j) = weight *( x0(i-1,j) + x0(i+1,j) &
                        + x0(i,j-1) + x0(i,j+1) +x0(i,j)*diag)
 30 continue
 20 continue

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The routine "updateBound" updates the bound values like this :

  1 !*******************************************************************
  2 SUBROUTINE updateBound(x, size_x, size_y, NeighBor, comm2d, row_type)
  3
  4 !*****************************************************************
  5 include 'mpif.h'
  6 !
  7 INTEGER size_x, size_y
  8 !Iterate
  9 double precision, dimension(0:size_y+1,0:size_x+1) :: x
 10 !Type row_type
 11 INTEGER :: row_type
 12 integer, parameter :: nbvi=4
 13 integer, parameter :: S=1, E=2, N=3, W=4
 14 integer, dimension(4) :: neighBor
 15 !
 16 INTEGER :: infompi, comm2d
 17 INTEGER :: flag
 18 INTEGER, DIMENSION(MPI_STATUS_SIZE) :: status
 19
 20 !********* North/South communication
************************************
 21 flag = 1
 22 !Send my boundary to North and receive from South
 23 CALL MPI_SENDRECV(x(size_y, 1), 1, row_type ,neighBor(N),flag, &
 24 x(0,1), 1, row_type,neighbor(S),flag, &
 25 comm2d, status, infompi)
 26
 27 !Send my boundary to South and receive from North
 28 CALL MPI_SENDRECV(x(1,1), 1, row_type ,neighbor(S),flag, &
 29 x(size_y+1,1), 1, row_type ,neighbor(N),flag, &
 30 comm2d, status, infompi)
 31
 32 !********* Est/West communication ************************************
 33 flag = 2
 34 !Send my boundary to West and receive from Est
 35 CALL MPI_SENDRECV(x(1,1), size_y, MPI_DOUBLE_PRECISION, neighbor(W),
flag, &
 36 x(1, size_x+1), size_y,
MPI_DOUBLE_PRECISION,neighbor(E), flag, &
 37 comm2d, status, infompi)
 38
 39 !Send my boundary to Est and receive from West
 40 CALL MPI_SENDRECV( x(1,size_x), size_y, MPI_DOUBLE_PRECISION,
neighbor(E), flag, &
 41 x(1,0),size_y, MPI_DOUBLE_PRECISION, neighbor(W),
flag, &
 42 comm2d, status, infompi)
 43
 44 END SUBROUTINE updateBound

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I am confused between the shift of the values near to the bounds done by the
"updateBound" routine and the main loop (at line 161 in main code) which
calls the routine "Explicit".
For a given process (say number 1) ( i use 4 here for execution), i send to
the east process (3) the penultimate column left column, to the north
process (0) the penultimate row top ,and to the others (mpi_proc_null=-2)
the penultimate right column and the bottom row. But how the 4 processes
are synchronous ? I don't understand too why all the processes go through
the solving piece of code calling the "Explicit" routine.

Here'i the sequential version of this simulation :

 49 program heat
 50 implicit none
 51 ! size of the discretization
 52 integer size_x, maxStep
 53 integer lda
 54 double precision, allocatable:: x(:,:),b(:,:), x0(:,:)
 55 double precision dt, h, result, epsilon
 56
 57 ! index loop
 58 integer i,j, step
 59 double precision t
 60 !
 61 intrinsic abs
 62 !
 63 !
 64 print *,' Size of the square '
 65 read(*,*) size_x
 66 h = 1.0/(size_x+1)
 67 dt = 0.25*h*h
 68 maxStep = 100
 69 print *, 'Max. number of steps '
 70 read(*,*) maxStep
 71 epsilon = 1.d-8
 72 !
 73 allocate(x(0:size_x+1,0:size_x+1))
 74 allocate(x0(0:size_x+1,0:size_x+1))
 75 allocate(b(0:size_x+1,0:size_x+1))
 76 !
 77 !
 78 ! initialization
 79 !
 80 call initvalues(x0, b, size_x+1, size_x )
 81 !
 82 step = 0
 83 t = 0.0
 84 ! REPEAT
 85 10 continue
 86 !
 87 step = step + 1
 88 t = t + dt
 89 !
 90 call Explicit(x0, x, b, size_x+1, size_x, size_x, dt, &
 91 h, result)
 92 result = sqrt(result)
 93 if ((result.gt.epsilon).and.(step.lt.maxStep)) goto 10
 94 !
 95 write(*,*)
 96 write(*,*) ' Convergence after ', step,' steps '
 97 write(*,*) ' Problem size ', size_x*size_x
 98 !

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Sorry for this long post but i would like to clarify my problem as much as
it was possible.

Any explanation would help me.

Thanks in advance