public static void compare(int node_num, double[] node_xy, int[] indx, int nunk, double[] f, Func <double, double, ExactResult> exact) //****************************************************************************80 // // Purpose: // // COMPARE compares the exact and computed solution at the nodes. // // Discussion: // // This is a rough comparison, done only at the nodes. Such a pointwise // comparison is easy, because the value of the finite element // solution is exactly the value of the finite element coefficient // associated with that node. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, int NODE_NUM, the number of nodes. // // Input, double NODE_XY[2*NODE_NUM], the nodes. // // Input, int INDX[NODE_NUM], the index of the unknown in the finite // element linear system. // // Input, int NUNK, the number of unknowns in the finite element system. // // Input, double F[NUNK], the solution vector of the finite // element system. // { int node; Console.WriteLine(""); Console.WriteLine("COMPARE:"); Console.WriteLine(" Compare computed and exact solutions at the nodes."); Console.WriteLine(""); Console.WriteLine(" X Y U U"); Console.WriteLine(" computed exact"); Console.WriteLine(""); for (node = 0; node < node_num; node++) { double x = node_xy[0 + node * 2]; double y = node_xy[1 + node * 2]; ExactResult res = exact(x, y); double u = res.u; int i = indx[node]; double uh = f[i - 1]; Console.WriteLine(x.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + y.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + uh.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + u.ToString(CultureInfo.InvariantCulture).PadLeft(12) + ""); } }
public static void boundary(int nx, int ny, int node_num, double[] node_xy, int[] indx, int ib, int nunk, ref double[] a, ref double[] f, Func <double, double, ExactResult> exact) //****************************************************************************80 // // Purpose: // // BOUNDARY modifies the linear system for boundary conditions. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, int NX, NY, controls the number of elements along the // X and Y directions. The number of elements will be // 2 * ( NX - 1 ) * ( NY - 1 ). // // Input, int NODE_NUM, the number of nodes. // // Input, double NODE_XY[2*NODE_NUM], the coordinates of nodes. // // Input, int INDX[NODE_NUM], gives the index of the unknown quantity // associated with the given node. // // Input, int IB, the half-bandwidth of the matrix. // // Input, int NUNK, the number of unknowns. // // Input/output, double A[(3*IB+1)*NUNK], the NUNK by NUNK // coefficient matrix, stored in a compressed format. // On output, A has been adjusted for boundary conditions. // // Input/output, double F[NUNK], the right hand side. // On output, F has been adjusted for boundary conditions. // { int row; // // Consider each node. // int node = 0; for (row = 1; row <= 2 * ny - 1; row++) { int col; for (col = 1; col <= 2 * nx - 1; col++) { node += 1; if (row != 1 && row != 2 * ny - 1 && col != 1 && col != 2 * nx - 1) { continue; } int i = indx[node - 1]; double x = node_xy[0 + (node - 1) * 2]; double y = node_xy[1 + (node - 1) * 2]; ExactResult res = exact(x, y); double u = res.u; int jlo = Math.Max(i - ib, 1); int jhi = Math.Min(i + ib, nunk); int j; for (j = jlo; j <= jhi; j++) { a[i - j + 2 * ib + (j - 1) * (3 * ib + 1)] = 0.0; } a[i - i + 2 * ib + (i - 1) * (3 * ib + 1)] = 1.0; f[i - 1] = u; } } }
public static void solution_write(double[] f, int[] indx, int node_num, int nunk, string output_filename, double[] node_xy, Func <double, double, ExactResult> exact) //****************************************************************************80 // // Purpose: // // SOLUTION_WRITE writes the solution to a file. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, double F[NUNK], the coefficients of the solution. // // Input, int INDX[NODE_NUM], gives the index of the unknown quantity // associated with the given node. // // Input, int NODE_NUM, the number of nodes. // // Input, int NUNK, the number of unknowns. // // Input, string OUTPUT_FILENAME, the name of the file // in which the data should be stored. // // Input, double NODE_XY[2*NODE_NUM], the X and Y coordinates of nodes. // { int node; List <string> output = new(); for (node = 0; node < node_num; node++) { double x = node_xy[0 + node * 2]; double y = node_xy[1 + node * 2]; double u; switch (indx[node]) { case > 0: u = f[indx[node] - 1]; break; default: { ExactResult res = exact(x, y); u = res.u; break; } } output.Add(u.ToString(CultureInfo.InvariantCulture).PadLeft(14)); } try { File.WriteAllLines(output_filename, output); } catch (Exception) { Console.WriteLine(""); Console.WriteLine("SOLUTION_WRITE - Warning!"); Console.WriteLine(" Could not write the solution file."); } }
private static void Main() //****************************************************************************80 // // Purpose: // // MAIN is the main routine for FEM2D_POISSON_RECTANGLE_LINEAR. // // Discussion: // // This program solves // // - d2U(X,Y)/dx2 - d2U(X,Y)/dy2 = F(X,Y) // // in a rectangular region in the plane. // // Along the boundary of the region, Dirichlet conditions // are imposed: // // U(X,Y) = G(X,Y) // // The code uses continuous piecewise linear basis functions on // triangles determined by a uniform grid of NX by NY points. // // u = sin ( pi * x ) * sin ( pi * y ) + x // // dudx = pi * cos ( pi * x ) * sin ( pi * y ) + 1 // dudy = pi * sin ( pi * x ) * cos ( pi * y ) // // d2udx2 = - pi * pi * sin ( pi * x ) * sin ( pi * y ) // d2udy2 = - pi * pi * sin ( pi * x ) * sin ( pi * y ) // // rhs = 2 * pi * pi * sin ( pi * x ) * sin ( pi * y ) // // THINGS YOU CAN EASILY CHANGE: // // 1) Change NX or NY, the number of nodes in the X and Y directions. // 2) Change XL, XR, YB, YT, the left, right, bottom and top limits of the rectangle. // 3) Change the exact solution in the EXACT routine, but make sure you also // modify the formula for RHS in the assembly portion of the program// // // HARDER TO CHANGE: // // 4) Change from "linear" to "quadratic" triangles; // 5) Change the region from a rectangle to a general triangulated region; // 6) Store the matrix as a sparse matrix so you can solve bigger systems. // 7) Handle Neumann boundary conditions. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 28 November 2008 // // Author: // // John Burkardt // { const int nx = 17; const int ny = 17; int e; int i; int j; double u; const double xl = 0.0; const double xr = 1.0; const double yb = 0.0; const double yt = 1.0; Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE_LINEAR"); Console.WriteLine(""); Console.WriteLine(" Solution of the Poisson equation:"); Console.WriteLine(""); Console.WriteLine(" - Uxx - Uyy = F(x,y) inside the region,"); Console.WriteLine(" U(x,y) = G(x,y) on the boundary of the region."); Console.WriteLine(""); Console.WriteLine(" The region is a rectangle, defined by:"); Console.WriteLine(""); Console.WriteLine(" " + xl + " = XL<= X <= XR = " + xr + ""); Console.WriteLine(" " + yb + " = YB<= Y <= YT = " + yt + ""); Console.WriteLine(""); Console.WriteLine(" The finite element method is used, with piecewise"); Console.WriteLine(" linear basis functions on 3 node triangular"); Console.WriteLine(" elements."); Console.WriteLine(""); Console.WriteLine(" The corner nodes of the triangles are generated by an"); Console.WriteLine(" underlying grid whose dimensions are"); Console.WriteLine(""); Console.WriteLine(" NX = " + nx + ""); Console.WriteLine(" NY = " + ny + ""); // // NODE COORDINATES // // Numbering of nodes is suggested by the following 5x10 example: // // J=5 | K=41 K=42 ... K=50 // ... | // J=2 | K=11 K=12 ... K=20 // J=1 | K= 1 K= 2 K=10 // +-------------------- // I= 1 I= 2 ... I=10 // const int node_num = nx * ny; Console.WriteLine(" Number of nodes = " + node_num + ""); double[] x = new double[node_num]; double[] y = new double[node_num]; int k = 0; for (j = 1; j <= ny; j++) { for (i = 1; i <= nx; i++) { x[k] = ((nx - i) * xl + (i - 1) * xr) / (nx - 1); y[k] = ((ny - j) * yb + (j - 1) * yt) / (ny - 1); k += 1; } } // // ELEMENT array // // Organize the nodes into a grid of 3-node triangles. // Here is part of the diagram for a 5x10 example: // // | \ | \ | \ | // | \| \| \| // 21---22---23---24-- // |\ 8 |\10 |\12 | // | \ | \ | \ | // | \ | \ | \ | \ | // | 7\| 9\| 11\| \| // 11---12---13---14---15---16---17---18---19---20 // |\ 2 |\ 4 |\ 6 |\ 8| |\ 18| // | \ | \ | \ | \ | | \ | // | \ | \ | \ | \ | ... | \ | // | 1\| 3\| 5\| 7 \| |17 \| // 1----2----3----4----5----6----7----8----9---10 // const int element_num = 2 * (nx - 1) * (ny - 1); Console.WriteLine(" Number of elements = " + element_num + ""); int[] element_node = new int[3 * element_num]; k = 0; for (j = 1; j <= ny - 1; j++) { for (i = 1; i <= nx - 1; i++) { element_node[0 + k * 3] = i + (j - 1) * nx - 1; element_node[1 + k * 3] = i + 1 + (j - 1) * nx - 1; element_node[2 + k * 3] = i + j * nx - 1; k += 1; element_node[0 + k * 3] = i + 1 + j * nx - 1; element_node[1 + k * 3] = i + j * nx - 1; element_node[2 + k * 3] = i + 1 + (j - 1) * nx - 1; k += 1; } } // // Assemble the coefficient matrix A and the right-hand side B of the // finite element equations, ignoring boundary conditions. // double[] a = new double[node_num * node_num]; double[] b = new double[node_num]; for (i = 0; i < node_num; i++) { b[i] = 0.0; } for (j = 0; j < node_num; j++) { for (i = 0; i < node_num; i++) { a[i + j * node_num] = 0.0; } } for (e = 0; e < element_num; e++) { int i1 = element_node[0 + e * 3]; int i2 = element_node[1 + e * 3]; int i3 = element_node[2 + e * 3]; double area = 0.5 * (x[i1] * (y[i2] - y[i3]) + x[i2] * (y[i3] - y[i1]) + x[i3] * (y[i1] - y[i2])); // // Consider each quadrature point. // Here, we use the midside nodes as quadrature points. // int q1; for (q1 = 0; q1 < 3; q1++) { int q2 = (q1 + 1) % 3; int nq1 = element_node[q1 + e * 3]; int nq2 = element_node[q2 + e * 3]; double xq = 0.5 * (x[nq1] + x[nq2]); double yq = 0.5 * (y[nq1] + y[nq2]); const double wq = 1.0 / 3.0; // // Consider each test function in the element. // int ti1; for (ti1 = 0; ti1 < 3; ti1++) { int ti2 = (ti1 + 1) % 3; int ti3 = (ti1 + 2) % 3; int nti1 = element_node[ti1 + e * 3]; int nti2 = element_node[ti2 + e * 3]; int nti3 = element_node[ti3 + e * 3]; double qi = 0.5 * ( (x[nti3] - x[nti2]) * (yq - y[nti2]) - (y[nti3] - y[nti2]) * (xq - x[nti2])) / area; double dqidx = -0.5 * (y[nti3] - y[nti2]) / area; double dqidy = 0.5 * (x[nti3] - x[nti2]) / area; double rhs = 2.0 * Math.PI * Math.PI * Math.Sin(Math.PI * xq) * Math.Sin(Math.PI * yq); b[nti1] += area * wq * rhs * qi; // // Consider each basis function in the element. // int tj1; for (tj1 = 0; tj1 < 3; tj1++) { int tj2 = (tj1 + 1) % 3; int tj3 = (tj1 + 2) % 3; int ntj1 = element_node[tj1 + e * 3]; int ntj2 = element_node[tj2 + e * 3]; int ntj3 = element_node[tj3 + e * 3]; // qj = 0.5 * ( // ( x[ntj3] - x[ntj2] ) * ( yq - y[ntj2] ) // - ( y[ntj3] - y[ntj2] ) * ( xq - x[ntj2] ) ) / area; double dqjdx = -0.5 * (y[ntj3] - y[ntj2]) / area; double dqjdy = 0.5 * (x[ntj3] - x[ntj2]) / area; a[nti1 + ntj1 * node_num] += area * wq * (dqidx * dqjdx + dqidy * dqjdy); } } } } // // BOUNDARY CONDITIONS // // If the K-th variable is at a boundary node, replace the K-th finite // element equation by a boundary condition that sets the variable to U(K). // k = 0; for (j = 1; j <= ny; j++) { for (i = 1; i <= nx; i++) { if (i == 1 || i == nx || j == 1 || j == ny) { ExactResult res = exact(x[k], y[k]); u = res.u; int j2; for (j2 = 0; j2 < node_num; j2++) { a[k + j2 * node_num] = 0.0; } a[k + k * node_num] = 1.0; b[k] = u; } k += 1; } } // SOLVE the linear system A * C = B. // // The solution is returned in C. // double[] c = Solve.r8ge_fs_new(node_num, a, b); // // COMPARE computed and exact solutions. // Console.WriteLine(""); Console.WriteLine( " K I J X Y U U Error"); Console.WriteLine(" exact computed"); Console.WriteLine(""); k = 0; for (j = 1; j <= ny; j++) { for (i = 1; i <= nx; i++) { ExactResult res = exact(x[k], y[k]); u = res.u; Console.WriteLine(" " + k.ToString(CultureInfo.InvariantCulture).PadLeft(4) + " " + i.ToString(CultureInfo.InvariantCulture).PadLeft(4) + " " + j.ToString(CultureInfo.InvariantCulture).PadLeft(4) + " " + x[k].ToString(CultureInfo.InvariantCulture).PadLeft(10) + " " + y[k].ToString(CultureInfo.InvariantCulture).PadLeft(10) + " " + u.ToString(CultureInfo.InvariantCulture).PadLeft(14) + " " + c[k].ToString(CultureInfo.InvariantCulture).PadLeft(14) + " " + Math.Abs(u - c[k]).ToString(CultureInfo.InvariantCulture).PadLeft(14) + ""); k += 1; } Console.WriteLine(""); } Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE_LINEAR:"); Console.WriteLine(" Normal end of execution."); }