Skip to content

Solvers

Solver(simulation, t_end)

Bases: ABC

Base class for system integrators. All subclasses must implement a run method.

PARAMETER DESCRIPTION
simulation

an instance of Simulation to solve.

TYPE: Simulation

t_end

positive integer at which to stop the simulation.

TYPE: int

Source code in psymple/simulate/solvers/solver.py
def __init__(self, simulation: Simulation, t_end: int):
    """
    Instantiate a solver.

    Args:
        simulation: an instance of `Simulation` to solve.
        t_end: positive integer at which to stop the simulation.
    """
    if t_end <= 0 or not isinstance(t_end, int):
        raise ValueError(
            "Simulation time must terminate at a positive integer, "
            f"not '{t_end}'."
        )
    self.t_end = t_end
    self.simulation = simulation

ContinuousIntegrator(simulation, t_end)

Bases: Solver

An interface to scipy.integrate.solve_ivp. The input from the simulation object is manipulated into a form acceptable by the scipy solver and run.

Using another solver

The attribute _callable created on instantiation is a function with signature (t,y) which is a form accepted by, or easily coerced into, many other python-implemented ODE solvers.

PARAMETER DESCRIPTION
simulation

an instance of Simulation to solve.

TYPE: Simulation

t_end

positive integer at which to stop the simulation.

TYPE: int

Source code in psymple/simulate/solvers/scipy_integrator.py
def __init__(self, simulation: Simulation, t_end: int):
    """
    Create a `ContinuousIntegrator` instance.

    Args:
        simulation: an instance of `Simulation` to solve.
        t_end: positive integer at which to stop the simulation.
    """
    super().__init__(simulation, t_end)
    self.simulation._compute_substitutions()
    self._callable = self._wrap_for_solve_ivp()

run()

Run the solver according to its parameters.

Source code in psymple/simulate/solvers/scipy_integrator.py
def run(self):
    """
    Run the solver according to its parameters.
    """
    # Initial values are defined as the most recent value in the time series
    initial_values = [v.time_series[-1] for v in self.simulation.variables.values()]
    res = solve_ivp(
        self._callable, [0, self.t_end], initial_values, dense_output=True
    )
    # Assign the interpolating solution object to the simulation
    self.simulation.solution = res.sol
    # Update time and variable time series with simulation result
    time_series = arange(0, self.t_end, 0.1)
    self.simulation.time.time_series = time_series
    for i, v in enumerate(self.simulation.variables.values()):
        v.time_series = res.sol(time_series)[i]

DiscreteIntegrator(simulation, t_end, n_steps)

Bases: Solver

A forward Euler method integrator.

Warning

This is a very rudimentary solver, and performs no accuracy checks or optimisation. It is primarily intended for prototyping or unit testing certain features since its behaviour is fully controlled.

PARAMETER DESCRIPTION
simulation

an instance of Simulation to solve.

TYPE: Simulation

t_end

positive integer at which to stop the simulation.

TYPE: int

n_steps

the number of substeps to compute per time unit.

TYPE: int

Source code in psymple/simulate/solvers/discrete_integrator.py
def __init__(self, simulation: Simulation, t_end: int, n_steps: int):
    """
    Create a `DiscreteIntegrator` instance.

    Args:
        simulation: an instance of `Simulation` to solve.
        t_end: positive integer at which to stop the simulation.
        n_steps: the number of substeps to compute per time unit.
    """
    super().__init__(simulation, t_end)
    self.n_steps = n_steps

run()

Run the solver according to its parameters.

Source code in psymple/simulate/solvers/discrete_integrator.py
def run(self):
    """
    Run the solver according to its parameters.
    """
    for i in range(self.t_end):
        self._advance_time_unit(self.n_steps)