Convection Flow in a Channel Problem

Hi. I need a favor in pointing the problem in my coding. I don’t know what’s missing in my source code, but for some reason, the solver kept on diverging.

Now I am working on convective flow in a channel with an open trapezoidal enclosure. I’m working for weeks but could not run it successfully.

I have tried to solve it using Newton Solver and SNES Solver, but it seems both produces the same error. The error appear:

*** Error: Unable to solve nonlinear system with PETScSNESSolver.
*** Reason: Solver did not converge.
*** Where: This error was encountered inside PETScSNESSolver.cpp.
*** Process: 0

Please help me. Here I attach the code:

# Import libraries
from __future__ import print_function
from fenics import *
from mshr import *
import matplotlib.pyplot as plt

# Create the main channel
channel = Rectangle(
                    Point(0., 1), # Bottom-Left
                    Point(5, 1.5) # Top-Right
                   )

# Create the trapezoidal polygon
trapezoid = Polygon([
                     Point(1.5, 0.0),  # Bottom-left
                     Point(2.5, 0.0),  # Bottom-right
                     Point(3, 1),  # Top-right
                     Point(1, 1)   # Top-left
                    ])

domain = channel + trapezoid

mesh = generate_mesh (domain, 128)
#mesh = generate_mesh (domain, 84.16)

#visualize the mesh
plot(mesh)

# Define vector element and finite element according to their order
P1 = VectorElement("CG", mesh.ufl_cell(), 2)
P2 = FiniteElement("CG", mesh.ufl_cell(), 1)
P3 = FiniteElement("CG", mesh.ufl_cell(), 2)

# Define function space
W = FunctionSpace(mesh, MixedElement([P1,P2,P3]))

# Define test function and trial function
(v,q,s) = TestFunctions(W)

w = Function(W)
(u,p,T) = (as_vector ((w[0], w[1])), w[2], w[3])

class Top(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[1], 1.5)
        
class ChannelExit(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[0], 5.)

class ChannelEntrance(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[0], 0.)

class BottomChannel(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[1], 1.)

class SideWallCavity(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and x[1] >= 0. and x[1] <= 1. and x[0] <= 3. and x[0] >= 1.
        
class BottomCavity(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[1], 0.)

class Heater(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[1], 0.) and x[0] >= 1.75 and x[0] <= 2.25

boundaries = MeshFunction ("size_t", mesh, 1)

boundaries.set_all(0)

chexit = ChannelExit()
chexit.mark(boundaries, 1)

chtop = Top()
chtop.mark(boundaries, 2)

chent = ChannelEntrance()
chent.mark(boundaries, 3)

chbot = BottomChannel()
chbot.mark(boundaries, 4)

cavsw = SideWallCavity()
cavsw.mark(boundaries, 5)

cavbot = BottomCavity()
cavbot.mark(boundaries, 6)

heater = Heater()
heater.mark(boundaries, 7)

#Velocity
v_chent = DirichletBC (W.sub(0), (1,0), boundaries, 3)

v_chtop = DirichletBC (W.sub(0), (0,0), boundaries, 2)
v_chbot = DirichletBC (W.sub(0), (0,0), boundaries, 4)
v_cavsw = DirichletBC (W.sub(0), (0,0), boundaries, 5)
v_cavbot = DirichletBC (W.sub(0), (0,0), boundaries, 6)
v_heater = DirichletBC (W.sub(0), (0,0), boundaries, 7)

#Temperature
t_chent = DirichletBC(W.sub(2), 0, boundaries, 3)
t_heater = DirichletBC(W.sub(2), 1, boundaries, 7)

#Momentum
p_chexit = DirichletBC(W.sub(1), 0, boundaries, 1)

bc = [v_chtop, v_chent, v_chbot, v_cavsw, v_cavbot, v_heater, t_chent, t_heater, p_chexit]

Re = 100.0
Pr = 1.3
Ri = 5

invRe = 1.0/Re
invPr = 1.0/Pr

Ri = Constant(Ri)
e = Constant((0,1))

# Coupled Equations
F1 = div(u)*q*dx

F2 = inner(grad(u)*u, v)*dx\
    + invRe*inner(grad(u),grad(v))*dx\
    - p*div(v)*dx\
    - T*Ri*dot(e,v)*dx

F3 = dot(u, grad(T))*s*dx\
    + invRe*invPr*dot(grad(T), grad(s))*dx

F = F1 + F2 + F3

# Run solver
J = derivative(F, w)

#problem = NonlinearVariationalProblem(F, w, bc, J)
#solver = NonlinearVariationalSolver(problem)

# Non linear solver parameters
#prm = solver.parameters

#prm['newton_solver']['linear_solver'] = 'mumps'
#prm['newton_solver']['maximum_iterations'] = 500

# Solve the problem
#solver.solve()

# Create the nonlinear problem and solver
problem = NonlinearVariationalProblem(F, w, bc, J)
solver = NonlinearVariationalSolver(problem)
prm = solver.parameters

# Set SNES solver parameters

prm['nonlinear_solver'] = 'snes'
prm['snes_solver']['method'] = 'newtonls'  # Choose SNES method
prm['snes_solver']['linear_solver'] = 'mumps'  # Linear solver for the Jacobian

# Solve the problem
solver.solve()