Hi all,
I’m trying to use the following non-linear solver to solve a variational plasticity problem with a mixed element state:
from dolfinx import la
from dolfinx.fem import form
from dolfinx.fem.petsc import (apply_lifting, assemble_matrix, assemble_vector,
create_matrix, create_vector, set_bc)
from ufl import TestFunction, TrialFunction, derivative
from petsc4py import PETSc
class NonlinearPDE_SNESProblem:
def __init__(self, F, u, bc):
V = u.function_space
du = TrialFunction(V)
self.L = form(F)
self.a = form(derivative(F, u, du))
self.bc = bc
self._F, self._J = None, None
self.u = u
def F(self, snes, x, F):
"""Assemble residual vector."""
x.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
x.copy(self.u.vector)
self.u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
with F.localForm() as f_local:
f_local.set(0.0)
assemble_vector(F, self.L)
apply_lifting(F, [self.a], bcs=[self.bc], x0=[x], scale=-1.0)
F.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
set_bc(F, self.bc, x, -1.0)
def J(self, snes, x, J, P):
"""Assemble Jacobian matrix."""
J.zeroEntries()
assemble_matrix(J, self.a, bcs=self.bc)
J.assemble()
The solver settings are the following:
snes = PETSc.SNES().create()
opts = PETSc.Options()
opts['snes_monitor'] = None
snes.setFromOptions()
snes.setType('vinewtonrsls')
snes.setFunction(problem.F, b)
snes.setJacobian(problem.J, J)
snes.setTolerances(atol=1e-10,rtol=1.0e-9, max_it=20)
snes.getKSP().setType("preonly")
snes.getKSP().setTolerances(rtol=1.0e-9)
snes.getKSP().getPC().setType("lu")
My method involves minimising a functional J_p, which encompasses free energy, lagrange multipliers and dissipation. The state consists of u, dp, N, lagrange1, lagrange2; [vector, scalar, tensor, scalar, scalar]
respectively.
J_p = elastic_strain_energy(u,full_plastic_strain)*dx
J_p += dt*dissipation_potential(dp/dt)*dx
J_p += dt*lagrange1*ufl.tr(N)*dx
J_p += dt*lagrange2*(ufl.inner(N,N)-2/3)*dx
Upon solving for a single timestep, all I get is:
time = 0.0000
0 SNES Function norm 8.106060082376e+08
It seems to give up after a single iteration with an enormous residual, so I tried reducing the problem to linear elasticity by driving all the non-linearly dependent variables to zero.
J_p = elastic_strain_energy(u,full_plastic_strain)*dx
J_p += ufl.inner(N,N)*dx
J_p += dp*dp*dx
J_p += lagrange1*lagrange1*dx
J_p += lagrange2*lagrange2*dx
Upon solving this, the solver does converge to the elastic solution, but still starts with the exact same huge residual.
time = 0.0000
0 SNES Function norm 8.106060082376e+08
1 SNES Function norm 5.235158616409e-07
The problem may well be in my set up of the functional, J_p, but I’m more interested in why this solver doesn’t carry on iterating up to its max_it = 20 in the first case, it just seems to give up and spit out that large norm. Further, I would be interested to know why they both have exact same large norm initially. N.B. I have used this solver for linear viscosity with a very similar approach and it works fine, converging, using up all its iterations, sensible looking norms at each step.
A MWE in this context is quite difficult to make small, as the model is fairly involved, but I can provide one if needed.
Kind regards,
Magnus