/// <summary> /// Iterates to a solution while adding a conductive path to ground on all nodes. /// </summary> /// <param name="maxIterations">The maximum number of iterations per step.</param> /// <param name="steps">The number of steps.</param> /// <returns> /// <c>true</c> if the diagonal gmin stepping succeeded; otherwise <c>false</c>. /// </returns> protected bool IterateDiagonalGminStepping(int maxIterations, int steps) { // We will add a DC path to ground to all nodes to aid convergence SpiceSharpWarning.Warning(this, Properties.Resources.Simulations_Biasing_StartDiagonalGminStepping); // We'll hack into the loading algorithm to apply our diagonal contributions var diagonalGmin = Math.Min(Iteration.Gmin, 1e-12); void ApplyGminStep(object sender, LoadStateEventArgs args) => _state.Solver.Precondition((matrix, vector) => ModifiedNodalAnalysisHelper <double> .ApplyDiagonalGmin(matrix, diagonalGmin)); AfterLoad += ApplyGminStep; // We could've ended up with some crazy value, so let's reset it for (var i = 0; i <= _state.Solution.Length; i++) { _state.Solution[i] = 0.0; } // Let's make it a bit easier for our iterations to converge for (var i = 0; i < steps; i++) { diagonalGmin *= 10.0; } // Start GMIN stepping Iteration.Mode = IterationModes.Junction; for (var i = 0; i <= steps; i++) { Iteration.IsConvergent = false; if (!Iterate(maxIterations)) { diagonalGmin = 0.0; SpiceSharpWarning.Warning(this, Properties.Resources.Simulation_Biasing_GminSteppingFailed); break; } diagonalGmin /= 10.0; Iteration.Mode = IterationModes.Float; } // Try one more time without the gmin stepping AfterLoad -= ApplyGminStep; diagonalGmin = 0.0; return(Iterate(maxIterations)); }
/// <summary> /// Iterates towards a solution. /// </summary> /// <param name="maxIterations">The maximum allowed iterations.</param> /// <returns> /// <c>true</c> if the iterations converged to a solution; otherwise, <c>false</c>. /// </returns> /// <exception cref="SpiceSharpException">Thrown if any behavior cannot load the matrix and/or right hand side vector, or if the solution /// is not a number (NaN).</exception> /// <exception cref="SingularException">Thrown if the equation matrix is singular.</exception> protected virtual bool Iterate(int maxIterations) { var solver = _state.Solver; var pass = false; var iterno = 0; try { while (true) { // Load the Y-matrix and right hand side vector Iteration.IsConvergent = true; Load(); iterno++; // Preorder matrix if (!_isPreordered) { solver.Precondition((matrix, vector) => ModifiedNodalAnalysisHelper <double> .PreorderModifiedNodalAnalysis(matrix, solver.Size - solver.Degeneracy)); _isPreordered = true; } if (Iteration.Mode == IterationModes.Junction) { _shouldReorder = true; } if (_shouldReorder) { // Reorder and factor the solver Statistics.ReorderTime.Start(); try { var eliminated = solver.OrderAndFactor(); if (eliminated < solver.Size) { throw new SingularException(eliminated + 1); } _shouldReorder = false; } finally { Statistics.ReorderTime.Stop(); } } else { // Just factor the solver (without losing time reordering) Statistics.FactoringTime.Start(); try { if (!solver.Factor()) { _shouldReorder = true; continue; } } finally { Statistics.FactoringTime.Stop(); } } // The current solution becomes the old solution _state.StoreSolution(); // Solve the equation Statistics.SolveTime.Start(); try { solver.Solve(_state.Solution); } finally { Statistics.SolveTime.Stop(); } // Reset ground nodes solver.GetElement(0).Value = 0.0; _state.Solution[0] = 0.0; _state.OldSolution[0] = 0.0; // Update foreach (var behavior in _updateBehaviors) { behavior.Update(); } // Exceeded maximum number of iterations if (iterno > maxIterations) { return(false); } if (Iteration.IsConvergent && iterno != 1) { Iteration.IsConvergent = IsConvergent(); } else { Iteration.IsConvergent = false; } switch (Iteration.Mode) { case IterationModes.Float: if (_nodesets.Count > 0) { if (pass) { Iteration.IsConvergent = false; } pass = false; } if (Iteration.IsConvergent) { return(true); } break; case IterationModes.Junction: Iteration.Mode = IterationModes.Fix; _shouldReorder = true; break; case IterationModes.Fix: if (Iteration.IsConvergent) { Iteration.Mode = IterationModes.Float; } pass = true; break; case IterationModes.None: Iteration.Mode = IterationModes.Float; break; default: throw new SpiceSharpException(Properties.Resources.Simulations_InvalidInitializationMode); } } } finally { Statistics.Iterations += iterno; } }