dragonfly_sim.utils.Nonlinear_utils

Classes

NonlinearProblem_mod

Nonlinear problem class for solving the non-linear problem

SNESNewtonSolver

Full-space Newton on PETSc SNES, driving a NonlinearProblem_mod.

Module Contents

class dragonfly_sim.utils.Nonlinear_utils.NonlinearProblem_mod(F: ufl.form.Form, J: ufl.form.Form, u: dolfinx.fem.function.Function, bcs: List[dolfinx.fem.bcs.DirichletBC] = [], form_compiler_options={}, jit_options={}, mat_type: str = None)

Nonlinear problem class for solving the non-linear problem \(F(u, v) = 0 \ \forall v \in V\) using PETSc as the linear algebra backend.

Copied from DOLFINx’s built-in NonlinearProblem and extended with a caller-selectable Jacobian matrix type (mat_type, e.g. “baij” for point-block ILU).

F(x: petsc4py.PETSc.Vec, b: petsc4py.PETSc.Vec)

Assemble the residual F into the vector b.

Args:

x: The vector containing the latest solution b: Vector to assemble the residual into

J(x: petsc4py.PETSc.Vec, A: petsc4py.PETSc.Mat)

Assemble the Jacobian matrix.

Args:

x: The vector containing the latest solution A: The matrix that will hold the Jacobian matrix

form(x: petsc4py.PETSc.Vec)

This function is called before the residual or Jacobian is computed. This is usually used to update ghost values.

Args:

x: The vector containing the latest solution

property L: dolfinx.fem.forms.Form

Compiled linear form (the residual form)

_A
_L
_a
_b
property a: dolfinx.fem.forms.Form

Compiled bilinear form (the Jacobian form)

bcs = []
mat_type = None
u
class dragonfly_sim.utils.Nonlinear_utils.SNESNewtonSolver(comm: mpi4py.MPI.Intracomm, problem: NonlinearProblem_mod, options_prefix: str = 'nls_solve_')

Full-space Newton on PETSc SNES, driving a NonlinearProblem_mod.

Replaces NewtonSolver_mod, which subclassed dolfinx’s C++ NewtonSolver – deprecated since dolfinx 0.10 and slated for removal. The attribute surface is the old one (rtol, atol, max_it, convergence_criterion, relaxation_parameter, error_on_nonconvergence, krylov_solver, A, b, solve(u) -> (n, converged)), and the defaults below reproduce the old solver step for step rather than adopting SNES’s own behaviour:

  • newtonls with the BASIC line search, so every step is taken in full, as NewtonSolver did. SNES’s default (bt) would evaluate the residual at extra trial points, and could shorten a step the old solver took in full.

  • dolfinx’s convergence test, not SNES’s: “incremental” judges ||dx_k|| against ||dx_1|| and never stops on the first step; “residual” judges ||F|| against ||F_0||. ||dx|| is the RAW Newton step, recorded before the step limiter rescales it.

  • a KSP that fails to converge does not stop the solve. NewtonSolver took the step regardless; SNES by default aborts with DIVERGED_LINEAR_SOLVE before taking any step (checked on this build).

  • the step limiter (set_step_limiter) replaces set_update. It runs as the line search’s pre-check and rescales dx IN PLACE; the basic line search then lands on x - dx, the same step the old x.axpy(-theta, dx) took.

Checked against NewtonSolver_mod on a nonlinear Poisson problem with Dirichlet BCs (1 and 3 ranks; both criteria, relaxation, a step limiter, max_it=1, a KSP capped short of convergence): iteration counts and converged flags identical, iterates equal to round-off (<= 4.4e-16). Not bit-identical: the Krylov solve itself differs in the last bit, from identical residual, settings and iteration count.

The Jacobian is assembled straight into problem._A, which is also the KSP’s operator. NewtonSolver_mod kept a second full-size matrix and copied problem._A into it every iteration.

The SNES iterate is its own vector, not u’s: the forms read u, and SNES evaluates the residual at a line-search work vector, so F and J copy their argument into u (owned entries, then a forward ghost update) before assembling. Handing SNES u’s vector instead would let that copy overwrite the iterate mid-line-search under any line search other than basic.

SNES options use the prefix nls_solve_, which the KSP inherits – the prefix the C++ NewtonSolver gave its KSP, so every -nls_solve_* option set by apply_krylov_solver_settings (or on the command line) still lands.

_converged(snes, it, norms)
_jacobian(snes, x, A, P)
_precheck(x, dx)
_residual(snes, x, b)
_sync(x)
destroy()

Free the SNES and this solver’s two vectors. The Jacobian belongs to the problem and is left alone.

set_step_limiter(limiter)

Install limiter(solver, x, dx), called once per Newton step with the current iterate x and the Newton step dx (the solve of J dx = F). It must rescale dx IN PLACE to the step it wants taken: the new iterate is x - dx. It must not modify x. Replaces relaxation_parameter when set.

solve(u: dolfinx.fem.function.Function)

Solve the non-linear problem into function u. Returns the number of Newton iterations and whether the solver converged.

property A: petsc4py.PETSc.Mat

Jacobian matrix (the problem’s own, not a copy).

_dx_norm = None
_f
_problem
_residual0 = None
_snes
_step_limiter = None
_x
atol = 1e-10
property b: petsc4py.PETSc.Vec

Residual vector.

comm
convergence_criterion = 'residual'
error_on_nonconvergence = True
property krylov_solver: petsc4py.PETSc.KSP

The Newton step’s linear solver.

max_it = 50
relaxation_parameter = 1.0
rtol = 1e-09
property snes: petsc4py.PETSc.SNES