# Solving Thermoelasticity Problems

Hi all, recently I’m trying to learn some code to solve the thermoplastic problem with the following code:

``````#####################    2024.5.7
import sys
sys.argv=['']
del sys

#######################   2024.5.8
import warnings

import numpy as np
from arguments import args
from utils import walltime
import fenics as fe
import os
import glob

#############################################################    2024.5.8
fe.parameters["form_compiler"]["representation"] = 'uflacs'

import warnings

@walltime
def simulation():

#########################   参数设定
ambient_T = args.T_ambient
rho = args.rho
Cp = args.c_p
k = args.kappa_T
h = args.h_conv
eta = args.power_fraction
r = args.r_beam
P = args.power
EPS = 1e-8        ##### 无限小值

E = fe.Constant(70e3)            ### 弹性模量
nu = fe.Constant(0.3)            ### 泊松比
lmbda = E*nu/(1+nu)/(1-2*nu)     ### 拉梅系数
mu = E/2./(1+nu)                 ### 切变模量
sig0 = fe.Constant(250.)
Et = E/100.
H = E*Et/(E-Et)                  ### ？？？

x0 = 0.2*args.domain_x
y0 = 0.5*args.domain_y

total_t = 1200*1e-6
vel = 0.6*args.domain_x/total_t
dt = 1e-6
ts = np.arange(0., total_t + dt, dt)
print(f"total time steps = {len(ts)}")

ele_size = 0.01

##############################################################################################################  画网格
mesh = fe.BoxMesh(fe.Point(0., 0., 0.), fe.Point(args.domain_x, args.domain_y, args.domain_z),
round(args.domain_x/ele_size), round(args.domain_y/ele_size), round(args.domain_z/ele_size))
mesh_file = fe.File(f'data/vtk/pbf/mesh/mesh.pvd')
mesh_file << mesh

#############################  Define bottom surface
class Bottom(fe.SubDomain):
def inside(self, x, on_boundary):
# The condition for a point x to be on bottom side is that x[2] < EPS
return on_boundary and x[2] < EPS

# Define top surface
class Top(fe.SubDomain):
def inside(self, x, on_boundary):
return on_boundary and x[2] > args.domain_z - EPS

# Define the other four surfaces
class SurroundingSurfaces(fe.SubDomain):
def inside(self, x, on_boundary):
return on_boundary and (x[0] < EPS or x[0] > args.domain_x - EPS or x[1] < EPS or x[1] > args.domain_y - EPS)

bottom = Bottom()
top = Top()
surrounding_surfaces = SurroundingSurfaces()
boundaries = fe.MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundaries.set_all(0)                                                           ###默认边界标记为0
bottom.mark(boundaries, 1)                                                      ###底部边界标记为1
top.mark(boundaries, 2)                                                         ###顶部边界标记为2
surrounding_surfaces.mark(boundaries, 3)                                        ###周围边界标记为3
ds = fe.Measure('ds')(subdomain_data=boundaries)
normal = fe.FacetNormal(mesh)

#############     ？？？？？？？？
deg_u = 2
deg_stress = 2
# TODO: can we do a tensor element?
U = fe.VectorFunctionSpace(mesh, "CG", deg_u)
W = fe.FunctionSpace(mesh, We)
# W = fe.FunctionSpace(mesh, We)
W0 = fe.FunctionSpace(mesh, W0e)

########################  定义微分算子
sig = fe.Function(W)
sig_old = fe.Function(W)
n_elas = fe.Function(W)
beta = fe.Function(W0)
# name = "a b" is bad (having a space)!
p = fe.Function(W0, name="Cumulative plastic strain")      ### 累积塑性应变
u = fe.Function(U, name="Total displacement")              ### 总唯一
du = fe.Function(U, name="Iteration correction")           ### 迭代校正 ？？？
Du = fe.Function(U, name="Current increment")              ### 当前增量
v = fe.TrialFunction(U)
u_ = fe.TestFunction(U)

############################################################    定义第一类边界条件
u_bcs = [fe.DirichletBC(U, fe.Constant((0., 0., 0.)), bottom)]

####################################    定义应变
def eps(v):      ### 应变
return e

#######################################    定义物理方程来计算弹性应力
def sigma(eps_el):        ### 物理方程
return lmbda*fe.tr(eps_el)*fe.Identity(3) + 2*mu*eps_el

###################################################   定义张量
def as_3D_tensor(X):        ### 张量？？？
return fe.as_tensor([[X[0], X[1], X[2]],
[X[3], X[4], X[5]],
[X[6], X[7], X[8]]])

###################################################   定义向量
def as_long_vector(X):     ### 向量？？？
return fe.as_vector([X[0, 0], X[0, 1], X[0, 2], X[1, 0], X[1, 1], X[1, 2], X[2, 0], X[2, 1], X[2, 2]])

#############################################################    ？？？？？
ppos = lambda x: (x+abs(x))/2.   ### ppos(x)=(x+|x|)/2

################################################     定义热应变
def thermal_strain(dT):     ### 热应变
alpha_V = 1e-5
return alpha_V*dT*fe.Identity(3)

#######################################################  计算 ？？？
def proj_sig(deps, dT, sig_old, p_old):
sig_n = as_3D_tensor(sig_old)   ### ？？？

# sig_elas = sig_n + sigma(deps)

d_eps_T = thermal_strain(dT)    ### 计算当前热应变
sig_elas = sig_n + sigma(deps - d_eps_T)   ### 弹性应力 = sig_n + ？？？

s = fe.dev(sig_elas)                    ###  弹性 应力偏张量
sig_eq = fe.sqrt(3/2.*fe.inner(s, s))   ###  Von mises应力
f_elas = sig_eq - sig0 - H*p_old
dp = ppos(f_elas)/(3*mu+H)
n_elas = s/sig_eq*ppos(f_elas)/f_elas
beta = 3*mu*dp/sig_eq
new_sig = sig_elas-beta*s

return as_long_vector(new_sig), as_long_vector(n_elas), beta, dp

###################     ？？？
def sigma_tang(e):
N_elas = as_3D_tensor(n_elas)
return sigma(e) - 3*mu*(3*mu/(3*mu+H)-beta)*fe.inner(N_elas, e)*N_elas-2*mu*beta*fe.dev(e)

##############################################################################   定义微分 dxm

#############################################   求解器
# TODO
a_Newton = fe.inner(eps(v), sigma_tang(eps(u_)))*dxm
res = -fe.inner(as_3D_tensor(sig), eps(u_))*dxm + 1e-10*fe.dot(normal, u_)*ds(2)

def local_project(v, V, u=None):
dv = fe.TrialFunction(V)
v_ = fe.TestFunction(V)
a_proj = fe.inner(dv, v_)*dxm
b_proj = fe.inner(v, v_)*dxm
solver = fe.LocalSolver(a_proj, b_proj)
solver.factorize()
if u is None:
u = fe.Function(V)
solver.solve_local_rhs(u)
return u
else:
solver.solve_local_rhs(u)

def global_project(v, V, u=None):
'''
Not working.
'''
if u is None:
return fe.project(v, V)
else:
u.assign(fe.project(v, V))

P0 = fe.FunctionSpace(mesh, "DG", 0)
p_avg = fe.Function(P0, name="Plastic strain")

V = fe.FunctionSpace(mesh, 'CG', 1)
T_crt = fe.interpolate(fe.Constant(ambient_T), V)   ###  将环境温度插值到 T_rt
T_pre = fe.interpolate(fe.Constant(ambient_T), V)   ###  将环境温度插值到 T_pre
T_old = fe.interpolate(fe.Constant(ambient_T), V)   ###  将环境温度插值到 T_old
T_old.rename('T', 'T')
v = fe.TestFunction(V)

# If theta = 0., we recover implicit Eulear; if theta = 1., we recover explicit Euler; theta = 0.5 seems to be a good choice.
theta = 0.5
T_rhs = theta*T_pre + (1 - theta)*T_crt
T_bcs = [fe.DirichletBC(V, fe.Constant(ambient_T), bottom)]

class LaserExpression(fe.UserExpression):
def __init__(self, t):
super(LaserExpression, self).__init__()
self.t = t

def eval(self, values, x):
t = self.t
values[0] = 2*P*eta/(np.pi*r**2) * np.exp(-2*((x[0] - x0 - vel*t)**2 + (x[1] - y0)**2) / r**2)   ###高斯热源

def value_shape(self):
return ()

###  定义热流密度
q_laser = LaserExpression(None)
q_convection = h * (T_rhs - ambient_T)  ### 与环境交换的热流密度

q_top = q_convection + q_laser ### 顶部热流密度
q_surr = q_convection          ###  周围热流密度

#### 热变分方程
res_T = rho*Cp/dt*(T_crt - T_pre) * v * fe.dx + k * fe.dot(fe.grad(T_rhs), fe.grad(v)) * fe.dx - q_top * v * ds(2) - q_surr * v * ds(3)

files_vtk = glob.glob('data/vtk/pbf/sols' + f"/*")
files_xdmf = glob.glob('data/xdmf/pbf/' + f"/*")
for f in files_vtk + files_xdmf:
os.remove(f)

T_vtk_file = fe.File(f'data/vtk/pbf/sols/T.pvd')
T_vtk_file << T_old
u_vtk_file = fe.File(f'data/vtk/pbf/sols/u.pvd')
u_vtk_file << u
p_vtk_file = fe.File(f'data/vtk/pbf/sols/p.pvd')
p_vtk_file << p_avg

file_results = fe.XDMFFile('data/xdmf/pbf/u.xdmf')
file_results.parameters["functions_share_mesh"] = True
file_results.write(T_old, 0)
file_results.write(u, 0)
file_results.write(p_avg, 0)

###  ？？？
plastic_inverval = 10

for i in range(len(ts) - 1):
# for i in range(100):

print(f"step {i + 1}, time = {ts[i + 1]}")
q_laser.t = theta*ts[i] + (1 - theta)*ts[i + 1]
solver_parameters = {'newton_solver': {'maximum_iterations': 20, 'linear_solver': 'mumps'}}
fe.solve(res_T == 0, T_crt, T_bcs, solver_parameters=solver_parameters)
T_pre.assign(T_crt)
print(f"min T = {np.min(np.array(T_pre.vector()))}")
print(f"max T = {np.max(np.array(T_pre.vector()))}")

if (i + 1) % plastic_inverval == 0:

T_crt_array = np.array(T_crt.vector())
T_crt_array = np.where(T_crt_array < args.T_ambient, args.T_ambient, T_crt_array)
T_crt_array = np.where(T_crt_array > args.T_melt, args.T_melt, T_crt_array)
T_old_array = np.array(T_old.vector())
T_old_array = np.where(T_old_array < args.T_ambient, args.T_ambient, T_old_array)
T_old_array = np.where(T_old_array > args.T_melt, args.T_melt, T_old_array)
dT = fe.Function(V)
dT.vector()[:] = T_crt_array - T_old_array

Nitermax, tol = 200, 1e-8  # parameters of the Newton-Raphson procedure
Nincr = 20
A, Res = fe.assemble_system(a_Newton, res, u_bcs)
nRes0 = Res.norm("l2")
nRes = nRes0
Du.interpolate(fe.Constant((0., 0., 0.)))

niter = 0
nRes = 1.
tol = 1e-8
# while nRes/nRes0 > tol and niter < Nitermax:
# while niter < Nitermax:
while nRes > tol:
print("\n")
fe.solve(A, du.vector(), Res, "mumps")
Du.assign(Du+du)
deps = eps(Du)

print(f"du norm = {np.linalg.norm(np.array(du.vector()))}")

sig_, n_elas_, beta_, dp_ = proj_sig(deps, dT, sig_old, p)

local_project(sig_, W, sig)
local_project(n_elas_, W, n_elas)
local_project(beta_, W0, beta)

print(f"sig dof = {np.array(sig.vector()).shape}")
print(f"sig norm = {np.linalg.norm(np.array(sig.vector()))}")
print(f"n_elas norm = {np.linalg.norm(np.array(n_elas.vector()))}")
print(f"beta norm = {np.linalg.norm(np.array(beta.vector()))}")

A, Res = fe.assemble_system(a_Newton, res, u_bcs)
nRes = Res.norm("l2")
print(f"Residual: {nRes}")
niter += 1

u.assign(u + Du)
sig_old.assign(sig)
p.assign(p + local_project(dp_, W0))
p_avg.assign(fe.project(p, P0))

T_old.assign(T_crt)

T_vtk_file << T_old
u_vtk_file << u
p_vtk_file << p_avg

file_results.write(T_old, i)
file_results.write(u, i)
file_results.write(p_avg, i)

if __name__ == '__main__':
simulation()
``````

However, the following termination prompt occurs at runtime:

``````total time steps = 1201
step 1, time = 1e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.673e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.542e-15 (tol = 1.000e-10) r (rel) = 1.325e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 222.90478952318136
max T = 626.8787673050991
step 2, time = 2e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.493e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.798e-15 (tol = 1.000e-10) r (rel) = 1.523e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 166.55333636485113
max T = 921.3033025511313
step 3, time = 3e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.356e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.812e-15 (tol = 1.000e-10) r (rel) = 1.618e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 127.37031053945051
max T = 1187.94139149658
step 4, time = 4e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.249e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.906e-15 (tol = 1.000e-10) r (rel) = 1.737e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 102.39728953243596
max T = 1430.6975413440534
step 5, time = 4.9999999999999996e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.166e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.940e-15 (tol = 1.000e-10) r (rel) = 1.819e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 89.18351978618001
max T = 1652.8452031367121
step 6, time = 6e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.100e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.890e-15 (tol = 1.000e-10) r (rel) = 1.852e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 85.6964775024509
max T = 1857.1351943306179
step 7, time = 7e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.047e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.842e-15 (tol = 1.000e-10) r (rel) = 1.877e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 90.24856579917454
max T = 2045.884735255056
step 8, time = 8e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 2.004e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 3.923e-15 (tol = 1.000e-10) r (rel) = 1.958e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 101.43697595655647
max T = 2221.050673091609
step 9, time = 9e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 1.967e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 4.236e-15 (tol = 1.000e-10) r (rel) = 2.154e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 118.09429848428876
max T = 2384.2897908180103
step 10, time = 9.999999999999999e-06
No Jacobian form specified for nonlinear variational problem.
Differentiating residual form F to obtain Jacobian J = F'.
Solving nonlinear variational problem.
Newton iteration 0: r (abs) = 1.935e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 4.225e-15 (tol = 1.000e-10) r (rel) = 2.184e-15 (tol = 1.000e-09)
Newton solver finished in 1 iterations and 1 linear solver iterations.
min T = 139.24792102761893
max T = 2537.00855348994
``````

please save your code in a python file and run it through there. This typically shows a stack trace of the error which may be helpful in debugging why the kernel crashed.

I tested the code and found that it crashes the kernel when it assembles a linear system:

``````A, Res = fe.assemble_system(a_Newton, res, u_bcs)
``````

So how do I assemble a linear system?