Пример #1
0
 public void HandleMatrixWillBeSet()
 {
     isStiffnessModified = true;
     foreach (ISubdomain subdomain in subdomains.Values)
     {
         if (subdomain.StiffnessModified)
         {
             Debug.WriteLine($"{this.GetType().Name}: Clearing saved matrices of subdomain {subdomain.ID}.");
             matrixManagers[subdomain.ID].Clear();
         }
     }
     flexibility    = null;
     preconditioner = null;
     projection     = null;
     //stiffnessDistribution = null; //WARNING: do not dispose of this. It is updated when BuildGlobalMatrix() is called.
 }
Пример #2
0
        public Vector CalcLagrangeMultipliers(Feti1FlexibilityMatrix flexibility, IFetiPreconditioner preconditioner,
                                              Feti1Projection projection, Vector disconnectedDisplacements, Vector rigidBodyModesWork, double globalForcesNorm,
                                              SolverLogger logger)
        {
            int               systemOrder       = flexibility.Order;
            PcgMatrix         pcgMatrix         = DefinePcgMatrix(flexibility, projection);
            PcgPreconditioner pcgPreconditioner = DefinePcgPreconditioner(preconditioner, projection);

            // λ0 = Q * G * inv(G^T * Q * G) * e
            Vector lagrangesParticular = projection.CalcParticularLagrangeMultipliers(rigidBodyModesWork);

            // Calculate rhs of the projected interface system: rhs = P^T * (d - F * λ0)
            var r0 = flexibility.Multiply(lagrangesParticular);

            r0.LinearCombinationIntoThis(-1.0, disconnectedDisplacements, 1.0);
            var pcgRhs = Vector.CreateZero(systemOrder);

            projection.ProjectVector(r0, pcgRhs, true);

            // Solve the interface problem using PCG algorithm
            var pcgBuilder = new PcgAlgorithm.Builder();

            pcgBuilder.MaxIterationsProvider = maxIterationsProvider;
            pcgBuilder.ResidualTolerance     = pcgConvergenceTolerance;
            pcgBuilder.Convergence           = pcgConvergenceStrategyFactory.CreateConvergenceStrategy(globalForcesNorm);
            PcgAlgorithm        pcg          = pcgBuilder.Build();
            var                 lagrangesBar = Vector.CreateZero(systemOrder);
            IterativeStatistics stats        = pcg.Solve(pcgMatrix, pcgPreconditioner, pcgRhs, lagrangesBar, true,
                                                         () => Vector.CreateZero(systemOrder));

            if (!stats.HasConverged)
            {
                throw new IterativeSolverNotConvergedException(Feti1Solver.name + " did not converge to a solution. PCG"
                                                               + $" algorithm run for {stats.NumIterationsRequired} iterations and the residual norm ratio was"
                                                               + $" {stats.ResidualNormRatioEstimation}");
            }

            // Calculate the actual lagrange multipliers from the separation formula: λ = λ0 + P * λbar
            var lagranges = Vector.CreateZero(systemOrder);

            projection.ProjectVector(lagrangesBar, lagranges, false);
            lagranges.AddIntoThis(lagrangesParticular);

            // Log statistics about PCG execution
            logger.LogIterativeAlgorithm(stats.NumIterationsRequired, stats.ResidualNormRatioEstimation);
            return(lagranges);
        }
Пример #3
0
        public Vector CalcLagrangeMultipliers(Feti1FlexibilityMatrix flexibility, IFetiPreconditioner preconditioner,
                                              Feti1Projection projection, Vector disconnectedDisplacements, Vector rigidBodyModesWork, double globalForcesNorm,
                                              SolverLogger logger)
        {
            // PCPG starts from the particular lagrange multipliers: λ0 = Q * G * inv(G^T * Q * G) * e
            Vector lagranges = projection.CalcParticularLagrangeMultipliers(rigidBodyModesWork);
            IFetiPcgConvergence pcpgConvergenceStrategy =
                pcgConvergenceStrategyFactory.CreateConvergenceStrategy(globalForcesNorm);
            var pcpg = new PcpgAlgorithm(maxIterationsProvider, pcpgConvergenceTolerance, pcpgConvergenceStrategy);
            IterativeStatistics stats =
                pcpg.Solve(flexibility, preconditioner, projection, disconnectedDisplacements, lagranges);

            if (!stats.HasConverged)
            {
                throw new IterativeSolverNotConvergedException(Feti1Solver.name + " did not converge to a solution. PCPG"
                                                               + $" algorithm run for {stats.NumIterationsRequired} iterations and the residual norm ratio was"
                                                               + $" {stats.ResidualNormRatioEstimation}");
            }

            // Log statistics about PCG execution
            logger.LogIterativeAlgorithm(stats.NumIterationsRequired, stats.ResidualNormRatioEstimation);
            return(lagranges);
        }
Пример #4
0
 private PcgPreconditioner DefinePcgPreconditioner(IFetiPreconditioner preconditioner, Feti1Projection projection)
 {
     if (projectionSidePreconditioner == ProjectionSide.None)
     {
         // x = prec(A) * y => x = prec(F) * y
         return(new PcgPreconditioner((x, y) => preconditioner.SolveLinearSystem(y, x)));
     }
     else if (projectionSidePreconditioner == ProjectionSide.Left)
     {
         // x = prec(A) * y => x = (P * prec(F)) * y => x = P * (prec(F) * y)
         return(new PcgPreconditioner((y, x) =>
         {
             int order = y.Length;
             var temp = Vector.CreateZero(order);
             preconditioner.SolveLinearSystem(y, temp);
             projection.ProjectVector(temp, x, false);
         }));
     }
     else if (projectionSidePreconditioner == ProjectionSide.Both)
     {
         // x = prec(A) * y => x = (P * prec(F) * P^T) * y => x = P * (prec(F) * (P^T * y))
         return(new PcgPreconditioner((y, x) =>
         {
             int order = y.Length;
             var temp1 = Vector.CreateZero(order);
             projection.ProjectVector(y, temp1, true);
             var temp2 = Vector.CreateZero(order);
             preconditioner.SolveLinearSystem(temp1, temp2);
             projection.ProjectVector(temp2, x, false);
         }));
     }
     else
     {
         throw new ArgumentException(
                   "The FETI-1 preconditioner can be multiplied from the left side, both sides or not at all.");
     }
 }
Пример #5
0
        public static void TestInterfaceProblemSolution()
        {
            // Setup the model and solver
            Model model = Quads4x4MappingMatricesTests.CreateModel();
            Dictionary <int, HashSet <INode> > cornerNodes = Quads4x4MappingMatricesTests.DefineCornerNodes(model);
            var fetiMatrices        = new DenseFetiDPSubdomainMatrixManager.Factory();
            var cornerNodeSelection = new UsedDefinedCornerNodes(cornerNodes);
            var solver = new FetiDPSolver.Builder(cornerNodeSelection, fetiMatrices).BuildSolver(model);

            model.ConnectDataStructures();
            solver.OrderDofs(false);
            solver.Initialize();

            // Mock the stiffness matrices and force vectors
            Dictionary <int, IFetiDPSubdomainMatrixManager> matrixManagers = MockStiffnesses();
            Dictionary <int, IFetiSubdomainMatrixManager>   matrixManagersPreconditioning = MockStiffnessesForPreconditioning();
            Dictionary <int, Matrix> Krr = MatricesKrr;
            Vector dr = VectorDr;

            // Access private fields of FetiDPSolver
            FieldInfo fi = typeof(FetiDPSolver).GetField("lagrangeEnumerator", BindingFlags.NonPublic | BindingFlags.Instance);
            var       lagrangeEnumerator = (FetiDPLagrangeMultipliersEnumerator)fi.GetValue(solver);

            fi = typeof(FetiDPSolver).GetField("dofSeparator", BindingFlags.NonPublic | BindingFlags.Instance);
            var dofSeparator = (FetiDPDofSeparator)fi.GetValue(solver);

            // Hardcoded coarse problem matrix and rhs
            var    coarseSolver   = new DenseFetiDPCoarseProblemSolver(model.Subdomains);
            Vector globalFcStar   = VectorFcStar;
            Matrix inverseKccStar = MatrixKccStar.Invert(); // It must be set as a private field using reflection.

            fi = typeof(DenseFetiDPCoarseProblemSolver).GetField("inverseGlobalKccStar",
                                                                 BindingFlags.NonPublic | BindingFlags.Instance);
            fi.SetValue(coarseSolver, inverseKccStar);

            // Dirichlet preconditioner
            var precondFactory = new DirichletPreconditioner.Factory();
            var repackagedKrr  = new Dictionary <int, IMatrixView>();

            foreach (var idMatrixPair in Krr)
            {
                repackagedKrr[idMatrixPair.Key] = idMatrixPair.Value;
            }
            var stiffnessDistribution = new HomogeneousStiffnessDistribution(model, dofSeparator);

            stiffnessDistribution.Update(null);
            IFetiPreconditioner preconditioner = precondFactory.CreatePreconditioner(model,
                                                                                     stiffnessDistribution, dofSeparator, lagrangeEnumerator, matrixManagersPreconditioning);

            // Solve the interface problem
            FetiDPInterfaceProblemSolver interfaceSolver = new FetiDPInterfaceProblemSolver.Builder().Build();
            var flexibility = new FetiDPFlexibilityMatrix(dofSeparator, lagrangeEnumerator, matrixManagers);
            var logger      = new SolverLogger("mock FETI-DP");

            (Vector lagranges, Vector uc) = interfaceSolver.SolveInterfaceProblem(
                flexibility, preconditioner, coarseSolver, globalFcStar, dr, GlobalForcesNorm, logger);

            // Check against expected solution
            double tol = 1E-7;

            Assert.True(SolutionLagrangeMultipliers.Equals(lagranges, tol));
            Assert.True(SolutionCornerDisplacements.Equals(uc, tol));
        }
Пример #6
0
        internal IterativeStatistics Solve(IInterfaceFlexibilityMatrix matrix, IFetiPreconditioner preconditioner,
                                           IInterfaceProjection projector, Vector rhs, Vector lagrangeMultipliers)
        {
            int n             = matrix.Order;
            int maxIterations = maxIterationsProvider.GetMaxIterations(matrix.Order);

            // r0 = d - F * λ0
            var residual = matrix.Multiply(lagrangeMultipliers);

            residual.LinearCombinationIntoThis(-1.0, rhs, 1.0);

            // Other allocations
            var    w                          = Vector.CreateZero(n);
            var    y                          = Vector.CreateZero(n);
            var    z                          = Vector.CreateZero(n);
            var    direction                  = Vector.CreateZero(n);
            var    matrixTimesDirection       = Vector.CreateZero(n);
            double residualDotProductPrevious = double.NaN;
            double residualNormRatio          = double.NaN;
            double beta                       = double.NaN;

            for (int iter = 1; iter <= maxIterations; ++iter)
            {
                // w(m-1) = P * r(m-1)
                projector.ProjectVector(residual, w, false);

                // z(m-1) = preconditioner * w(m-1)
                preconditioner.SolveLinearSystem(w, z);

                // Check convergence: usually if ||z|| / ||f|| < tolerance
                residualNormRatio = convergence.EstimateResidualNormRatio(lagrangeMultipliers, z);
                if (residualNormRatio <= residualTolerance)
                {
                    //TODO: is it correct to check for convergence here? How many iterations should I return?
                    return(new IterativeStatistics
                    {
                        AlgorithmName = name,
                        HasConverged = true,
                        NumIterationsRequired = iter - 1, //TODO: not sure about this.
                        ResidualNormRatioEstimation = residualNormRatio
                    });
                }

                // y(m-1) = P * z(m-1)
                projector.ProjectVector(z, y, false);

                double residualDotProductCurrent = y.DotProduct(w);

                if (iter == 1)
                {
                    // β(1) = 0
                    beta = 0;

                    // p(1) = y0
                    direction.CopyFrom(y);
                }
                else
                {
                    // β(m) = (y(m-1) * w(m-1)) / (y(m-2) * w(m-2))
                    beta = residualDotProductCurrent / residualDotProductPrevious;

                    // p(m) = y(m-1) + β(m) * p(m-1), if m > 1
                    direction.LinearCombinationIntoThis(beta, y, 1.0);
                }
                residualDotProductPrevious = residualDotProductCurrent;

                // γ(m) = (y(m-1) * w(m-1)) / (p(m) * F * p(m))
                matrix.Multiply(direction, matrixTimesDirection);
                double stepSize = (y * w) / (direction * matrixTimesDirection);

                // λ(m) = λ(m-1) + γ(m) * p(m)
                lagrangeMultipliers.AxpyIntoThis(direction, stepSize);

                // r(m) = r(m-1) -γ(m) * F * p(m)
                residual.AxpyIntoThis(matrixTimesDirection, -stepSize);
            }

            return(new IterativeStatistics
            {
                AlgorithmName = name,
                HasConverged = false,
                NumIterationsRequired = maxIterations,
                ResidualNormRatioEstimation = residualNormRatio
            });
        }
Пример #7
0
 internal PreconditionerAsMatrixQ(IFetiPreconditioner preconditioner)
 {
     this.preconditioner = preconditioner;
 }
        public (Vector lagrangeMultipliers, Vector cornerDisplacements) SolveInterfaceProblem(FetiDPFlexibilityMatrix flexibility,
                                                                                              IFetiPreconditioner preconditioner, IFetiDPCoarseProblemSolver coarseProblemSolver,
                                                                                              Vector globalFcStar, Vector dr, double globalForcesNorm, SolverLogger logger)
        {
            int systemOrder = flexibility.Order;

            // Matrix, preconditioner & rhs
            var    pcgMatrix         = new InterfaceProblemMatrix(flexibility, coarseProblemSolver);
            var    pcgPreconditioner = new InterfaceProblemPreconditioner(preconditioner);
            Vector pcgRhs            = CreateInterfaceProblemRhs(flexibility, coarseProblemSolver, globalFcStar, dr);

            // Solve the interface problem using PCG algorithm
            var pcgBuilder = new PcgAlgorithm.Builder();

            pcgBuilder.MaxIterationsProvider = maxIterationsProvider;
            pcgBuilder.ResidualTolerance     = pcgConvergenceTolerance;
            pcgBuilder.Convergence           = pcgConvergenceStrategyFactory.CreateConvergenceStrategy(globalForcesNorm);
            PcgAlgorithm        pcg       = pcgBuilder.Build(); //TODO: perhaps use the pcg from the previous analysis if it has reorthogonalization.
            var                 lagranges = Vector.CreateZero(systemOrder);
            IterativeStatistics stats     = pcg.Solve(pcgMatrix, pcgPreconditioner, pcgRhs, lagranges, true,
                                                      () => Vector.CreateZero(systemOrder));

            // Log statistics about PCG execution
            if (!stats.HasConverged)
            {
                throw new IterativeSolverNotConvergedException(FetiDPSolver.name + " did not converge to a solution. PCG"
                                                               + $" algorithm run for {stats.NumIterationsRequired} iterations and the residual norm ratio was"
                                                               + $" {stats.ResidualNormRatioEstimation}");
            }
            logger.LogIterativeAlgorithm(stats.NumIterationsRequired, stats.ResidualNormRatioEstimation);

            // Calculate corner displacements: uc = inv(KccStar) * (fcStar + FIrc^T * lagranges)
            Vector uc = flexibility.MultiplyTransposedFIrc(lagranges);

            uc.AddIntoThis(globalFcStar);
            uc = coarseProblemSolver.MultiplyInverseCoarseProblemMatrixTimes(uc);

            return(lagranges, uc);
        }
 internal InterfaceProblemPreconditioner(IFetiPreconditioner fetiPreconditioner)
 {
     this.fetiPreconditioner = fetiPreconditioner;
 }
Пример #10
0
        public void Solve()
        {
            var watch = new Stopwatch();

            foreach (ISingleSubdomainLinearSystem linearSystem in linearSystems.Values)
            {
                if (linearSystem.Solution == null)
                {
                    linearSystem.SolutionConcrete = linearSystem.CreateZeroVectorConcrete();
                }
            }

            // Calculate generalized inverses and rigid body modes of subdomains to assemble the interface flexibility matrix.
            if (isStiffnessModified)
            {
                // Reorder internal dofs if needed by the preconditioner. TODO: Should I have done this previously in Initialize()?
                watch.Start();
                if (preconditionerFactory.ReorderInternalDofsForFactorization)
                {
                    foreach (ISubdomain subdomain in model.Subdomains)
                    {
                        if (subdomain.ConnectivityModified)
                        {
                            Debug.WriteLine($"{this.GetType().Name}: Reordering internal dofs of subdomain {subdomain.ID}.");
                            matrixManagers[subdomain.ID].ReorderInternalDofs(dofSeparator, subdomain);
                        }
                    }
                }

                // Calculate the preconditioner before factorizing each subdomain's Kff
                preconditioner = preconditionerFactory.CreatePreconditioner(model, stiffnessDistribution, dofSeparator,
                                                                            lagrangeEnumerator, matrixManagersGeneral);
                watch.Stop();
                Logger.LogTaskDuration("Calculating preconditioner", watch.ElapsedMilliseconds);

                // Invert each subdomain's Kff
                watch.Restart();
                foreach (int s in subdomains.Keys)
                {
                    if (subdomains[s].StiffnessModified)
                    {
                        Debug.WriteLine($"{this.GetType().Name}: Inverting the free-free stiffness matrix of subdomain {s}"
                                        + (factorizeInPlace ? " in place.": " using extra memory."));
                        matrixManagers[s].InvertKff(factorPivotTolerances[s], factorizeInPlace);
                    }
                }
                watch.Stop();
                Logger.LogTaskDuration("Matrix factorization", watch.ElapsedMilliseconds);

                watch.Restart();
                BuildProjection();
                flexibility = new Feti1FlexibilityMatrix(matrixManagers, lagrangeEnumerator);
                watch.Stop();
                Logger.LogTaskDuration("Setting up interface problem", watch.ElapsedMilliseconds);
                watch.Reset();

                isStiffnessModified = false;
            }

            // Calculate the rhs vectors of the interface system
            watch.Start();
            Vector disconnectedDisplacements = CalcDisconnectedDisplacements();
            Vector rbmWork          = CalcRigidBodyModesWork();
            double globalForcesNorm = CalcGlobalForcesNorm();

            watch.Stop();
            Logger.LogTaskDuration("Setting up interface problem", watch.ElapsedMilliseconds);

            // Solve the interface problem
            watch.Restart();
            Vector lagranges = interfaceProblemSolver.CalcLagrangeMultipliers(flexibility, preconditioner, projection,
                                                                              disconnectedDisplacements, rbmWork, globalForcesNorm, Logger);

            watch.Stop();
            Logger.LogTaskDuration("Solving interface problem", watch.ElapsedMilliseconds);

            // Calculate the displacements of each subdomain
            watch.Restart();
            Vector rbmCoeffs = CalcRigidBodyModesCoefficients(disconnectedDisplacements, lagranges);
            Dictionary <int, Vector> actualDisplacements = CalcActualDisplacements(lagranges, rbmCoeffs);

            foreach (var idSystem in linearSystems)
            {
                idSystem.Value.SolutionConcrete = actualDisplacements[idSystem.Key];
            }
            watch.Stop();
            Logger.LogTaskDuration("Calculate displacements from lagrange multipliers", watch.ElapsedMilliseconds);

            Logger.IncrementAnalysisStep();
        }
Пример #11
0
        public void Solve()
        {
            var watch = new Stopwatch();

            foreach (var linearSystem in linearSystems.Values)
            {
                if (linearSystem.SolutionConcrete == null)
                {
                    linearSystem.SolutionConcrete = linearSystem.CreateZeroVectorConcrete();
                }
            }

            // Separate the force vector
            watch.Start();
            var fr  = new Dictionary <int, Vector>();
            var fbc = new Dictionary <int, Vector>();

            foreach (int s in subdomains.Keys)
            {
                int[]  remainderDofs = dofSeparator.RemainderDofIndices[s];
                int[]  cornerDofs    = dofSeparator.CornerDofIndices[s];
                Vector f             = linearSystems[s].RhsConcrete;
                fr[s]  = f.GetSubvector(remainderDofs);
                fbc[s] = f.GetSubvector(cornerDofs);
            }
            watch.Stop();
            Logger.LogTaskDuration("Separating vectors & matrices", watch.ElapsedMilliseconds);
            watch.Reset();

            if (isStiffnessModified)
            {
                // Separate the stiffness matrix
                watch.Start();
                foreach (int s in subdomains.Keys)
                {
                    if (!subdomains[s].StiffnessModified)
                    {
                        continue;
                    }
                    IFetiDPSubdomainMatrixManager matrices = matrixManagers[s];
                    int[] remainderDofs = dofSeparator.RemainderDofIndices[s];
                    int[] cornerDofs    = dofSeparator.CornerDofIndices[s];
                    matrices.ExtractKrr(remainderDofs);
                    matrices.ExtractKcrKrc(cornerDofs, remainderDofs);
                    matrices.ExtractKcc(cornerDofs);
                }
                watch.Stop();
                Logger.LogTaskDuration("Separating vectors & matrices", watch.ElapsedMilliseconds);


                // Reorder internal dofs if needed by the preconditioner. TODO: Should I have done this previously in Initialize()?
                watch.Start();
                if (preconditionerFactory.ReorderInternalDofsForFactorization)
                {
                    foreach (ISubdomain subdomain in model.Subdomains)
                    {
                        if (subdomain.ConnectivityModified)
                        {
                            Debug.WriteLine($"{this.GetType().Name}: Reordering internal dofs of subdomain {subdomain.ID}.");
                            matrixManagers[subdomain.ID].ReorderInternalDofs(dofSeparator, subdomain);
                        }
                    }
                }

                // Calculate the preconditioner before factorizing each subdomain's Kff
                preconditioner = preconditionerFactory.CreatePreconditioner(model, stiffnessDistribution, dofSeparator,
                                                                            lagrangeEnumerator, matrixManagersGeneral);
                watch.Stop();
                Logger.LogTaskDuration("Calculating preconditioner", watch.ElapsedMilliseconds);

                // Factorize each subdomain's Krr
                watch.Restart();
                foreach (int s in subdomains.Keys)
                {
                    if (!subdomains[s].StiffnessModified)
                    {
                        continue;
                    }
                    //TODO: If I can reuse Krr, I can also reuse its factorization. Therefore this must be inPlace. In contrast, FETI-1 needs Kff intact for Stiffness distribution, in the current design).
                    Debug.WriteLine(
                        $"{this.GetType().Name}: Inverting the remainder-remainder stiffness matrix of subdomain {s} in place.");
                    matrixManagers[s].InvertKrr(true);
                }
                watch.Stop();
                Logger.LogTaskDuration("Matrix factorization", watch.ElapsedMilliseconds);

                // Define FETI-DP flexibility matrices
                watch.Restart();
                flexibility = new FetiDPFlexibilityMatrix(dofSeparator, lagrangeEnumerator, matrixManagers);

                // Static condensation of remainder dofs (Schur complement).
                coarseProblemSolver.CreateAndInvertCoarseProblemMatrix(CornerNodesOfSubdomains, dofSeparator, matrixManagers);
                watch.Stop();
                Logger.LogTaskDuration("Setting up interface problem", watch.ElapsedMilliseconds);
                watch.Reset();

                isStiffnessModified = false;
            }

            // Static condensation for the force vectors
            watch.Start();
            Vector globalFcStar = coarseProblemSolver.CreateCoarseProblemRhs(dofSeparator, matrixManagers, fr, fbc);

            // Calculate the rhs vectors of the interface system
            Vector dr = CalcDisconnectedDisplacements(fr);
            double globalForcesNorm = CalcGlobalForcesNorm();

            watch.Stop();
            Logger.LogTaskDuration("Setting up interface problem", watch.ElapsedMilliseconds);

            // Solve the interface problem
            watch.Restart();
            (Vector lagranges, Vector uc) = interfaceProblemSolver.SolveInterfaceProblem(flexibility, preconditioner,
                                                                                         coarseProblemSolver, globalFcStar, dr, globalForcesNorm, Logger);
            watch.Stop();
            Logger.LogTaskDuration("Solving interface problem", watch.ElapsedMilliseconds);

            // Calculate the displacements of each subdomain
            watch.Restart();
            Dictionary <int, Vector> actualDisplacements = CalcActualDisplacements(lagranges, uc, fr);

            foreach (var idSystem in linearSystems)
            {
                idSystem.Value.SolutionConcrete = actualDisplacements[idSystem.Key];
            }
            watch.Stop();
            Logger.LogTaskDuration("Calculate displacements from lagrange multipliers", watch.ElapsedMilliseconds);

            Logger.IncrementAnalysisStep();
        }