private PcgMatrix DefinePcgMatrix(Feti1FlexibilityMatrix flexibility, Feti1Projection projection) { //TODO: projection.ProjectVector() overwrites the rhs vector passed in. However that is not clear by the method. // I should either always return the resulting vector (negating any optimizations) or set the convention that // vectors passed in as results will always be overwritten. The latter forces the method that accepts them to // clear them (if the method needs to), which is not needed if the resulting vector has just be initialized to 0. if (projectionSideMatrix == ProjectionSide.Left) { // A * x = (P^T * F) * x = P^T * (F * x) return(new PcgMatrix(flexibility.Order, (x, y) => projection.ProjectVector(flexibility.Multiply(x), y, true))); } else if (projectionSideMatrix == ProjectionSide.Both) { // A * x = (P^T * F * P) * x = P^T * (F * (P * x)) return(new PcgMatrix(flexibility.Order, (x, y) => { var temp = Vector.CreateZero(flexibility.Order); projection.ProjectVector(x, temp, false); projection.ProjectVector(flexibility.Multiply(temp), y, true); })); } else { throw new ArgumentException("The FETI-1 flexibility matrix can be multiplied from the left or both sides."); } }
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); }
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."); } }
/// <summary> /// Calculates the actual lagrange multipliers depending on the separation formula. /// </summary> internal Vector CombineLagrangeMultipliers(Vector lagrangesParticular, Vector lagrangesBar, Feti1Projection projection) { if (lagrangeSeparation == LagrangeMultiplierSeparation.Simple) { // λ = λ0 + P * λbar return(lagrangesBar + lagrangesParticular); } else if (lagrangeSeparation == LagrangeMultiplierSeparation.WithProjection) { // λ = λ0 + P * λbar var lagranges = Vector.CreateZero(lagrangesBar.Length); projection.ProjectVector(lagrangesBar, lagranges, false); lagranges.AddIntoThis(lagrangesParticular); return(lagranges); } else { throw new ArgumentException("The lagrange separation can only be: a) λ = λ0 + λbar or b) λ = λ0 + P * λbar"); } }