Exemple #1
0
        /// <summary>
        /// Solves an eigen value problem of the form Kφ = λMφ through the Lanczos iteration method. Both matrices should be positive definite.
        /// </summary>
        /// <param name="nSubSpace">Size of the modal subspace to converge</param>
        /// <remarks>
        /// This method uses the subspace iteration and Jacobi methods to aproach a limited number of eigen values of a large DOF system.
        /// This method has been presented by K.J. Bathe as a quite robust one. Convergence might be slower than through Lanczos method, but the implementation involves much simpler algorithms, and
        /// convergence is much easier to control and checked.
        /// Gram-smith KM-ortogonalization occurs simultaneously for all vectors through a Ritz transformation. This is why  the method is very stable and less round-off errors sensitive.
        /// This method has been brought here as a complement to the OpenVOGEL project publisehd on GPLv3.
        /// Open VOGEL (openvogel.org)
        /// Open source software for aerodynamics
        /// Copyright (C) 2020 Guillermo Hazebrouck ([email protected])
        /// <http://www.gnu.org/licenses/>.
        /// </remarks>
        public void SubspaceIteration(SymmetricMatrix M,
                                      SymmetricMatrix K,
                                      int nSubSpace,
                                      int nModes,
                                      out Vector D,
                                      out Matrix V)
        {
            //------------------------------------------------------------------------------------
            // Check subspace dimension
            //------------------------------------------------------------------------------------

            int nDOF = M.RowCount;

            if (K.RowCount != nDOF)
            {
                throw new Exception("the size of the matrices does not match");
            }

            if (nSubSpace > nDOF)
            {
                throw new Exception("the subspace size is too large");
            }

            //------------------------------------------------------------------------------------
            // Set eigen values convergence threshold
            //------------------------------------------------------------------------------------

            double er_eval = EValError_Subspace;

            //------------------------------------------------------------------------------------
            // Decompose K in LU
            //------------------------------------------------------------------------------------

            LinearEquations K_LU = new LinearEquations();

            K_LU.ComputeLU(K);

            //------------------------------------------------------------------------------------
            // Initialize temporal storage matrices
            //------------------------------------------------------------------------------------

            SymmetricMatrix K_p = new SymmetricMatrix(nSubSpace);
            SymmetricMatrix M_p = new SymmetricMatrix(nSubSpace);
            Matrix          Q   = new Matrix(nSubSpace);
            Vector          L   = new Vector(nSubSpace);

            D = new Vector(nSubSpace);
            V = new Matrix(nDOF, nSubSpace);

            bool Converged = false;
            int  Step      = 0;

            Matrix MV = new Matrix(nDOF, nSubSpace);
            Matrix MX = new Matrix(nDOF, nSubSpace);
            Matrix X  = new Matrix(nDOF, nSubSpace);

            //------------------------------------------------------------------------------------
            // Set starting vectors
            //------------------------------------------------------------------------------------

            Random Rand = new Random();

            for (int i = 0; i < nDOF; i++)
            {
                V[i, 0] = M[i, i];
            }

            for (int i = 1; i < nSubSpace; i++)
            {
                if (i == nSubSpace - 1)
                {
                    for (int j = 0; j < nDOF; j++)
                    {
                        double Sign;
                        if (Rand.NextDouble() > 0.5)
                        {
                            Sign = 1.0;
                        }
                        else
                        {
                            Sign = -1.0;
                        }
                        V[j, i] = Rand.NextDouble() * Sign;
                    }
                }
                else
                {
                    V[i, i] = 1.0;
                }
            }

            //------------------------------------------------------------------------------------
            // Start sub space iteration loop
            //------------------------------------------------------------------------------------

            while (Step < 15 && !Converged)
            {
                //--------------------------------------------------------------------------------
                // Find M.V
                //--------------------------------------------------------------------------------

                if (Step == 0)
                {
                    MV.Copy(V);
                }
                else
                {
                    // compute M.V

                    for (int i = 0; i < nDOF; i++)
                    {
                        for (int j = 0; j < nSubSpace; j++)
                        {
                            double p = 0;
                            for (int k = 0; k < nDOF; k++)
                            {
                                p += M[i, k] * V[k, j];
                            }
                            MV[i, j] = p;
                        }
                    }
                }

                //--------------------------------------------------------------------------------
                // Find new vector X:
                //--------------------------------------------------------------------------------

                K_LU.SolveLU(MV, X);

                //--------------------------------------------------------------------------------
                // Find projected K -> K_p = X_T.K.X (note that M.V = K.X, and then K_p = X_T.M.V)
                //--------------------------------------------------------------------------------

                for (int i = 0; i < nSubSpace; i++)
                {
                    for (int j = i; j < nSubSpace; j++)
                    {
                        double p = 0;
                        for (int k = 0; k < nDOF; k++)
                        {
                            p += X[k, i] * MV[k, j];
                        }
                        K_p[i, j] = p;
                    }
                }

                //--------------------------------------------------------------------------------
                // Find M.X
                //--------------------------------------------------------------------------------

                for (int i = 0; i < nDOF; i++)
                {
                    for (int j = 0; j < nSubSpace; j++)
                    {
                        double p = 0;
                        for (int k = 0; k < nDOF; k++)
                        {
                            p += M[i, k] * X[k, j];
                        }
                        MX[i, j] = p;
                    }
                }

                //--------------------------------------------------------------------------------
                // Find projected M -> M_p = X_T.M.X
                //--------------------------------------------------------------------------------

                for (int i = 0; i < nSubSpace; i++)
                {
                    for (int j = i; j < nSubSpace; j++)
                    {
                        double p = 0;
                        for (int k = 0; k < nDOF; k++)
                        {
                            p += X[k, i] * MX[k, j];
                        }
                        M_p[i, j] = p;
                    }
                }

                //--------------------------------------------------------------------------------
                // Save current values to check convergence
                //--------------------------------------------------------------------------------

                for (int i = 0; i < nSubSpace; i++)
                {
                    L[i] = D[i];
                }

                //--------------------------------------------------------------------------------
                // Solve reduced eigensystem in the projected space
                //--------------------------------------------------------------------------------

                Jacobi(K_p, M_p, Q, D);

                //--------------------------------------------------------------------------------
                // Apply Ritz transformation -> V = X.Q
                // V should tend to the truncated modal basis (subspace).
                //--------------------------------------------------------------------------------

                for (int i = 0; i < nDOF; i++)
                {
                    for (int j = 0; j < nSubSpace; j++)
                    {
                        double p = 0;
                        for (int k = 0; k < nSubSpace; k++)
                        {
                            p += X[i, k] * Q[k, j];
                        }
                        V[i, j] = p;
                    }
                }

                //--------------------------------------------------------------------------------
                // Check convergence
                // Only the required values are cheked for convergence (not the entire subspace)
                //--------------------------------------------------------------------------------

                Converged = true;

                for (int i = 0; i < nModes && Converged; i++)
                {
                    Converged = Converged && System.Math.Abs((D[i] - L[i]) / L[i]) < er_eval;
                }

                Step++;
            }
        }