The following code solves a 2-D Laplace equation by using a relaxation scheme.
The exercise is solved in 3 steps:
4.1 : Parallelize the code by using OpenMP directives. Work on the most computationally intensive loop.
4.2 : Try to include also the while loop in the parallel region
4.3 (Fortran users only): Also the part about the "T" array-sintax may be parallelized... (hint: use "omp workshare")
WARNING for C programmers: the solution may differ depending on what version of OpenMP is installed on your workstation (3.1 or older).
C source code // solves 2-D Laplace equation using a relaxation scheme #define MAX(A,B) (((A) > (B)) ? (A) : (B)) #include <stdio.h> #include <math.h> #include <float.h> #include <stdlib.h> #include <string.h> #include <time.h> int main() { double *T, *Tnew, *Tmp; double tol, var = DBL_MAX, top = 100.0; unsigned n, n2, maxIter, i, j, iter = 0; int itemsread; FILE *fout; printf("Enter mesh size, max iterations and tolerance: "); itemsread = scanf("%u ,%u ,%lf", &n, &maxIter, &tol); if (itemsread!=3) { fprintf(stderr, "Input error!\n"); exit(-1); } time_t startTime = clock(); n2 = n+2; T = calloc(n2*n2, sizeof(*T)); Tnew = calloc(n2*n2, sizeof(*T)); if (T == NULL || Tnew == NULL) { fprintf(stderr, "Not enough memory!\n"); exit(EXIT_FAILURE); } // set boundary conditions for (i=1; i<=n; i++) { T[(n+1)*n2+i] = Tnew[(n+1)*n2+i] = i * top / (n+1); T[i*n2+n+1] = Tnew[i*n2+n+1] = i * top / (n+1); } while(var > tol && iter <= maxIter) { ++iter; var = 0.0; for (i=1; i<=n; ++i) { for (j=1; j<=n; ++j) { Tnew[i*n2+j] = 0.25*( T[(i-1)*n2+j] + T[(i+1)*n2+j] + T[i*n2+(j-1)] + T[i*n2+(j+1)] ); var = MAX(var, fabs(Tnew[i*n2+j] - T[i*n2+j])); } }
Tmp=T; T=Tnew; Tnew=Tmp; if (iter%100 == 0) printf("iter: %8u, variation = %12.4lE\n", iter, var); } double endTime = (clock() - startTime) / (double) CLOCKS_PER_SEC; printf("Elapsed time (s) = %.2lf\n", endTime); printf("Mesh size: %u\n", n); printf("Stopped at iteration: %u\n", iter); printf("Maximum error: %lE\n", var); // saving results to file fout = fopen("results", "w"); if (fout == NULL) { perror("results"); exit(-1); } for (i=1; i<=n; ++i) for (j=1; j<=n; ++j) fprintf(fout, "%8u %8u %18.9lE\n", i, j, T[i*n2+j]); fclose(fout); free(T); free(Tnew); return 0; }
FORTRAN source code
program laplace
implicit none
integer, parameter :: dp=kind(1.d0)
integer :: n, maxIter, i, j, iter = 0
real (dp), dimension(:,:), pointer :: T, Tnew, Tmp=>null()
real (dp) :: tol, var = 1.d0, top = 100.d0
real :: starttime, endtime
integer :: ierr
write(*,*) 'Enter mesh size, max iterations and tollerance:'
read(*,*,iostat=ierr) n, maxIter, tol
if(ierr /= 0) STOP 'Input error!'
call cpu_time(startTime)
allocate (T(0:n+1,0:n+1), Tnew(0:n+1,0:n+1),stat=ierr)
if(ierr/=0) STOP 'T Tnew matrix allocation failed'
T(0:n,0:n) = 0.d0
T(n+1,1:n) = (/ (i, i=1,n) /) * (top / (n+1))
T(1:n,n+1) = (/ (i, i=1,n) /) * (top / (n+1))
Tnew = T
do while (var > tol .and. iter <= maxIter)
iter = iter + 1
var = 0.d0
do j = 1, n
do i = 1, n
Tnew(i,j) = 0.25d0 * ( T(i-1,j) + T(i+1,j) + T(i,j-1) + T(i,j+1) )
var = max(var, abs( Tnew(i,j) - T(i,j) ))
end do
end do
Tmp =>T; T =>Tnew; Tnew => Tmp;
if( mod(iter,100) == 0 ) write(*,"(a,i8,e12.4)") &
' iter, variation:', iter, var
end do
call cpu_time(endTime)
write(*,'(/A,F10.4)') ' Elapsed time (s) =', endTime - startTime
write(*,*) 'Mesh size =', n
write(*,*) 'Stopped at iteration =', iter
write(*,*) 'The maximum error =', var
open(10, file='results', action='write', iostat=ierr)
if(ierr /= 0) STOP 'Error in opening output file!'
write(10, "(i8, i8, e18.9)") (( i, j, T(i,j), i=1,n), j=1,n)
close(10)
deallocate (T, Tnew)
nullify(Tmp)
end program laplace