/* * heat diffusion example, as discussed in textbook. * * command line arguments are number of points, maximum number of * iterations, and convergence threshold. * * parallel version with OpenMP, more complex SPMD-like approach. */ #include #include #include #include #define LEFTVAL 1.0 #define RIGHTVAL 10.0 void initialize(double uk[], double ukp1[], int nx) { int i; uk[0] = LEFTVAL; uk[nx-1] = RIGHTVAL; for (i = 1; i < nx-1; ++i) uk[i] = 0.0; for (i = 0; i < nx; ++i) ukp1[i] = uk[i]; } int main(int argc, char *argv[]) { int nx; int maxsteps; double threshold; double *uk; double *ukp1; double *temp; double dx, dt; double start_time, end_time; double maxdiff; int step; int nthreads; if (argc < 4) { fprintf(stderr, "usage is %s points max_iterations convergence_threshold\n", argv[0]); exit(EXIT_FAILURE); } start_time = omp_get_wtime(); nx = atoi(argv[1]); maxsteps = atoi(argv[2]); threshold = atof(argv[3]); #pragma omp parallel { #pragma omp single { nthreads = omp_get_num_threads(); } } if ((nx % nthreads) != 0) { fprintf(stderr, "Number of threads must evenly divide %d\n", nx); exit(EXIT_FAILURE); } uk = malloc(sizeof(double) * nx); ukp1 = malloc(sizeof(double) * nx); if (!uk || !ukp1) { fprintf(stderr, "Unable to allocate memory\n"); return EXIT_FAILURE; } dx = 1.0/nx; dt = 0.5*dx*dx; maxdiff = threshold; initialize(uk, ukp1, nx); #pragma omp parallel { double diff; double local_maxdiff; double local_step; int my_id; int loop_start; int loop_end; int i; my_id = omp_get_thread_num(); loop_start = my_id * (nx/nthreads); if (my_id == 0) loop_start = 1; loop_end = (my_id + 1) * (nx/nthreads); if (my_id == nthreads-1) loop_end = nx-1; for (local_step = 0; (local_step < maxsteps) && (maxdiff >= threshold); ++local_step) { /* compute new values */ /* for (i = 1; i < nx-1; ++i) */ for (i = loop_start; i < loop_end; ++i) { ukp1[i]=uk[i]+ (dt/(dx*dx))*(uk[i+1]-2*uk[i]+uk[i-1]); } /* check for convergence */ local_maxdiff = 0.0; #pragma omp single { maxdiff = 0.0; } /* for (i = 1; i < nx-1; ++i) */ for (i = loop_start; i < loop_end; ++i) { diff = fabs(uk[i] - ukp1[i]); if (diff > local_maxdiff) local_maxdiff = diff; } #pragma omp critical { if (local_maxdiff > maxdiff) maxdiff = local_maxdiff; } /* "copy" ukp1 to uk by swapping pointers */ #pragma omp barrier #pragma omp single { temp = ukp1; ukp1 = uk; uk = temp; } } /* save count of steps in shared variable */ #pragma omp single { step = local_step; } } end_time = omp_get_wtime(); printf("OpenMP program (%d threads):\n", nthreads); printf("nx = %d, maxsteps = %d, threshold = %g\n", nx, maxsteps, threshold); if (maxdiff < threshold) { printf("converged in %d iterations\n", step); } else { printf("failed to converge in %d iterations, maxdiff = %g\n", step, maxdiff); } printf("execution time = %g\n", end_time - start_time); /* clean up and end */ return EXIT_SUCCESS; }