transient ¤
Transient solvers to be used with Diffrax.
Classes:
| Name | Description |
|---|---|
BDF2FactorizedTransientSolver | BDF2 upgrade of :class: |
BDF2RefactoringTransientSolver | BDF2 upgrade of :class: |
BDF2VectorizedTransientSolver | BDF2 upgrade of :class: |
FactorizedTransientSolver | Transient solver using a Modified Newton (frozen-Jacobian) scheme. |
RefactoringTransientSolver | Transient solver with full Newton (quadratic) convergence using |
SDIRK3FactorizedTransientSolver | 3rd-order A-stable SDIRK3 solver with frozen-Jacobian Newton across all stages. |
SDIRK3RefactoringTransientSolver | 3rd-order A-stable SDIRK3 solver with KLU refactor at each Newton iteration. |
SDIRK3VectorizedTransientSolver | 3rd-order A-stable SDIRK3 solver using full Newton-Raphson at each stage. |
VectorizedTransientSolver | Transient solver that works strictly on FLAT (Real) vectors. |
Functions:
| Name | Description |
|---|---|
free_numeric | Dispatch free to the correct backend based on handle type. |
setup_transient | Configures and returns a function for executing transient analysis. |
BDF2FactorizedTransientSolver ¤
Bases: FactorizedTransientSolver
BDF2 upgrade of :class:FactorizedTransientSolver (frozen-Jacobian Newton).
Factors J_eff once at the predictor state and reuses it across all Newton iterations, trading quadratic convergence for cheaper per-iteration cost. The BDF2 Jacobian scaling α₀/h is used when factoring.
BDF2RefactoringTransientSolver ¤
Bases: RefactoringTransientSolver
BDF2 upgrade of :class:RefactoringTransientSolver (KLU refactor per iteration).
Full quadratic Newton convergence via klujax.refactor at each iteration, combined with BDF2 time discretisation for 2nd-order accuracy.
BDF2VectorizedTransientSolver ¤
Bases: VectorizedTransientSolver
BDF2 upgrade of :class:VectorizedTransientSolver.
Implements variable-step BDF2 via the companion method. On the first step Backward Euler is used automatically; from step 2 onward BDF2 is activated. The Jacobian scaling changes from 1/h (BE) to α₀/h (BDF2) where α₀ = (1 + 2ω)/(1 + ω) and ω = h_n/h_{n-1}.
solver_state is a 3-tuple (y_nm1, h_nm1, q_nm1). h_nm1 is initialised to +inf so that ω = 0 on the first step, making the BDF2 formula reduce to Backward Euler via IEEE 754 arithmetic (no branching). q_nm1 caches Q(y_{n-1}) to avoid recomputing it each step.
FactorizedTransientSolver ¤
Bases: VectorizedTransientSolver
Transient solver using a Modified Newton (frozen-Jacobian) scheme.
At each timestep the system Jacobian is assembled and factored once at a predicted state, then reused across all Newton iterations. Compared to a full Newton-Raphson solver this trades quadratic convergence for a much cheaper per-iteration cost — one triangular solve instead of a full factorisation — making it efficient for circuits where the Jacobian varies slowly between steps.
Convergence is linear rather than quadratic, so newton_max_steps is set higher than a standard Newton solver would require. Adaptive damping min(1, 0.5 / max|δy|) is applied at each iteration to stabilise convergence in stiff or strongly nonlinear regions.
Both real and complex assembly paths are supported; the complex path concatenates real and imaginary parts into a single real-valued vector, allowing purely real linear algebra kernels to be reused for frequency-domain-style analyses.
Requires a :class:~circulax.solvers.linear.KLUSplitFactorSolver as the linear_solver — use analyze_circuit(..., backend="klu_split_factor").
RefactoringTransientSolver ¤
Bases: FactorizedTransientSolver
Transient solver with full Newton (quadratic) convergence using klujax.refactor.
At each timestep the Jacobian is factored once at the predicted state to allocate the numeric handle. Each Newton iteration then calls klujax.refactor — which reuses the existing memory and fill-reducing permutation but recomputes L/U values for the current iterate J(y_k) — followed by a triangular solve. This gives full quadratic Newton convergence at a fraction of the cost of re-factoring from scratch each iteration.
Convergence is quadratic so newton_max_steps is set to 20, matching :class:VectorizedTransientSolver. Adaptive damping min(1, 0.5 / max|δy|) is applied at each iteration to stabilise convergence in stiff or strongly nonlinear regions.
Requires :class:~circulax.solvers.linear.KLUSplitQuadratic as the linear_solver — use analyze_circuit(..., backend="klu_split").
SDIRK3FactorizedTransientSolver ¤
Bases: FactorizedTransientSolver
3rd-order A-stable SDIRK3 solver with frozen-Jacobian Newton across all stages.
Factors J_eff = dF/dy + (1/(γh))·dQ/dy once at the predictor state, then reuses it for all Newton iterations in all three SDIRK stages. This is the recommended backend for large sparse circuits — the single factorisation is shared across all stages because SDIRK's constant diagonal γ gives the same effective Jacobian at every stage.
SDIRK3RefactoringTransientSolver ¤
Bases: RefactoringTransientSolver
3rd-order A-stable SDIRK3 solver with KLU refactor at each Newton iteration.
Provides full quadratic Newton convergence via klujax.refactor within each stage, combined with SDIRK3 time discretisation for 3rd-order accuracy.
SDIRK3VectorizedTransientSolver ¤
Bases: VectorizedTransientSolver
3rd-order A-stable SDIRK3 solver using full Newton-Raphson at each stage.
Uses Alexander's L-stable 3-stage SDIRK tableau with the companion method. Each timestep performs 3 sequential Newton solves (one per stage) with the Jacobian reassembled at every iteration. The same solver_state 2-tuple (y_prev, dt_prev) as Backward Euler is used — SDIRK3 is a one-step method.
VectorizedTransientSolver ¤
Bases: AbstractSolver
Transient solver that works strictly on FLAT (Real) vectors.
Delegates complexity handling to the 'linear_solver' strategy.
free_numeric ¤
Dispatch free to the correct backend based on handle type.
klujax.KLUHandleManager exposes .close(), which calls the backend's FFI free function. Duck-typing is used so handles are freed correctly without isinstance checks against concrete backend types.
Source code in circulax/solvers/transient.py
setup_transient ¤
setup_transient(
groups: list,
linear_strategy: CircuitLinearSolver,
transient_solver: AbstractSolver = None,
) -> Callable[..., Solution]
Configures and returns a function for executing transient analysis.
This function acts as a factory, preparing a transient solver that is pre-configured with the circuit's linear strategy. It returns a callable that executes the time-domain simulation using diffrax.diffeqsolve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
groups | list | A list of component groups that define the circuit. | required |
linear_strategy | CircuitLinearSolver | The configured linear solver strategy, typically obtained from | required |
transient_solver | optional | The transient solver class to use. If None, | None |
Returns:
| Type | Description |
|---|---|
Callable[..., Solution] | Callable[..., Any]: A function that executes the transient analysis. |
Callable[..., Solution] | This returned function accepts the following arguments: t0 (float): The start time of the simulation. t1 (float): The end time of the simulation. dt0 (float): The initial time step for the solver. y0 (ArrayLike): The initial state vector of the system. saveat (diffrax.SaveAt, optional): Specifies time points at which to save the solution. Defaults to None. max_steps (int, optional): The maximum number of steps the solver can take. Defaults to 100000. throw (bool, optional): If True, the solver will raise an error on failure. Defaults to False. term (diffrax.AbstractTerm, optional): The term defining the ODE. Defaults to a zero-value ODETerm. stepsize_controller (diffrax.AbstractStepSizeController, optional): The step size controller. Defaults to |
Source code in circulax/solvers/transient.py
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 | |