Example #1
0
    private static void test04()

    //******************************************************************************
    //
    //  Purpose:
    //
    //    TEST04 tests PMGMRES_ILU_CR on a simple 5 by 5 matrix.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    25 July 2007
    //
    //  Author:
    //
    //    John Burkardt
    //
    {
        const int N      = 5;
        const int NZ_NUM = 9;

        double[] a =
        {
            1.0, 2.0, 1.0,
            2.0,
            3.0, 3.0,
            4.0,
            1.0, 5.0
        };
        int i;

        int[] ia      = { 0, 3, 4, 6, 7, 9 };
        int   itr_max = 0;

        int[] ja =
        {
            0, 3, 4,
            1,
            0, 2,
            3,
            1, 4
        };
        int mr = 0;

        double[] rhs = { 14.0, 4.0, 12.0, 16.0, 27.0 };
        int      test;

        double[] x_estimate = new double[N];
        double[] x_exact    = { 1.0, 2.0, 3.0, 4.0, 5.0 };

        Console.WriteLine("");
        Console.WriteLine("TEST04");
        Console.WriteLine("  Test PMGMRES_ILU_CR on a simple 5 x 5 matrix.");

        Console.WriteLine("");
        for (i = 0; i < N + 1; i++)
        {
            Console.WriteLine("  ia[" + i + "] = " + ia[i] + "");
        }

        for (test = 1; test <= 3; test++)
        {
            //
            //  Set the initial solution estimate.
            //
            for (i = 0; i < N; i++)
            {
                x_estimate[i] = 0.0;
            }

            double x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            switch (test)
            {
            case 1:
                itr_max = 1;
                mr      = 20;
                break;

            case 2:
                itr_max = 2;
                mr      = 10;
                break;

            case 3:
                itr_max = 5;
                mr      = 4;
                break;
            }

            const double tol_abs = 1.0E-08;
            const double tol_rel = 1.0E-08;

            Console.WriteLine("");
            Console.WriteLine("  Test " + test + "");
            Console.WriteLine("  Matrix order N = " + N + "");
            Console.WriteLine("  Inner iteration limit = " + mr + "");
            Console.WriteLine("  Outer iteration limit = " + itr_max + "");
            Console.WriteLine("  Initial X_ERROR = " + x_error + "");

            RestartedGeneralizedMinimumResidual.pmgmres_ilu_cr(N, NZ_NUM, ia, ja, a, ref x_estimate, rhs, itr_max,
                                                               mr,
                                                               tol_abs, tol_rel);

            x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            Console.WriteLine("  Final X_ERROR = " + x_error + "");
        }
    }
Example #2
0
    private static void test02()

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    TEST02 tests MGMRES_ST on a 9 by 9 matrix.
    //
    //  Discussion:
    //
    //    A =
    //      2  0  0 -1  0  0  0  0  0
    //      0  2 -1  0  0  0  0  0  0
    //      0 -1  2  0  0  0  0  0  0
    //     -1  0  0  2 -1  0  0  0  0
    //      0  0  0 -1  2 -1  0  0  0
    //      0  0  0  0 -1  2 -1  0  0
    //      0  0  0  0  0 -1  2 -1  0
    //      0  0  0  0  0  0 -1  2 -1
    //      0  0  0  0  0  0  0 -1  2
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    18 October 2006
    //
    //  Author:
    //
    //    John Burkardt
    //
    {
        const int N      = 9;
        const int NZ_NUM = 23;

        double[] a =
        {
            2.0,  -1.0,
            2.0,  -1.0,
            -1.0,  2.0,
            -1.0,  2.0, -1.0,
            -1.0,  2.0, -1.0,
            -1.0,  2.0, -1.0,
            -1.0,  2.0, -1.0,
            -1.0,  2.0, -1.0,
            -1.0, 2.0
        };
        int[] ia =
        {
            0, 0,
            1, 1,
            2, 2,
            3, 3, 3,
            4, 4, 4,
            5, 5, 5,
            6, 6, 6,
            7, 7, 7,
            8, 8
        };
        int[] ja =
        {
            0, 3,
            1, 2,
            1, 2,
            0, 3, 4,
            3, 4, 5,
            4, 5, 6,
            5, 6, 7,
            6, 7, 8,
            7, 8
        };
        double[] rhs =
        {
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0,
            1.0
        };
        int seed = 123456789;
        int test;

        double[] x_estimate = new double[1];
        double[] x_exact    =
        {
            3.5,
            1.0,
            1.0,
            6.0,
            7.5,
            8.0,
            7.5,
            6.0,
            3.5
        };

        Console.WriteLine("");
        Console.WriteLine("TEST02");
        Console.WriteLine("  Test MGMRES_ST on matrix that is not quite the -1,2,-1 matrix,");
        Console.WriteLine("  of order N = " + N + "");

        for (test = 1; test <= 2; test++)
        {
            int i;
            switch (test)
            {
            case 1:
            {
                Console.WriteLine("");
                Console.WriteLine("  First try, use zero initial vector:");
                Console.WriteLine("");

                x_estimate = new double[N];
                for (i = 0; i < N; i++)
                {
                    x_estimate[i] = 0.0;
                }

                break;
            }

            default:
                Console.WriteLine("");
                Console.WriteLine("  Second try, use random initial vector:");
                Console.WriteLine("");

                UniformRNG.r8vec_uniform_01(N, ref seed, ref x_estimate);
                break;
            }

            //
            //  Set the initial solution estimate.
            //
            double x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            Console.WriteLine("  Before solving, X_ERROR = " + x_error + "");

            const int    itr_max = 20;
            const int    mr      = N - 1;
            const double tol_abs = 1.0E-08;
            const double tol_rel = 1.0E-08;

            RestartedGeneralizedMinimumResidual.mgmres_st(N, NZ_NUM, ia, ja, a, ref x_estimate, rhs, itr_max, mr,
                                                          tol_abs, tol_rel);

            x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            Console.WriteLine("  After solving, X_ERROR = " + x_error + "");

            Console.WriteLine("");
            Console.WriteLine("  Final solution estimate:");
            Console.WriteLine("");
            for (i = 0; i < N; i++)
            {
                Console.WriteLine("  " + i.ToString().PadLeft(8)
                                  + "  " + x_estimate[i].ToString(CultureInfo.InvariantCulture).PadLeft(12) + "");
            }
        }
    }
Example #3
0
    private static void test01()

    //****************************************************************************80
    //
    //  Purpose:
    //
    //    TEST01 tests MGMRES_ST on the simple -1,2-1 matrix.
    //
    //  Discussion:
    //
    //    This is a very weak test, since the matrix has such a simple
    //    structure, is diagonally dominant (though not strictly),
    //    and is symmetric.
    //
    //    To make the matrix bigger, simply increase the value of N.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    13 July 2007
    //
    //  Author:
    //
    //    John Burkardt
    //
    {
        const int N      = 20;
        const int NZ_NUM = 3 * N - 2;

        double[] a = new double[NZ_NUM];
        int      i;

        int[] ia      = new int[NZ_NUM];
        int   itr_max = 0;

        int[] ja = new int[NZ_NUM];
        int   mr = 0;

        double[] rhs = new double[N];
        int      test;

        double[] x_estimate = new double[N];
        double[] x_exact    = new double[N];

        Console.WriteLine("");
        Console.WriteLine("TEST01");
        Console.WriteLine("  Test MGMRES_ST on the simple -1,2-1 matrix.");
        //
        //  Set the matrix.
        //  Note that we use zero based index values in IA and JA.
        //
        int k = 0;

        for (i = 0; i < N; i++)
        {
            switch (i)
            {
            case > 0:
                ia[k] = i;
                ja[k] = i - 1;
                a[k]  = -1.0;
                k    += 1;
                break;
            }

            ia[k] = i;
            ja[k] = i;
            a[k]  = 2.0;
            k    += 1;

            if (i >= N - 1)
            {
                continue;
            }

            ia[k] = i;
            ja[k] = i + 1;
            a[k]  = -1.0;
            k    += 1;
        }

        //
        //  Set the right hand side:
        //
        for (i = 0; i < N - 1; i++)
        {
            rhs[i] = 0.0;
        }

        rhs[N - 1] = N + 1;
        //
        //  Set the exact solution.
        //
        for (i = 0; i < N; i++)
        {
            x_exact[i] = i + 1;
        }

        for (test = 1; test <= 3; test++)
        {
            //
            //  Set the initial solution estimate.
            //
            for (i = 0; i < N; i++)
            {
                x_estimate[i] = 0.0;
            }

            double x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            switch (test)
            {
            case 1:
                itr_max = 1;
                mr      = 20;
                break;

            case 2:
                itr_max = 2;
                mr      = 10;
                break;

            case 3:
                itr_max = 5;
                mr      = 4;
                break;
            }

            const double tol_abs = 1.0E-08;
            const double tol_rel = 1.0E-08;

            Console.WriteLine("");
            Console.WriteLine("  Test " + test + "");
            Console.WriteLine("  Matrix order N = " + N + "");
            Console.WriteLine("  Inner iteration limit = " + mr + "");
            Console.WriteLine("  Outer iteration limit = " + itr_max + "");
            Console.WriteLine("  Initial X_ERROR = " + x_error + "");

            RestartedGeneralizedMinimumResidual.mgmres_st(N, NZ_NUM, ia, ja, a, ref x_estimate, rhs, itr_max, mr,
                                                          tol_abs, tol_rel);

            x_error = 0.0;
            for (i = 0; i < N; i++)
            {
                x_error += Math.Pow(x_exact[i] - x_estimate[i], 2);
            }

            x_error = Math.Sqrt(x_error);

            Console.WriteLine("  Final X_ERROR = " + x_error + "");
        }
    }
Example #4
0
    private static void Main(string[] args)
    //****************************************************************************80
    //
    //  Purpose:
    //
    //    MAIN is the main program for FEM2D_POISSON_SPARSE.
    //
    //  Discussion:
    //
    //    This program uses a sparse matrix storage format and an iterative solver,
    //    which allow it to solve larger problems faster.
    //
    //    This program solves the Poisson equation
    //
    //      -DEL H(X,Y) DEL U(X,Y) + K(X,Y) * U(X,Y) = F(X,Y)
    //
    //    in a triangulated 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.
    //
    //  Problem specification:
    //
    //    The user defines the geometry by supplying two data files
    //    which list the node coordinates, and list the nodes that make up
    //    each element.
    //
    //    The user specifies the right hand side of the Dirichlet boundary
    //    conditions by supplying a function
    //
    //      void dirichlet_condition ( int node_num, double node_xy[2*node_num],
    //        double node_bc[node_num] )
    //
    //    The user specifies the coefficient function H(X,Y) of the Poisson
    //    equation by supplying a routine of the form
    //
    //      void h_coef ( int node_num, double node_xy[2*node_num],
    //        double node_h[node_num] )
    //
    //    The user specifies the coefficient function K(X,Y) of the Poisson
    //    equation by supplying a routine of the form
    //
    //      void k_coef ( int node_num, double node_xy[2*node_num],
    //        double node_k[node_num] )
    //
    //    The user specifies the right hand side of the Poisson equation
    //    by supplying a routine of the form
    //
    //      void rhs ( int node_num, double node_xy[2*node_num],
    //        double node_f[node_num] )
    //
    //  Usage:
    //
    //    fem2d_poisson_sparse prefix
    //
    //    where 'prefix' is the common filename prefix so that:
    //
    //    * prefix_nodes.txt contains the coordinates of the nodes;
    //    * prefix_elements.txt contains the indices of nodes forming each element.
    //
    //    Files created include:
    //
    //    * prefix_values.txt, the value of the solution at every node.
    //
    //  Licensing:
    //
    //    This code is distributed under the GNU LGPL license.
    //
    //  Modified:
    //
    //    25 January 2013
    //
    //  Author:
    //
    //    John Burkardt
    //
    //  Local parameters:
    //
    //    Local, double A[NZ_NUM], the coefficient matrix.
    //
    //    Local, int ELEMENT_NODE[3*ELEMENT_NUM];
    //    ELEMENT_NODE(I,J) is the global index of local node I in element J.
    //
    //    Local, int ELEMENT_NUM, the number of elements.
    //
    //    Local, integer ELEMENT_ORDER, the element order.
    //
    //    Local, double F[NODE_NUM], the right hand side.
    //
    //    Local, int IA[NZ_NUM], the row indices of the nonzero entries
    //    of the coefficient matrix.
    //
    //    Local, int JA[NZ_NUM], the column indices of the nonzero entries
    //    of the coefficient matrix.
    //
    //    Local, bool NODE_BOUNDARY[NODE_NUM], is TRUE if the node is
    //    found to lie on the boundary of the region.
    //
    //    Local, int NODE_CONDITION[NODE_NUM],
    //    indicates the condition used to determine the variable at a node.
    //    0, there is no condition (and no variable) at this node.
    //    1, a finite element equation is used;
    //    2, a Dirichlet condition is used.
    //    3, a Neumann condition is used.
    //
    //    Local, int NODE_NUM, the number of nodes.
    //
    //    Local, double NODE_U[NODE_NUM], the finite element coefficients.
    //
    //    Local, double NODE_XY[2*NODE_NUM], the coordinates of nodes.
    //
    //    Local, int NZ_NUM, the number of nonzero entries
    //    in the coefficient matrix.
    //
    //    Local, integer QUAD_NUM, the number of quadrature points used for
    //    assembly.  This is currently set to 3, the lowest reasonable value.
    //    Legal values are 1, 3, 4, 6, 7, 9, 13, and for some problems, a value
    //    of QUAD_NUM greater than 3 may be appropriate.
    //
    {
        const bool debug = false;
        int        node;

        double[]  node_u = null;
        string    prefix;
        const int quad_num = 3;
        int       seed     = 123456789;

        Console.WriteLine("");
        Console.WriteLine("FEM2D_POISSON_SPARSE:");
        Console.WriteLine("");
        Console.WriteLine("  A finite element method solver for the Poisson problem");
        Console.WriteLine("  in an arbitrary triangulated region in 2 dimensions,");
        Console.WriteLine("  using sparse storage and an iterative solver.");
        Console.WriteLine("");
        Console.WriteLine("  - DEL H(x,y) DEL U(x,y) + K(x,y) * U(x,y) = F(x,y) in the region");
        Console.WriteLine("");
        Console.WriteLine("                                     U(x,y) = G(x,y) on the boundary.");
        Console.WriteLine("");
        Console.WriteLine("  The finite element method is used,");
        Console.WriteLine("  with triangular elements,");
        Console.WriteLine("  which must be a 3 node linear triangle.");
        //
        //  Get the filename prefix.
        //
        try
        {
            prefix = args[0];
        }
        catch
        {
            Console.WriteLine("");
            Console.WriteLine("  Please enter the filename prefix:");

            prefix = Console.ReadLine();
        }

        if (prefix != "baffle" && prefix != "ell" && prefix != "lake")
        {
            Console.WriteLine("Supported prefix value in this test is one of : baffle, ell, lake");
            return;
        }

        //
        //  Create the file names.
        //
        string node_filename     = prefix + "_nodes.txt";
        string element_filename  = prefix + "_elements.txt";
        string solution_filename = prefix + "_values.txt";

        Console.WriteLine("");
        Console.WriteLine("  Node file is \"" + node_filename + "\".");
        Console.WriteLine("  Element file is \"" + element_filename + "\".");
        //
        //  Read the node coordinate file.
        //
        TableHeader h        = typeMethods.r8mat_header_read(node_filename);
        int         dim_num  = h.m;
        int         node_num = h.n;

        Console.WriteLine("  Number of nodes =          " + node_num + "");

        int[] node_condition = new int[node_num];

        double[] node_xy = typeMethods.r8mat_data_read(node_filename, dim_num, node_num);

        typeMethods.r8mat_transpose_print_some(dim_num, node_num, node_xy, 1, 1, 2, 10,
                                               "  First 10 nodes");
        //
        //  Read the triangle description file.
        //
        h = typeMethods.i4mat_header_read(element_filename);
        int element_order = h.m;
        int element_num   = h.n;

        Console.WriteLine("");
        Console.WriteLine("  Element order =            " + element_order + "");
        Console.WriteLine("  Number of elements =       " + element_num + "");

        if (element_order != 3)
        {
            Console.WriteLine("");
            Console.WriteLine("FEM2D_POISSON_SPARSE - Fatal error!");
            Console.WriteLine("  The input triangulation has order " + element_order + "");
            Console.WriteLine("  However, a triangulation of order 3 is required.");
            return;
        }

        int[] element_node = typeMethods.i4mat_data_read(element_filename, element_order,
                                                         element_num);

        typeMethods.i4mat_transpose_print_some(3, element_num,
                                               element_node, 1, 1, 3, 10, "  First 10 elements");

        Console.WriteLine("");
        Console.WriteLine("  Quadrature order =          " + quad_num + "");
        //
        //  Determine which nodes are boundary nodes and which have a
        //  finite element unknown.  Then set the boundary values.
        //
        bool[] node_boundary = Boundary.triangulation_order3_boundary_node(node_num, element_num,
                                                                           element_node);
        //
        //  Determine the node conditions.
        //  For now, we'll just assume all boundary nodes are Dirichlet.
        //
        for (node = 0; node < node_num; node++)
        {
            node_condition[node] = node_boundary[node] switch
            {
                true => 2,
                _ => 1
            };
        }

        //
        //  Determine the element neighbor array, just so we can estimate
        //  the nonzeros.
        //
        int[] element_neighbor = new int[3 * element_num];

        element_neighbor = Neighbor.triangulation_order3_neighbor_triangles(element_num, element_node);
        //
        //  Count the number of nonzeros.
        //
        int[] adj_col = new int[node_num + 1];

        int nz_num = Adjacency.triangulation_order3_adj_count(node_num, element_num,
                                                              element_node, element_neighbor, adj_col);

        Console.WriteLine("");
        Console.WriteLine("  Number of nonzero coefficients NZ_NUM = " + nz_num + "");
        //
        //  Set up the sparse row and column index vectors.
        //
        int[] ia = new int[nz_num];
        int[] ja = new int[nz_num];

        Adjacency.triangulation_order3_adj_set2(node_num, element_num, element_node,
                                                element_neighbor, nz_num, adj_col, ia, ja);

        //
        //  Allocate space for the coefficient matrix A and right hand side F.
        //
        double[] a = new double[nz_num];
        double[] f = new double[node_num];
        //
        //  Assemble the finite element coefficient matrix A and the right-hand side F.
        //
        switch (prefix)
        {
        case "baffle":
            DSP.assemble_poisson_dsp(node_num, node_xy, element_num,
                                     element_node, quad_num, nz_num, ia, ja, ref a, ref f, baffle.rhs, baffle.h_coef, baffle.k_coef);
            break;

        case "ell":
            DSP.assemble_poisson_dsp(node_num, node_xy, element_num,
                                     element_node, quad_num, nz_num, ia, ja, ref a, ref f, ell.rhs, ell.h_coef, ell.k_coef);
            break;

        case "lake":
            DSP.assemble_poisson_dsp(node_num, node_xy, element_num,
                                     element_node, quad_num, nz_num, ia, ja, ref a, ref f, lake.rhs, lake.h_coef, lake.k_coef);
            break;
        }

        switch (debug)
        {
        //
        //  Print a portion of the matrix.
        //
        case true:
            DSP.dsp_print_some(node_num, node_num, nz_num, ia, ja, a, 1, 1, 10, 10,
                               "  Part of Finite Element matrix A:");

            typeMethods.r8vec_print_some(node_num, f, 1, 10,
                                         "  Part of right hand side vector F:");
            break;
        }

        //
        //  Adjust the linear system to account for Dirichlet boundary conditions.
        //
        switch (prefix)
        {
        case "baffle":
            DSP.dirichlet_apply_dsp(node_num, node_xy, node_condition, nz_num, ia, ja,
                                    ref a, ref f, baffle.dirichlet_condition);
            break;

        case "ell":
            DSP.dirichlet_apply_dsp(node_num, node_xy, node_condition, nz_num, ia, ja,
                                    ref a, ref f, ell.dirichlet_condition);
            break;

        case "lake":
            DSP.dirichlet_apply_dsp(node_num, node_xy, node_condition, nz_num, ia, ja,
                                    ref a, ref f, lake.dirichlet_condition);
            break;
        }

        switch (debug)
        {
        case true:
            DSP.dsp_print_some(node_num, node_num, nz_num, ia, ja, a, 1, 1, 10, 10,
                               "  Part of finite Element matrix A after boundary adjustments:");

            typeMethods.r8vec_print_some(node_num, f, 1, 10,
                                         "  Part of right hand side vector F:");
            break;
        }

        //
        //  Solve the linear system using an iterative solver.
        //
        UniformRNG.r8vec_uniform_01(node_num, ref seed, ref node_u);

        int    itr_max = 20;
        int    mr      = 20;
        double tol_abs = 0.000001;
        double tol_rel = 0.000001;

        RestartedGeneralizedMinimumResidual.mgmres(a, ia, ja, ref node_u, f, node_num, nz_num, itr_max, mr, tol_abs,
                                                   tol_rel);

        typeMethods.r8vec_print_some(node_num, node_u, 1, 10,
                                     "  Part of the solution vector vector U:");
        //
        //  Write an ASCII file that can be read into MATLAB.
        //
        typeMethods.r8mat_write(solution_filename, 1, node_num, node_u);

        Console.WriteLine("");
        Console.WriteLine("FEM2D_POISSON_SPARSE:");
        Console.WriteLine("  Wrote an ASCII file");
        Console.WriteLine("    \"" + solution_filename + "\".");
        Console.WriteLine("  of the form");
        Console.WriteLine("    U ( X(I), Y(I) )");
        Console.WriteLine("  which can be used for plotting.");

        switch (debug)
        {
        case true:
            typeMethods.r8vec_print_some(node_num, node_u, 1, 10,
                                         "  Part of the solution vector:");
            break;
        }

        Console.WriteLine("");
        Console.WriteLine("FEM2D_POISSON_SPARSE:");
        Console.WriteLine("  Normal end of execution.");

        Console.WriteLine("");
    }
}