void rhs ( int nx, int ny, double f[NX][NY] ) /******************************************************************************/ /* * Purpose: * RHS initializes the right hand side "vector". * Discussion: * It is convenient for us to set up RHS as a 2D array. However, each * entry of RHS is really the right hand side of a linear system of the * form * A * U = F * In cases where U(I,J) is a boundary value, then the equation is simply * U(I,J) = F(i,j) * and F(I,J) holds the boundary data. * Otherwise, the equation has the form * (1/DX^2) * ( U(I+1,J)+U(I-1,J)+U(I,J-1)+U(I,J+1)-4*U(I,J) ) = F(I,J) * where DX is the spacing and F(I,J) is the value at X(I), Y(J) of * pi^2 * ( x^2 + y^2 ) * sin ( pi * x * y ) * Licensing: * This code is distributed under the GNU LGPL license. * Modified: * 28 October 2011 * Author: * John Burkardt * Parameters: * Input, int NX, NY, the X and Y grid dimensions. * Output, double F[NX][NY], the initialized right hand side data. * */ { double fnorm; int i; int j; double x; double y; /* * The "boundary" entries of F store the boundary values of the solution. * The "interior" entries of F store the right hand sides of the Poisson equation. * */ for ( j = 0; j < ny; j++ ) { y = ( double ) ( j ) / ( double ) ( ny - 1 ); for ( i = 0; i < nx; i++ ) { x = ( double ) ( i ) / ( double ) ( nx - 1 ); if ( i == 0 || i == nx - 1 || j == 0 || j == ny - 1 ) { f[i][j] = u_exact ( x, y ); } else { f[i][j] = - uxxyy_exact ( x, y ); } } } fnorm = r8mat_rms ( nx, ny, f ); printf ( " RMS of F = %g\n", fnorm ); return; }
void check_params( struct user_parameters* params, int matrix_size, int block_size, double dx, double dy, double *f_, int niter, double *u_, double *unew_) { double x, y; int i, j; double *udiff_ =(double*)malloc(matrix_size * matrix_size * sizeof(double)); double (*udiff)[matrix_size][matrix_size] = (double (*)[matrix_size][matrix_size])udiff_; double (*unew)[matrix_size][matrix_size] = (double (*)[matrix_size][matrix_size])unew_; double (*u)[matrix_size][matrix_size] = (double (*)[matrix_size][matrix_size])u_; double (*f)[matrix_size][matrix_size] = (double (*)[matrix_size][matrix_size])f_; // Check for convergence. for (j = 0; j < matrix_size; j++) { y = (double) (j) / (double) (matrix_size - 1); for (i = 0; i < matrix_size; i++) { x = (double) (i) / (double) (matrix_size - 1); (*udiff)[i][j] = (*unew)[i][j] - u_exact(x, y); if( (*udiff)[i][j] > 1.0E-6 ) { printf("error: %d, %d: %f\n", i, j, (*udiff)[i][j]); } } } double error = r8mat_rms(matrix_size, matrix_size, udiff_); double error1; // Set the right hand side array F. rhs(matrix_size, matrix_size, f_, block_size); for (j = 0; j < matrix_size; j++) { for (i = 0; i < matrix_size; i++) { if (i == 0 || i == matrix_size - 1 || j == 0 || j == matrix_size - 1) { (*unew)[i][j] = (*f)[i][j]; (*u)[i][j] = (*f)[i][j]; } else { (*unew)[i][j] = 0.0; (*u)[i][j] = 0.0; } } } sweep_seq(matrix_size, matrix_size, dx, dy, f_, 0, niter, u_, unew_); // Check for convergence. for (j = 0; j < matrix_size; j++) { y = (double) (j) / (double) (matrix_size - 1); for (i = 0; i < matrix_size; i++) { x = (double) (i) / (double) (matrix_size - 1); (*udiff)[i][j] = (*unew)[i][j] - u_exact(x, y); if( (*udiff)[i][j] > 1.0E-6 ) { printf("error: %d, %d: %f\n", i, j, (*udiff)[i][j]); } } } error1 = r8mat_rms(matrix_size, matrix_size, udiff_); params->succeed = fabs(error - error1) < 1.0E-6; if(!params->succeed) { printf("error = %f, error1 = %f\n", error, error1); } free(udiff_); }
int main ( int argc, char *argv[] ) /******************************************************************************/ /* * Purpose: * MAIN is the main program for POISSON_OPENMP. * Discussion: * POISSON_OPENMP is a program for solving the Poisson problem. * This program uses OpenMP for parallel execution. * The Poisson equation * - DEL^2 U(X,Y) = F(X,Y) * is solved on the unit square [0,1] x [0,1] using a grid of NX by * NX evenly spaced points. The first and last points in each direction * are boundary points. * The boundary conditions and F are set so that the exact solution is * U(x,y) = sin ( pi * x * y ) * so that * - DEL^2 U(x,y) = pi^2 * ( x^2 + y^2 ) * sin ( pi * x * y ) * The Jacobi iteration is repeatedly applied until convergence is detected. * For convenience in writing the discretized equations, we assume that NX = NY. * Licensing: * This code is distributed under the GNU LGPL license. * Modified: * 14 December 2011 * Author: * John Burkardt * */ { int converged; double diff; double dx; double dy; double error; double f[NX][NY]; int i; int id; int itnew; int itold; int j; int jt; int jt_max = 20; int nx = NX; int ny = NY; double tolerance = 0.000001; double u[NX][NY]; double u_norm; double udiff[NX][NY]; double uexact[NX][NY]; double unew[NX][NY]; double unew_norm; double wtime; double x; double y; dx = 1.0 / ( double ) ( nx - 1 ); dy = 1.0 / ( double ) ( ny - 1 ); /* * Print a message. * */ timestamp ( ); printf ( "\n" ); printf ( "POISSON_OPENMP:\n" ); printf ( " C version\n" ); printf ( " A program for solving the Poisson equation.\n" ); printf ( "\n" ); printf ( " Use OpenMP for parallel execution.\n" ); // printf ( " The number of processors is %d\n", omp_get_num_procs ( ) ); { // id = omp_get_thread_num ( ); // if ( id == 0 ) //{ // printf ( " The maximum number of threads is %d\n", omp_get_num_threads ( ) ); // } } printf ( "\n" ); printf ( " -DEL^2 U = F(X,Y)\n" ); printf ( "\n" ); printf ( " on the rectangle 0 <= X <= 1, 0 <= Y <= 1.\n" ); printf ( "\n" ); printf ( " F(X,Y) = pi^2 * ( x^2 + y^2 ) * sin ( pi * x * y )\n" ); printf ( "\n" ); printf ( " The number of interior X grid points is %d\n", nx ); printf ( " The number of interior Y grid points is %d\n", ny ); printf ( " The X grid spacing is %f\n", dx ); printf ( " The Y grid spacing is %f\n", dy ); /* * Set the right hand side array F. * */ rhs ( nx, ny, f ); /* * Set the initial solution estimate UNEW. * We are "allowed" to pick up the boundary conditions exactly. * */ for ( j = 0; j < ny; j++ ) { for ( i = 0; i < nx; i++ ) { if ( i == 0 || i == nx - 1 || j == 0 || j == ny - 1 ) { unew[i][j] = f[i][j]; } else { unew[i][j] = 0.0; } } } unew_norm = r8mat_rms ( nx, ny, unew ); /* * Set up the exact solution UEXACT. * */ for ( j = 0; j < ny; j++ ) { y = ( double ) ( j ) / ( double ) ( ny - 1 ); for ( i = 0; i < nx; i++ ) { x = ( double ) ( i ) / ( double ) ( nx - 1 ); uexact[i][j] = u_exact ( x, y ); } } u_norm = r8mat_rms ( nx, ny, uexact ); printf ( " RMS of exact solution = %g\n", u_norm ); /* * Do the iteration. * */ converged = 0; printf ( "\n" ); printf ( " Step ||Unew|| ||Unew-U|| ||Unew-Exact||\n" ); printf ( "\n" ); for ( j = 0; j < ny; j++ ) { for ( i = 0; i < nx; i++ ) { udiff[i][j] = unew[i][j] - uexact[i][j]; } } error = r8mat_rms ( nx, ny, udiff ); printf ( " %4d %14g %14g\n", 0, unew_norm, error ); //wtime = omp_get_wtime ( ); itnew = 0; for ( ; ; ) { itold = itnew; itnew = itold + 500; /* * SWEEP carries out 500 Jacobi steps in parallel before we come * back to check for convergence. * */ sweep ( nx, ny, dx, dy, f, itold, itnew, u, unew ); /* * Check for convergence. * */ u_norm = unew_norm; unew_norm = r8mat_rms ( nx, ny, unew ); for ( j = 0; j < ny; j++ ) { for ( i = 0; i < nx; i++ ) { udiff[i][j] = unew[i][j] - u[i][j]; } } diff = r8mat_rms ( nx, ny, udiff ); for ( j = 0; j < ny; j++ ) { for ( i = 0; i < nx; i++ ) { udiff[i][j] = unew[i][j] - uexact[i][j]; } } error = r8mat_rms ( nx, ny, udiff ); printf ( " %4d %14g %14g %14g\n", itnew, unew_norm, diff, error ); if ( diff <= tolerance ) { converged = 1; break; } } if ( converged ) { printf ( " The iteration has converged.\n" ); } else { printf ( " The iteration has NOT converged.\n" ); } //wtime = omp_get_wtime ( ) - wtime; printf ( "\n" ); printf ( " Elapsed seconds = %g\n", wtime ); /* * Terminate. * */ printf ( "\n" ); printf ( "POISSON_OPENMP:\n" ); printf ( " Normal end of execution.\n" ); printf ( "\n" ); timestamp ( ); return 0; }
double run(struct user_parameters* params) { int matrix_size = params->matrix_size; if (matrix_size <= 0) { matrix_size = 512; params->matrix_size = matrix_size; } int block_size = params->blocksize; if (block_size <= 0) { block_size = 128; params->blocksize = block_size; } int niter = params->titer; if (niter <= 0) { niter = 4; params->titer = niter; } double dx; double dy; double error; int ii,i; int jj,j; int nx = matrix_size; int ny = matrix_size; double *f = (double *)malloc(nx * nx * sizeof(double)); double *u = (double *)malloc(nx * nx * sizeof(double)); double *unew = (double *)malloc(nx * ny * sizeof(double)); /* test if valid */ if ( (nx % block_size) || (ny % block_size) ) { params->succeed = 0; params->string2display = "*****ERROR: blocsize must divide NX and NY"; return 0; } /// INITIALISATION dx = 1.0 / (double) (nx - 1); dy = 1.0 / (double) (ny - 1); // Set the right hand side array F. rhs(nx, ny, f, block_size); /* Set the initial solution estimate UNEW. We are "allowed" to pick up the boundary conditions exactly. */ #pragma omp parallel { #pragma omp single for (j = 0; j < ny; j+= block_size) { for (i = 0; i < nx; i+= block_size) { #pragma omp task firstprivate(i,j) private(ii,jj) for (jj=j; jj<j+block_size; ++jj) { for (ii=i; ii<i+block_size; ++ii) { if (ii == 0 || ii == nx - 1 || jj == 0 || jj == ny - 1) { (unew)[ii * ny + jj] = (f)[ii * ny + jj]; } else { (unew)[ii * ny + jj] = 0.0; } } } } } } /// KERNEL INTENSIVE COMPUTATION START_TIMER; sweep(nx, ny, dx, dy, f, 0, niter, u, unew, block_size); END_TIMER; if(params->check) { double x; double y; double *udiff = (double *)malloc(nx * ny * sizeof(double)); /// CHECK OUTPUT // Check for convergence. for (j = 0; j < ny; j++) { y = (double) (j) / (double) (ny - 1); for (i = 0; i < nx; i++) { x = (double) (i) / (double) (nx - 1); (udiff)[i * ny + j] = (unew)[i * ny + j] - u_exact(x, y); } } error = r8mat_rms(nx, ny, udiff); double error1; // Set the right hand side array F. rhs(nx, ny, f, block_size); /* Set the initial solution estimate UNEW. We are "allowed" to pick up the boundary conditions exactly. */ for (j = 0; j < ny; j++) { for (i = 0; i < nx; i++) { if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) { (unew)[i * ny + j] = (f)[i * ny + j]; } else { (unew)[i * ny + j] = 0.0; } } } sweep_seq(nx, ny, dx, dy, f, 0, niter, u, unew); // Check for convergence. for (j = 0; j < ny; j++) { y = (double) (j) / (double) (ny - 1); for (i = 0; i < nx; i++) { x = (double) (i) / (double) (nx - 1); (udiff)[i * ny + j] = (unew)[i * ny + j] - u_exact(x, y); } } error1 = r8mat_rms(nx, ny, udiff); params->succeed = fabs(error - error1) < 1.0E-6; free(udiff); } free(f); free(u); free(unew); return TIMER; }