Skip to content

LinearSolver

LinearSolver assembles the linear PDE system, applies boundary conditions, and solves the resulting sparse linear system.

from gbmsc_pde import LinearSolver

solution = LinearSolver(pde, boundary_conditions).solve()

Constructor

LinearSolver(pde, bcs)

Parameters:

  • pde: configured LinearPDE instance.
  • bcs: configured BoundaryConditions instance.

Direct Solve

u = LinearSolver(pde, boundary_conditions).solve(solver="direct")

The direct path uses:

scipy.sparse.linalg.spsolve

This is the default solver.

Iterative Solves

u = LinearSolver(pde, boundary_conditions).solve(
    solver="gmres",
    tol=1e-8,
    maxiter=1000,
)

Supported iterative methods:

  • "cg"
  • "gmres"
  • "bicgstab"

Optional preconditioners may be passed through preconditioner. Use preconditioner="jacobi" for a diagonal Jacobi preconditioner.

Returning Assembly Data

For assembly data:

u, data = LinearSolver(pde, boundary_conditions).solve(return_data=True)

The returned data dictionary contains:

  • A: boundary-modified sparse system matrix,
  • b: boundary-modified right-hand side,
  • first_derivatives: (Mx, My),
  • second_derivatives: (Mxx, Myy),
  • nnz: number of nonzero entries in A,
  • sparsity: percentage of zero entries, (1 - A.nnz / (A.shape[0] * A.shape[1])) * 100,
  • solve_time: linear solve time in seconds,
  • assembly_time: assembly and boundary-application time in seconds,
  • solver_info: SciPy iterative solver info, or 0 for direct solves.

This is useful for measuring sparsity, conditioning estimates, or residuals.

Diagnostics Example

u, data = LinearSolver(pde, boundary_conditions).solve(return_data=True)

A = data["A"]
b = data["b"]
Mx, My = data["first_derivatives"]
Mxx, Myy = data["second_derivatives"]
sparsity = data["sparsity"]
residual = A.dot(u) - b
cpu_time = data["assembly_time"] + data["solve_time"]