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. }
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); }
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); }
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."); } }
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)); }
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 }); }
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; }
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(); }
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(); }