Skip to content

time_integrator

The time_integrator module contains a base class for solvers.

For concrete classes see:

If you're unsure what you're looking for, try odeiter.RK4

TimeIntegrator

Bases: ABC

A base class for solvers.

Source code in src/odeiter/time_integrator.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
class TimeIntegrator(ABC):
    """A base class for solvers."""

    @abstractproperty
    def name(self) -> str:
        ...

    @abstractproperty
    def order(self) -> int:
        """The order of the method. If this method is order $o$
        then cutting the time-step in half should reduce the error
        by a factor of $(1/2)^o$.

        This is limited by machine precision. Additionally, it may not exhibit
        this convergence behavior if the time step is too large, or if the
        forcing term is not smooth enough.
        """
        ...

    @abstractmethod
    def solution_generator(
        self,
        u0: np.ndarray[float],
        rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
        time: TimeDomain,
    ) -> Generator[np.ndarray[float], None, None]:
        """
        Return a generator that yields the solution at each time in time.array.

        Parameters:
            u0: a numpy array of initial conditions. It should have the same shape as
                the solution at each time step.
            rhs: A function rhs(t, u) that is the right-hand-side of the equation
                 u' = rhs(t, u).
            time: An odeiter.TimeDomain instance.

        Returns:
            a generator that yeilds the solution at each time
            step in time.array.
        """
        ...

    def solve(
        self,
        u0: np.ndarray[float],
        rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
        time: TimeDomain,
    ) -> list[np.ndarray[float]]:
        """
        Return a list of the solutions at each time for times in time.array.
        Equivalent to `list(solver.solution_generator(u0, rhs, time))`.

        Parameters:
            u0: a numpy array of initial conditions. It should have the same shape as
                the solution at each time step.
            rhs: A function rhs(t, u) that is the right-hand-side of the equation
                 u' = rhs(t, u).
            time: An odeiter.TimeDomain instance.

        Returns:
            A list of the solution at each time in `time.array`.
        """
        return list(self.solution_generator(u0, rhs, time))

    def t_final(
        self,
        u0: np.ndarray[float],
        rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
        time: TimeDomain,
    ) -> np.ndarray[float]:
        """
        Returns the solution at the final time `time.array[-1]`.
        Equivalent to `solver.solve[-1]`.

        Parameters:
            u0: a numpy array of initial conditions. It should have the same shape as
                the solution at each time step.
            rhs: A function rhs(t, u) that is the right-hand-side of the equation
                 u' = rhs(t, u).
            time: An odeiter.TimeDomain instance.

        Returns:
            The solution at the final time.
        """
        for u in self.solution_generator(u0, rhs, time):
            pass
        return u

order()

The order of the method. If this method is order \(o\) then cutting the time-step in half should reduce the error by a factor of \((1/2)^o\).

This is limited by machine precision. Additionally, it may not exhibit this convergence behavior if the time step is too large, or if the forcing term is not smooth enough.

Source code in src/odeiter/time_integrator.py
16
17
18
19
20
21
22
23
24
25
26
@abstractproperty
def order(self) -> int:
    """The order of the method. If this method is order $o$
    then cutting the time-step in half should reduce the error
    by a factor of $(1/2)^o$.

    This is limited by machine precision. Additionally, it may not exhibit
    this convergence behavior if the time step is too large, or if the
    forcing term is not smooth enough.
    """
    ...

solution_generator(u0, rhs, time) abstractmethod

Return a generator that yields the solution at each time in time.array.

Parameters:

Name Type Description Default
u0 ndarray[float]

a numpy array of initial conditions. It should have the same shape as the solution at each time step.

required
rhs Callable[[float, ndarray[float]], ndarray[float]]

A function rhs(t, u) that is the right-hand-side of the equation u' = rhs(t, u).

required
time TimeDomain

An odeiter.TimeDomain instance.

required

Returns:

Type Description
None

a generator that yeilds the solution at each time

None

step in time.array.

Source code in src/odeiter/time_integrator.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@abstractmethod
def solution_generator(
    self,
    u0: np.ndarray[float],
    rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
    time: TimeDomain,
) -> Generator[np.ndarray[float], None, None]:
    """
    Return a generator that yields the solution at each time in time.array.

    Parameters:
        u0: a numpy array of initial conditions. It should have the same shape as
            the solution at each time step.
        rhs: A function rhs(t, u) that is the right-hand-side of the equation
             u' = rhs(t, u).
        time: An odeiter.TimeDomain instance.

    Returns:
        a generator that yeilds the solution at each time
        step in time.array.
    """
    ...

solve(u0, rhs, time)

Return a list of the solutions at each time for times in time.array. Equivalent to list(solver.solution_generator(u0, rhs, time)).

Parameters:

Name Type Description Default
u0 ndarray[float]

a numpy array of initial conditions. It should have the same shape as the solution at each time step.

required
rhs Callable[[float, ndarray[float]], ndarray[float]]

A function rhs(t, u) that is the right-hand-side of the equation u' = rhs(t, u).

required
time TimeDomain

An odeiter.TimeDomain instance.

required

Returns:

Type Description
list[ndarray[float]]

A list of the solution at each time in time.array.

Source code in src/odeiter/time_integrator.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def solve(
    self,
    u0: np.ndarray[float],
    rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
    time: TimeDomain,
) -> list[np.ndarray[float]]:
    """
    Return a list of the solutions at each time for times in time.array.
    Equivalent to `list(solver.solution_generator(u0, rhs, time))`.

    Parameters:
        u0: a numpy array of initial conditions. It should have the same shape as
            the solution at each time step.
        rhs: A function rhs(t, u) that is the right-hand-side of the equation
             u' = rhs(t, u).
        time: An odeiter.TimeDomain instance.

    Returns:
        A list of the solution at each time in `time.array`.
    """
    return list(self.solution_generator(u0, rhs, time))

t_final(u0, rhs, time)

Returns the solution at the final time time.array[-1]. Equivalent to solver.solve[-1].

Parameters:

Name Type Description Default
u0 ndarray[float]

a numpy array of initial conditions. It should have the same shape as the solution at each time step.

required
rhs Callable[[float, ndarray[float]], ndarray[float]]

A function rhs(t, u) that is the right-hand-side of the equation u' = rhs(t, u).

required
time TimeDomain

An odeiter.TimeDomain instance.

required

Returns:

Type Description
ndarray[float]

The solution at the final time.

Source code in src/odeiter/time_integrator.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def t_final(
    self,
    u0: np.ndarray[float],
    rhs: Callable[[float, np.ndarray[float]], np.ndarray[float]],
    time: TimeDomain,
) -> np.ndarray[float]:
    """
    Returns the solution at the final time `time.array[-1]`.
    Equivalent to `solver.solve[-1]`.

    Parameters:
        u0: a numpy array of initial conditions. It should have the same shape as
            the solution at each time step.
        rhs: A function rhs(t, u) that is the right-hand-side of the equation
             u' = rhs(t, u).
        time: An odeiter.TimeDomain instance.

    Returns:
        The solution at the final time.
    """
    for u in self.solution_generator(u0, rhs, time):
        pass
    return u