SYNOPSIS
use PerlGSL::DiffEq;
#Differential Equation(s)
sub eqn {
#initial conditions returned if called without parameters
unless (@_) {
return (0,1);
}
my ($t, @y) = @_;
#example: y''(t)==-y(t)
my @derivs = (
$y[1], # y'[0] = y[1]
-$y[0], # y'[1] = - y[0]
);
return @derivs;
}
$sine = ode_solver(\&eqn, [0, 2*3.14, 100]);
DESCRIPTION
This module provides a Perl-ish interface to the Gnu Scientific Library's (GSL) ODEIV2 library, (documentation). This library is the new ordinary differential equation solver as of GSL version 1.15.
NAMESPACE
This module used to be named Math::GSLx::ODEIV2, a name I never liked. After writing interfaces to GSL's integration libraries I decided to unite the modules under a common namespace PerlGSL. This namespace/distribution contains modular interfaces to the GSL. Read more in the documentation for PerlGSL.
INTERFACE STABILITY
This module is in an beta state. It needs more tests and the ability to configure more of the options that the GSL library allows. Currently this module leans on the fact that GSL has an extensive test suite. While the author has put some thought into the interface it may change in the future as the above mentioned functionality is added or as bugs appear. Bug reports are encouraged!
Also, as of version 0.06, support for including a Jacobian of the system has been added, including the step types that this allows, however this functionality is almost totally untested. Until some of the stiff/extreme test cases can be ported from GSL the author is not certain the the functionality has been properly implemented. Sadly t/sine.*
pass even when not properly implemented, which is unnerving. Caveat emptor.
EXPORTED FUNCTIONS
ode_solver
This is the main function of the module.
$solution = ode_solver( $diffeq_code_ref, $t_range)
or
$solution = ode_solver( $diffeq_code_ref, $t_range, $opts_hashref)
or
$solution = ode_solver( [$diffeq_code_ref, $jacobian_code_ref], $t_range, $opts_hashref)
Before detailing how to call ode_solver
, lets see how to construct the differential equation system.
the differential equation system
The differential equation system is defined in a code reference (in the example $diffeq_code_ref
). This code reference (or anonymous subroutine) must have a specific construction:
If called without arguments (i.e.
$diffeq_code_ref->()
) it should return the initial conditions for the system, the number of initial values returned will set the number of differential equations.When called with arguments, the first argument will be time (or the independent parameter) and the rest will be the function values in the same order as the initial conditions. The returns in this case should be the values of the derivatives of the function values.
If one or more of the returned values are not numbers (as determined by Scalar::Util
looks_like_number
), the solver will immediately return all calculations up until (and not including) this step, accompanied by a warning. This may be done intentionally to exit the solve routine earlier than the end time specified in the second argument.Please note that as with other differential equation solvers, any higher order differential equations must be converted into systems of first order differential equations.
Optionally the system may be further described with a code reference which defines the Jacobian of the system (in the example $jacobian_code_ref
). Again, this code reference has a specific construction. The arguments will be passed in exactly the same way as for the equations code reference (though it will not be called without arguments). The returns should be two array references.
The first is the Jacobian matrix formed as an array reference containing array references. It should be square where each dimension is equal to the number of differential equations. Each "row" contains the derivatives of the related differential equations with respect to each dependant parameter, respectively.
[ [ d(dy[0]/dt)/d(y[0]), d(dy[0]/dt)/d(y[1]), ... ], [ d(dy[1]/dt)/d(y[0]), d(dy[1]/dt)/d(y[1]), ... ], ... [ ..., d(dy[n]/dt)/d(y[n])], ]
The second returned array reference contains the derivatives of the differential equations with respect to the independant parameter.
[ d(dy[0]/dt)/dt, ..., d(dy[n]/dt)/dt ]
The Jacobian code reference is only needed for certain step types, those step types whose names end in _j
.
required arguments
ode_solver
requires two arguments, they are as follows:
first argument
The first argument may be either a code reference or an array reference containing one or two code references. In the single code reference form this represents the differential equation system, constructed as described above. In the array reference form, the first argument must be the differential equation system code reference, but now optionally a code reference for the Jacobian of the system may be supplied as the second item.
second argument
The second argument, $t_range
, specifies the time values that are used for the calculation. This may be used one of two ways:
An array reference containing numbers specifying start time, finish time, and number of steps.
A scalar number specifying finish time. In this case the start time will be zero and 100 steps will be used.
optional argument (the options hash reference)
The third argument, $opts_hashref
, is a hash reference containing other options. They are as follows:
type
specifies the step type to be used. The default isrk8pd
. The available step types can be found using the exportable function "get_step_types". Those step types whose name ends in_j
require the Jacobian.h_init
the initial "h" step used by the solver. Defaults to1e-6
.h_max
the maximum "h" step allowed to the adaptive step size solver. Set to zero to use the default value specified the GSL, this is the default behavior if unspecified. Note: the module will croak ifh_init
is set greater thanh_max
, however ifh_init
is not specified and the default would violate this relation,h_init
will be set toh_max
implicitly.Error scaling options. These all refer to the adaptive step size contoller which is well documented in the GSL manual.
epsabs
andepsrel
the allowable error levels (absolute and relative respectively) used in the system. Defaults are1e-6
and0.0
respectively.a_y
anda_dydt
set the scaling factors for the function value and the function derivative respectively. While these may be used directly, these can be set using the shorthand ...scaling
, a shorthand for setting the above option. The available values may bey
meaning{a_y = 1, a_dydt = 0}
(which is the default), oryp
meaning{a_y = 0, a_dydt = 1}
. Note that setting the above scaling factors will override the corresponding field in this shorthand.
return
The return is an array reference of array references. Each inner array reference will contain the time and function value of each function in order as above. This format allows easy loading into PDL if so desired:
$pdl = pdl($solution);
of course one may recover one column by simple use of a map
:
@solution_t_vals = map { $_->[0] } @$solution;
@solution_y1_vals = map { $_->[1] } @$solution;
...
For a usage example see the "SYNOPSIS" for a sine function given by y''(t)=-y(t)
.
EXPORTABLE FUNCTIONS
get_step_types
Returns the available step types which may be specified in the "ode_solver" function's options hashref. Note that those step types whose name end in _j
require the Jacobian.
get_gsl_version
A simple function taking no arguments and returning the version number of the GSL library as specified in gsl/gsl_version.h
. This was originally used for dependency checking but now remains simply for the interested user.
FUTURE GOALS
On systems with PDL installed, I would like to include some mechanism which will store the numerical data in a piddle directly, saving the overhead of creating an SV for each of the pieces of data generated. I envision this happening as transparently as possible when PDL is available. This will probably take some experimentation to get it right.
SEE ALSO
SOURCE REPOSITORY
http://github.com/jberger/PerlGSL-DiffEq
AUTHOR
Joel Berger, <joel.a.berger@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2012 by Joel Berger
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The GSL is licensed under the terms of the GNU General Public License (GPL)