This is a read only copy of the old FEniCS QA forum. Please visit the new QA forum to ask questions

Stalling least squares functional convergence

0 votes

I am seeing stalling convergence of the least squares functional when solving a least squares discretization of Poisson. This is part of a larger algorithm in which I solve the problem on a coarse mesh, then solve a residual equation (where the residual is calculated using the coarse solution) on a refined mesh. Furthermore, the right hand side for the residual problem is "chopped" such that it is non-zero only over a subset of the domain and set to zero elsewhere. As I refine the mesh for the residual equation and measure the least squares functional, I see convergence stall. Theory says that this should not happen. Have I implemented something incorrectly in my calculation of the least squares functional, or is Fenics doing some incorrect calculation somewhere here? A minimal example code which displays this stalling convergence behavior is below.

from dolfin import *

# Global options and files
#set_log_level(PROGRESS)
outfile = open('lsf.txt', 'w')
n_coarse = 2
n_refine = 7
order = 1

# Define expressions and subdomains used later
##############################################
##############################################

class HomeTurf(SubDomain):
    def inside(self, x, on_boundary):
        return True if (x[0] <= 0.5 and x[1] <= 0.5) else False

class Chopper(Expression):  
    def __init__(self, homeTurf):
        self.homeTurf = homeTurf
    def eval(self, values, x):
        if self.homeTurf.inside(x, False):
            values[0] = 1.0
        else:
            values[0] = 0.0

class allBoundary(SubDomain):
    def inside(self, x, on_boundary):
        return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS or x[1] < DOLFIN_EPS or x[1] > 1.0 - DOLFIN_EPS

class westeastBoundary(SubDomain):
    def inside(self, x, on_boundary):
        return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS

class southnorthBoundary(SubDomain):
    def inside(self, x, on_boundary):
        return x[1] < DOLFIN_EPS or x[1] > 1.0 - DOLFIN_EPS

# Create boundary objects
boundarySN  = southnorthBoundary()
boundaryWE  = westeastBoundary()
boundaryALL = allBoundary()
home_turf   = HomeTurf()


# Define the PDE
##############################################
##############################################

def L(U):
    # definitions
    (ux, uy, p) = split(U)
    u = as_vector((ux,uy))

    # equations
    eq1 = u - grad(p)
    eq2 = div(u)
    eq3 = curl(u)
    return (eq1,eq2,eq3)


def f():
    # right hand side equations
    rhs1 = Expression(('0.0','0.0'))
    rhs2 = Expression('-2.0*x[0]*(x[0]-1.0) - 2.0*x[1]*(x[1]-1.0)')
    rhs3 = Expression('0.0')
    return (rhs1, rhs2, rhs3)

# Compute solution on coarse mesh
##############################################
##############################################

# Create initial mesh on unit square
mesh0 = UnitSquareMesh(n_coarse, n_coarse,"crossed")

# Create Vector Space  [ux, uy, p]
V0 = VectorFunctionSpace(mesh0, "Lagrange", order, 3)

u0 = TrialFunction(V0)
v0 = TestFunction(V0)

bilinear_form = 0
for Lu,Lv in zip(L(u0),L(v0)):
    bilinear_form += inner(Lu,Lv)*dx

linear_form = 0
for rhs,Lv in  zip(f(),L(v0)):
    linear_form += inner(rhs,Lv)*dx

# Setup boundary conditions and solve
bc_ux = DirichletBC(V0.sub(0), Expression('0.0'), boundarySN)
bc_uy = DirichletBC(V0.sub(1), Expression('0.0'), boundaryWE)
bc_p = DirichletBC(V0.sub(2), Expression('0.0'), boundaryALL)
BCs = [bc_ux, bc_uy, bc_p];

U0 = Function(V0)

solve(bilinear_form == linear_form, U0, bcs=BCs, solver_parameters={"linear_solver": "cg"})#,"preconditioner":"hypre_amg"})

# Compute solution to chopped residual equation on refined meshes
##############################################
##############################################

# Initialize new mesh
mesh = UnitSquareMesh(n_coarse, n_coarse,"crossed")

for iteration in range(n_refine):

    # Refine mesh
    mesh = refine(mesh)

    # Create Chi function (this chops the right hand side)
    DG_0 = FunctionSpace(mesh, "DG", 0)
    Chi = interpolate(Chopper(home_turf), DG_0);

    # Update vectorspace and trial/test function
    V = VectorFunctionSpace(mesh, "Lagrange", order, 3)
    u = TrialFunction(V)
    v = TestFunction(V)

    # Fine grid representation of coarse grid solution
    U0_curr = interpolate(U0, V)

    # Setup chopped right hand side
    ChiRes = []
    for Lu0,rhs in zip(L(U0_curr),f()):
            ChiRes.append(Chi*(rhs - Lu0))

    # Build bilinear/linear forms
    bilinear_form = 0
    for Lu,Lv in zip(L(u),L(v)):
            bilinear_form += inner(Lu,Lv)*dx

    linear_form = 0
    for rhs,Lv in  zip(ChiRes,L(v)):
            linear_form += inner(rhs,Lv)*dx

    # Construct BCs
    bc_ux = DirichletBC(V.sub(0), Expression('0.0'), boundarySN)
    bc_uy = DirichletBC(V.sub(1), Expression('0.0'), boundaryWE)
    bc_p = DirichletBC(V.sub(2), Expression('0.0'), boundaryALL)
    BCs = [bc_ux, bc_uy, bc_p];

    # Compute solution
    dU = Function(V)
    solve(bilinear_form == linear_form, dU, bcs=BCs, solver_parameters={"linear_solver": "cg"})#,"preconditioner":"hypre_amg"})

    # Compute LSF
    LSF = 0
    for Lu,rhs in zip(L(dU),ChiRes):
            LSF += inner(Lu-rhs,Lu-rhs)*dx

    lsf = sqrt(assemble(LSF))
    print "    dofs = ", mesh.num_cells()
    print "    LSF = ", lsf
    outfile.write(str(mesh.num_cells())+' '+str(lsf)+'\n')

# plot(dU[2])
# interactive()
closed with the note: On further examination, we found a theoretical reason for the stalling convergence here. There is no problem with the above code.
asked May 2, 2016 by wayne.b.mitchell FEniCS Novice (160 points)
closed May 9, 2016 by wayne.b.mitchell
...