Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a hard coded differential equation through Runge-Kutta 4

I'm trying to implement Runge-Kutta for example problems dy/dt = y - t^2 + 1 and dy/dt = t * y + t^3 in C# and I cannot seem to get the output I'm expecting. I have split my program into several classes to try and look at the work individually. I think that my main error is coming from trying to pass a method through the Runge-Kutta process as a variable using a delegate.

Equation Class:

namespace RK4
{
    public class Eqn
    {
        double t;
        double y;
        double dt;
        double b;
        public Eqn(double t, double y, double dt, double b)
        {
            this.t = t;
            this.y = y;
            this.dt = dt;
            this.b = b;
        }
        public void Run1()
        {
            double temp;
            int step = 1;
            RK4 n = new RK4();
            while (t < b)
                    {
                        temp = n.Runge(t, y, dt, FN1);
                        y = temp;
                        Console.WriteLine("At step number {0}, t: {1}, y: {2}", step, t, y);
                        t = t + dt;
                        step++;
                    }
        }
        public void Run2()
        {
            int step = 1;
            RK4 m = new RK4();
            while (t < b)
            {
                y = m.Runge(t, y, dt, FN2);
                Console.WriteLine("At step number {0}, t: {1}, y: {2}", step, t, y);
                t = t + dt;
                step++;
            }
        }
        public static double FN1(double t, double y)
        {
            double x = y - Math.Pow(t, 2) + 1;
            return x;
        }
        public static double FN2(double t, double y)
        {
            double x = t * y + Math.Pow(t, 3);
            return x;
        }
    }
}

Then Runge-Kutta 4 Class:

    namespace RK4
    {
        class RK4
        {
            public delegate double Calc(double t, double y);
            public double Runge(double t, double y, double dt, Calc yp)
            {
                double k1 = dt * yp(t, y);
                double k2 = dt * yp(t + 0.5 * dt, y + k1 * 0.5 * dt);
                double k3 = dt * yp(t + 0.5 * dt, y + k2 * 0.5 * dt);
                double k4 = dt * yp(t + dt, y + k3 * dt);
                return (y + (1 / 6) * (k1 + 2 * k2 + 2 * k3 + k4));
            }
        }
    }

And my Program Class:

namespace RK4
{
    class Program
    {
            static void Main(string[] args)
        {
            RunProgram();
        }
        public static void RunProgram()
        {
            Console.WriteLine("*******************************************************************************");
            Console.WriteLine("************************** Fourth Order Runge-Kutta ***************************");
            Console.WriteLine("*******************************************************************************");
            Console.WriteLine("\nWould you like to implement the fourth-order Runge-Kutta on:");
            string Fn1 = "y' = y - t^2 + 1";
            string Fn2 = "y' = t * y + t^3";
            Console.WriteLine("1) {0}", Fn1);
            Console.WriteLine("2) {0}", Fn2);
            Console.WriteLine("Please enter 1 or 2");
            switch (Int32.Parse(Console.ReadLine()))
            {
                case 1:
                    Console.WriteLine("\nPlease enter beginning of the interval (a):");
                    double a = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter end of the interval (b):");
                    double b = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter the step size (h) to be used:");
                    double h = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter the inital conditions to satisfy y({0}) = d",a);
                    Console.WriteLine("d = ");
                    double d = Double.Parse(Console.ReadLine());
                    Console.Clear();
                    Console.WriteLine("Using the interval [{0},{1}] and step size of {2} and the inital condition of y({3}) = {4}:", a, b, h, a, d);
                    Console.WriteLine("With equation: {0}", Fn1);
                    Eqn One = new Eqn(a, d, h, b);
                    One.Run1();
                    Console.WriteLine("Press enter to exit.");
                    Console.ReadLine();
                    Environment.Exit(1);
                    break;
                case 2:
                    Console.WriteLine("\nPlease enter beginning of the interval (a):");
                    a = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter end of the interval (b):");
                    b = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter the step size (h) to be used:");
                    h = Double.Parse(Console.ReadLine());
                    Console.WriteLine("Please enter the inital conditions to satisfy y({0}) = d",a);
                    Console.WriteLine("d = ");
                    d = Double.Parse(Console.ReadLine());
                    Console.Clear();
                    Console.WriteLine("Using the interval [{0},{1}] and step size of {2} and the inital condition of y({3}) = {4}:", a, b, h, a, d);
                    Console.WriteLine("With equation: {0}", Fn1);
                    Eqn Two = new Eqn(a, d, h, b);
                    Two.Run2();
                    Console.WriteLine("Press enter to exit.");
                    Console.ReadLine();
                    Environment.Exit(1);
                    break;
                default:
                    Console.WriteLine("Improper input, please press enter to exit.");
                    Console.ReadLine();
                    Environment.Exit(1);
                    break;
            }
        }
    }
}

This is not elegant programming by any means but I don't have the working knowledge to know what I'm doing wrong at this point. From what I was reading I thought that the delegate within the RK4 class would be able to pass through my hard coded diff eq.

like image 752
Wesley Lethem Avatar asked Dec 08 '15 15:12

Wesley Lethem


People also ask

Which kind of differential equations can be solved using Runge-Kutta method?

Only first order ordinary differential equations can be solved by using the Runge Kutta 4th order method.

How do you solve the fourth order Runge-Kutta?

Using the Runge-Kutta method of order 4, find y(0.2) if dy/dx = (y – x)/(y + x), y(0) = 1 and h = 0.2. Find the value of y(0.3) from the differential equation dy/dx = 3ex + 2y; y(0) = 0, h = 0.3 by the fourth order Runge-Kutta method.

Does the fourth order Runge-Kutta method use?

The first step uses the forward Euler method and the second step uses the backward Euler method. Collectively, we can say that these two steps use Euler methods. Explanation: The third step of the fourth-order Runge-Kutta method uses midpoint rule to correct the values and the last step uses Simpson's rule.

How do I improve my Runge-Kutta method?

One of the most common methods for solving numerically (1) is Runge-Kutta (RK) method. Most efforts to increase the order of RK method have been accomplished by increasing the number of Taylor's series terms used and thus the number of function evaluations.


1 Answers

You are doing a classical error in the RK4 implementation: Having two variants to position the multiplication with dt to choose from, you are using both.

It is either

k2 = dt*f(t+0.5*dt, y+0.5*k1)

or

k2 = f(t+0.5*dt, y+0.5*dt*k1)

and analogously in the other lines of the algorithm.

like image 61
Lutz Lehmann Avatar answered Oct 17 '22 19:10

Lutz Lehmann