Hi,
I am trying to solve a incompressible hyperelasticity Problem with a SNES solver. I always got an errormessage and i dont know why. Maybe someone of you can help me please. The Error is:
src/petsc4py.PETSc.c:352134: __Pyx_PyCFunction_FastCall: Assertion !PyErr_Occurred()' failed.
Here is my code:
"""Unit tests for Newton solver assembly"""
import numpy as np
import math
import ufl
from dolfinx import cpp as _cpp
from dolfinx import fem, la, mesh, plot, io, nls, log, cpp
from mpi4py import MPI
from petsc4py import PETSc
class NonlinearPDE_SNESProblem:
def __init__(self, F, J, u, bcs):
self.L = F
self.a = J
self.bcs = bcs
self.u = u
# Create matrix and vector to be used for assembly
# of the non-linear problem
self.A = fem.petsc.create_matrix(self.a)
self.b = fem.petsc.create_vector(self.L)
def F(self, snes, x, b):
"""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 b.localForm() as b_local:
b_local.set(0.0)
fem.assemble_vector(b, self.L)
fem.apply_lifting(b, [self.a], [self.bcs], [x],-1.0)
b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
fem.set_bc(b, self.bcs, x, -1.0)
def J(self, snes, x, A, P):
"""Assemble Jacobian matrix."""
A.zeroEntries()
fem.assemble_matrix(A, self.a, self.bcs)
A.assemble()
def nonlinear_pde_snes():
"""Test Newton solver for a simple nonlinear PDE"""
c1 = PETSc.ScalarType(0.15)
def P(u,p):
# Kinematics
d = len(u)
I = ufl.variable(ufl.Identity(d))
F = ufl.variable(I + ufl.grad(u))
C = ufl.variable(F.T * F)
I1 = ufl.variable(ufl.tr(C))
I2 = ufl.variable(ufl.tr(C*C))
J = ufl.variable(ufl.det(F))
# Stored strain energy density
psi = c1*(I1-3)
# Hyper-elasticity
return ufl.diff(psi, F) + p * J * ufl.inv(F.T)
# Create mesh and function space
comm = MPI.COMM_WORLD
rank = comm.rank
domain = mesh.create_box(MPI.COMM_WORLD,[[0.0,0.0,0.0], [1, 1, 1]], [10,10,10], mesh.CellType.hexahedron)
P2 = ufl.VectorElement("Lagrange", domain.ufl_cell(), 2)
P1 = ufl.FiniteElement("Lagrange", domain.ufl_cell(), 1)
state_space = fem.FunctionSpace(domain, P2 * P1)
V, _ = state_space.sub(0).collapse()
def left(x):
return np.isclose(x[0], 0)
def right(x):
return np.isclose(x[0], 1)
fdim = domain.topology.dim -1
left_facets = mesh.locate_entities_boundary(domain, fdim, left)
right_facets = mesh.locate_entities_boundary(domain, fdim, right)
# Concatenate and sort the arrays based on facet indices. Left facets marked with 1, right facets with two
marked_facets = np.hstack([left_facets, right_facets])
marked_values = np.hstack([np.full_like(left_facets, 1), np.full_like(right_facets, 2)])
sorted_facets = np.argsort(marked_facets)
facet_tag = mesh.meshtags(domain, fdim, marked_facets[sorted_facets], marked_values[sorted_facets])
u0_bc = fem.Function(V)
u0 = lambda x: np.zeros_like(x, dtype=PETSc.ScalarType)
u0_bc.interpolate(u0)
class incremented_displacement_expression:
def __init__(self):
self.t = 0.0
def eval(self, x):
# linearly incremented displacement
return np.stack((np.full(x.shape[1], self.t * 0.01), np.zeros(x.shape[1]), np.zeros(x.shape[1])))
incremented_displacement_expr = incremented_displacement_expression()
incremented_displacement_expr.t = 0
incremented_displacement = fem.Function(V)
incremented_displacement.interpolate(incremented_displacement_expr.eval)
left_dofs = fem.locate_dofs_topological((state_space.sub(0), V), facet_tag.dim, facet_tag.find(1))
right_dofs = fem.locate_dofs_topological((state_space.sub(0), V), facet_tag.dim, facet_tag.find(2))
bc_left = fem.dirichletbc(u0_bc, left_dofs, state_space.sub(0))
bc_right = fem.dirichletbc(incremented_displacement, right_dofs, state_space.sub(0))
bcs = [bc_left,bc_right]
#Define TestFunction
state = fem.Function(state_space, name="state")
test_state = ufl.TestFunctions(state_space)
u, p = ufl.split(state)
v, q = test_state
d = len(u)
I = ufl.variable(ufl.Identity(d))
F = ufl.variable(I + ufl.grad(u))
det_F = ufl.variable(ufl.det(F))
metadata = {"quadrature_degree": 4}
ds = ufl.Measure('ds', domain=domain, metadata=metadata)
dx = ufl.Measure("dx", domain=domain, metadata=metadata)
#Variational Problem
R = ufl.inner(ufl.grad(v), P(u,p))*dx + q * (det_F - 1) * dx
residual = fem.form(R)
Jac = ufl.derivative(R, state)
jacobian = fem.form(Jac)
# Create nonlinear problem
problem = NonlinearPDE_SNESProblem(residual,jacobian, state, bcs)
b = la.create_petsc_vector(state_space .dofmap.index_map, state_space .dofmap.index_map_bs)
J = fem.petsc.create_matrix(problem.a)
# Create Newton solver and solve
snes = PETSc.SNES().create(domain.comm)
opts = PETSc.Options() # read the prefix of solver
opts['snes_linesearch_type'] = 'bt'
opts['snes_monitor'] = None
opts['snes_linesearch_monitor'] = None
snes.setFromOptions() # make above settings effective
snes.setFunction(problem.F,b)
snes.setJacobian(problem.J,J)
snes.setTolerances(rtol=1.0e-9, max_it=10)
snes.getKSP().setType("preonly")
snes.getKSP().setTolerances(rtol=1.0e-9)
snes.getKSP().getPC().setType("lu")
for n in range(0,50):
incremented_displacement_expr.t = n
incremented_displacement.interpolate(incremented_displacement_expr.eval)
snes.solve(None,state.vector)
state.x.scatter_forward()
nonlinear_pde_snes()