Exemple #1
0
 public void ChangeStep()
 {
     dt = dt / 2.0;
     if (dt < epsilon)
     {
         throw new ArgumentException("Cannot generate numerical solution");
     }
     zn = NordsieckState.Rescale(zn, 0.5d);
 }
Exemple #2
0
        /// <summary>
        /// Implementation of Gear's BDF method with dynamically changed step size and order. Order changes between 1 and 3.
        /// </summary>
        /// <param name="t0">Initial time point</param>
        /// <param name="x0">Initial phase vector</param>
        /// <param name="f">Right parts of the system</param>
        /// <param name="opts">Options for accuracy control and initial step size</param>
        /// <returns>Sequence of infinite number of solution points.</returns>
        public static IEnumerable <SolPoint> GearBDF(double t0, Vector x0, Func <double, Vector, Vector> f, Options opts)
        {
            double t = t0;
            Vector x = x0.Clone();
            int    n = x0.Length;

            double tout = t0;
            Vector xout = new Vector();

            if (opts.OutputStep > 0) // Store previous solution point if OutputStep is specified (non-zero)
            {
                xout  = x0.Clone();
                tout += opts.OutputStep;
            }

            // Firstly, return initial point
            yield return(new SolPoint(t0, x0.Clone()));

            //Initial step size.
            Vector dx = f(t0, x0).Clone();
            double dt;

            if (opts.InitialStep != 0)
            {
                dt = opts.InitialStep;
            }
            else
            {
                var tol = opts.RelativeTolerance;
                var ewt = Vector.Zeros(n);
                var ywt = Vector.Zeros(n);
                var sum = 0.0;
                for (int i = 0; i < n; i++)
                {
                    ewt[i] = opts.RelativeTolerance * Math.Abs(x[i]) + opts.AbsoluteTolerance;
                    ywt[i] = ewt[i] / tol;
                    sum    = sum + (double)dx[i] * dx[i] / (ywt[i] * ywt[i]);
                }

                dt = Math.Sqrt(tol / ((double)1.0d / (ywt[0] * ywt[0]) + sum / n));
            }

            dt = Math.Min(dt, opts.MaxStep);
            var resdt = dt;

            int qmax  = 5;
            int qcurr = 2;


            //Compute Nordstieck's history matrix at t=t0;
            Matrix zn = new Matrix(n, qmax + 1);

            for (int i = 0; i < n; i++)
            {
                zn[i, 0] = x[i];
                zn[i, 1] = dt * dx[i];
                for (int j = qcurr; j < qmax + 1; j++)
                {
                    zn[i, j] = 0.0d;
                }
            }

            var eold = Vector.Zeros(n);

            NordsieckState currstate = new NordsieckState();

            currstate.delta    = 0.0d;
            currstate.Dq       = 0.0d;
            currstate.dt       = dt;
            currstate.en       = eold;
            currstate.tn       = t;
            currstate.xn       = x0;
            currstate.qn       = qcurr;
            currstate.qmax     = qmax;
            currstate.nsuccess = 0;
            currstate.zn       = zn;
            currstate.rFactor  = 1.0d;

            bool isIterationFailed = false;

            //Can produce any number of solution points
            while (true)
            {
                // Reset fail flag
                isIterationFailed = false;

                // Predictor step
                var z0 = currstate.zn.Clone();
                currstate.zn = NordsieckState.ZNew(currstate.zn);
                currstate.en = Vector.Zeros(n);
                currstate.xn = currstate.zn.CloneColumn(0);

                // Corrector step
                currstate = PredictorCorrectorScheme(currstate, ref isIterationFailed, f, opts);

                if (isIterationFailed) // If iterations are not finished - bad convergence
                {
                    currstate.zn       = z0;
                    currstate.nsuccess = 0;
                    currstate.ChangeStep();
                }
                else // Iterations finished
                {
                    var r = Math.Min(1.1d, Math.Max(0.2d, currstate.rFactor));

                    if (currstate.delta >= 1.0d)
                    {
                        if (opts.MaxStep < Double.MaxValue)
                        {
                            r = Math.Min(r, opts.MaxStep / currstate.dt);
                        }

                        if (opts.MinStep > 0)
                        {
                            r = Math.Max(r, opts.MinStep / currstate.dt);
                        }

                        r = Math.Min(r, opts.MaxScale);
                        r = Math.Max(r, opts.MinScale);

                        currstate.dt = currstate.dt * r; // Decrease step
                        currstate.zn = NordsieckState.Rescale(currstate.zn, r);
                    }
                    else
                    {
                        // Output data
                        if (opts.OutputStep > 0) // Output points with specified step
                        {
                            while (currstate.tn <= tout && tout <= currstate.tn + currstate.dt)
                            {
                                yield return(new SolPoint(tout, Vector.Lerp(tout, currstate.tn,
                                                                            xout, currstate.tn + currstate.dt, currstate.xn)));

                                tout += opts.OutputStep;
                            }
                            Vector.Copy(currstate.xn, xout);
                        }
                        else // Output each point

                        {
                            yield return(new SolPoint(currstate.tn + currstate.dt, currstate.xn));
                        }

                        currstate.tn = currstate.tn + currstate.dt;

                        if (opts.MaxStep < Double.MaxValue)
                        {
                            r = Math.Min(r, opts.MaxStep / currstate.dt);
                        }

                        if (opts.MinStep > 0)
                        {
                            r = Math.Max(r, opts.MinStep / currstate.dt);
                        }

                        r = Math.Min(r, opts.MaxScale);
                        r = Math.Max(r, opts.MinScale);

                        currstate.dt = currstate.dt * r;

                        currstate.zn = NordsieckState.Rescale(currstate.zn, r);
                    }
                }
            }
        }