Hello everyone,
I am trying to implement the variable stiffness i.e. change the stiffness after some load step in FEniCS.To implement this, I am using User Expression, it was giving me the error. The same expression without User Expression operation works fine. Please help me to fix the issue, I am new to the FEniCS.
The minimal code is as follow,
from fenics import *
from mshr import *
import matplotlib.pyplot as plt
from ufl import nabla_div
import numpy as np
from ufl import replace
import sys, os, shutil, math
from numpy.linalg import eig
from dolfin import *
from numpy import array
import time
from ufl import eq
from ufl import le
from ufl import ge
# Define Material Properties
E_1 = 22700. # Young's Modulus
nu_1 = 0.2 # Poisson ratio
mu = E_1/(2.0*(1.0 + nu_1)) #lame's constant
lmbda = (E_1 * nu_1)/((1.0 - 2.0*nu_1)*(1.0 + nu_1)) #lame's constant
# Mesh Data
mesh = Mesh('mesh_Ln5.xml') # Import mesh
ndim = mesh.topology().dim() # Dimension of a geometry
thickness = 50.
# Create function space for 2D elasticity + Damage
V_u = VectorFunctionSpace(mesh, 'CG', 1) # Vector function space for displacement field
# Define the function, test and trial fields (alpha is phase field)
u, du, v = Function(V_u), TrialFunction(V_u), TestFunction(V_u)
u.rename('displacement','displacement')
tol = 1E-5 # Tolerance for boundary identification
tol_v = 1e-20 # Tolerance for square-root calculation
def boundary_D_l(x, on_boundary): # Find bottom edge of specimen
return x[0] >= 54.0 - tol and x[0] <= 56.0 - tol and x[1] <= 0.0 + tol
def boundary_D_r(x, on_boundary): # left lower corner to fix
return x[0] >= 654.0 - tol and x[0] <= 656.0 - tol and x[1] <= 0.0 + tol
def boundary_D_t(x, on_boundary): # Find location of traction/displacement
return x[1] >= 150.0-tol and x[0] >= 354.98-tol and x[0] <= 355.02+tol
bcl = DirichletBC(V_u, Constant((0.0 ,0.0)), boundary_D_l, method='pointwise') # Apply boundary condition
bcr = DirichletBC(V_u.sub(1), Constant(0.0), boundary_D_r, method='pointwise') # Apply boundary condition
# Calculation of positive part of strain
def eps_positive(u):
A = sym(grad(u))
a = A[0,0]
b = A[0,1]
c = A[1,0]
d = A[1,1]
eig_1 = ((tr(A) + sqrt(tr(A)**2-4*det(A) + tol_v))/2) # Evaluation of Eigen value
eig_2 = ((tr(A) - sqrt(tr(A)**2-4*det(A) + tol_v))/2) # Evaluation of Eigen value
phi_1 = (eig_1 - b - d)/(a + c - eig_1)
phi_2 = (eig_2 - b - d)/(a + c - eig_2)
eig_v_1 = [phi_1/sqrt(phi_1**2 + 1), 1/sqrt(phi_1**2 + 1)] # Evaluation of Eigen vector
eig_v_2 = [phi_2/sqrt(phi_2**2 + 1), 1/sqrt(phi_2**2 + 1)] # Evaluation of Eigen vector
# Positive Strain Tensor
sn_P = 0.5*(eig_1 + abs(eig_1))*np.outer(eig_v_1,eig_v_1) + 0.5*(eig_2 + abs(eig_2))*np.outer(eig_v_2,eig_v_2)
sn_1 = as_matrix(sn_P.tolist())
return sn_1
# Calculation of negative part of strain
def eps_negative(u):
A = sym(grad(u))
a = A[0,0]
b = A[0,1]
c = A[1,0]
d = A[1,1]
eig_1 = ((tr(A) + sqrt(tr(A)**2-4*det(A) + tol_v))/2) # Evaluation of Eigen value
eig_2 = ((tr(A) - sqrt(tr(A)**2-4*det(A) + tol_v))/2) # Evaluation of Eigen value
phi_1 = (eig_1 - b - d)/(a + c - eig_1)
phi_2 = (eig_2 - b - d)/(a + c - eig_2)
eig_v_1 = [phi_1/sqrt(phi_1**2 + 1), 1/sqrt(phi_1**2 + 1)] # Evaluation of Eigen vector
eig_v_2 = [phi_2/sqrt(phi_2**2 + 1), 1/sqrt(phi_2**2 + 1)] # Evaluation of Eigen vector
# Negative Strain Tensor
sn_N = 0.5*(eig_1 - abs(eig_1))*np.outer(eig_v_1,eig_v_1) + 0.5*(eig_2 - abs(eig_2))*np.outer(eig_v_2,eig_v_2)
sn_1 = as_matrix(sn_N.tolist())
return sn_1
def eps(u):
"""Strain tensor as a function of the displacement"""
return sym(grad(u))
# expressions_with variable_stiffness
class el_en_1(UserExpression):
def __init__(self, u_sol, **kwargs):
super().__init__(**kwargs)
self.u_sol = u_sol
def eval(self, value, x):
value = 0.5*lmbda*(0.5*(tr(eps(u_sol)) + abs(tr(eps(u_sol)))))**2 + mu*tr(eps_positive(u_sol)*eps_positive(u_sol))
def value_shape(self):
return (2,)
class el_en_2(UserExpression):
def __init__(self, u_sol, **kwargs):
super().__init__(**kwargs)
self.u_sol = u_sol
def eval(self, value, x):
value = 0.5*lmbda*(0.5*(tr(eps(u_sol)) - abs(tr(eps(u_sol)))))**2 + mu*tr(eps_negative(u_sol)*eps_negative(u_sol))
def value_shape(self):
return (2,)
ele_ene_1 = el_en_1(u_sol=u,element = V_u.ufl_element())
ele_ene_2 = el_en_2(u_sol=u,element = V_u.ufl_element())
#print(ele_ene_1.shape)
elastic_energy_1 = ele_ene_1#0.5*lmbda*(0.5*(tr(eps(u)) + abs(tr(eps(u)))))**2 + mu*tr(eps_positive(u)*eps_positive(u)) # Positive part of strain energy density
elastic_energy_2 = ele_ene_2#0.5*lmbda*(0.5*(tr(eps(u)) - abs(tr(eps(u)))))**2 + mu*tr(eps_negative(u)*eps_negative(u)) # negative part of strain energy density
elastic_energy = (elastic_energy_1 + elastic_energy_2)*thickness*dx # total strain energy density (bulk energy density)
total_energy = elastic_energy
# First and second directional derivative wrt u
E_u = derivative(total_energy,u,v) # first directional derivatives of total energy with respect of displacement test function v
Jd = derivative(E_u, u, du)
# define loading steps
num_steps = 200 # total number of load steps
total_disp = -0.2 # total applied displacement
steps_loading = 200
disp_steps = total_disp/(steps_loading)
u_R = Expression(('disp_app'),disp_app = disp_steps, n=0., degree=0) # Define loading as expression so that it can be updated for next step
bct = DirichletBC(V_u.sub(1), u_R, boundary_D_t, method='pointwise') # define boundary condition
bc_disp = [bcl, bcr, bct] # Apply boundary conditions
# Solver for displacement field
problem_u = NonlinearVariationalProblem(E_u, u, bc_disp, Jd)
solver_u = NonlinearVariationalSolver(problem_u)
prm = solver_u.parameters
prm["newton_solver"]["relative_tolerance"] = 5E-1
prm["newton_solver"]["absolute_tolerance"] = 5E-3
prm["newton_solver"]["convergence_criterion"] = "residual"
prm["newton_solver"]["error_on_nonconvergence"] = True
prm["newton_solver"]["linear_solver"] = 'mumps'
prm["newton_solver"]["lu_solver"]["symmetric"] = False
prm["newton_solver"]["maximum_iterations"] = 2000
prm["newton_solver"]["relaxation_parameter"] = 1.0
prm["newton_solver"]["krylov_solver"]["nonzero_initial_guess"] = True
for n in range(num_steps):
u_R.disp_app = disp_steps*(n+1)
solver_u.solve()
The error is as follow,
Thank you
Manish Kumar