Skip to content

core.solvers

Numerical ODE solvers used by the simulation engine.

Provides a classical 4th-order Runge-Kutta integrator (rk4th_ode_solver) that advances the internal ballistics state at each time step. Accepts a generic equation callable and a dictionary of state variables, returning updated values after one step of size d_t.

Only the entries in the state-variable dictionary are advanced through the four stages; any other keyword arguments are held constant for the whole step. A source term that depends on an integrated variable (such as the pressure-dependent chamber inflow) must therefore be supplied through the equation callable — for example, as a callable evaluated at each stage pressure — rather than as a precomputed constant.

machwave.core.solvers

Numerical methods for differential equations, optimization, and similar.

rk4th_ode_solver(variables, equation, d_t, **kwargs)

Advance a system of ODEs by one step using the 4th-order Runge-Kutta method.

Parameters:

Name Type Description Default
variables dict[str, float]

Mapping of variable name to current value.

required
equation Callable

Callable returning the derivatives of the variables.

required
d_t float

Time step [s].

required
**kwargs Any

Additional keyword arguments forwarded to equation. These are held constant across all four stages, while variables are advanced; a term that depends on a variables entry must be computed inside equation (or passed as a callable it resolves) so it stays consistent across the stages.

{}

Returns:

Type Description
float

Tuple containing the new values of the variables followed by the

...

averaged auxiliary term; length equals len(variables) + 1.

Source code in machwave/core/solvers/rk4.py
def rk4th_ode_solver(
    variables: dict[str, float],
    equation: Callable,
    d_t: float,
    **kwargs: Any,
) -> tuple[float, ...]:
    """
    Advance a system of ODEs by one step using the 4th-order Runge-Kutta method.

    Args:
        variables: Mapping of variable name to current value.
        equation: Callable returning the derivatives of the variables.
        d_t: Time step [s].
        **kwargs: Additional keyword arguments forwarded to `equation`. These
            are held constant across all four stages, while `variables` are
            advanced; a term that depends on a `variables` entry must be
            computed inside `equation` (or passed as a callable it resolves)
            so it stays consistent across the stages.

    Returns:
        Tuple containing the new values of the variables followed by the
        averaged auxiliary term; length equals `len(variables) + 1`.
    """
    k_1 = equation(**variables, **kwargs)
    k_2 = equation(
        **{
            key: value + 0.5 * k_1[index] * d_t
            for index, (key, value) in enumerate(variables.items())
        },
        **kwargs,
    )
    k_3 = equation(
        **{
            key: value + 0.5 * k_2[index] * d_t
            for index, (key, value) in enumerate(variables.items())
        },
        **kwargs,
    )
    k_4 = equation(
        **{
            key: value + k_3[index] * d_t
            for index, (key, value) in enumerate(variables.items())
        },
        **kwargs,
    )

    derivatives = (
        variables[key]
        + (1 / 6) * (k_1[index] + 2 * (k_2[index] + k_3[index]) + k_4[index]) * d_t
        for index, key in enumerate(variables.keys())
    )

    return (
        *derivatives,
        (1 / 6) * (k_1[-1] + 2 * (k_2[-1] + k_3[-1]) + k_4[-1]),
    )