Fork me on GitHub

Solvers

The Solver class takes care of

  • initializing the problem
  • running the simulation
  • storing the results efficiently

Using the Solver class

Initialize and Run

You would generally start by picking a system system and a numerical scheme scheme and initialize the solver object as:

solver = Solver(scheme=scheme, system=system)

The most important methods are then initialize() and run().

The initialization method is run as follows, for a given initial data u0:

solver.initialize(u0=u0)

The next method to use is run(), which actually runs the simulation. The required parameter is time which indicates the time span of the simulation:

solver.run(time=1.)

Storage

One of the most valuable features of odelab is the data storage. In many cases, either because the simulation is run for a very long time, or because the dimension of the phase space is very large, the produced data may be significant. In those cases, you do not want the whole data to be stored in memory, especially since the past data is hardly of any interest to the numerical scheme (which only needs a few steps back to move forward).

Convenience Methods

The data may easily be accessed using some convenience methods.

The methods initial() and final() give access to the initial and final state of the system.

The method get_events() may be used to extract some of the produced results, on a given time span, and with a given sampling rate.

Plotting the Data

Components

One may quickly plot the results using the method plot(). The simplest use of that method is to plot all the coordinates on the whole time span, with:

solver.plot()

One may restrict the plotted coordinates using by given them in a list. For instance, to only plot the first and third coordinates:

solver.plot([0,2])

Generalized Components

Note that a method of the corresponding System object may also be used as components (what we call here generalized component). For example, if the system object implements a method energy which computes the energy of a given state, as:

def energy(self, t,u):
    return ...

then it is possible to plot the energy using:

solver.plot('energy')

It is possible to combine it with other components, or other System methods, by gathering them in a list:

solver.plot([0,'energy']) # plot the first coordinate, and the energy

2D Plot

It is also possible to plot one coordinate against another. Suppose that coordinates 0 and 1 are positions in a plane. The trajectory is conveniently plotted with:

solver.plot(1, time_component=0)

The method plot2D() is an alias to the call above. One may thus call:

solver.plot2D(0,1) # plot coordinate 1 against coordinate 0

Retrieving the data

Since the data is stored in a file, the file must be opened when retrieving the data, and closed after that. This is achieved using the open_store() context manager:

with solver.open_store() as events:
    first_component = events[0]

Format of the data

The data is stored in a matrix of size \(N \times T\), where \(N\) is the size of the phase space, and \(T\) is the number of time points. In order to obtain the first component of the simulated vector, you would do as follows:

with solver.open_store() as events:
    events[0] # first component
    events[0,5] # first component at time offset 5
    events[:,0] # the initial condition

Note

Note that the initial and final conditions may be obtained with initial() and final() respectively.

File and simulation name

File Name

odelab always stores the result in a file. For convenience, if no file name is specified, they are stored inside a temporary file.

If you want to create a file in which to store the data, you may do so by using the path parameter when creating the Solver object:

solver = Solver(scheme=scheme, system=system, path='...')

The given path must be either a path to a new file to be created by odelab, or to an existing file of type HDF5. It could, for instance, point to the file storage of an earlier simulation.

Simulation Name

Each simulation has a name, which is also automatically created if none is specified. The name is given at the initialization:

solver.initialize(..., name='my_simulation')

The corresponding simulation may then be loaded at any later time using:

solver = load_solver(path, name)

API

Solver – ODE Solvers

The class Solver takes care of calling the numerical scheme to produce data, and of storing that data.

The higher level class is Solver, which is initialized with an instance of a Scheme class.

odelab.solver.SingleStepSolver

alias of Solver

class odelab.solver.Solver(scheme, system, path=None, init_scheme=None)

General Solver class, that takes care of calling the step function and storing the intermediate results.

exception FinalTimeNotReached

Raised when the final time was not reached within the given max_iter number of iterations.

exception Solver.NotInitialized

Raised when the solver is not properly initialized.

exception Solver.NotRun

Raised when trying to access the events although the solver is empty.

exception Solver.RuntimeError

Raised to relay an exception occurred while running the solver.

exception Solver.Unstable

Raised when the scheme produces NaN values.

Solver.final(process=True)

Convenience method to obtain the last computed value.

Solver.generate(events)

Generates the (t,u) values.

Solver.get_events(t0=None, time=None, sampling_rate=1.0)

Return the events from time t0, during time time, sampled.

Solver.get_u(index, process=True)

Return u[index] after post-processing.

Solver.initial(process=True)

Convenience method to obtain the initial condition.

Solver.initialize(u0=None, t0=0, time=None, name=None)

Initialize the solver to the initial condition \(u(t0) = u0\).

Parameters:
  • u0 (array) – initial condition; if it is not provided, it is set to the previous initial condition.
  • t0 (scalar) – initial time
  • time (scalar) – span of the simulation
  • name (string) – name of this simulation
Solver.open_store(*args, **kwds)

Method to open the data store. Any access to the events must make use of this method:

with solver.open_store() as events:
...
Solver.plot(components=None, plot_exact=True, error=False, time_component=None, t0=None, time=None, **plot_args)

Plot.

Solver.plot2D(time_component=0, other_component=1, *args, **kwargs)

Plot components vs another one

Solver.plot_function(function, *args, **kwargs)

Plot a given function of the state. May be useful to plot constraints or energy.

This is now a convenience function that calls the method plot().
Parameters:function (string) –

name of the method to call on the current system object

Example:the code solver.plot_function('energy') will call the method solver.system.energy on the current stored solution points.
Solver.run(time=None, max_iter=None)

Run the simulation for a given time.

Parameters:
  • time (scalar) – the time span for which to run; if none is given, the default self.time is used
  • max_iter – the maximum number of iterations; if None, an estimate is computed base on the time step and time span
Solver.set_name(name=None)

Set or guess a name for this session.

odelab.solver.load_solver(path, name)

Create a solver object from a path to an hdf5 file.

odelab.solver.load_solver_v2(path, name)

Create a solver object from a path to an hdf5 file.