Hello !
After some long research, I finally didn’t manage to solve my issue.
I decided to simplify my problem and remove the damage equation. I have just keeped the linear elastic equation and I do a pure traction test applied on the top edge of a square, discretized with 2*2 elements.
But my problem keeps diverging with a Newton solver. At the first time step, I use a linear elastic stress formulation (hooke law in plane strain) to avoid trouble. Then for the following time step, I switch to the spectral decompositon of the stress and I finally got divergence issue.
Fortunately, I managed to highlight the issue. Insteed of having the value 0., I got 10e-18 order value. And when I divided by this, I don’t have an error but the results are huge (with 10e+25 order that is logical). I wanted an error to force the code with a try/except but currently the value belongs to [-1e-18; 1e18].
Just for the information, I also tested a guess value belongs to C1 class but the code diverged too.
@bleyerj Bleyer had already treated this kind of formulation with the package mgis.fenics but I would like to manage this formulation in 2D with fenics first before used mgis package for more complexe cases (3D).
I joined are the results I got when I run the code. I joined the code too to show how I compute the eigen values and vectors.
I will be grateful for any advice !
Thanks a lot for the help.
Lamia
Results :
Display U_ unknow function
__________________________________________________________
ux.vector().get_local() : [ 0.00000000e+00 0.00000000e+00 -1.20492473e-17 -2.25378701e-17
0.00000000e+00 6.59121014e-18 -1.78618593e-18 -1.40755132e-18
0.00000000e+00 5.58999480e-18 -2.81510265e-18 0.00000000e+00
0.00000000e+00]
uy.vector().get_local() : [0.22222222 0.11111111 0.16666667 0.22222222 0. 0.05555556
0.11111111 0.16666667 0.22222222 0. 0.05555556 0.11111111
0. ]
Strain component in cartesian basis
__________________________________________________________
eps00 : [ 8.23315702e-17 1.99907200e-18 3.48658126e-17 -2.79660615e-17
-4.26654172e-17 -3.50600942e-18 -1.23538316e-18 -3.48658126e-17
-2.63994473e-17 2.54952951e-17 3.50600942e-18 4.71694314e-19
-8.32517308e-18]
eps11 : [0.22222222 0.22222222 0.22222222 0.22222222 0.22222222 0.22222222
0.22222222 0.22222222 0.22222222 0.22222222 0.22222222 0.22222222
0.22222222]
eps01 : [ 3.75936277e-18 2.55270551e-17 2.26150643e-17 -2.40409858e-17
6.97678205e-19 3.27099423e-17 -1.21789723e-17 -3.94820142e-17
7.99832289e-18 -7.85679934e-18 -3.00930695e-17 -7.87934707e-18
7.76037125e-18]
Discriminant (check issue with sqrt()
__________________________________________________________
delta : [0.04938272 0.04938272 0.04938272 0.04938272 0.04938272 0.04938272
0.04938272 0.04938272 0.04938272 0.04938272 0.04938272 0.04938272
0.04938272]
lambda0 : [0.33333333 0.33333333 0.33333333 0.33333333 0.33333333 0.33333333
0.33333333 0.33333333 0.33333333 0.33333333 0.33333333 0.33333333
0.33333333]
Eigen value lambda0 et lamdba1
__________________________________________________________
lambda0 = [0.22222222 0.22222222 0.22222222 0.22222222 0.22222222 0.22222222
0.22222222 0.22222222 0.22222222 0.22222222 0.22222222 0.22222222
0.22222222]
lambda1 = [ 7.24453566e-17 -1.49764460e-16 -9.16925266e-17 9.88792381e-17
-5.04721926e-17 -1.92802123e-16 6.76542156e-17 1.85367594e-16
-7.59148035e-17 7.11236625e-17 1.75454889e-16 5.60893924e-17
-6.40195569e-17]
Eigen vector components v0 = [v0x, v0y], v1= [v1x, v1y]
__________________________________________________________
v0x = [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
v0y = [ 1.16585344e+17 -1.42508396e+16 6.18573817e+16 5.78184618e+16
3.43871879e+16 2.76925921e+16 -4.31071142e+15 -2.26450483e+16
-1.58441840e+16 2.44384602e+15 -1.51142633e+16 5.77919406e+15
-1.43041773e+16]
v1x = [-1.16585344e+17 1.42508396e+16 -6.18573817e+16 -5.78184618e+16
-3.43871879e+16 -2.76925921e+16 4.31071142e+15 2.26450483e+16
1.58441840e+16 -2.44384602e+15 1.51142633e+16 -5.77919406e+15
1.43041773e+16]
v1y = [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
Implementation :
"""
Usefull function
"""
from fenics import *
import numpy as np
import matplotlib.pyplot as plt
import sys
import time
# Define strain-rate and stress tensor
def epsilon(u):
return sym(nabla_grad(u))
def eig_val_2D(m):
#DOLFIN_EPS = 1E-14
delta = sqrt( m[0,0]**2 + m[1,1]**2 - 2 * m[0,0]* m[1,1] + 4 * m[0,1]+m[1,0])
m00 = (m[0,0]+m[1,1])/2. + 0.5 * delta
m01 = 0.0
m10 = 0.0
m11 = (m[0,0]+m[1,1])/2. - 0.5 * delta
return m00, m01, m11, m10
import ufl
def eig_vec_2D(m):
delta = m[0, 0]**2 + m[1, 1]**2 - 2*m[0, 0]*m[1, 1] + 4*m[0, 1]*m[1, 0]
v0x = 1.0 # associated to 0.5*tr(m)+0.5 * delta
v1y = 1.0 # associated to 0.5*tr(m)-0.5 * delta
#w = (m[1, 1] - m[0, 0] + sqrt(delta)) / (m[0, 1]) #+DOLFIN_EPS )
#v0y = 0.5 * w
#v1x = -0.5 * w
v0y = conditional(ufl.eq(m[0,1], 0.), 0., 0.5 * (m[1, 1] - m[0, 0] + sqrt(delta)) / (m[0, 1]) )
v1x = conditional(ufl.eq(m[0,1], 0. ), 0., -0.5 * (m[1, 1] - m[0, 0] + sqrt(delta)) / (m[0, 1]) )
return v0x, v0y,v1x,v1y
def strain_p(m):
#m = epsilon(u)
m00, m01, m11, m10 = eig_val_2D(m)
w00 = conditional(gt(m00, 0.), m00, 0.)
w11 = conditional(gt(m11, 0.), m11, 0.)
D_pos_eigval = as_tensor([[w00, 0.],[0., w11]])
v1x, v1y,v2x, v2y = eig_vec_2D(m)
P_pos_eigval = as_tensor([[v1x, v2x],[v1y, v2y]])
return dot(P_pos_eigval, dot(D_pos_eigval,P_pos_eigval.T ))
def sigma_miehe(u, G , lmbda, ndim):
eps = epsilon(u)
eps_plus = strain_p(eps)
eps_moins = eps - eps_plus
sig_plus = lmbda * tr(eps_plus) * Identity(ndim) + 2*G * eps_plus
sig_moins = lmbda * tr(eps_moins) * Identity(ndim) + 2*G * eps_moins
return sig_plus + sig_moins
def sigma_bourdin(u, G, lmbda,ndim):
return 2 * G * epsilon(u) + lmbda*tr(epsilon(u))*Identity(ndim)
# Bulk energy ----------------------------------
def psi_plus(u, lmbda, G ):
eps = epsilon(u)
eps1, m01, eps2, m10= eig_val_2D(eps)
tr_eps_plus = ppos(tr(eps))
eps_plus_doubledot_eps_plus = ppos(eps1)**2 + ppos(eps2)**2
energy = (1./2.)*lmbda*(tr_eps_plus**2) + G * eps_plus_doubledot_eps_plus
return energy
# Historical variable -----------------------------------
def H(u_old, u_new, H_old, lmbda, G):
psi_i_new = psi_plus(u_new, lmbda, G)
psi_i_old = psi_plus(u_old, lmbda, G)
psi_new = ppos(psi_i_new)
psi_old = ppos(psi_i_old )
return conditional(lt(psi_old, psi_new), psi_new, H_old)
print("======================================================================")
ERROR = 40
set_log_level(ERROR) # log level
PROGRESS = 16
#set_log_level(PROGRESS) # 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
# ------------------
# folder name : save file Create VTK file for saving solution
# ------------------
savedir = "results_CubeLinElas_Miehe_nx10/"
vtkfileU = File(savedir+'displacement.pvd')
vtkfileSigma = File(savedir+'stress.pvd')
"""
=========================================================
Problem
=========================================================
"""
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]
#psi_cr = 0#Constant(Gc/(2*lw))
T = 1. # final time
num_steps = 10 # number of time steps
#dt = T / num_steps # time step size
time_step = np.linspace(0, T, num_steps)
n = 2 # ele : 20201 cellsize h = 0.01 mm l/h = 1
mesh = UnitSquareMesh(n, n,'crossed')
Nnode = len(mesh.coordinates())
coord = mesh.coordinates()
ndim = mesh.topology().dim()
V = VectorFunctionSpace(mesh,'Lagrange', 1)
V_alpha = FunctionSpace(mesh,'Lagrange', 1)
V_H = FunctionSpace(mesh,'DG', 0)
Tens = TensorFunctionSpace(mesh, 'Lagrange', 1)
"""
=========================================================
Boundary condition
=========================================================
"
Disp = Expression( 't', t = 0.0, degree = 1 )
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.sub(1) , Constant((0.)), boundary_bottom)
bcu_right = DirichletBC( V.sub(0) , Constant(0.), boundary_right)
bcu_left = DirichletBC( V.sub(0) , Constant(0.), boundary_left)
bcu_up = DirichletBC( V.sub(1) , Disp, boundary_up )
bcu = [bcu_bottom, bcu_up, bcu_right, bcu_left]
du,v,u_ = TrialFunction(V), TestFunction(V), Function(V)
sig_funct = Function(Tens, name="Stress")
"""
=========================================================
Define Variational problem
=========================================================
"""
#u_guess = interpolate(Expression( ('x[1]', 'x[0]*x[0]'), degree = 2 ),V)
#u_.assign(u_guess)
it = 0
DOLFIN_EPS = 1E-14
for t in time_step[1:]:
it +=1
Disp.t = t
print("\n")
print("======================================================================")
print('\n -> Time Step : %d, Time [s] : %.3g, Ux_given [mm] : %.3g mm ' %(it, t, Disp.t))
print("======================================================================")
if it < 4:
sigma = sigma_bourdin(u_ , G, lmbda,ndim)
else:
sigma = sigma_miehe(u_ , G , lmbda, ndim)
#sigma = sigma_miehe(u_ , G , lmbda, ndim)
f = inner( sigma, epsilon(v) ) * dx + dot( Constant((0., 0.)), v ) * ds
J = derivative(f, u_, du)
problem = NonlinearVariationalProblem(f, u_, bcu, J)
solver = NonlinearVariationalSolver(problem)
newton_prm = solver.parameters['newton_solver']
newton_prm['relative_tolerance'] = 1e-8
newton_prm['absolute_tolerance'] = 1e-8
newton_prm['maximum_iterations'] = 100
newton_prm['krylov_solver']['nonzero_initial_guess'] = True
#---------------- RESOLUTION
iter_u = solver.solve()
#---------------- Dispay - Check errors
ux = u_.sub(0, deepcopy=True)
uy = u_.sub(1, deepcopy=True)
print("\n")
print(" Display U_ unknow function")
print("__________________________________________________________")
print("\n ux.vector().get_local() : ", ux.vector().get_local()[:])
print("\n uy.vector().get_local() : ", uy.vector().get_local()[:])
eps = epsilon(u_)
print("\nStrain component in cartesian basis")
print("__________________________________________________________")
print(' \neps00 :',project(epsilon(u_)[0, 0], V_alpha).vector().get_local() )
print(' eps11 :',project(epsilon(u_)[1, 1], V_alpha).vector().get_local() )
print(' eps01 :',project(epsilon(u_)[0, 1], V_alpha).vector().get_local() )
print("\nDiscriminant (check issue with sqrt() ")
print("__________________________________________________________")
delta = (eps[0,0]**2 + eps[1,1]**2 - 2 * eps[0,0]* eps[1,1] + 4 * eps[0,1]+eps[1,0])
print('\ndelta : ', project(delta, V_alpha).vector().get_local())
#print('lmbPart 1 : ', project((eps[0,0]+eps[1,1])/2. , V_alpha).vector().get_local())
#print('lmbPart 2 : ', project( sqrt(delta), V_alpha).vector().get_local())
print('lambda0 : ', project((eps[0,0]+eps[1,1])/2. + sqrt(delta) , V_alpha).vector().get_local())
print("\nEigen value lambda0 et lamdba1")
print("__________________________________________________________")
lambda00, m01, lambda11, m10 = eig_val_2D(eps)
print('\nlambda0 = ', project(lambda00, V_alpha).vector().get_local())
print('lambda1 = ' , project(lambda11, V_alpha).vector().get_local())
print("\nEigen vector components v0 = [v0x, v0y], v1= [v1x, v1y]")
print("__________________________________________________________")
v0x, v0y, v1x, v1y = eig_vec_2D(eps)
print('\nv0x = ', project(v0x, V_alpha).vector().get_local())
print('v0y = ' , project(v0y, V_alpha).vector().get_local())
print('v1x = ', project(v1x, V_alpha).vector().get_local())
print('v1y = ' , project(v1y, V_alpha).vector().get_local())
print(" \nPositive strain compoenents in cartesian basis")
print(" eps_plus = P*macaulay(D)*P^T = [ [eps00_p,eps01_p ], [eps11_p],eps10_p ]")
print("__________________________________________________________")
eps_p = strain_p(eps)
print(' \neps00_p :',project(eps_p[0, 0], V_alpha).vector().get_local() )
print(' eps11_p :',project(eps_p[1, 1], V_alpha).vector().get_local() )
#print(' eps01_p :',project(eps_p[0, 1], V_alpha).vector().get_local() )
print(" \nStress components in cartesian basis")
print(" \nDisplay stress component project in cartesian basis ")
print(" sig = sig_plus + sig_minus = [ [s00, s01 ], [s11], s10 ]")
print("__________________________________________________________")
print(' \nsig00 :',project(sigma[0, 0], V_alpha).vector().get_local() )
print(' sig11 :',project(sigma[1, 1], V_alpha).vector().get_local() )
#print(' sig01 :',project(sigma[0, 1], V_alpha).vector().get_local() )
#---------------- PostProcess
sig_funct.assign(project(sigma, Tens))
elastic_energy = 0.5*inner(sigma, epsilon(u_))*dx
elastic_energy_density = project(0.5*inner(sigma, epsilon(u_)), V_alpha)
elastic_energy_value = assemble(elastic_energy)
Fn = assemble(sigma[0,0]*ds(2))
Ft = assemble(sigma[1,1]*ds(2))
ux = u_.sub(0, deepcopy=True)
uy = u_.sub(1, deepcopy=True)
vtkfileU << u_
vtkfileSigma << sig_funct
print( "\nEel_density_max: %.8g" % (elastic_energy_density.vector().max()))
print("\n(Fn, Ft): (%.8g,%.8g)"%(Fn,Ft))
print("\nElastic energies : (%g)"%(elastic_energy_value))
print("-------------------------------------------------------------")