Hello everyone. I am interested in solving Cahn-Hilliard tutorial with a modification of adding bounds to the concentration value. Most of the previous discussion suggests to make use of SNES solver. So as per the major instruction for using the SNES solver for nonlinear PDE, I visited the GitHub and make use of class NonlinearPDE_SNESProblem and attempted to solve. The modified code of Cahn-Hilliard tutorial is,
import os
import dolfinx
from mpi4py import MPI
from petsc4py import PETSc
from basix.ufl import element, mixed_element
from dolfinx.io import XDMFFile
import numpy as np
import ufl
from dolfinx import cpp as _cpp
from dolfinx import la, default_real_type
from dolfinx.fem import (Function,form, functionspace)
from dolfinx.fem.petsc import (apply_lifting, assemble_matrix, assemble_vector,
create_matrix,set_bc)
from dolfinx.mesh import create_unit_square, CellType
from ufl import TestFunction, TrialFunction, derivative, dx, grad, inner
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()
lmbda = 1.0e-02 # surface parameter
dt = 5.0e-06 # time step
theta = 0.5 # time stepping family, e.g. theta=1 -> backward Euler, theta=0.5 -> Crank-Nicholson
msh = create_unit_square(MPI.COMM_WORLD, 24, 24, CellType.triangle)
P1 = element("Lagrange", msh.basix_cell(), 1)
ME = functionspace(msh, mixed_element([P1, P1]))
q, v = ufl.TestFunctions(ME)
u = Function(ME) # current solution
u0 = Function(ME) # solution from previous converged step
# Split mixed functions
c, mu = ufl.split(u)
c0, mu0 = ufl.split(u0)
# Zero u
u.x.array[:] = 0.0
# Compute the chemical potential df/dc
c = ufl.variable(c)
f = 100 * c**2 * (1 - c)**2
dfdc = ufl.diff(f, c)
# mu_(n+theta)
mu_mid = (1.0 - theta) * mu0 + theta * mu
# Weak statement of the equations
F0 = inner(c, q) * dx - inner(c0, q) * dx + dt * inner(grad(mu_mid), grad(q)) * dx
F1 = inner(mu, v) * dx - inner(dfdc, v) * dx - lmbda * inner(grad(c), grad(v)) * dx
F = F0 + F1
bc =[]
problem = NonlinearPDE_SNESProblem(F,u,bc)
# Interpolate initial condition
np.random.seed(30)
u.sub(0).interpolate(lambda x: 0.25 + 0.01 * (0.5 - np.random.rand(x.shape[1])))
u.x.scatter_forward()
b = la.create_petsc_vector(ME.dofmap.index_map, ME.dofmap.index_map_bs)
J = create_matrix(problem.a)
# Create Newton solver and solve
snes = PETSc.SNES().create()
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")
# Output file
file = XDMFFile(MPI.COMM_WORLD, "SNES.xdmf", "w")
file.write_mesh(msh)
# Step in time
t = 0.0
# Reduce run time if on test (CI) server
if "CI" in os.environ.keys() or "GITHUB_ACTIONS" in os.environ.keys():
T = 3 * dt
else:
T = 10 * dt
# Get the sub-space for c and the corresponding dofs in the mixed space
# vector
V0, dofs = ME.sub(0).collapse()
c = u.sub(0)
u0.x.array[:] = u.x.array
while (t < T):
t += dt
r = snes.solve(None, u.vector)
print(f"Step {int(t/dt)}: num iterations: {r[0]}")
u0.x.array[:] = u.x.array
file.write_function(c, t)
file.close()
I wanted to add bounds, but before that I tried to solve with SNES solver, unfortunately it causes error like shown below,
python3: src/petsc4py.PETSc.c:352134: __Pyx_PyCFunction_FastCall: Assertion `!PyErr_Occurred()' failed.
[Legion:37114] *** Process received signal ***
[Legion:37114] Signal: Aborted (6)
[Legion:37114] Signal code: (-6)
[Legion:37114] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7f17e5dc4520]
[Legion:37114] [ 1] /lib/x86_64-linux-gnu/libc.so.6(pthread_kill+0x12c)[0x7f17e5e189fc]
[Legion:37114] [ 2] /lib/x86_64-linux-gnu/libc.so.6(raise+0x16)[0x7f17e5dc4476]
[Legion:37114] [ 3] /lib/x86_64-linux-gnu/libc.so.6(abort+0xd3)[0x7f17e5daa7f3]
[Legion:37114] [ 4] /lib/x86_64-linux-gnu/libc.so.6(+0x2871b)[0x7f17e5daa71b]
[Legion:37114] [ 5] /lib/x86_64-linux-gnu/libc.so.6(+0x39e96)[0x7f17e5dbbe96]
Can someone please tell that the way of proceeding is correct or not to satisfy my aim of solving a time dependent bound problem as I am not sure of the reason for this error. Also please give me some ideas or tips in solving the same. Any ideas for my problem is greatly appreciated. Thanks in advance for all your time and support.