示例#1
0
    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) + "");
        }
    }
示例#2
0
    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;
            }
        }
    }
示例#3
0
    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.");
        }
    }
示例#4
0
    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.");
    }