# include # include # include # include # include "toms886.h" int main ( ); double sigma1 ( double t1, double t2, double a1, double a2, double b1, double b2, int family, int deg ); double isigm1 ( double sigma1, double sigma2, double a1, double a2, double b1, double b2, int family, int deg ); double sigma2 ( double t1, double t2, double a1, double a2, double b1, double b2, int family, int deg ); double isigm2 ( double sigma1, double sigma2, double a1, double a2, double b1, double b2, int family, int deg ); void target ( double a1, double b1, double a2, double b2, int ntg1, int ntgmax, double tg1[], double tg2[], int *ntg ); /******************************************************************************/ int main ( ) /******************************************************************************/ /* Purpose: rectangle() interpolates the Franke function on a rectangle. Discussion: This driver computes the interpolation of the Franke function on the rectangle R(A,B) = [A1,B1] x [A2,B2] with A=(A1,A2)=(0,0) and B=(B1,B2)=(1,1) (unit square) at the FAMILY = 1 of Padua points. The degree of interpolation is DEG = 60 and the number of target points is NTG = NTG1^2, NTG1 = 100. The maps from the reference square [-1,1]^2 to the rectangle are SIGMA1 and SIGMA2 with inverses ISIGM1 and ISIGM2. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Local, int DEGMAX, the maximum degree of interpolation. Local, int NPDMAX, the maximum number of Padua points = (DEGMAX + 1) * (DEGMAX + 2) / 2. Local, int NTG1MX, the maximum value of the parameter determining the number of target points. Local, int NTGMAX, the maximum number of target points, dependent on NTG1MX. Local, int DEG, the degree of interpolation, Local, int NTG1, the parameter determining the number of target points. Local, int FAMILY, specifies the desired family of Padua points. Local, int NPD, the number of Padua points = (DEG + 1) * (DEG + 2) / 2. Local, int NTG, the number of target points, dependent on NTG1. Local, double PD1[NPDMAX], the first coordinates of the Padua points. Local, double PD2[NPDMAX], the second coordinates of the Padua points. Local, double WPD[NPDMAX], the weights. Local, double FPD[NPDMAX], the function at the Padua points. Workspace, double RAUX1[(DEGMAX+1)*(DEGMAX+2)]. Workspace, double RAUX2[(DEGMAX+1)*(DEGMAX+2)]. Local, double C0[(0:DEGMAX+1)*(0:DEGMAX+1)], the coefficient matrix. Local, double TG1[NTGMAX], the first coordinates of the target points. Local, double TG2[NTGMAX], the second coordinates of the target points. Local, double INTFTG[NTGMAX], the values of the interpolated function. Local, double MAXERR, the maximum norm of the error at target points. Local, double ESTERR, the estimated error. */ { # define DEGMAX 60 # define NTG1MX 100 # define NPDMAX ( ( DEGMAX + 1 ) * ( DEGMAX + 2 ) / 2 ) # define NTGMAX ( NTG1MX * NTG1MX ) double a1; double a2; double b1; double b2; double c0[(DEGMAX+2)*(DEGMAX+2)]; int deg; int degmax = DEGMAX; double esterr; int family; char filename[255]; double gmax; double gmin; double fpd[NPDMAX]; double fxy; int i; double intftg[NTGMAX]; double ixy; double maxdev; double maxerr; double mean; int npd; int ntg; int ntg1; int ntgmax = NTGMAX; FILE *output; double pd1[NPDMAX]; double pd2[NPDMAX]; double raux1[(DEGMAX+1)*(DEGMAX+2)]; double raux2[(DEGMAX+1)*(DEGMAX+2)]; double tg1[NTGMAX]; double tg2[NTGMAX]; double wpd[NPDMAX]; double x; double y; a1 = 0.0; a2 = 0.0; b1 = 1.0; b2 = 1.0; family = 1; deg = 60; ntg1 = 100; timestamp ( ); printf ( "\n" ); printf ( "RECTANGLE:\n" ); printf ( " C version\n" ); printf ( " Interpolation of the Franke function\n" ); printf ( " on the unit square [0,1] x [0,1]\n" ); printf ( " of degree = %d\n", deg ); if ( degmax < deg ) { fprintf ( stderr, "\n" ); fprintf ( stderr, "RECTANGLE - Fatal error!\n" ); fprintf ( stderr, " DEGMAX < DEG.\n" ); fprintf ( stderr, " DEG = %d\n", deg ); fprintf ( stderr, " DEGMAX = %d\n", degmax ); exit ( 1 ); } /* Build the first family of Padua points in the square [-1,1]^2 */ pdpts ( deg, pd1, pd2, wpd, &npd ); /* Compute the Franke function at Padua points mapped to the region. */ for ( i = 0; i < npd; i++ ) { x = sigma1 ( pd1[i], pd2[i], a1, a2, b1, b2, family, deg ); y = sigma2 ( pd1[i], pd2[i], a1, a2, b1, b2, family, deg ); fpd[i] = franke ( x, y ); } /* Write X, Y, F(X,Y) to a file. */ strcpy ( filename, "rectangle_fpd.txt" ); output = fopen ( filename, "wt" ); for ( i = 0; i < npd; i++ ) { x = sigma1 ( pd1[i], pd2[i], a1, a2, b1, b2, family, deg ); y = sigma2 ( pd1[i], pd2[i], a1, a2, b1, b2, family, deg ); fprintf ( output, "%g %g %g\n", x, y, fpd[i] ); } fclose ( output ); printf ( "\n" ); printf ( " Wrote F(x,y) at Padua points in '%s'\n", filename ); /* Compute the matrix C0 of the coefficients in the bivariate orthonormal Chebyshev basis */ padua2 ( deg, degmax, npd, wpd, fpd, raux1, raux2, c0, &esterr ); /* Evaluate the target points in the region. */ target ( a1, b1, a2, b2, ntg1, ntgmax, tg1, tg2, &ntg ); /* Evaluate the interpolant at the target points. */ for ( i = 0; i < ntg; i++ ) { x = isigm1 ( tg1[i], tg2[i], a1, a2, b1, b2, family, deg ); y = isigm2 ( tg1[i], tg2[i], a1, a2, b1, b2, family, deg ); intftg[i] = pd2val ( deg, degmax, c0, x, y ); } /* Write the function value at target points to a file. */ strcpy ( filename, "rectangle_ftg.txt" ); output = fopen ( filename, "wt" ); for ( i = 0; i < ntg; i++ ) { fprintf ( output, "%g %g %g\n", tg1[i], tg2[i], franke ( tg1[i], tg2[i] ) ); } fclose ( output ); printf ( " Wrote F(x,y) at target points in '%s'\n", filename ); /* Write the interpolated function value at target points to a file. */ strcpy ( filename, "ellipse_itg.txt" ); output = fopen ( filename, "wt" ); for ( i = 0; i < ntg; i++ ) { fprintf ( output, "%g %g %g\n", tg1[i], tg2[i], intftg[i] ); } fclose ( output ); printf ( " Wrote I(F)(x,y) at target points in '%s'\n", filename ); /* Compute the error relative to the max deviation from the mean. */ maxerr = 0.0; mean = 0.0; gmax = - HUGE_VAL; gmin = + HUGE_VAL; for ( i = 0; i < ntg; i++ ) { fxy = franke ( tg1[i], tg2[i] ); ixy = intftg[i]; maxerr = fmax ( maxerr, fabs ( fxy - ixy ) ); mean = mean + fxy; gmax = fmax ( gmax, fxy ); gmin = fmin ( gmin, fxy ); } if ( gmax == gmin ) { maxdev = 1.0; } else { mean = mean / ( double ) ( ntg ); maxdev = fmax ( gmax - mean, mean - gmin ); } /* Print error ratios. */ printf ( "\n" ); printf ( " Estimated error: %g\n", esterr / maxdev ); printf ( " Actual error: %g\n", maxerr / maxdev ); printf ( " Expected error: %g\n", 0.2468E-10 ); /* Terminate. */ printf ( "\n" ); printf ( "RECTANGLE:\n" ); printf ( " Normal end of execution.\n" ); printf ( "\n" ); timestamp ( ); return 0; # undef DEGMAX # undef NTG1MX # undef NPDMAX # undef NTGMAX } /******************************************************************************/ double sigma1 ( double t1, double t2, double a1, double a2, double b1, double b2, int family, int deg ) /******************************************************************************/ /* Purpose: SIGMA1 maps first coordinate from square to the rectangle. Discussion: This function returns the first component of the map from the square [-1,1]^2 to the rectangle [A1,B1] x [A2,B2]. FAMILY and DEG select the rotation in order to get the corresponding FAMILY of Padua points at degree DEG. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Input, double T1, T2, the coordinates of a point in the square. Input, double A1, B1, A2, B2, the coordinates of the extreme corners of the rectangle. Input, int FAMILY, DEG, select the family of Padua points at degree DEG. Output, double SIGMA1, the X coordinate of the corresponding point in the rectangle. */ { double pi = 3.1415926535897931; double theta; double value; theta = ( double ) ( 2 * ( deg % 2 ) - 1 ) * ( double ) ( family - 1 ) * pi / 2.0; value = t1 * cos ( theta ) - t2 * sin ( theta ); value = ( ( b1 - a1 ) * value + ( b1 + a1 ) ) / 2.0; return value; } /******************************************************************************/ double isigm1 ( double sigma1, double sigma2, double a1, double a2, double b1, double b2, int family, int deg ) /******************************************************************************/ /* Purpose: ISIGM1 maps first coordinate from the rectangle to the square. Discussion: This function returns the first component of the map from the rectangle [A1,B1] x [A2,B2] to the square [-1,1]^2. FAMILY and DEG select the rotation in order to get the corresponding FAMILY of Padua points at degree DEG. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Input, double SIGMA1, SIGMA2, the coordinates of a point in the rectangle. Input, double A1, B1, A2, B2, the coordinates of the extreme corners of the rectangle. Input, int FAMILY, DEG, select the family of Padua points at degree DEG. Output, double ISIGM1, the X coordinate of the corresponding point in the square. */ { double isigm2; const double pi = 3.1415926535897931; double theta; double value; theta = ( double ) ( 2 * ( deg % 2 ) - 1 ) * ( double ) ( family - 1 ) * pi / 2.0; value = ( 2.0 * sigma1 - ( b1 + a1 ) ) / ( b1 - a1 ); isigm2 = ( 2.0 * sigma2 - ( b2 + a2 ) ) / ( b2 - a2 ); value = value * cos ( theta ) + isigm2 * sin ( theta ); return value; } /******************************************************************************/ double sigma2 ( double t1, double t2, double a1, double a2, double b1, double b2, int family, int deg ) /******************************************************************************/ /* Purpose: SIGMA2 maps second coordinate from square to the rectangle. Discussion: This function returns the second component of the map from the square [-1,1]^2 to the rectangle [A1,B1] x [A2,B2]. FAMILY and DEG select the rotation in order to get the corresponding FAMILY of Padua points at degree DEG. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Input, double T1, T2, the coordinates of a point in the square. Input, double A1, B1, A2, B2, the coordinates of the extreme corners of the rectangle. Input, int FAMILY, DEG, select the family of Padua points at degree DEG. Output, double SIGMA2, the Y coordinate of the corresponding point in the rectangle. */ { const double pi = 3.1415926535897931; double theta; double value; theta = ( double ) ( 2 * ( deg % 2 ) - 1 ) * ( double ) ( family - 1 ) * pi / 2.0; value = t1 * sin ( theta ) + t2 * cos ( theta ); value = ( ( b2 - a2 ) * value + ( b2 + a2 ) ) / 2.0; return value; } /******************************************************************************/ double isigm2 ( double sigma1, double sigma2, double a1, double a2, double b1, double b2, int family, int deg ) /******************************************************************************/ /* Purpose: ISIGM2 maps the second coordinate from the rectangle to the square. Discussion: This function returns the second component of the map from the rectangle [A1,B1] x [A2,B2] to the square [-1,1]^2. FAMILY and DEG select the rotation in order to get the corresponding FAMILY of Padua points at degree DEG. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Input, double SIGMA1, SIGMA2, the coordinates of a point in the ellipse. Input, double A1, B1, A2, B2, the coordinates of the extreme corners of the rectangle. Input, int FAMILY, DEG, select the family of Padua points at degree DEG. Output, double ISIGM2, the Y coordinate of the corresponding point in the rectangle. */ { double isigm1; const double pi = 3.1415926535897931; double theta; double value; theta = ( double ) ( 2 * ( deg % 2 ) - 1 ) * ( double ) ( family - 1 ) * pi / 2.0; isigm1 = ( 2.0 * sigma1 - ( b1 + a1 ) ) / ( b1 - a1 ); value = ( 2.0 * sigma2 - ( b2 + a2 ) ) / ( b2 - a2 ); value = - isigm1 * sin ( theta ) + value * cos ( theta ); return value; } /******************************************************************************/ void target ( double a1, double b1, double a2, double b2, int ntg1, int ntgmax, double tg1[], double tg2[], int *ntg ) /******************************************************************************/ /* Purpose: TARGET returns the target points on the rectangle. Discussion: Target points (uniform grid) on the rectangle [A1,B1] x [A2,B2]. The number of target points is NTG = NTG1^2. Licensing: This code is distributed under the MIT license. Modified: 16 February 2014 Author: Original FORTRAN77 version by Marco Caliari, Stefano De Marchi, Marco Vianello. This C version by John Burkardt. Reference: Marco Caliari, Stefano de Marchi, Marco Vianello, Algorithm 886: Padua2D: Lagrange Interpolation at Padua Points on Bivariate Domains, ACM Transactions on Mathematical Software, Volume 35, Number 3, October 2008, Article 21, 11 pages. Parameters: Input, double A1, B1, A2, B2, the coordinates of the extreme corners of the rectangle. Input, int NTG1, a parameter determining the number of target points Input, int NTGMAX, the maximum number of target points. Output, double TG1[NTG], TG2[NTG], the X and Y coordinates of the target points. Output, int *NTG, the number of target points computed. */ { int i; int j; if ( ntg1 < 2 ) { printf ( "\n" ); printf ( "TARGET - Fatal error!\n" ); printf ( " NTG1 < 2.\n" ); printf ( " NTG1 = %d\n", ntg1 ); exit ( 1 ); } if ( ntgmax < ntg1 * ntg1 ) { printf ( "\n" ); printf ( "TARGET - Fatal error!\n" ); printf ( " NTGMAX < NTG1 * NTG1.\n" ); printf ( " NTG1 = %d\n", ntg1 ); printf ( " NTGMAX = %d\n", ntgmax ); exit ( 1 ); } *ntg = 0; for ( i = 1; i <= ntg1; i++ ) { for ( j = 1; j <= ntg1; j++ ) { tg1[*ntg] = a1 + ( double ) ( j - 1 ) * ( b1 - a1 ) / ( double ) ( ntg1 - 1 ); tg2[*ntg] = a2 + ( double ) ( i - 1 ) * ( b2 - a2 ) / ( double ) ( ntg1 - 1 ); *ntg = *ntg + 1; } } return; }