← All NMath Code Examples
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports CenterSpace.NMath.Core
Namespace CenterSpace.NMath.Examples.VisualBasic
<summary>
A .NET Example in Visual Basic showing how to use the RungeKutta45OdeSolver
to solve a nonstiff set of equations describing the motion of a rigid body
without external forces:
y1= y2*y3, y1(0) = 0
y2= -y1*y3, y2(0) = 1
y3= -0.51*y1*y2, y3(0) = 1
</summary>
Module RungeKutta45OdeSolverExample
Sub Main()
Console.WriteLine()
Simple example solving the system of differential equations of
motion for a rigid body with no external forces. The equations
are defined above by the function Rigid().
Console.WriteLine("Simple Solve -----------------------------------")
Console.WriteLine()
SimpleSolve()
Console.WriteLine(Environment.NewLine)
A mass matrix and an output function are options that may
be specified for the solver. The output function is a callback
that is invoked at initialization, each integration step and
after the conclusion of the last integration step. Thus the
solution process can be monitored, and even terminated Imports
the output function.
Console.WriteLine("Output Function and Mass Matrix Solve ---------")
Console.WriteLine()
WithOutputFunctionAndMassMatrix()
Console.WriteLine(Environment.NewLine)
The above examples use the NMath class RungeKutta45OdeSolver. This
class uses an adaptive algorithm to figure out the optimal time step
size at each integration step. NMath also supplies a class,
RungeKutta5OdeSolver that does NOT use an adaptive step size
algorithm, allowing the user to specify the time values for
each integration step.
Console.WriteLine("Non-adaptive Step Size -------------------------")
Console.WriteLine()
NonAdaptiveStepSizeExample()
Console.WriteLine()
Console.WriteLine("Press Enter Key")
Console.Read()
End Sub
Sub SimpleSolve()
Construct the solver.
Dim Solver As New RungeKutta45OdeSolver()
Construct the time span vector. If this vector contains exactly
two points, the solver interprets these to be the initial and
final time values. Step size and function output points are
provided automatically by the solver. Here the initial time
value t0 is 0.0 and the final time value is 12.0.
Dim TimeSpan As New DoubleVector(0.0, 12.0)
Initial y vector.
Dim y0 As New DoubleVector(0.0, 1.0, 1.0)
Construct solver options. Here we set the absolute and relative tolerances to use.
At the ith integration step the error, e(i) for the estimated solution
y(i) satisfies
e(i) <= max(RelativeTolerance * Math.Abs(y(i)), AbsoluteTolerance(i))
The solver can increase the number of output points by a specified factor
called Refine (useful for creating smooth plots). The default value is
4. Here we set the Refine value to 1, meaning we do not wish any
additional output points to be added by the solver.
Dim SolverOptions As New RungeKutta45OdeSolver.Options()
SolverOptions.AbsoluteTolerance = New DoubleVector(0.0001, 0.0001, 0.00001)
SolverOptions.RelativeTolerance = 0.0001
SolverOptions.Refine = 1
Construct the delegate representing our system of differential equations...
Dim odeFunction As New Func(Of Double, DoubleVector, DoubleVector)(AddressOf Rigid)
...and solve. The solution is returned as a key/value pair. The first Keyelement of the pair is
the time span vector, the second Valueelement of the pair is the corresponding solution values.
That is, if the computed solution function is y then
y(soln.Key(i)) = soln.Value(i)
Dim Soln As RungeKutta45OdeSolver.Solution(Of DoubleMatrix) = Solver.Solve(odeFunction, TimeSpan, y0, SolverOptions)
Console.WriteLine("T = " & Soln.T.ToString("G5"))
Console.WriteLine("Y = ")
Console.WriteLine(Soln.Y.ToTabDelimited("G5"))
End Sub
<summary>
Function describing the system of differential equations.
</summary>
<param name="t">Time parameter.</param>
<param name="y">State vector.</param>
<returns>The vector of values of the derivatives of the functions
at a specified time t and function values y:
y1= y2*y3,
y2= -y1*y3,
y3= -0.51*y1*y2
</returns>
Function Rigid(ByVal T As Double, ByVal Y As DoubleVector) As DoubleVector
Dim dy As New DoubleVector(3)
dy(0) = Y(1) * Y(2)
dy(1) = -Y(0) * Y(2)
dy(2) = -0.51 * Y(0) * Y(1)
Return dy
End Function
<summary>
The output function to be called by the ODE solver at each integration step.
If this function returns true the solver continues with the next step, if
it returns false the solver is halted.
This output function just outputs to the console upon each invocation.
</summary>
<param name="t">The time value at the current integration step. If flag is equal to Initialize,
this will be the initial time value t0.</param>
<param name="y">The calculated function value at the current integration step. If flag is equal to Initialize,
this will be the initial function value y0.</param>
<param name="flag">Flag indicating what stage the solver is at:
Initialize - before solving begins. y and t values are the problems initial values.
IntegrationStep - just finished an integration step. y and t values are the values
calculated at that step.
Done - just finished last step. y and t values are the last values in the returned
solution.</param>
<returns>true if the solver is to proceed with the calculation, false forces the solver
to stop.</returns>
Function OutputFunction(ByVal T As DoubleVector, ByVal Y As DoubleMatrix, ByVal Flag As RungeKutta45OdeSolver.OutputFunctionFlag) As Boolean
If Flag = RungeKutta45OdeSolver.OutputFunctionFlag.Initialize Then
Console.WriteLine("Output function : Initialize")
Return True
End If
If Flag = RungeKutta45OdeSolver.OutputFunctionFlag.IntegrationStep Then
Console.WriteLine("Output function Integration step:")
Console.WriteLine("t = " + T.ToString("G5"))
Console.WriteLine("y = ")
Console.WriteLine(Y.ToTabDelimited("G5"))
Return True
End If
If Flag = RungeKutta45OdeSolver.OutputFunctionFlag.Done Then
Console.WriteLine("Output function: Done")
Return True
End If
Console.WriteLine("Output function: Unknown flag")
Return False
End Function
Sub WithOutputFunctionAndMassMatrix()
Construct the solver.
Dim Solver As New RungeKutta45OdeSolver()
Construct the time span vector. If this vector contains exactly
two points, the solver interprets these to be the initial and
final time values. Step size and function output points are
provided automatically by the solver. Here the initial time
value t0 is 0.0 and the final time value is 12.0.
Dim TimeSpan As New DoubleVector(0.0, 12.0)
Initial y vector.
Dim y0 As New DoubleVector(0.0, 1.0, 1.0)
Construct solver options. Here we set the absolute and relative tolerances to use.
At the ith integration step the error, e(i) for the estimated solution
y(i) satisfies
e(i) <= max(RelativeTolerance*Math.Abs(y(i)), AbsoluteTolerance(i))
Dim SolverOptions As New RungeKutta45OdeSolver.Options()
SolverOptions.AbsoluteTolerance = New DoubleVector(0.0001, 0.0001, 0.00001)
SolverOptions.OutputFunction = New Func(Of DoubleVector, DoubleMatrix, RungeKutta45OdeSolver.OutputFunctionFlag, Boolean)(AddressOf OutputFunction)
SolverOptions.RelativeTolerance = 0.0001
Construct the delegate representing our system of differential equations...
Dim odeFunction As New Func(Of Double, DoubleVector, DoubleVector)(AddressOf Rigid)
...and solve. The solution is returned as a key/value pair. The first Keyelement of the pair is
the time span vector, the second Valueelement of the pair is the corresponding solution values.
That is, if the computed solution function is y then
y(soln.Key(i)) = soln.Value(i)
Dim Soln As RungeKutta45OdeSolver.Solution(Of DoubleMatrix) = Solver.Solve(odeFunction, TimeSpan, y0, SolverOptions)
Print out a few values
Console.WriteLine("Number of time values = " & Soln.T.Length)
For I As Integer = 0 To Soln.T.Length - 1
If (I Mod 7 = 0) Then
Console.WriteLine("y({0}) = {1}", Soln.T(I).ToString("G5"), Soln.Y.Row(I).ToString("G5"))
End If
Next
We can also specify a mass matrix in the solver options...
Dim M As New DoubleMatrix("3x3[1 2 1 2 1 3 9 4 1]")
SolverOptions.MassMatrix = M
Soln = Solver.Solve(odeFunction, TimeSpan, y0, SolverOptions)
Print out a few values for the mass matrix solution.
Console.WriteLine(Environment.NewLine & "With constant mass matrix:")
Console.WriteLine("Number of time values = " & Soln.T.Length)
For I = 0 To Soln.T.Length - 1
If (I Mod 7 = 0) Then
Console.WriteLine("y({0}) = {1}", Soln.T(I).ToString("G5"), Soln.Y.Row(I).ToString("G5"))
End If
Next
You can also solve with default values for all the options
Soln = Solver.Solve(odeFunction, TimeSpan, y0)
End Sub
Sub NonAdaptiveStepSizeExample()
Construct the solver.
Dim Solver As New RungeKutta5OdeSolver()
Construct the time span vector. Imports the non-adaptive solve
function, integration steps will be performed only at the points
in the time span vector.
Dim TimeSpan As New DoubleVector(85, 0, 0.15)
Initial y vector.
Dim y0 As New DoubleVector(0.0, 1.0, 1.0)
Construct the delegate representing our system of differential equations...
Dim odeFunction As New Func(Of Double, DoubleVector, DoubleVector)(AddressOf Rigid)
...and solve. Each row of the returned matrix contains the calculated function values at the
corresponding point in the input time span vector.
Dim Soln As DoubleMatrix = Solver.Solve(odeFunction, TimeSpan, y0)
Print out a few values
Console.WriteLine("Number of time values = " & TimeSpan.Length)
For I As Integer = 0 To TimeSpan.Length - 1
If (I Mod 7 = 0) Then
Console.WriteLine("y({0}) = {1}", TimeSpan(I).ToString("G5"), Soln.Row(I).ToString("G5"))
End If
Next
Solve with a constant mass matrix
Dim M As New DoubleMatrix("3x3[1 2 1 2 1 3 9 4 1]")
Dim SolverOptions As New RungeKutta5OdeSolver.Options()
SolverOptions.MassMatrix = M
Soln = Solver.Solve(odeFunction, TimeSpan, y0, SolverOptions)
Print out a few values for the mass matrix solution.
Console.WriteLine(Environment.NewLine & "With constant mass matrix:")
Console.WriteLine("Number of time values = " & TimeSpan.Length)
For I As Integer = 0 To TimeSpan.Length - 1
If (I Mod 7 = 0) Then
Console.WriteLine("y({0}) = {1}", TimeSpan(I).ToString("G5"), Soln.Row(I).ToString("G5"))
End If
Next
Solve with an output function that is a class member function.
Dim outputFunctionObject As New SimpleNonAdaptiveOutput()
SolverOptions.OutputFunction = New Func(Of Double, DoubleVector, RungeKutta45OdeSolver.OutputFunctionFlag, Boolean)(AddressOf outputFunctionObject.OutputFunction)
Soln = Solver.Solve(odeFunction, TimeSpan, y0, SolverOptions)
End Sub
End Module
Class containing an example output function for the Dormand Prince ODE non-adaptive solve
function. The class does nothing but accumulate the solutions at each solver
integration stop.
Class SimpleNonAdaptiveOutput
Gets and sets a list of the time values.
Private _T As List(Of Double) = Nothing
Public Property T As List(Of Double)
Get
Return _T
End Get
Set(ByVal value As List(Of Double))
_T = value
End Set
End Property
Gets and sets a list of the calculated function values.
Private _Y As List(Of DoubleVector) = Nothing
Public Property Y As List(Of DoubleVector)
Get
Return _Y
End Get
Set(ByVal value As List(Of DoubleVector))
_Y = value
End Set
End Property
Gets and sets a flag indicating whether or not the output
function/class has been initialized.
Private _Init As Boolean = False
Public Property IsInitialized As Boolean
Get
Return _Init
End Get
Set(ByVal value As Boolean)
_Init = value
End Set
End Property
Flag indicating the output function is done being invoked.
Private _IsDone As Boolean = False
Public Property IsDone As Boolean
Get
Return _IsDone
End Get
Set(ByVal value As Boolean)
_IsDone = value
End Set
End Property
Constructs and initializes a SimpleNonAdaptiveOutput object.
Public Sub SimpleNonAdaptiveOutput()
IsInitialized = False
IsDone = False
T = Nothing
Y = Nothing
End Sub
<summary>
The output function to be called by the ODE solver at each integration step. If this function returns true
the solver continues with the next step, if it returns false the solver is halted.
</summary>
<param name="Time">The time value at the current integration step. If flag is equal to Initialize,
this will be the initial time value t0.</param>
<param name="YValue">The calculated function value at the current integration step. If flag is equal to Initialize,
this will be the initial function value y0.</param>
<param name="Flag">Flag indicating what stage the solver is at:
Initialize - before solving begins. y and t values are the problems initial values.
IntegrationStep - just finished an integration step. y and t values are the values
calculated at that step.
Done - just finished last step. y and t values are the last values in the returned
solution.</param>
<returns>true if the solver is to proceed with the calculation, false forces the solver
to stop.</returns>
Public Function OutputFunction(ByVal Time As Double, ByVal YValue As DoubleVector, ByVal Flag As RungeKutta45OdeSolver.OutputFunctionFlag) As Boolean
If (Flag = RungeKutta45OdeSolver.OutputFunctionFlag.Initialize) Then
T = New List(Of Double)()
T.Add(Time)
Y = New List(Of DoubleVector)()
Y.Add(YValue)
IsInitialized = True
IsDone = False
Return True
End If
If (Flag = RungeKutta45OdeSolver.OutputFunctionFlag.Done) Then
IsDone = True
T.Add(Time)
Y.Add(YValue)
Return True
End If
If (Flag = RungeKutta45OdeSolver.OutputFunctionFlag.IntegrationStep) Then
T.Add(Time)
Y.Add(YValue)
Return True
End If
Throw New InvalidArgumentException("Unknown output function flag: " + Flag)
End Function
End Class
End Namespace
← All NMath Code Examples