private static void Main() /****************************************************************************80 * // * // Purpose: * // * // MAIN is the main program for FEM2D_POISSON_RECTANGLE. * // * // Discussion: * // * // FEM2D_POISSON_RECTANGLE solves * // * // -Laplacian U(X,Y) = F(X,Y) * // * // in a rectangular region in the plane. Along the boundary, * // Dirichlet boundary conditions are imposed. * // * // U(X,Y) = G(X,Y) * // * // The code uses continuous piecewise quadratic basis functions on * // triangles determined by a uniform grid of NX by NY points. * // * // Licensing: * // * // This code is distributed under the GNU LGPL license. * // * // Modified: * // * // 23 September 2008 * // * // Author: * // * // John Burkardt * // * // Local parameters: * // * // Local, double A[(3*IB+1)*NUNK], the coefficient matrix. * // * // Local, double ELEMENT_AREA[ELEMENT_NUM], the area of each element. * // * // Local, double C[NUNK], the finite element coefficients, solution of A * C = F. * // * // Local, double EH1, the H1 seminorm error. * // * // Local, double EL2, the L2 error. * // * // Local, int ELEMENT_NODE[ELEMENT_NUM*NNODES]; ELEMENT_NODE(I,J) is the * // global node index of the local node J in element I. * // * // Local, int ELEMENT_NUM, the number of elements. * // * // Local, double F[NUNK], the right hand side. * // * // Local, int IB, the half-bandwidth of the matrix. * // * // Local, int INDX[NODE_NUM], gives the index of the unknown quantity * // associated with the given node. * // * // Local, int NNODES, the number of nodes used to form one element. * // * // Local, double NODE_XY[2*NODE_NUM], the X and Y coordinates of nodes. * // * // Local, int NQ, the number of quadrature points used for assembly. * // * // Local, int NUNK, the number of unknowns. * // * // Local, int NX, the number of points in the X direction. * // * // Local, int NY, the number of points in the Y direction. * // * // Local, double WQ[NQ], quadrature weights. * // * // Local, double XL, XR, YB, YT, the X coordinates of * // the left and right sides of the rectangle, and the Y coordinates * // of the bottom and top of the rectangle. * // * // Local, double XQ[NQ*ELEMENT_NUM], YQ[NQ*ELEMENT_NUM], the X and Y * // coordinates of the quadrature points in each element. */ { const int NNODES = 6; const int NQ = 3; const int NX = 7; const int NY = 7; const int ELEMENT_NUM = (NX - 1) * (NY - 1) * 2; const int NODE_NUM = (2 * NX - 1) * (2 * NY - 1); double eh1 = 0; double el2 = 0; double[] element_area = new double[ELEMENT_NUM]; int[] element_node = new int[NNODES * ELEMENT_NUM]; int[] indx = new int[NODE_NUM]; const string node_eps_file_name = "fem2d_poisson_rectangle_nodes.eps"; const string node_txt_file_name = "fem2d_poisson_rectangle_nodes.txt"; double[] node_xy = new double[2 * NODE_NUM]; int nunk = 0; const string solution_txt_file_name = "fem2d_poisson_rectangle_solution.txt"; const string triangulation_eps_file_name = "fem2d_poisson_rectangle_elements.eps"; const string triangulation_txt_file_name = "fem2d_poisson_rectangle_elements.txt"; double[] wq = new double[NQ]; const double xl = 0.0E+00; double[] xq = new double[NQ * ELEMENT_NUM]; const double xr = 1.0E+00; const double yb = 0.0E+00; double[] yq = new double[NQ * ELEMENT_NUM]; const double yt = 1.0E+00; Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(""); Console.WriteLine(" Solution of the Poisson equation on a unit box"); Console.WriteLine(" in 2 dimensions."); Console.WriteLine(""); Console.WriteLine(" - Uxx - Uyy = F(x,y) in the box"); Console.WriteLine(" U(x,y) = G(x,y) on the boundary."); Console.WriteLine(""); Console.WriteLine(" The finite element method is used, with piecewise"); Console.WriteLine(" quadratic basis functions on 6 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 + ""); Console.WriteLine(""); Console.WriteLine(" Number of nodes = " + NODE_NUM + ""); Console.WriteLine(" Number of elements = " + ELEMENT_NUM + ""); // // Set the coordinates of the nodes. // XY.xy_set(NX, NY, NODE_NUM, xl, xr, yb, yt, ref node_xy); // // Organize the nodes into a grid of 6-node triangles. // Grid.grid_t6(NX, NY, NNODES, ELEMENT_NUM, ref element_node); // // Set the quadrature rule for assembly. // QuadratureRule.quad_a(node_xy, element_node, ELEMENT_NUM, NODE_NUM, NNODES, ref wq, ref xq, ref yq); // // Determine the areas of the elements. // Element.area_set(NODE_NUM, node_xy, NNODES, ELEMENT_NUM, element_node, element_area); // // Determine which nodes are boundary nodes and which have a // finite element unknown. Then set the boundary values. // Burkardt.FEM.Boundary.indx_set(NX, NY, NODE_NUM, ref indx, ref nunk); Console.WriteLine(" Number of unknowns = " + nunk + ""); // // Determine the bandwidth of the coefficient matrix. // int ib = Matrix.bandwidth(NNODES, ELEMENT_NUM, element_node, NODE_NUM, indx); Console.WriteLine(""); Console.WriteLine(" Total bandwidth is " + 3 * ib + 1 + ""); switch (NX) { // // Make an EPS picture of the nodes. // case <= 10 when NY <= 10: bool node_label = true; typeMethods.nodes_plot(node_eps_file_name, NODE_NUM, node_xy, node_label); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Wrote an EPS file"); Console.WriteLine(" \"" + node_eps_file_name + "\"."); Console.WriteLine(" containing a picture of the nodes."); break; } // // Write the nodes to an ASCII file that can be read into MATLAB. // typeMethods.nodes_write(NODE_NUM, node_xy, node_txt_file_name); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Wrote an ASCII node file"); Console.WriteLine(" " + node_txt_file_name + ""); Console.WriteLine(" of the form"); Console.WriteLine(" X(I), Y(I)"); Console.WriteLine(" which can be used for plotting."); switch (NX) { // // Make a picture of the elements. // case <= 10 when NY <= 10: int node_show = 1; int triangle_show = 2; Plot.triangulation_order6_plot(triangulation_eps_file_name, NODE_NUM, node_xy, ELEMENT_NUM, element_node, node_show, triangle_show); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Wrote an EPS file"); Console.WriteLine(" \"" + triangulation_eps_file_name + "\"."); Console.WriteLine(" containing a picture of the elements."); break; } // // Write the elements to a file that can be read into MATLAB. // Element.element_write(NNODES, ELEMENT_NUM, element_node, triangulation_txt_file_name); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Wrote an ASCII element file"); Console.WriteLine(" \"" + triangulation_txt_file_name + "\"."); Console.WriteLine(" of the form"); Console.WriteLine(" Node(1) Node(2) Node(3) Node(4) Node(5) Node(6)"); Console.WriteLine(" which can be used for plotting."); // // Allocate space for the coefficient matrix A and right hand side F. // double[] a = new double[(3 * ib + 1) * nunk]; double[] f = new double[nunk]; int[] pivot = new int[nunk]; // // Assemble the coefficient matrix A and the right-hand side F of the // finite element equations. // Matrix.assemble(NODE_NUM, node_xy, NNODES, ELEMENT_NUM, element_node, NQ, wq, xq, yq, element_area, indx, ib, nunk, ref a, ref f); // // Print a tiny portion of the matrix. // Matrix.dgb_print_some(nunk, nunk, ib, ib, a, 1, 1, 5, 5, " Initial 5 x 5 block of coefficient matrix A:"); typeMethods.r8vec_print_some(nunk, f, 10, " Part of the right hand side F:"); // // Modify the coefficient matrix and right hand side to account for // boundary conditions. // Burkardt.FEM.Boundary.boundary(NX, NY, NODE_NUM, node_xy, indx, ib, nunk, ref a, ref f, exact); // // Print a tiny portion of the matrix. // Matrix.dgb_print_some(nunk, nunk, ib, ib, a, 1, 1, 5, 5, " A after boundary adjustment:"); typeMethods.r8vec_print_some(nunk, f, 10, " F after boundary adjustment:"); // // Solve the linear system using a banded solver. // int ierr = Matrix.dgb_fa(nunk, ib, ib, ref a, ref pivot); if (ierr != 0) { Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE - Error!"); Console.WriteLine(" DGB_FA returned an error condition."); Console.WriteLine(""); Console.WriteLine(" The linear system was not factored, and the"); Console.WriteLine(" algorithm cannot proceed."); return; } int job = 0; double[] c = Matrix.dgb_sl(nunk, ib, ib, a, pivot, f, job); typeMethods.r8vec_print_some(nunk, c, 10, " Part of the solution vector:"); // // Calculate error using 13 point quadrature rule. // QuadratureRule.errors(element_area, element_node, indx, node_xy, c, ELEMENT_NUM, NNODES, nunk, NODE_NUM, ref el2, ref eh1, exact); // // Compare the exact and computed solutions just at the nodes. // typeMethods.compare(NODE_NUM, node_xy, indx, nunk, c, exact); // // Write an ASCII file that can be read into MATLAB. // typeMethods.solution_write(c, indx, NODE_NUM, nunk, solution_txt_file_name, node_xy, exact); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Wrote an ASCII solution file"); Console.WriteLine(" " + solution_txt_file_name + ""); Console.WriteLine(" of the form"); Console.WriteLine(" U( X(I), Y(I) )"); Console.WriteLine(" which can be used for plotting."); Console.WriteLine(""); Console.WriteLine("FEM2D_POISSON_RECTANGLE:"); Console.WriteLine(" Normal end of execution."); Console.WriteLine(""); }