Exemplo n.º 1
0
        /// <summary>
        /// Truncates the timestep based on the states.
        /// </summary>
        /// <param name="sender">The sender (integration method).</param>
        /// <param name="args">The <see cref="TruncateEvaluateEventArgs"/> instance containing the event data.</param>
        protected virtual void TruncateStates(object sender, TruncateEvaluateEventArgs args)
        {
            args.ThrowIfNull(nameof(args));

            // Don't truncate the first step
            if (BaseTime.Equals(0.0))
            {
                return;
            }

            // Truncate!
            var newDelta = args.Delta;

            foreach (var state in TruncatableStates)
            {
                newDelta = Math.Min(newDelta, state.Truncate());
            }

            if (newDelta > 0.9 * IntegrationStates[0].Delta)
            {
                if (Order < MaxOrder)
                {
                    // Try increasing the order
                    Order++;
                    args.Order = Order;

                    // Try truncation again
                    newDelta = args.Delta;
                    foreach (var state in TruncatableStates)
                    {
                        newDelta = Math.Min(newDelta, state.Truncate());
                    }

                    // Increasing the order doesn't make a significant difference
                    if (newDelta <= 1.05 * IntegrationStates[0].Delta)
                    {
                        Order--;
                        args.Order = Order;
                    }
                }
            }
            else
            {
                args.Accepted = false;
            }

            args.Delta = newDelta;
        }
Exemplo n.º 2
0
        /// <summary>
        /// Truncates the timestep using nodes.
        /// </summary>
        /// <param name="sender">The sender (integration method).</param>
        /// <param name="args">The <see cref="T:SpiceSharp.IntegrationMethods.TruncateEvaluateEventArgs" /> instance containing the event data.</param>
        protected override void TruncateNodes(object sender, TruncateEvaluateEventArgs args)
        {
            args.ThrowIfNull(nameof(args));

            // Get the state
            var state   = args.Simulation.RealState;
            var timetmp = double.PositiveInfinity;
            var nodes   = args.Simulation.Variables;

            var delsum = 0.0;

            for (var i = 0; i <= Order; i++)
            {
                delsum += IntegrationStates[i].Delta;
            }

            for (var i = 0; i < nodes.Count; i++)
            {
                var node  = nodes[i];
                var index = node.Index;
                var tol   = Math.Max(Math.Abs(state.Solution[index]), Math.Abs(Prediction[index])) * RelTol + AbsTol;
                var diff  = state.Solution[index] - Prediction[i];

                if (!diff.Equals(0.0))
                {
                    var tmp = tol * TrTol * delsum / (diff * IntegrationStates[0].Delta);
                    tmp = Math.Abs(tmp);
                    switch (Order)
                    {
                    case 0: break;

                    case 1:
                        tmp = Math.Sqrt(tmp);
                        break;

                    default:
                        tmp = Math.Exp(Math.Log(tmp) / (Order + 1));
                        break;
                    }

                    tmp    *= IntegrationStates[0].Delta;
                    timetmp = Math.Min(timetmp, tmp);
                }

                args.Delta = timetmp;
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Truncates the timestep using nodes.
        /// </summary>
        /// <param name="sender">The sender (integration method).</param>
        /// <param name="args">The <see cref="TruncateEvaluateEventArgs" /> instance containing the event data.</param>
        protected override void TruncateNodes(object sender, TruncateEvaluateEventArgs args)
        {
            args.ThrowIfNull(nameof(args));

            // Get the state
            var    state = args.Simulation.RealState;
            double tol, diff, tmp;
            var    timetemp = double.PositiveInfinity;
            var    nodes    = args.Simulation.Variables;
            int    index;

            // In my opinion, the original Spice method is kind of bugged and can be much better...
            switch (Order)
            {
            case 1:
                foreach (var node in nodes)
                {
                    if (node.UnknownType != VariableType.Voltage)
                    {
                        continue;
                    }
                    index = node.Index;

                    // Milne's estimate for the second-order derivative using a Forward Euler predictor and Backward Euler corrector
                    diff = state.Solution[index] - Prediction[index];

                    // Avoid division by zero
                    if (!diff.Equals(0.0))
                    {
                        tol      = Math.Max(Math.Abs(state.Solution[index]), Math.Abs(Prediction[index])) * LteRelTol + LteAbsTol;
                        tmp      = IntegrationStates[0].Delta * Math.Sqrt(Math.Abs(2.0 * TrTol * tol / diff));
                        timetemp = Math.Min(timetemp, tmp);
                    }
                }
                break;

            case 2:
                foreach (var node in nodes)
                {
                    if (node.UnknownType != VariableType.Voltage)
                    {
                        continue;
                    }
                    index = node.Index;

                    // Milne's estimate for the third-order derivative using an Adams-Bashforth predictor and Trapezoidal corrector
                    diff = state.Solution[index] - Prediction[index];
                    var deriv = IntegrationStates[1].Delta / IntegrationStates[0].Delta;
                    deriv = diff * 4.0 / (1 + deriv * deriv);

                    // Avoid division by zero
                    if (!deriv.Equals(0.0))
                    {
                        tol      = Math.Max(Math.Abs(state.Solution[index]), Math.Abs(Prediction[index])) * LteRelTol + LteAbsTol;
                        tmp      = IntegrationStates[0].Delta * Math.Pow(Math.Abs(12.0 * TrTol * tol / deriv), 1.0 / 3.0);
                        timetemp = Math.Min(timetemp, tmp);
                    }
                }
                break;

            default:
                throw new CircuitException("Invalid order");
            }

            // Get the minimum timestep
            args.Delta = timetemp;
        }