Error : ArityMismatch: Applying nonlinear operator Abs

Hello !

I am using for the first time the quadrature element. But I met an error with the NonlinearVariationalProblem I define due to the ‘Abs’ operator. I have already met this error when I used a linear solver but in this case I use a Newton solver. I define manually the Jacobian because it seems the derivature function does not work with Quadrature element.
I do a single egde notched test in mode II solved with a phase field model (staggered resolution).
I am facing the following error :

Form has no parts with arity 2.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Traceback (most recent call last):
  File "/scratchm/lmersel/FEniCS/PFmodel/PF_fenics_Lamia/SingleNotchTest/Split_Amor/PetcsSNES/Hmod_QuadSpace/Main_SENT_SNES_Am_Hmod_QuadSpace.py", line 206, in <module>
    problem_u     = NonlinearVariationalProblem(f_u,u_,bcu , J_u) #==========> Problme
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/dolfin/fem/problem.py", line 92, in __init__
    J = Form(J, form_compiler_parameters=form_compiler_parameters)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/dolfin/fem/form.py", line 43, in __init__
    ufc_form = ffc_jit(form, form_compiler_parameters=form_compiler_parameters,
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/dolfin/jit/jit.py", line 47, in mpi_jit
    return local_jit(*args, **kwargs)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/dolfin/jit/jit.py", line 97, in ffc_jit
    return ffc.jit(ufl_form, parameters=p)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/jitcompiler.py", line 217, in jit
    module = jit_build(ufl_object, module_name, parameters)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/jitcompiler.py", line 130, in jit_build
    module, signature = dijitso.jit(jitable=ufl_object,
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/dijitso/jit.py", line 165, in jit
    header, source, dependencies = generate(jitable, name, signature, params["generator"])
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/jitcompiler.py", line 65, in jit_generate
    code_h, code_c, dependent_ufl_objects = compile_object(ufl_object,
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/compiler.py", line 142, in compile_form
    return compile_ufl_objects(forms, "form", object_names,
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/compiler.py", line 185, in compile_ufl_objects
    analysis = analyze_ufl_objects(ufl_objects, kind, parameters)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/analysis.py", line 89, in analyze_ufl_objects
    form_datas = tuple(_analyze_form(form, parameters)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/analysis.py", line 89, in <genexpr>
    form_datas = tuple(_analyze_form(form, parameters)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ffc/analysis.py", line 169, in _analyze_form
    form_data = compute_form_data(form,
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/algorithms/compute_form_data.py", line 418, in compute_form_data
    check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode)  # Currently testing how fast this is
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/algorithms/check_arities.py", line 177, in check_form_arity
    check_integrand_arity(itg.integrand(), arguments, complex_mode)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/algorithms/check_arities.py", line 159, in check_integrand_arity
    arg_tuples = map_expr_dag(rules, expr, compress=False)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/corealg/map_dag.py", line 37, in map_expr_dag
    result, = map_expr_dags(function, [expression], compress=compress)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/corealg/map_dag.py", line 84, in map_expr_dags
    r = handlers[v._ufl_typecode_](v)
  File "/stck/lmersel/CODE_PROGRAMME/anaconda3/envs/fenics/lib/python3.10/site-packages/ufl/algorithms/check_arities.py", line 41, in nonlinear_operator
    raise ArityMismatch("Applying nonlinear operator {0} to expression depending on form argument {1}.".format(o._ufl_class_.__name__, t))
ufl.algorithms.check_arities.ArityMismatch: Applying nonlinear operator Abs to expression depending on form argument v_0.

My code is :

#https://comet-fenics.readthedocs.io/en/latest/demo/2D_plasticity/vonMises_plasticity.py.html#vonmisesplasticity
from fenics import *
import numpy as np
import matplotlib.pyplot as plt
import sys
import time

level = 16
set_log_level(level)

ppos = lambda x: (x+abs(x))/2.
pneg = lambda x: (x-abs(x))/2.

def w(alpha):
    return alpha**2

def w_prime(alpha):
    return 2*alpha

#Degradation function
def gk(alpha, k= 1e-6):
    return (1-alpha)**2 + k

def gk_prime(alpha, k= 1e-6):
    return 2*(alpha-1)

def epsilon(u):
    e  = sym(nabla_grad(u))
    return e

def psi_plus(u, K0,G):
    eps = epsilon(u)
    return 0.5* K0*ppos(tr(eps))**2 + G *inner(dev(eps),dev(eps))

def psi_moins(u, K0,G):
    eps = epsilon(u)
    return 0.5* K0*pneg(tr(eps))**2

def psi_0(u, G, K0):
    return  psi_plus(u, K0,G)+psi_moins(u, K0,G)

def psi(u,alpha, G, K0):
    return  gk(alpha, k= 1e-6)*psi_plus(u, K0,G)+psi_moins(u, K0,G)

def sigma_amor(u,alpha , G, K0,ndim):
    eps = epsilon(u)
    plus_tr_eps     = ppos(tr(eps)) #0.5*(tr(eps)+abs(tr(eps)))
    moins_tr_eps    = pneg(tr(eps)) #0.5*(tr(eps)-abs(tr(eps)))
    psi_plus_prime  = 0.5* K0 * plus_tr_eps * Identity(ndim) + 2*G *dev(eps)
    psi_moins_prime = 0.5* K0 * moins_tr_eps * Identity(ndim)
    s = gk(alpha, k= 1e-6) * psi_plus_prime + psi_moins_prime
    return s 




# ------------------
# Parameters
# ------------------
ERROR = 40
set_log_level(ERROR) # log level
parameters.parse()   # read paramaters from command line
# set some dolfin specific parameters
parameters["form_compiler"]["optimize"]     = True
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["representation"] = "uflacs" # quadrature is deprecated


"""
=========================================================
                        Physical parameters
=========================================================
"""

E, nu     = Constant(210000), Constant(0.3) #[MPa]
G         = Constant(E / (2.0*(1.0 + nu))) # [MPa]
lmbda     = Constant (E * nu / ((1.0 + nu)* (1.0 - 2.0*nu)))
K0, Gc    = Constant(lmbda+2./3.*G), Constant(2.7)
cw, lw    = Constant(2), Constant(0.01) # [mm]

T = 0.02           # final time
num_steps = 200    # number of time steps
dt = T / num_steps # time step size
time_step = np.linspace(0, T, num_steps)

"""
=========================================================
                        Create mesh
=========================================================
"""

nx = 150
ny = 150 # 14 400 cell h = 0.01 mm
mesh = UnitSquareMesh(nx, ny,'crossed')
Nnode = len(mesh.coordinates())
Ncell = len(mesh.cells())
coord = mesh.coordinates()
ndim = mesh.topology().dim()


"""
=========================================================
                        Space discretization
=========================================================
"""
degU ,degDam       = 1, 1
deg_history, deg_stress = 2, 2

V           = VectorFunctionSpace(mesh,'Lagrange', degU)
V_alpha     = FunctionSpace(mesh,'Lagrange', degDam)
#V_H        = FunctionSpace(mesh,'DG', degH) #degH = 0
W0e         = FiniteElement("Quadrature", mesh.ufl_cell(), degree=deg_history, quad_scheme='default')
V_H         = FunctionSpace(mesh, W0e)

We          = TensorElement("Quadrature", mesh.ufl_cell(), degree=deg_stress, shape=(3,3), quad_scheme='default')
Tens        = FunctionSpace(mesh, We)

"""
=========================================================
                        Boundary condition
=========================================================
"""

Disp_shear      = Expression( ('t', '0.'), t = 0.0, degree = 1 ) # Constant((0.,0.))

# boolean boundary function
boundary_bottom  = 'near(x[1], 0)'
boundary_up      = 'near(x[1], 1)'
boundary_left    = 'near(x[0], 0)'
boundary_right   = 'near(x[0], 1)'
class Precrack(SubDomain):
    def inside(self, x, on_boundary):
        return (between(x[0], (0., 0.5))  and near(x[1], 0.5) ) # and : &&
crack  = Precrack()

bottom     = CompiledSubDomain(boundary_bottom)
up         = CompiledSubDomain(boundary_up)
left       = CompiledSubDomain(boundary_left)
right      = CompiledSubDomain(boundary_right)
boundaries = MeshFunction("size_t", mesh,1)
boundaries.set_all(0)
bottom.mark(boundaries, 1) # mark left as 1
up.mark(boundaries, 2) # mark right as 2
left.mark(boundaries, 3) # mark right as 3
right.mark(boundaries, 4) # mark right as 4
crack.mark(boundaries, 5) # mark right as 5
ds = Measure("ds",subdomain_data=boundaries) # left: ds(1), right: ds(2), crack : ds(4), ds(0) all the edges


bcu_bottom = DirichletBC( V , Constant((0.,0.)), boundary_bottom)
bcu_right  = DirichletBC( V.sub(1) , Constant(0.), boundary_right)
bcu_left   = DirichletBC( V.sub(1) , Constant(0.), boundary_left)
bcu_up     = DirichletBC( V , Disp_shear, boundary_up )
bcu        = [bcu_bottom, bcu_up, bcu_right, bcu_left]


bcp_bottom = DirichletBC(V_alpha, Constant(0.), boundary_bottom)
bcp_up     = DirichletBC(V_alpha, Constant(0.), boundary_up)
bcp_crack  = DirichletBC(V_alpha, Constant(1.), boundaries,5)
bc_alpha   = [bcp_bottom, bcp_up, bcp_crack]

"""
=========================================================
    Define Trial and Test Function
    Define functions for solutions at current times steps
=========================================================
"""
du,v,u_ = TrialFunction(V), TestFunction(V), Function(V)
dalpha,beta,alpha_ = TrialFunction(V_alpha), TestFunction(V_alpha), Function(V_alpha)

# INITIAL CONDITION
u_old, alpha_old      = Function(V), Function(V_alpha)
H_new ,H_old          = Function(V_H),Function(V_H)
g              = gk(alpha_old,1.0e-6)
sig_funct      = Function(Tens, name="Stress")
Psi_elastic    = Function(V_H, name ="elastic_energy_density" )

"""
=========================================================
                        Define Variational problem
=========================================================
use Quadrature elements a custom integration measure must be defined to 
match the quadrature degree and scheme used by the Quadrature elements
"""
metadata = {"quadrature_degree": deg_stress, "quadrature_scheme": "default"}
dxm = dx(metadata=metadata)

#---------------- Mechanical equation
tn = Constant((0., 0.)) # external stress

f_u = inner( sigma_amor(u_, alpha_, G , K0, ndim) , epsilon(v) ) * dxm + dot( tn, v ) * ds
a_u = lhs(f_u)
L_u = rhs(f_u)
#J_u = derivative(f_u, u_, du) # jacobian
J_u = inner(epsilon(du), sigma_amor(v, alpha_, G , K0, ndim))*dxm # jacobian
problem_u     = NonlinearVariationalProblem(f_u,u_,bcu , J_u)
solver_u      = NonlinearVariationalSolver(problem_u)
newton_prm = solver_u.parameters['newton_solver']
newton_prm['relative_tolerance'] = 1e-8
newton_prm['absolute_tolerance'] = 1e-8
newton_prm['maximum_iterations'] = 2000
newton_prm['error_on_nonconvergence'] = False


#--------------- Phase Field equation
f_alpha = H_new*inner(beta, gk_prime(alpha_)) * dx \
          + (Gc/(cw*lw)) * (beta*w_prime(alpha_) + (2.*lw**2)*inner(grad(beta), grad(alpha_))) * dx 
a_alpha = lhs(f_alpha)
L_alpha = rhs(f_alpha)
J_alpha = derivative(f_alpha, alpha_, dalpha) # jacobian
alpha_min = interpolate(Constant(DOLFIN_EPS), V_alpha) # lower bound
alpha_max = interpolate(Constant(1.0), V_alpha)        # upper bound
problem_alpha = NonlinearVariationalProblem(f_alpha,alpha_ ,bc_alpha, J_alpha)
problem_alpha.set_bounds(alpha_min, alpha_max)
solver_alpha  = NonlinearVariationalSolver(problem_alpha)

snes_prm = {"nonlinear_solver": "snes",
            "snes_solver"     : { "method": "vinewtonssls",
                                  "maximum_iterations": 2000,
                                  "relative_tolerance": 1e-9,
                                  "absolute_tolerance": 1e-9,
                                  "report": True,
                                  "error_on_nonconvergence": False,
                                }}
solver_alpha.parameters.update(snes_prm)


# Stocked Forces and Energy value

forces        = np.zeros((len(time_step),3))
loading       = np.zeros((len(time_step),2))
energies      = np.zeros((len(time_step),3))
#Data_SIG      = np.zeros((num_steps, 3, Nnode))
Data_SIG      = np.zeros((num_steps, 3, Ncell))
Data_Usol     = np.zeros((num_steps, 2, Nnode))
H_tab         = np.zeros((num_steps, Ncell))

#---------------- RESOLUTION
t= 0.
it = 0
tol = 0.001 # 1e-6
maxiter = 300

stop_tt = 10
import ufl


for t in time_step[:stop_tt]:

    it +=1
    Disp_shear.t = t
    loading[it]= np.array([it,Disp_shear.t])
    print("\n========================================================")
    print("\n -> Timestep : %d s, Time : %.3g s, Ux_given :  %.3g mm  "%(it, t, Disp_shear.t))
    print("\n========================================================")

    k = 0
    res_H = 1.
    #A, Res = assemble_system(J_u, f_u, bcu)
    #Du.interpolate(Constant((0, 0)))
    print("\n ----- > Start Staggered Loop")
    while (res_H > tol) and (k < maxiter):

        k +=1
        #----Step 1 : Displacement resolution
        iter_u = solver_u.solve()
        #solve(A, du.vector(), Res, "mumps")
        #Du.assign(Du+du)

        #----Step 2 : Computation of H energy history
        elastic_energy_density=project(psi_plus(u_, K0,G), V_H)
        H_new.vector().set_local(np.max((elastic_energy_density.vector().get_local(),H_tab[it-1]),axis=0))
        print("\n________________________________________")
        print("\n PETscSNESSolver Parameters for Damage pb")
        print("__________________________________________")
        iter_alpha = solver_alpha.solve()
        print("\nEnd SNES Parameters__________________________")

        #---- Check Residual
        H_gap = H_new.vector().get_local() - H_old.vector().get_local()
        index_max = np.argmax(H_gap)
        H_gap_max = (H_new.vector().get_local() - H_old.vector().get_local()).max()
        res_H = abs(H_gap_max)/ H_old.vector().get_local()[index_max]
        
        err_u      = errornorm(u_, u_old, norm_type = 'l2', mesh = None)
        err_alpha  = errornorm(alpha_, alpha_old,   norm_type = 'l2', mesh = None)
        err = max(err_u, err_alpha) 

        
        #---- Step 4 : Update previous solution
        #u_old.assign(u_+Du)
        u_old.assign(u_)
        alpha_old.assign(alpha_)
        g = gk(alpha_old,1.0e-6)
        H_old.assign(H_new)

        print( "\nIteration: %d, err_u: %.8g, err_alpha : %.8g, Residual: %.8g \n" % (k, err_u, err_alpha, res_H))
        
 
    
    iter = [k]
    print("\n ----- > Timestep : %d"%(it))
    ux , uy      = u_.sub(0, deepcopy=True), u_.sub(1, deepcopy=True)
    H_tab[it, :] = project(H_new, V_H).vector().get_local()
    Psi_elastic.assign(project(psi(u_,alpha_, G, K0), V_H))

    # vertice value (mapping different from ddf value)
    Data_Usol[it, 0, :] = ux.compute_vertex_values()[:]
    Data_Usol[it, 1, :] = uy.compute_vertex_values()[:]

    
    sig_funct.assign(project(sigma_amor(u_, alpha_, G , K0, ndim), Tens))
    s11 = project(sigma_amor(u_, alpha_, G , K0, ndim)[0, 0], V_H)
    Data_SIG[it, 0, :] = s11.vector().get_local()
    s22 = project(sigma_amor(u_, alpha_, G , K0, ndim)[1, 1], V_H)
    Data_SIG[it, 1, :] = s22.vector().get_local()
    s12 = project(sigma_amor(u_, alpha_, G , K0, ndim)[1, 0], V_H)
    Data_SIG[it, 2, :] = s12.vector().get_local()
        
    # Calculate the axial and tangent force resultant
    Fn = assemble(sigma_amor(u_,alpha_, G , K0, ndim)[0,0]*ds(2))
    Ft = assemble(sigma_amor(u_,alpha_, G , K0, ndim)[1,1]*ds(2))
    forces[it] = np.array([t,Fn, Ft])

    #Calculate individually the energy
    elastic_energy       = 0.5*inner(sigma_amor(u_,alpha_, G , K0, ndim), epsilon(u_))*dxm
    dissipated_energy    = Gc/cw*(w(alpha_)/lw + lw*dot(grad(alpha_), grad(alpha_)))*dx
    elastic_energy_value = assemble(elastic_energy)
    surface_energy_value = assemble(dissipated_energy)

    if it == 1 :
        surf_off_set = surface_energy_value
        print(' surf_offset_precrack : ',  surf_off_set)
        
    energies[it]  = np.array([t,elastic_energy_value,surface_energy_value - surf_off_set])
    
    # monitor the results    
    if MPI.comm_world.rank == 0:
        print( "Eel_max: %.8g \nH_n_max: %.8g \nalpha_max: %.8g" % (elastic_energy_density.vector().max(), H_new.vector().max(), alpha_.vector().max()) )
        print("\nIterationU and IterationAlpha: (%i,%i)"%(iter_u[0],iter_alpha[0]))
        
        print("\nElastic and surface energies : (%g,%g)"%(elastic_energy_value,surface_energy_value - surf_off_set)) # WHY they display a scalar (a value) and not scale field (vector)
        print("-------------------------------------------------------------")

Do you have an idea of how could I define the formulation differently to avoid the error ?

Thanks for the hints !

Lamia

Your code is much too long for me to look in detail. See for example how to create a MWE.

At a glance of the error message though it looks like you’re trying to solve a nonlinear problem as if it were linear. Somewhere you’re probably computing abs(u) where u is a ufl.TrialFunction or ufl.TestFunction. Clearly this doesn’t make sense and likely the reason you get the error.

Think for your answer and really sorry for the long code. I changed it with a simple one.
I think the error comes from the Jacobian that I defined with an ‘inner’ function. Indeed I use the test ‘v’ and trial function ‘du’ like this :

du,v,u_  = TrialFunction(V), TestFunction(V), Function(V)

metadata = {"quadrature_degree": deg_stress, "quadrature_scheme": "default"}
dxm      = dx(metadata=metadata)

f_u      = inner( sigma_amor(u_, G , K0, ndim) , epsilon(v) ) * dxm + dot( tn, v ) * ds
J_u      = inner(epsilon(du), sigma_amor(v, G , K0, ndim))*dxm # jacobi

I tried to follow the guideline of the link talking about Nonlinear variational problem. But I think I missed something in the explication because I don’t get the error I did.
And the stress is indeed expressed with ‘abs’ operator.

I join the full code where I reduced the problem to the mechanical formulation and removed the damage problem.

from fenics import *
import numpy as np
import matplotlib.pyplot as plt
import sys
import time

level = 16
set_log_level(level)

ppos = lambda x: (x+abs(x))/2.
pneg = lambda x: (x-abs(x))/2.

def epsilon(u):
    return sym(nabla_grad(u))

def psi_plus(u, K0,G):
    eps = epsilon(u)
    return 0.5* K0*ppos(tr(eps))**2 + G *inner(dev(eps),dev(eps))

def psi_moins(u, K0,G):
    return 0.5* K0*pneg(tr(epsilon(u)))**2

def psi_0(u, G, K0):
    return  psi_plus(u, K0,G)+psi_moins(u, K0,G)

def sigma_amor(u, G, K0,ndim):
    eps = epsilon(u)
    psi_plus_prime  = 0.5* K0 * ppos(tr(eps)) * Identity(ndim) + 2*G *dev(eps)
    psi_moins_prime = 0.5* K0 * pneg(tr(eps)) * Identity(ndim)
    return psi_plus_prime + psi_moins_prime


# ------------------
# Parameters
# ------------------
ERROR = 40
set_log_level(ERROR) # log level
parameters.parse()   # read paramaters from command line
# set some dolfin specific parameters
parameters["form_compiler"]["optimize"]     = True
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["representation"] = "uflacs" # quadrature is deprecated


"""
=========================================================
                        Physical parameters
=========================================================
"""

E, nu     = Constant(210000), Constant(0.3) #[MPa]
G, lmbda        = Constant(E / (2.0*(1.0 + nu))), Constant (E * nu / ((1.0 + nu)* (1.0 - 2.0*nu)))# [MPa]
K0, Gc    = Constant(lmbda+2./3.*G), Constant(2.7)
cw, lw    = Constant(2), Constant(0.01) # [mm]

T, num_steps = 0.02 , 200 # final time, number of time steps
time = np.linspace(0, T, num_steps)
"""
=========================================================
                        Create mesh
=========================================================
"""

nx, ny = 150, 150
mesh = UnitSquareMesh(nx, ny,'crossed')
Nnode,Ncell = len(mesh.coordinates()), len(mesh.cells())
coord = mesh.coordinates()
ndim = mesh.topology().dim()


"""
=========================================================
                        Space discretization
=========================================================
"""
degU ,degDam       = 1, 1
deg_history, deg_stress = 2, 2

V           = VectorFunctionSpace(mesh,'Lagrange', degU)
W0e         = FiniteElement("Quadrature", mesh.ufl_cell(), degree=deg_history, quad_scheme='default')
V_H         = FunctionSpace(mesh, W0e) # for the energy

We          = TensorElement("Quadrature", mesh.ufl_cell(), degree=deg_stress, shape=(3,3), quad_scheme='default')
Tens        = FunctionSpace(mesh, We) # for stress and strain 

"""
=========================================================
                        Boundary condition
=========================================================
"""

Disp_shear      = Expression( ('t', '0.'), t = 0.0, degree = 1 ) 

# boolean boundary function
boundary_bottom  = 'near(x[1], 0)'
boundary_up      = 'near(x[1], 1)'
boundary_left    = 'near(x[0], 0)'
boundary_right   = 'near(x[0], 1)'

bottom     = CompiledSubDomain(boundary_bottom)
up         = CompiledSubDomain(boundary_up)
left       = CompiledSubDomain(boundary_left)
right      = CompiledSubDomain(boundary_right)

boundaries = MeshFunction("size_t", mesh,1)
boundaries.set_all(0)
bottom.mark(boundaries, 1) # mark left as 1
up.mark(boundaries, 2) # mark right as 2
left.mark(boundaries, 3) # mark right as 3
right.mark(boundaries, 4) # mark right as 4
ds = Measure("ds",subdomain_data=boundaries) # left: ds(1), right: ds(2), crack : ds(4), ds(0) all the edges


bcu_bottom = DirichletBC( V , Constant((0.,0.)), boundary_bottom)
bcu_right  = DirichletBC( V.sub(1) , Constant(0.), boundary_right)
bcu_left   = DirichletBC( V.sub(1) , Constant(0.), boundary_left)
bcu_up     = DirichletBC( V , Disp_shear, boundary_up )
bcu        = [bcu_bottom, bcu_up, bcu_right, bcu_left]

"""
=========================================================
    Define Trial and Test Function
    Define functions for solutions at current times steps
=========================================================
"""
du,v,u_ = TrialFunction(V), TestFunction(V), Function(V)

# INITIAL CONDITION
u_old     = Function(V)
H_new ,H_old          = Function(V_H),Function(V_H)
sig_funct      = Function(Tens, name="Stress")


"""
=========================================================
                        Define Variational problem
=========================================================
"""
metadata = {"quadrature_degree": deg_stress, "quadrature_scheme": "default"}
dxm = dx(metadata=metadata)

#---------------- Mechanical equation
tn = Constant((0., 0.)) # external stress

f_u = inner( sigma_amor(u_, G , K0, ndim) , epsilon(v) ) * dxm + dot( tn, v ) * ds
a_u = lhs(f_u)
L_u = rhs(f_u)
#J_u = derivative(f_u, u_, du) # jacobian
J_u = inner(epsilon(du), sigma_amor(v, G , K0, ndim))*dxm # jacobian
problem_u     = NonlinearVariationalProblem(f_u,u_,bcu , J_u)
solver_u      = NonlinearVariationalSolver(problem_u)
newton_prm = solver_u.parameters['newton_solver']
newton_prm['relative_tolerance'] = 1e-8
newton_prm['absolute_tolerance'] = 1e-8
newton_prm['maximum_iterations'] = 2000
newton_prm['error_on_nonconvergence'] = False

H_tab         = np.zeros((num_steps, Ncell))

#---------------- RESOLUTION
t, it= 0., 
tol, maxiter = 0.001, 300

for t in time[:10]:

    it +=1
    Disp_shear.t = t
    print("\n========================================================")
    print("\n -> Timestep : %d s, Time : %.3g s, Ux_given :  %.3g mm  "%(it, t, Disp_shear.t))
    print("\n========================================================")

    k,res_H = 0, 1.
    while (res_H > tol) and (k < maxiter):

        k +=1
        #----Step 1 : Displacement resolution
        iter_u = solver_u.solve()
 
        #----Step 2 : Computation of H energy history
        elastic_energy_density=project(psi_plus(u_, K0,G), V_H)
        H_new.vector().set_local(np.max((elastic_energy_density.vector().get_local(),H_tab[it-1]),axis=0))
        
        #---- Check Residual
        H_gap = H_new.vector().get_local() - H_old.vector().get_local()
        H_gap_max, index_max =H_gap.max(), np.argmax(H_gap)
        res_H = abs(H_gap_max)/ H_old.vector().get_local()[index_max]

        #---- Step 4 : Update previous solution
        u_old.assign(u_)
        H_old.assign(H_new)
        print( "\nIteration: %d,  Residual: %.8g \n" % (k, res_H))
        
    iter = [k]
    H_tab[it, :] = project(H_new, V_H).vector().get_local()

    #Calculate individually the energy
    elastic_energy       = 0.5*inner(sigma_amor(u_, G , K0, ndim), epsilon(u_))*dxm
    elastic_energy_value = assemble(elastic_energy)

    print("\nElastic and surface energies : (%g,%g)"%(elastic_energy_value) )
    print("-------------------------------------------------------------")

Thanks for your help !

I found the mistake. My definition of the residual was wrong. I used the same stress tensor in both Jacobian and residual espression. So I defined a function sigma used in the residual valued from the solution u. And I change the way to solve the problem because I get trouble with NonlinearVaritionalProblem class.
I just use the assembly_system(J, du, res) than solve. Now the code runs :slight_smile:

I claimed victory too soon. The code runs when the formulation of the Jacobian are not defined with nonlinear operator, in my case I use ‘Abs’ operator.
I want to solve J. du = f than do u = u+du (an iteration of the Newton Raphson method) but my Jacobian are defined with an abs function evaluted with a testFunction.

ppos = lambda x: (x+abs(x))/2.
pneg = lambda x: (x-abs(x))/2.
#ppos = lambda x: 1*x
#pneg = lambda x: 1*x
def sigma_amor(u, G, K0,ndim):
    eps = epsilon(u)
    psi_plus_prime  = 0.5* K0 * ppos(tr(eps)) * Identity(ndim) + 2*G *dev(eps)
    psi_moins_prime = 0.5* K0 * pneg(tr(eps)) * Identity(ndim)
    return psi_plus_prime + psi_moins_prime

v ,u_ = TrialFunction(V), TestFunction(V)
u , u_old     = Function(V), Function(V)
du = Function(V, name="Iteration correction")
Du = Function(V, name="Current increment")
sig     = Function(Vect, name="Stress")

"""
=========================================================
                        Define Variational problem
=========================================================
"""
metadata = {"quadrature_degree": deg_stress, "quadrature_scheme": "default"}
dxm = dx(metadata=metadata)

#---------------- Mechanical equation
tn = Constant((0., 0.)) # external stress
f_u = inner( as_2D_tensor(sig), epsilon(u_) ) * dxm + dot( tn , u_ ) * ds
J_u = inner(epsilon(v), sigma_amor(u_, G , K0, ndim))*dxm # jacobian

And in the iterative loop, I have :

for t in time:
    it +=1
    Disp_shear.t = t
    k = 0
    err_u = 1.
    A, Res = assemble_system(J_u, f_u, bcu)
    Du.interpolate(Constant((0, 0)))
    while (err_u > tol) and (k < maxiter):

        k +=1
        solve(A, du.vector(), Res, "cg") 
        Du.assign(Du+du)
        u.assign(u+Du)
        sig = as_2D_vector(sigma_amor(u, G, K0,ndim))  # very long operation 
        err_u      = errornorm(u, u_old, norm_type = 'l2', mesh = None)
        print('iteration : %i, err_u : %0.8g'% (k,err_u))
        u_old.assign(u)
    iter = [k]

Finally, does it mean that I have to solve an iteration of the Newthon Raphson with a Newton Raphson because of the Abs operator ?

Thanks,

Lamia

I added the following parameters at the beginning of my code :

parameters["form_compiler"].update( {"optimize": True, "cpp_optimize": True, "representation":"uflacs",
"log_level": 25, "split": True, "quadrature_degree": 4})

I never know how to parameterized the compiler but it works now :slight_smile: