/// <summary> /// A method for computing a solution to a third order IVP ODE using RK4 /// </summary> /// <param name="f1">The first function to be solved</param> /// <param name="f2">The second function to be solved</param> /// <param name="f3">The third function to be solved</param> /// <param name="y0">The initial values for the system</param> /// <param name="a">The lower bound to the range</param> /// <param name="b">The upper bound to the range</param> /// <param name="NumSteps">The number of steps to take in the range</param> /// <returns>A list of points calculated by the function</returns> public List <Vector>[] RK4(double[] y0, double a, double b, int NumSteps, int choice) { List <Vector> odesol1 = new List <Vector>(); double h = (Math.Max(a, b) - Math.Min(a, b)) / (NumSteps - 1.0); double xt = a; double[] yNew = y0, yOld = new double[yNew.Length]; int i = 0; double deriv = 0; Function udash = x => x[2]; Function u2dash = x => x[3]; Function u3dash = x => x[0]; Function kappa1 = x => (1.0 / 3.0) + Math.Sin(x[0]); Function kappa2 = x => (1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0); Function kappa3 = x => (1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0); Function kappa4 = x => (1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0); Function kappa5 = x => (1.0 / 10.0) + Math.Sin(x[0]); Function kappa6 = x => 1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3); Function kappa7 = x => 1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4); while (i < NumSteps) { switch (choice) { case (1): deriv = DrawCurve.RichardsonWithError(kappa1, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 3.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 3.0) + Math.Sin(x[0])) * ((1.0 / 3.0) + Math.Sin(x[0])) * x[2]); break; case (2): deriv = DrawCurve.RichardsonWithError(kappa2, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0))) * x[3] - (((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0)) * ((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0)) * x[2]);; break; case (3): deriv = DrawCurve.RichardsonWithError(kappa3, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0))) * x[3] - (((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0)) * ((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0)) * x[2]); break; case (4): deriv = DrawCurve.RichardsonWithError(kappa4, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0))) * x[3] - (((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0)) * ((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0)) * x[2]); break; case (5): deriv = DrawCurve.RichardsonWithError(kappa5, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 10.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 10.0) + Math.Sin(x[0])) * ((1.0 / 10.0) + Math.Sin(x[0])) * x[2]); break; case (6): deriv = DrawCurve.RichardsonWithError(kappa6, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3))) * x[3] - ((1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3)) * (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3)) * x[2]); break; case (7): deriv = DrawCurve.RichardsonWithError(kappa7, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4))) * x[3] - ((1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4)) * (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4)) * x[2]); break; default: deriv = DrawCurve.RichardsonWithError(kappa1, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 3.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 3.0) + Math.Sin(x[0])) * ((1.0 / 3.0) + Math.Sin(x[0])) * x[2]); break; } odesol1.Add(new Vector(xt, yNew[0], 0)); for (int j = 0; j < yNew.Length; j++) { yOld[j] = yNew[j]; } yNew = RK4Step(udash, u2dash, u3dash, xt, h, yOld); xt = xt + h; i++; } return(new List <Vector>[] { odesol1 }); }
/// <summary> /// A method for computing a solution to a third order IVP ODE using RKF /// </summary> /// <param name="f1">The first function to be solved</param> /// <param name="f2">The second function to be solved</param> /// <param name="f3">The third function to be solved</param> /// <param name="y0">The initial values for the system</param> /// <param name="a">The lower bound to the range</param> /// <param name="b">The upper bound to the range</param> /// <param name="NumSteps">The number of steps to take in the range</param> /// <returns>A list of points calculated by the function</returns> public List <Vector>[] RKF(double[] y0, double a, double b, int NumSteps, int choice) { List <Vector> odesol1 = new List <Vector>(); double h = (Math.Max(a, b) - Math.Min(a, b)) / (NumSteps - 1.0); double xt = a, x0 = 0; double[] yNew = y0, yOld = new double[yNew.Length]; int i = 0; double deriv = 0; List <double[]> resultStep = new List <double[]>(); //double tolerance = 1E-9; double err = 0, tol = 1E-4, /*maxErr = 0, delta = 0,*/ s = 0; double hmin = 1E-9; double hmax = 5; Function udash = x => x[2]; Function u2dash = x => x[3]; Function u3dash = x => x[0]; Function kappa1 = x => (1.0 / 3.0) + Math.Sin(x[0]); Function kappa2 = x => (1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0); Function kappa3 = x => (1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0); Function kappa4 = x => (1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0); Function kappa5 = x => (1.0 / 10.0) + Math.Sin(x[0]); Function kappa6 = x => 1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3); Function kappa7 = x => 1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4); while (i < NumSteps) { /*if (i >= NumSteps) * { * break; * }*/ switch (choice) { case (1): deriv = DrawCurve.RichardsonWithError(kappa1, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 3.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 3.0) + Math.Sin(x[0])) * ((1.0 / 3.0) + Math.Sin(x[0])) * x[2]); break; case (2): deriv = DrawCurve.RichardsonWithError(kappa2, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0))) * x[3] - (((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0)) * ((1.0 / 5.0) + 2 * Math.Sin(x[0]) + 3 * Math.Cos(x[0] / 3.0)) * x[2]);; break; case (3): deriv = DrawCurve.RichardsonWithError(kappa3, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0))) * x[3] - (((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0)) * ((1.0 / 5.0) + Math.Sin(x[0] / 2.0) - Math.Cos(x[0] / 3.0)) * x[2]); break; case (4): deriv = DrawCurve.RichardsonWithError(kappa4, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0))) * x[3] - (((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0)) * ((1.0 / 5.0) + Math.Sin(x[0] / 3.0) + 2 * Math.Cos(x[0] / 2.0)) * x[2]); break; case (5): deriv = DrawCurve.RichardsonWithError(kappa5, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 10.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 10.0) + Math.Sin(x[0])) * ((1.0 / 10.0) + Math.Sin(x[0])) * x[2]); break; case (6): deriv = DrawCurve.RichardsonWithError(kappa6, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3))) * x[3] - ((1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3)) * (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (3)) * x[2]); break; case (7): deriv = DrawCurve.RichardsonWithError(kappa7, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4))) * x[3] - ((1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4)) * (1 + (3.0 / (5 + 4 * Math.Cos(x[0]))) * (4)) * x[2]); break; default: deriv = DrawCurve.RichardsonWithError(kappa5, xt, 1E-6, 10000, 1E-9); u3dash = x => (deriv / ((1.0 / 10.0) + Math.Sin(x[0]))) * x[3] - (((1.0 / 10.0) + Math.Sin(x[0])) * ((1.0 / 10.0) + Math.Sin(x[0])) * x[2]); break; } odesol1.Add(new Vector(xt, yNew[0], 0)); for (int j = 0; j < yNew.Length; j++) { yOld[j] = yNew[j]; } resultStep = RKFStep(udash, u2dash, u3dash, xt, h, yOld); /*for (int j = 0; j < 3; j++) * { * err = Math.Max(err, resultStep[2][j]); * }*/ err = resultStep[2][0]; s = Math.Pow(0.5 * tol / err, 0.25); if (err < tol) { yNew = resultStep[0]; xt = x0 + h; x0 = xt; } if (s < 0.1) { s = 0.1; } else if (s > 4.0) { s = 4.0; } h *= s; if (h > b - x0) { h = b - x0; } if (h > hmax) { h = hmax; } else if (h < hmin) { h = hmin; } i++; err = 0; } deriv = 0; return(new List <Vector>[] { odesol1 }); }