Use external solvers#

FElupe uses SuperLU as direct sparse solver by default because it is shipped with SciPy (and SciPy is already a dependency of FElupe). While it is definitely a good choice for small to mid-sized problems, faster alternatives are easy to install and use. This section demonstrates several possibilities, e.g. a fast direct solver from PyPardiso (pip install pypardiso) and the minres iterative solver from SciPy. Custom solvers may be passed to the evaluation of a job.

import felupe as fem

job = fem.Job(steps)
job.evaluate(solver=solver) # function `x = solver(A, b)`

Solvers from SciPy Sparse:

# the default solver
from scipy.sparse.linalg import spsolve as solver
import scipy.sparse.linalg as spla
from scipy.sparse import tril

def solver(A, b):
    return spla.spsolve_triangular(tril(A).tocsr(), b).squeeze()

Note: minres may be replaced by another iterative method.

import scipy.sparse.linalg as spla

def solver(A, b):
    "Wrapper function for iterative solvers from scipy.sparse."

    return spla.minres(A, b)[0]

Solvers from external packages:

Ensure to have PyPardiso installed.

pip install pypardiso
from pypardiso import spsolve as solver

# undocumented, untested workaround if multiple blas libaries are installed
# import os
# os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

Ensure to have PyPardiso installed.

pip install pypardiso
from pypardiso import PyPardisoSolver
from scipy.sparse import triu

def solver(A, b):
    # mtype = 1: real and structurally symmetric, supernode pivoting
    # mtype = 2: real and symmetric positive definite
    # mtype =-2: real and symmetric indefinite,
    #             diagonal or Bunch-Kaufman pivoting
    # mtype = 6: complex and symmetric
    return PyPardisoSolver(mtype=2).solve(triu(A).tocsr(), b).squeeze()