Beispiel #1
0
double rhs_1st_equation (double x, double t, Gas_parameters * parameters) {
  return g_t (x, t) + 
          .5 * (
              2 * u_exact (x, t) * g_x (x, t) + 
              g_exact(x, t) * u_x (x, t) + 
              (2 - g_exact (x, t)) * u_x (x, t));
}
Beispiel #2
0
/* RHS initializes the right hand side "vector". */
void rhs(int matrix_size, int matrix_size2, double *f_, int block_size)
{
    double (*f)[matrix_size][matrix_size] = (double (*)[matrix_size][matrix_size])f_;
    int i,ii;
    int j,jj;
    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.

#pragma omp parallel
#pragma omp master
    //for collapse(2)
    for (j = 0; j < matrix_size; j+=block_size)
        for (i = 0; i < matrix_size; i+=block_size)
#pragma omp task firstprivate(block_size,i,j,matrix_size) private(ii,jj,x,y)
            for (jj=j; jj<j+block_size; ++jj)
            {
                y = (double) (jj) / (double) (matrix_size - 1);
                for (ii=i; ii<i+block_size; ++ii)
                {
                    x = (double) (ii) / (double) (matrix_size - 1);
                    if (ii == 0 || ii == matrix_size - 1 || jj == 0 || jj == matrix_size - 1)
                        (*f)[ii][jj] = u_exact(x, y);
                    else
                        (*f)[ii][jj] = - uxxyy_exact(x, y);
                }
            }
}
Beispiel #3
0
/* RHS initializes the right hand side "vector". */
void rhs(int nx, int ny, double *f, int block_size)
{
    int i,ii;
    int j,jj;
    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.

#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(block_size,i,j,nx,ny) private(ii,jj,x,y)
for (jj=j; jj<j+block_size; ++jj)
            {
                y = (double) (jj) / (double) (ny - 1);
                for (ii=i; ii<i+block_size; ++ii)
                {
                    x = (double) (ii) / (double) (nx - 1);
                    if (ii == 0 || ii == nx - 1 || jj == 0 || jj == ny - 1)
                        (f)[ii * ny + jj] = u_exact(x, y);
                    else
                        (f)[ii * ny + jj] = - uxxyy_exact(x, y);
                }
            }
        }
    }
    }
}
double FD::ErrorRMS()
{
    double sum = 0;
    for(int i = 0; i < N; i ++)
    {
        double exact = u_exact(i,M);
        sum +=(data[M][i]-exact)*(data[M][i]-exact)/exact/exact;
    }
    sum = sum/(1+N);
    sum = sqrt(sum);    
    return sum;
}
double FD :: MaxPointwiseError()
{
    double max = 0;
    for(int i = 1; i < M+1;i++)
        for(int j = 1; j < N; j++)
        {
            double exact = u_exact(j, i );
            if(abs(exact-data[i][j])>max)
                max = abs(exact-data[i][j]);
        }
    return max;
}
Beispiel #6
0
void error_norm(double rms[]) {

//---------------------------------------------------------------------
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//     this function computes the norm of the difference between the
//     computed solution and the exact solution
//---------------------------------------------------------------------

      int c, i, j, k, m, ii, jj, kk, d, error;
      double xi, eta, zeta, u_exact[5], rms_work[5],
           add;

      for (m = 1; m <= 5; m++) {
         rms_work(m) = 0.0e0;
      }

      for (c = 1; c <= ncells; c++) {
         kk = 0;
         for (k = cell_low(3,c); k <= cell_high(3,c); k++) {
            zeta = (double)(k) * dnzm1;
            jj = 0;
            for (j = cell_low(2,c); j <= cell_high(2,c); j++) {
               eta = (double)(j) * dnym1;
               ii = 0;
               for (i = cell_low(1,c); i <= cell_high(1,c); i++) {
                  xi = (double)(i) * dnxm1;
                  exact_solution(xi, eta, zeta, u_exact);

                  for (m = 1; m <= 5; m++) {
                     add = u(m,ii,jj,kk,c)-u_exact(m);
                     rms_work(m) = rms_work(m) + add*add;
                  }
                  ii = ii + 1;
               }
               jj = jj + 1;
            }
            kk = kk + 1;
         }
      }

      RCCE_allreduce((char*)rms_work, (char*)rms, 5, RCCE_DOUBLE, RCCE_SUM, RCCE_COMM_WORLD);

      for (m = 1; m <= 5; m++) {
         for (d = 1; d <= 3; d++) {
            rms(m) = rms(m) / (double)(grid_points(d)-2);
         }
         rms(m) = sqrt(rms(m));
      }

      return;
}
void calc_error ( int nx, int ny, int nz, double u[],  double f[],
                  double xlo,  double ylo, double zlo,
                  double xhi,  double yhi, double zhi )
{
    double  error_max, error_l2;
    int     i, j, k, i_max=-1, j_max=-1, k_max = -1;
    double  u_true, u_true_norm;
    double  x, y, z, dx, dy, dz, term;

    dx = (xhi - xlo) / ( double ) ( nx - 1 );
    dy = (yhi - ylo) / ( double ) ( ny - 1 );
    dz = (yhi - ylo) / ( double ) ( nz - 1 );

    error_max   = 0.0;
    error_l2    = 0.0;

    /* print statements below are commented out but  may help in debugging */
    //printf("   i    j   k       x       y    z         uexact          ucomp            error\n");
    
    for ( k = 0; k < nz; k++ ) {
      z = zlo + k * dz;
      for ( j = 0; j < ny; j++ ) {
        y = ylo + j * dy;
        for ( i = 0; i < nx; i++ ) {
            x = xlo + i * dx;
            u_true = u_exact ( x, y, z );
            term   =  U(i,j,k) - u_true;
            //printf(" %d  %d  %d %12.5e %12.5e %12.5e %12.5e  %12.5e %12.5e \n",i,j,k,x,y,z,u_true,U(i,j,k),term);
            error_l2  = error_l2 + term*term;
            if (ABS(term) > error_max){
              error_max =  ABS(term);
            }
        } /* end for i */
      } /* end for j */
    } /* end for k */

    error_l2 = sqrt(dx*dy*dz*error_l2);

    printf ( "\n  max Error in computed soln:    %12.5e    \n", error_max );
    printf ( "  l2 norm of Error on %4d by %4d by %4d grid\n  (dx %12.5e dy %12.5e dz %12.5e):   %12.5e\n",
             nx,ny,nz,dx,dy,dz,error_l2 );

    return;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
double error_f(double x, double y, gsl_vector *solution)
{
    return fabs(reconstruct_at(solution,x,y)-u_exact(x,y));
}
Beispiel #11
0
void init_prob ( int nx, int ny, int nz, double  f[], double u[],
                 double xlo,  double ylo, double zlo,
                 double xhi,  double yhi, double zhi )
{
  int    i, j, k;
  double x, y, z, dx, dy, dz;

    dx = (xhi - xlo) / ( double ) ( nx - 1 );
    dy = (yhi - ylo) / ( double ) ( ny - 1 );
    dz = (zhi - zlo) / ( double ) ( nz - 1 );

    /* Set the boundary conditions. For this simple test use exact solution in bcs */

    j = 0;   // low y bc
    y = ylo;

    for ( k = 0; k < nz; k++ ) {
      z = zlo + k*dz;
      for ( i = 0; i < nx; i++ ) {
        x = xlo + i * dx;
        U(i,j,k) = u_exact ( x, y, z );  // notese que cuando aca se habla de ijk, en realidad es una macro que asigna la posicion necesaria
      }
    }

    j = ny - 1;  // hi y
    y = yhi;
    
    for ( k = 0; k < nz; k++ ) {
      z = zlo + k*dz;
      for ( i = 0; i < nx; i++ ) {
        x = xlo + i * dx;
        U(i,j,k) = u_exact ( x, y, z );
      }
    }

    i = 0;  // low x
    x = xlo;

    for ( k = 0; k < nz; k++ ) {
      z = zlo + k*dx;
      for ( j = 0; j < ny; j++ ) {
        y = ylo + j * dy;
        U(i,j,k) = u_exact ( x, y, z );
      }
    }

    i = nx - 1; // hi x
    x = xhi;

    for ( k = 0; k < nz; k++ ) {
      z = zlo + k*dx;    
      for ( j = 0; j < ny; j++ ) {
        y = ylo + j * dy;
        U(i,j,k) = u_exact ( x, y, z );
      }
    }

    k = 0; // low z
    z = zlo;

    for ( j = 0; j < ny; j++ ) {
      y = ylo + j * dy;
      for ( i = 0; i < nx; i++) {
        x = xlo + i * dx;
        U(i,j,k) = u_exact ( x, y, z );
      }
    }

    k = nz - 1; // hi z
    z = zhi;
    
    for ( j = 0; j < ny; j++ ) {
      y = ylo + j * dy;
      for ( i = 0; i < nx; i++) {
        x = xlo + i * dx;
        U(i,j,k) = u_exact ( x, y, z );
      }
    }
    
    omp_set_num_threads(7);
    #pragma omp parallel for default(none)\
    	shared(nx, ny, nz, dx, dy, dz, u, f, xlo, ylo, zlo) private(i, j, k, z, y, x) 
    /* Set the right hand side  */
    for ( k = 0; k < nz; k++ ){
      z = zlo + k * dz;
      for ( j = 0; j < ny; j++ ){
        y = ylo + j * dy;
        for ( i = 0; i < nx; i++ ) {
          x = xlo + i * dx;
          F(i,j,k) =  uxx_exact ( x, y, z ) + uyy_exact ( x, y, z ) + uzz_exact( x, y, z );
        }
      }
    }

    return;
}
Beispiel #12
0
double rhs_2nd_equation (double x, double t, Gas_parameters * parameters) {
  return u_t (x, t) + 
          u_exact (x, t) * u_x (x, t) + 
          parameters->p_ro * g_x (x, t) -
          parameters->viscosity * exp (-g_exact (x, t)) * u_xx (x, t);
}
Beispiel #13
0
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_);
}
Beispiel #14
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;
}