PETSc Krylov solver failed to converge with big neumann boundary conditions

Hey!
I try to solve the hyperelastic uniaxial stress example as a nonlinearproblem in a mathematically correct form. It shows the same strain as in the analytical proove in an order of 1e-4 for all pressures. Here, the code is given for incompressible solid, means nu=.5
For stability, a MixedElement function space was used with the hydrostatic pressure, that should result in 0.

While setting the external pressure up to 5e8 the problem converges. Even while plotting strain over different stresses, the curve looks as it should. With higher pressure, resulting in a strain > 3.6 the problem not converges anymore.

I hope, anyone can give me a hint, why the problem results in the following and a solution cannot be found.

*** Error:   Unable to solve linear system using PETSc Krylov solver.
*** Reason:  Solution failed to converge in 0 iterations (PETSc reason DIVERGED_PC_FAILED, residual norm ||r|| = 0.000000e+00).
*** Where:   This error was encountered inside PETScKrylovSolver.cpp.
*** Process: 0
*** 
*** DOLFIN version: 2019.1.0
*** Git changeset:  7e99df3564aea9dc05729ddb64498ae47b6bc15d

the code:

from dolfin import *

boundary_vals = {
        "hold":     1,
        "free":     2,
        "pressure": 3,
        "mirrorY": 4,  # hold y
        "mirrorX": 5,  # hold x
        "mirrorZ": 6,  # hold Z
        "cells":    0  # internal cells
        }


def solve_elasticity(
        p: float = 4.0e6,
        mu: float = 362.2e3,
        K: float = 0.,
        nu: float = .5,
        resolution: int = 10,
        fem_rel_tol: float = 1e-6,
        ) -> int:

    # === input parameters after nondimensionalisation
    p_inner = -p/mu
    # assuming l, rho = 1., 1.
    dt = Constant(mu**(1/2))
    mu = 1.

    # mesh and faccet functions
    mesh = UnitCubeMesh(resolution, resolution, resolution)
    facet_function = MeshFunction('size_t', mesh, mesh.topology().dim()-1)
    x0 = AutoSubDomain(lambda x: near(x[0], 0))
    x1 = AutoSubDomain(lambda x: near(x[0], 1))
    y0 = AutoSubDomain(lambda x: near(x[1], 0))
    x0.mark(facet_function, boundary_vals['mirrorX'])
    y0.mark(facet_function, boundary_vals['mirrorY'])
    z0 = AutoSubDomain(lambda x: near(x[2], 0))
    z0.mark(facet_function, boundary_vals['mirrorZ'])
    x1.mark(facet_function, boundary_vals['pressure'])
    mesh = facet_function.mesh()
    # ==========================================================================

    vtk_resuls_file = File('test_u.pvd')

    # Build function space
    element_v = VectorElement("Lagrange", mesh.ufl_cell(), 1)
    element_s = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    mixed_element = MixedElement([element_v, element_v, element_s])
    W = FunctionSpace(mesh, mixed_element)

    # ## == Prepare Dirichlet BCs =============================================
    bcmX = DirichletBC(
            W.sub(0).sub(0), Constant(0.0), facet_function,
            boundary_vals["mirrorX"])
    bcmY = DirichletBC(
            W.sub(0).sub(1), Constant(0.0), facet_function,
            boundary_vals["mirrorY"])
    bcmZ = DirichletBC(
            W.sub(0).sub(2), Constant(0.0), facet_function,
            boundary_vals["mirrorZ"])
    bcs = [bcmY, bcmX, bcmZ]

    # dimensionalized output Functions
    w_write = Function(W)
    write_u, v_write, p_write = w_write.split()
    write_u.rename("u", "displacement")

    dx = Measure("dx")
    ds = Measure("ds", subdomain_data=facet_function, subdomain_id=2)

    # Limit quadrature degree
    dx = dx(degree=4)
    ds = ds(degree=4)

    I_ = Identity(W.mesh().geometry().dim())

    w = Function(W)
    u, v, p = split(w)
    w0 = Function(W)
    u0, v0, p0 = split(w0)

    _u, _v, _p = TestFunctions(W)
    dw = TrialFunction(W)

    P, pp, T, S = stress(u, p, I_, K, mu)
    P0, pp0, T0, S0 = stress(u0, p0, I_, K, mu)

    F1a = - inner(v, _u) * dx
    F2a = inner(P, grad(_v)) * dx
    Fp = pp * _p * dx

    Fv = (1.0 / dt) * inner(u - u0, _u) * dx + F1a
    Fa = (1.0 / dt) * inner(v - v0, _v) * dx + F2a

    # Traction at Neumann boundary
    dss = ds(subdomain_data=facet_function)
    F = I_ + grad(u)
    facet_normal = FacetNormal(mesh)
    bF_magnitude = Constant(0.0)
    bF = det(F) * dot(bF_magnitude * facet_normal, inv(F))  # 1PK on boundary
    FF = inner(bF, _v) * dss(boundary_vals['pressure'])

    F_ = Fv + Fa + Fp + FF
    Jac = derivative(F_, w, dw)

    # ## == Initialize solver =================================================
    problem = NonlinearVariationalProblem(F_, w, bcs=bcs, J=Jac)
    solver = NonlinearVariationalSolver(problem)
    solver.parameters['symmetric'] = False  # default value

    solver.parameters['newton_solver']['relative_tolerance'] = fem_rel_tol
    solver.parameters['newton_solver']['maximum_iterations'] = 50
    solver.parameters['newton_solver']['krylov_solver']['relative_tolerance'] = fem_rel_tol
    solver.parameters['newton_solver']['krylov_solver']['absolute_tolerance'] = fem_rel_tol
    solver.parameters['newton_solver']['linear_solver'] = 'superlu_dist'

    # Extract solution components
    u, v, p = w.split()

    bF_magnitude.assign(Constant(p_inner))
    #  w0.assign(w)
    solver.solve()

    write_u.assign(project(
        u, solver_type="cg", preconditioner_type="amg"))
    vtk_resuls_file << (write_u)


def stress(u, p, I_, K, mu):
    """Returns Piola-Kirchhoff stresses and hydrostatic pressure
    for given u, p."""

    F = I_ + grad(u)
    J = det(F)
    B = F * F.T                       # left Cauchy–Green deformation tensor

    sigma = -p*I_ + mu * (B)  # cauchy stress
    T = J**(-1) * sigma

    P = J * T * inv(F).T                   # 1st Piola-Kirchhoff stress
    S = J * dot(dot(inv(F), T), inv(F).T)  # 2nd Piola-Kirchhoff stress

    # hydrostatic pressure from \partial \psi / \partial J
    hydrostat_p = - Constant(1.0) + J

    return P, hydrostat_p, T, S


if __name__ == '__main__':

    solve_elasticity(p=5e8)  # works
    solve_elasticity(p=6e8)  # not converges

using SNES solver, the same happens.

        solver.parameters['nonlinear_solver'] = 'snes'
        solver.parameters['snes_solver']['linear_solver'] = 'superlu_dist'

I used ‘umfpack’ as a linear solver instead of ‘superlu_dist’ and then it converges, works even for 10e8, havent tried any further :slight_smile:

thank you for the reply.
umfpack works only a little better with the unitcube and for a more complicated mesh even worse :confused: