public Vector Multiply(Vector vector) { var result = Vector.CreateZero(vector.Length); preconditioner.SolveLinearSystem(vector, result); return(result); }
public void SolveLinearSystem(IVectorView rhsVector, IVector lhsVector) { //TODO: remove casts. I think PCG, LinearTransformation and preconditioners should be generic, bounded by // IVectorView and IVector var lhs = (Vector)lhsVector; var rhs = (Vector)rhsVector; fetiPreconditioner.SolveLinearSystem(rhs, lhs); }
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."); } }
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 }); }