private IVector CalculateRhsImplicit(ILinearSystem linearSystem, bool addRhs) { int id = linearSystem.Subdomain.ID; capacityTimesTemperature[id] = provider.MassMatrixVectorProduct(linearSystem.Subdomain, temperature[id]); conductivityTimesTemperature[id] = provider.DampingMatrixVectorProduct(linearSystem.Subdomain, temperature[id]); IVector rhsResult = rhsPrevious[id].LinearCombination(1 - beta, rhs[id], beta); rhsResult.AxpyIntoThis(capacityTimesTemperature[id], 1 / timeStep); rhsResult.AxpyIntoThis(conductivityTimesTemperature[id], -(1 - beta)); rhsPrevious[id] = rhs[id]; return(rhsResult); }
/// <summary> /// Calculates the initial approximation to the linear system's solution vector, by using a series of conjugate direction /// vectors that have been stored previously by PCG during the solution of other linear systems with the same matrix. /// This method should be used to solve linear systems with different right hand side vectors and the same matrix. /// </summary> /// <param name="rhsNew">The right hand side vector of the new linear system.</param> /// <param name="initialSolution"> /// The initial approximation to the solution vector, which PCG will improve. It will be overwritten by this method. /// </param> /// <param name="isSolutionZero"> /// Set to true if <paramref name="initialSolution"/> is the zero vector, to avoid clearing it. /// </param> /// <exception cref="InvalidOperationException">Thrown if there are no direction vectors stored yet.</exception> public void CalculateInitialSolutionFromStoredDirections(IVectorView rhsNew, IVector initialSolution, bool isSolutionZero) { if (reorthoCache.Directions.Count < 1) { throw new InvalidOperationException("There are no direction vectors stored."); } if (!isSolutionZero) { initialSolution.Clear(); } //TODO: An implementation by G. Stavroulakis discarded the last stored direction vector at this point. Why? //reorthoCache.RemoveNewDirectionVectorData(1); // x0 = D_nd * x_d, x_d = inv(Q_nd * D_nd) * D_nd^T * b // D_nd = [d_1 ... d_nd], Q_nd = A * D_nd = [q_1 ... q_nd], Q_nd * D_nd = diag([d1*A*d1 ... d_nd*A*d_nd]) for (int i = 0; i < reorthoCache.Directions.Count; ++i) { // x_d[i] = 1/(d_i * q_i) * (d_i * b) double xd = reorthoCache.Directions[i].DotProduct(rhsNew) / reorthoCache.DirectionsTimesMatrixTimesDirections[i]; Debug.Assert(!double.IsNaN(xd)); Debug.Assert(!double.IsPositiveInfinity(xd)); Debug.Assert(!double.IsNegativeInfinity(xd)); // x0 += d_i * x_d[i] initialSolution.AxpyIntoThis(reorthoCache.Directions[i], xd); } }
/// <summary> /// Gram–Schmidt orthogonalization to the stored vectors, without normalization. /// </summary> /// <param name="v">The vector to reorthogonalize. It will be overwritten with the result. If there are no stored /// vectors, it will remain unchanged without being copied.</param> internal void Reorthogonalize(IVector v) { // reorthogonalize 1 by 1 foreach (var p in store) { // we don't have to normalize since it is explicitly done in the code and so we don't need to redo it v.AxpyIntoThis(p, -(v.DotProduct(p))); // orthogonalize to each stored vector } }
private IVector CalculateRhsImplicit(ILinearSystem linearSystem, bool addRhs) { //TODO: what is the meaning of addRhs? Do we need this when solving dynamic thermal equations? // result = (1-b)* rhsPrevious + beta * rhs + 1/dt * 1stOrderMatrix * unknown - (1-b) * 0thOrderMatrix * unknown int id = linearSystem.Subdomain.ID; firstOrderMatrixTimesUnknown[id] = provider.MassMatrixVectorProduct(linearSystem.Subdomain, unknown[id]); zerothOrderMatrixTimesUnknown[id] = provider.DampingMatrixVectorProduct(linearSystem.Subdomain, unknown[id]); IVector rhsResult = rhsPrevious[id].LinearCombination(1 - beta, rhs[id], beta); rhsResult.AxpyIntoThis(firstOrderMatrixTimesUnknown[id], 1 / timeStep); rhsResult.AxpyIntoThis(zerothOrderMatrixTimesUnknown[id], -(1 - beta)); rhsPrevious[id] = rhs[id]; return(rhsResult); }
private IVector CalculateRhsImplicit(ILinearSystem linearSystem, bool addRhs) { //TODO: what is the meaning of addRhs? Do we need this when solving dynamic thermal equations? // result = (1-b)* rhsPrevious + beta * rhs + 1/dt * Capacity * temperature - (1-b) * Conductivity * temperature int id = linearSystem.Subdomain.ID; capacityTimesTemperature[id] = provider.MassMatrixVectorProduct(linearSystem.Subdomain, temperature[id]); conductivityTimesTemperature[id] = provider.DampingMatrixVectorProduct(linearSystem.Subdomain, temperature[id]); IVector rhsResult = rhsPrevious[id].LinearCombination(1 - beta, rhs[id], beta); rhsResult.AxpyIntoThis(capacityTimesTemperature[id], 1 / timeStep); rhsResult.AxpyIntoThis(conductivityTimesTemperature[id], -(1 - beta)); rhsPrevious[id] = rhs[id]; return(rhsResult); }
private IVector CalculateRhsImplicit(ILinearSystem linearSystem, int modelNo, bool addRhs) { //TODO: what is the meaning of addRhs? Do we need this when solving dynamic thermal equations? //TODO: stabilizingRhs has not been implemented // result = -dt(conductuvity*temperature + rhs -dt(stabilizingConductivity*temperature + StabilizingRhs)) int id = linearSystem.Subdomain.ID; firstOrderMatrixTimesUnknown[modelNo][id] = providers[modelNo].MassMatrixVectorProduct(linearSystem.Subdomain, unknown[modelNo][id]); secondOrderMatrixTimesUnknown[modelNo][id] = providers[modelNo].DampingMatrixVectorProduct(linearSystem.Subdomain, unknown[modelNo][id]); IVector rhsResult = rhsPrevious[modelNo][id].LinearCombination(1 - beta, rhs[modelNo][id], beta); rhsResult.AxpyIntoThis(firstOrderMatrixTimesUnknown[modelNo][id], 1 / timeStep); rhsResult.AxpyIntoThis(secondOrderMatrixTimesUnknown[modelNo][id], -(1 - beta)); rhsPrevious[modelNo][id] = rhs[modelNo][id]; return(rhsResult); }
private void UpdateDirectionVector(IVectorView preconditionedResidual, IVector direction) { // d = s - sum(β_i * d_i), 0 <= i < currentIteration // β_i = (s * q_i) / (d_i * q_i) direction.CopyFrom(preconditionedResidual); for (int i = 0; i < reorthoCache.Directions.Count; ++i) { double beta = preconditionedResidual.DotProduct(reorthoCache.MatrixTimesDirections[i]) / reorthoCache.DirectionsTimesMatrixTimesDirections[i]; direction.AxpyIntoThis(reorthoCache.Directions[i], -beta); } }
/// <summary> /// See <see cref="IPcgResidualUpdater.UpdateResidual(PcgAlgorithmBase, IVector)"/> /// </summary> public void UpdateResidual(PcgAlgorithmBase pcg, IVector residual) { //TODO: perhaps this should be done in an Initialize() method if (numIterationsBeforeCorrection == int.MinValue) { numIterationsBeforeCorrection = (int)Math.Floor(Math.Sqrt(pcg.Rhs.Length)); } if ((pcg.Iteration % numIterationsBeforeCorrection == 0) && (pcg.Iteration != 0)) //The first iteration uses the correct residual. { // Calculate the exact residual: r = b - A * x ExactResidual.Calculate(pcg.Matrix, pcg.Rhs, pcg.Solution, residual); } else { // Normally the residual vector is updated as: r = r - α * A*d residual.AxpyIntoThis(pcg.MatrixTimesDirection, -pcg.StepSize); } }
public void UpdateResidual(CGAlgorithm cg, IVector residual, out double resDotRes) { // Update the residual vector normally: r = r - α * A*d residual.AxpyIntoThis(cg.MatrixTimesDirection, -cg.StepSize); resDotRes = residual.DotProduct(residual); //TODO: it is weird that this sets resDotRes and cg.ResDotRes // Check if the CG will converge. TODO: Remove duplicate comutations: this check will also be done by CG later. double residualNormRatio = convergence.EstimateResidualNormRatio(cg); // let's pray that ICGResidualConvergence does not mutate any fields bool hasConverged = residualNormRatio <= residualTolerance; // Avoid premature convergence by calculating th exact residual. if (hasConverged) { // Exact residual: r = b - A * x ExactResidual.Calculate(cg.Matrix, cg.Rhs, cg.Solution, residual); // Recalculate the r * r resDotRes = residual.DotProduct(residual); } }
/// <summary> /// Calculates the initial approximation to the linear system's solution vector, by using a series of conjugate direction /// vectors that have been stored previously by PCG during the solution of other linear systems with the same matrix. /// This method should be used to solve linear systems with different right hand side vectors and the same matrix. /// </summary> /// <param name="rhsNew">The right hand side vector of the new linear system.</param> /// <param name="initialSolution"> /// The initial approximation to the solution vector, which PCG will improve. It will be overwritten by this method. /// </param> /// <exception cref="InvalidOperationException">Thrown if there are no direction vectors stored yet.</exception> public void CalculateInitialSolutionFromStoredDirections(IVectorView rhsNew, IVector initialSolution) { //TODO: An implementation by G. Stavroulakis discarded the last stored direction vector at this point. Why? //reorthoCache.RemoveNewDirectionVectorData(1); // x0 = D_nd * x_d, x_d = inv(Q_nd * D_nd) * D_nd^T * b // D_nd = [d_1 ... d_nd], Q_nd = A * D_nd = [q_1 ... q_nd], Q_nd * D_nd = diag([d1*A*d1 ... d_nd*A*d_nd]) for (int i = 0; i < ReorthoCache.Directions.Count; ++i) { // x_d[i] = (d_i * b) / (d_i * q_i) double xd = ReorthoCache.Directions[i].DotProduct(rhsNew) / ReorthoCache.DirectionsTimesMatrixTimesDirections[i]; Debug.Assert(!double.IsNaN(xd)); Debug.Assert(!double.IsPositiveInfinity(xd)); Debug.Assert(!double.IsNegativeInfinity(xd)); // x0 += d_i * x_d[i] initialSolution.AxpyIntoThis(ReorthoCache.Directions[i], xd); } }
/// <summary> /// See <see cref="ICGResidualUpdater.UpdateResidual(CGAlgorithm, IVector, out double)"/> /// </summary> public void UpdateResidual(CGAlgorithm cg, IVector residual, out double resDotRes) { // Normally the residual vector is updated as: r = r - α * A*d residual.AxpyIntoThis(cg.MatrixTimesDirection, -cg.StepSize); resDotRes = residual.DotProduct(residual); }
/// <summary> /// See <see cref="IPcgResidualUpdater.UpdateResidual(PcgAlgorithmBase, IVector)"/> /// </summary> public void UpdateResidual(PcgAlgorithmBase pcg, IVector residual) { // Normally the residual vector is updated as: r = r - α * A*d residual.AxpyIntoThis(pcg.MatrixTimesDirection, -pcg.StepSize); }
/// <summary> /// Performs the operation: /// <paramref name="thisVector"/>[i] = <paramref name="thisVector"/>[i] + <paramref name="otherVector"/>[i], for /// 0 <= i < <paramref name="thisVector"/>.<see cref="IIndexable1D.Length"/> /// = <paramref name="otherVector"/>.<see cref="IIndexable1D.Length"/>. /// The resulting vector overwrites the entries of this <see cref="IVector"/> instance. /// </summary> /// <param name="thisVector"> /// A vector with the same <see cref="IIndexable1D.Length"/> as <paramref name="otherVector"/>. /// </param> /// <param name="otherVector"> /// A vector with the same <see cref="IIndexable1D.Length"/> as <paramref name="thisVector"/>. /// </param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if <paramref name="thisVector"/> and <paramref name="otherVector"/> have different /// <see cref="IIndexable1D.Length"/>. /// </exception> public static void AddIntoThis(this IVector thisVector, IVectorView otherVector) => thisVector.AxpyIntoThis(otherVector, 1.0);
/// <summary> /// Performs the operation: /// <paramref name="thisVector"/>[i] = <paramref name="thisVector"/>[i] - <paramref name="otherVector"/>[i], /// for 0 <= i < <paramref name="thisVector"/>.<see cref="IIndexable1D.Length"/> /// = <paramref name="otherVector"/>.<see cref="IIndexable1D.Length"/>. /// The resulting vector overwrites the entries of this <see cref="IVector"/> instance. /// </summary> /// <param name="thisVector"> /// A vector with the same <see cref="IIndexable1D.Length"/> as <paramref name="otherVector"/>. /// </param> /// <param name="otherVector"> /// A vector with the same <see cref="IIndexable1D.Length"/> as <paramref name="thisVector"/>. /// </param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if <paramref name="thisVector"/> and <paramref name="otherVector"/> have different /// <see cref="IIndexable1D.Length"/>. /// </exception> public static void SubtractIntoThis(this IVector thisVector, IVectorView otherVector) => thisVector.AxpyIntoThis(otherVector, -1.0);