Skip to content

Preconditioners

Iterative solvers accept an optional preconditioner through the M keyword, consistent with scipy.sparse.linalg.cg and cupyx.scipy.sparse.linalg.cg.

OpenSees assembles the system matrix A during solve, not when you construct the solver. Pass a callable M(A); OpenSees invokes it when the matrix structure or coefficients change, and reuses the cached result when matrix_status='UNCHANGED'. Use a built-in preconditioner from openseespy_solvers.scipy.precond or openseespy_solvers.cupy.precond, or supply your own callable M(A).

Built-in preconditioners

Pass the built-in callable to M= on an iterative solver such as cg() (do not call it yourself):

from openseespy_solvers.scipy import cg, precond

solver = cg(rtol=1e-8, M=precond.jacobi)
from openseespy_solvers.cupy import cg, precond

solver = cg(rtol=1e-8, M=precond.jacobi)

When a built-in accepts extra keyword arguments (for example drop_tol on ilu), wrap it in a lambda so M stays a single-argument callable:

solver = cg(
    rtol=1e-8,
    M=lambda A: precond.ilu(A, drop_tol=1e-4, fill_factor=10),
)

scipy

openseespy_solvers.scipy.precond provides:

jacobi : M = diag(1 / diag(A)).

ilu : Incomplete LU as a LinearOperator; extra keywords are forwarded to scipy.sparse.linalg.spilu.

direct : Full sparse factorization as a LinearOperator, primarily for lobpcg M=. Pass a direct solver such as spsolve(), e.g. M=precond.direct(spsolve()).

cupy

openseespy_solvers.cupy.precond provides the same names on GPU:

jacobi : Diagonal preconditioner as a device LinearOperator (element-wise apply).

ilu : Incomplete LU via cupyx.scipy.sparse.linalg.spilu. Defaults to fill_factor=1 so factorization runs on the GPU with no fill-in (ILU(0)-like). Other fill_factor values use scipy.sparse.linalg on CPU for the factorization; only solve stays on GPU.

direct : Full sparse factorization as a LinearOperator, primarily for lobpcg M=. Pass a direct solver such as direct_solver(), e.g. M=precond.direct(direct_solver()).

Your own preconditioner

Define a function M(A) that returns a LinearOperator or sparse matrix in the same backend as the solver:

import numpy as np
import scipy.sparse as sp
from openseespy_solvers.scipy import cg

def my_precond(A):
    d = A.diagonal()
    inv = np.ones_like(d)
    inv[d != 0] = 1.0 / d[d != 0]
    return sp.diags(inv)

solver = cg(rtol=1e-8, M=my_precond)

Other accepted values for M:

None : No preconditioning.

LinearOperator or sparse matrix : A fixed, pre-built M. Not recommended: the equation count is unknown until OpenSees builds the analysis model.

See also