예제 #1
0
            /// <summary>
            /// Accepts a solution at the current timepoint.
            /// </summary>
            public virtual void Accept()
            {
                // Store the accepted solution
                State.Solution.CopyTo(States.Value.Solution);

                // When just starting out, we want to copy all the states to the previous states.
                if (BaseTime.Equals(0.0))
                {
                    foreach (var istate in States)
                    {
                        istate.Delta = Parameters.MaxStep;
                        States.Value.State.CopyTo(istate.State);
                    }
                }

                // Accept all the registered states
                foreach (var state in RegisteredStates)
                {
                    state.Accept();
                }

                // Clear the breakpoints
                while (Time > Breakpoints.First)
                {
                    Breakpoints.ClearBreakpoint();
                }
                Break = false;
            }
예제 #2
0
        /// <summary>
        /// Evaluates whether or not the current solution can be accepted.
        /// </summary>
        /// <param name="simulation">The time-based simulation.</param>
        /// <param name="newDelta">The next requested timestep in case the solution is not accepted.</param>
        /// <returns>
        /// <c>true</c> if the time point is accepted; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="SpiceSharp.CircuitException">Timestep {0:e} is too small at time {1:e}".FormatString(newDelta, BaseTime)</exception>
        public override bool Evaluate(TimeSimulation simulation, out double newDelta)
        {
            // Spice 3f5 ignores the first timestep
            if (BaseTime.Equals(0.0))
            {
                newDelta = IntegrationStates[0].Delta;
                return(true);
            }

            var result = base.Evaluate(simulation, out newDelta);

            // Limit the expansion of the timestep
            newDelta = Math.Min(Expansion * IntegrationStates[0].Delta, newDelta);

            // Limit the maximum timestep
            if (newDelta > MaxStep)
            {
                newDelta = MaxStep;
            }

            // If the timestep is consistently made smaller than the minimum timestep, throw an exception
            if (newDelta <= MinStep)
            {
                // If we already tried
                if (_oldDelta <= MinStep)
                {
                    throw new CircuitException("Timestep {0:e} is too small at time {1:e}".FormatString(newDelta, BaseTime));
                }
                newDelta = MinStep;
            }

            return(result);
        }
예제 #3
0
        /// <summary>
        /// Continues the simulation.
        /// </summary>
        /// <param name="simulation">The time-based simulation</param>
        /// <param name="delta">The initial probing timestep.</param>
        public override void Continue(TimeSimulation simulation, ref double delta)
        {
            // Modify the timestep
            delta = Math.Min(delta, MaxStep);

            // Handle breakpoints
            if (Time.Equals(Breakpoints.First) || Breakpoints.First - Time <= MinStep)
            {
                // Cut integration order
                Order = 1;

                // Limit the next timestep
                var mt = Math.Min(_saveDelta, Breakpoints.Delta);
                delta = Math.Min(delta, 0.1 * mt);

                // Spice will divide the first timestep by 10
                if (BaseTime.Equals(0.0))
                {
                    delta /= 10.0;
                }

                // Don't go below MinStep without reason
                delta = Math.Max(delta, 2.0 * MinStep);
            }
            else if (Time + delta >= Breakpoints.First)
            {
                Break      = true;
                _saveDelta = delta;
                delta      = Breakpoints.First - Time;
            }

            base.Continue(simulation, ref delta);
        }
예제 #4
0
 /// <inheritdoc/>
 public void Accept()
 {
     if (BaseTime.Equals(0.0))
     {
         foreach (var state in _states)
         {
             _states.Value.CopyTo(state);
         }
     }
     foreach (var state in _registeredStates)
     {
         state.Accept();
     }
 }
예제 #5
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;
        }
예제 #6
0
            /// <inheritdoc/>
            public virtual void Prepare()
            {
                var delta = Math.Min(Delta, Parameters.MaxStep);

                // Breakpoints
                if (Time.Equals(Breakpoints.First) || Breakpoints.First - Time <= Parameters.MinStep)
                {
                    // Cut integration order
                    Order = 1;

                    // Limit the next timestep
                    var mt = Math.Min(_saveDelta, Breakpoints.Delta);
                    delta = Math.Min(delta, 0.1 * mt);

                    // Spice will divide the first timestep by 10
                    if (BaseTime.Equals(0.0))
                    {
                        delta /= 10.0;
                    }

                    // Don't go below MinStep without reason
                    delta = Math.Max(delta, 2.0 * Parameters.MinStep);
                }
                else if (Time + delta >= Breakpoints.First)
                {
                    Break      = true;
                    _saveDelta = delta;
                    delta      = Breakpoints.First - Time;
                }

                // Start
                States.Accept();
                BaseTime           = Time;
                States.Value.Delta = delta;
                Delta = delta;
            }
예제 #7
0
            /// <inheritdoc/>
            /// <exception cref="TimestepTooSmallException">Thrown when the timestep is too small.</exception>
            public virtual bool Evaluate(double maxTimestep)
            {
                double newDelta;

                maxTimestep.GreaterThan(nameof(maxTimestep), 0);

                // Ignore checks on the first timepoint
                if (BaseTime.Equals(0.0))
                {
                    if (maxTimestep < States.Value.Delta)
                    {
                        Delta = maxTimestep;
                    }
                    else
                    {
                        Delta = States.Value.Delta;
                    }
                    return(true);
                }
                else
                {
                    newDelta = double.PositiveInfinity;

                    // Truncate the timestep
                    foreach (var truncatable in TruncatableStates)
                    {
                        newDelta = Math.Min(newDelta, truncatable.Truncate());
                    }
                    if (newDelta <= 0.0)
                    {
                        throw new TimestepTooSmallException(newDelta, BaseTime);
                    }

                    if (newDelta > 0.9 * States.Value.Delta)
                    {
                        if (Order < MaxOrder)
                        {
                            // Let's see if we can increase the timestep by using a bigger integration order
                            Order++;

                            // Truncate the timestep using the higher order
                            newDelta = double.PositiveInfinity;
                            foreach (var truncatable in TruncatableStates)
                            {
                                newDelta = Math.Min(newDelta, truncatable.Truncate());
                            }
                            if (newDelta <= 0.0)
                            {
                                throw new TimestepTooSmallException(newDelta, BaseTime);
                            }

                            // Is the higher (more expensive) order useful?
                            if (newDelta <= 1.05 * States.Value.Delta)
                            {
                                Order--;
                            }
                        }
                    }
                    else
                    {
                        Delta = Math.Min(newDelta, maxTimestep);
                        return(false);
                    }
                }

                // Limit the expansion of the timestep
                newDelta = Math.Min(Parameters.MaximumExpansion * States.Value.Delta, newDelta);

                // Limit the maximum timestep
                if (newDelta > Parameters.MaxStep)
                {
                    newDelta = Parameters.MaxStep;
                }
                if (newDelta > maxTimestep)
                {
                    newDelta = maxTimestep;
                }

                // Check for timesteps that became too small
                if (newDelta <= Parameters.MinStep)
                {
                    // Was the previously tried timestep already at the minimum?
                    if (States.Value.Delta <= Parameters.MinStep)
                    {
                        throw new TimestepTooSmallException(newDelta, BaseTime);
                    }

                    // Else let's just try one more time with the minimum timestep
                    newDelta = Parameters.MinStep;
                    Order    = 1;
                }

                Delta = newDelta;
                return(true);
            }