[TOC]
using System;
using System.Collections.Generic;
using CenterSpace.NMath.Core;
using CenterSpace.NMath.Analysis;
namespace RungeKuttaExample
{
class Program
{
/// <summary>
/// Example illustrating the use of the RungeKuttaSolver class for solving
/// first order initial value differential equations.
/// </summary>
/// <param name="args">Program arguments.</param>
static void Main( string[] args )
{
// Consider the first order initial value problem
// y' = (3 - 4*y)/2*x, y(1) = -4
// which has solution
// y = 0.75 - 19.0/(4*x^2)
// To solve this differential equation using the
// Runge Kutta method, we first construct a FirstOrderInitialValueProblem
// object which contains delegate for computing y' from x and y, and
// the initial values.
NMathFunctions.DoubleBinaryFunction f = delegate( double x, double y )
{
return ( 3.0 - 4.0 * y ) / ( 2.0 * x );
};
double x0 = 1.0;
double y0 = -4.0;
FirstOrderInitialValueProblem prob = new FirstOrderInitialValueProblem { F = f, Y0 = y0, X0 = x0 };
// The Runge Kutta method returns the solution function, f, as a set of tabulated values
// xi and f(xi). The initial x-value, x0 is the x0 of the initial condition. Number of
// specified points and delta determine the remaining xi as
// xi = x0 + i*delta
int numPoints = 3000;
double delta = .0005;
// Construct a first order Runge Kutta solver (also known as Eulers method) and solve
// our first order initial values differential equation.
RungeKuttaSolver solver = new RungeKuttaSolver( numPoints, delta, RungeKuttaSolver.SolverOrder.First );
KeyValuePair<double[], double[]> tabulatedValues = solver.Solve( prob );
// Construct a delegate for the actual solution function for comparison.
NMathFunctions.DoubleUnaryFunction actualSolutionFunction = delegate( double x )
{
return 0.75 - ( 19.0 / ( 4.0 * x * x ) );
};
// The solution to the differential equation is returned as a key-value pair. The
// key is an array of doubles containing the x-values and the value is an array
// containing the y = f(x) values. Below we compare the computed function values
// to the know function values by computing the maximum absolute value of their
// differences (l-infinity norm of the difference).
DoubleVector xValues = new DoubleVector( tabulatedValues.Key );
DoubleVector calculatedSolutionYvalues = new DoubleVector( tabulatedValues.Value );
DoubleVector actualSolutionYvalues = xValues.Apply( actualSolutionFunction );
double maxDiff = ( calculatedSolutionYvalues - actualSolutionYvalues ).InfinityNorm();
Console.WriteLine( "Maximum error using first order Runge Kutta = " + maxDiff );
// Solve the same problem with a second order Runge Kutta method and compute
// the error. Note the error decreases.
solver.Order = RungeKuttaSolver.SolverOrder.Second;
tabulatedValues = solver.Solve( prob );
calculatedSolutionYvalues = new DoubleVector( tabulatedValues.Value );
maxDiff = ( calculatedSolutionYvalues - actualSolutionYvalues ).InfinityNorm();
Console.WriteLine( "Maximum error using second order Runge Kutta = " + maxDiff );
// You can also specify a TabulatedFunction object into which to place the
// solution. We specify a NaturalCubicSpline function and use a fourth order
// Runge Kutta to solve the same problem. Note the solution improves.
TabulatedFunction solutionFunction = new NaturalCubicSpline();
solver.Order = RungeKuttaSolver.SolverOrder.Fourth;
solver.Solve( prob, ref solutionFunction );
maxDiff = 0;
for ( int i = 0; i < solutionFunction.NumberOfTabulatedValues; ++i )
{
double absDiff = Math.Abs( solutionFunction.GetY( i ) - actualSolutionFunction( solutionFunction.GetX( i ) ) );
maxDiff = Math.Max( maxDiff, absDiff );
}
Console.WriteLine( "Maximum error using fourth order Runge Kutta = " + maxDiff );
Console.WriteLine();
Console.WriteLine("Press Enter Key");
Console.Read();
}
}
}
[TOC]