I didn’t think it was necessary, but here it goes. The mesh is generated with gmsh, here’s the file.geo:
SetFactory("OpenCASCADE");
Box(1) = {0, 0, 0, 1e-3, 1e-3, 1e-2};
Physical Volume("the_rod", 20) = {1};
Physical Surface("left_side",21) = {6};
Physical Surface("res_of_rod_surface",22) = {1,2,3,4,5};
and the corresponding file.msh:
$MeshFormat
4.1 0 8
$EndMeshFormat
$PhysicalNames
3
2 21 "left_side"
2 22 "res_of_rod_surface"
3 20 "the_rod"
$EndPhysicalNames
$Entities
8 12 6 1
1 0 0 0.01 0
2 0 0 0 0
3 0 0.001 0.01 0
4 0 0.001 0 0
5 0.001 0 0.01 0
6 0.001 0 0 0
7 0.001 0.001 0.01 0
8 0.001 0.001 0 0
1 -1e-07 -1e-07 -1.000000000002735e-07 1e-07 1e-07 0.0100001 0 2 2 -1
2 -1e-07 -9.999999999994822e-08 0.009999900000000001 1e-07 0.0010001 0.0100001 0 2 1 -3
3 -1e-07 0.0009999 -1.000000000002735e-07 1e-07 0.0010001 0.0100001 0 2 4 -3
4 -1e-07 -9.999999999994822e-08 -1e-07 1e-07 0.0010001 1e-07 0 2 2 -4
5 0.0009999 -1e-07 -1.000000000002735e-07 0.0010001 1e-07 0.0100001 0 2 6 -5
6 0.0009999 -9.999999999994822e-08 0.009999900000000001 0.0010001 0.0010001 0.0100001 0 2 5 -7
7 0.0009999 0.0009999 -1.000000000002735e-07 0.0010001 0.0010001 0.0100001 0 2 8 -7
8 0.0009999 -9.999999999994822e-08 -1e-07 0.0010001 0.0010001 1e-07 0 2 6 -8
9 -9.999999999994822e-08 -1e-07 -1e-07 0.0010001 1e-07 1e-07 0 2 2 -6
10 -9.999999999994822e-08 -1e-07 0.009999900000000001 0.0010001 1e-07 0.0100001 0 2 1 -5
11 -9.999999999994822e-08 0.0009999 -1e-07 0.0010001 0.0010001 1e-07 0 2 4 -8
12 -9.999999999994822e-08 0.0009999 0.009999900000000001 0.0010001 0.0010001 0.0100001 0 2 3 -7
1 -1e-07 -9.999999999994822e-08 -1.000000000002735e-07 1e-07 0.0010001 0.0100001 1 22 4 -1 4 3 -2
2 0.0009999 -9.999999999994822e-08 -1.000000000002735e-07 0.0010001 0.0010001 0.0100001 1 22 4 -5 8 7 -6
3 -9.999999999994822e-08 -1e-07 -1.000000000002735e-07 0.0010001 1e-07 0.0100001 1 22 4 -9 1 10 -5
4 -9.999999999994822e-08 0.0009999 -1.000000000002735e-07 0.0010001 0.0010001 0.0100001 1 22 4 -11 3 12 -7
5 -9.999999999994822e-08 -9.999999999994822e-08 -1e-07 0.0010001 0.0010001 1e-07 1 22 4 -4 9 8 -11
6 -9.999999999994822e-08 -9.999999999994822e-08 0.009999900000000001 0.0010001 0.0010001 0.0100001 1 21 4 -2 10 6 -12
1 -9.999999999994822e-08 -9.999999999994822e-08 -1.000000000002735e-07 0.0010001 0.0010001 0.0100001 1 20 6 -1 2 -3 4 -5 6
$EndEntities
$Nodes
19 86 1 86
0 1 0 1
1
0 0 0.01
0 2 0 1
2
0 0 0
0 3 0 1
3
0 0.001 0.01
0 4 0 1
4
0 0.001 0
0 5 0 1
5
0.001 0 0.01
0 6 0 1
6
0.001 0 0
0 7 0 1
7
0.001 0.001 0.01
0 8 0 1
8
0.001 0.001 0
1 1 0 9
9
10
11
12
13
14
15
16
17
0 0 0.001000000000000003
0 0 0.002000000000000007
0 0 0.00300000000000001
0 0 0.004000000000000013
0 0 0.005000000000000011
0 0 0.006000000000000008
0 0 0.007000000000000006
0 0 0.008000000000000004
0 0 0.009000000000000003
1 3 0 9
18
19
20
21
22
23
24
25
26
0 0.001 0.001000000000000003
0 0.001 0.002000000000000007
0 0.001 0.00300000000000001
0 0.001 0.004000000000000013
0 0.001 0.005000000000000011
0 0.001 0.006000000000000008
0 0.001 0.007000000000000006
0 0.001 0.008000000000000004
0 0.001 0.009000000000000003
1 5 0 9
27
28
29
30
31
32
33
34
35
0.001 0 0.001000000000000003
0.001 0 0.002000000000000007
0.001 0 0.00300000000000001
0.001 0 0.004000000000000013
0.001 0 0.005000000000000011
0.001 0 0.006000000000000008
0.001 0 0.007000000000000006
0.001 0 0.008000000000000004
0.001 0 0.009000000000000003
1 7 0 9
36
37
38
39
40
41
42
43
44
0.001 0.001 0.001000000000000003
0.001 0.001 0.002000000000000007
0.001 0.001 0.00300000000000001
0.001 0.001 0.004000000000000013
0.001 0.001 0.005000000000000011
0.001 0.001 0.006000000000000008
0.001 0.001 0.007000000000000006
0.001 0.001 0.008000000000000004
0.001 0.001 0.009000000000000003
2 1 0 10
45
46
47
48
49
50
51
52
53
54
0 0.0005 0.003500000000000011
0 0.0005 0.006500000000000007
0 0.0005 0.009500000000000001
0 0.0005 0.0005000000000000016
0 0.0005 0.001500000000000005
0 0.0005 0.005500000000000008
0 0.0004999999999999999 0.002500000000000008
0 0.0005000000000000008 0.004500000000000013
0 0.0005000000000000008 0.007500000000000008
0 0.0005 0.008499999999999997
2 2 0 10
55
56
57
58
59
60
61
62
63
64
0.001 0.0005 0.003500000000000011
0.001 0.0005 0.006500000000000007
0.001 0.0005 0.009500000000000001
0.001 0.0005 0.0005000000000000016
0.001 0.0004999999999999999 0.002500000000000008
0.001 0.0005 0.004500000000000013
0.001 0.0005 0.001500000000000005
0.001 0.0005 0.005500000000000009
0.001 0.0005000000000000008 0.007500000000000008
0.001 0.0005 0.008499999999999997
2 3 0 10
65
66
67
68
69
70
71
72
73
74
0.0005000000000000016 0 0.008499999999999997
0.0005 0 0.003500000000000011
0.0005 0 0.006500000000000007
0.0005 0 0.0005000000000000016
0.0004999999999999999 0 0.002500000000000008
0.0005000000000000008 0 0.004500000000000013
0.0005 0 0.001500000000000005
0.0005 0 0.005500000000000008
0.0005 0 0.007500000000000008
0.0005 0 0.009500000000000001
2 4 0 10
75
76
77
78
79
80
81
82
83
84
0.0005000000000000016 0.001 0.008499999999999997
0.0005 0.001 0.003500000000000011
0.0004999999999999999 0.001 0.006500000000000008
0.0004999999999999999 0.001 0.0005000000000000016
0.0005 0.001 0.001500000000000005
0.0004999999999999999 0.001 0.002500000000000008
0.0005000000000000008 0.001 0.004500000000000013
0.0005000000000000001 0.001 0.005500000000000008
0.0005000000000000003 0.001 0.007500000000000005
0.0005 0.001 0.009500000000000001
2 5 0 1
85
0.0005 0.0005 0
2 6 0 1
86
0.0005 0.0005 0.01
3 1 0 0
$EndNodes
$Elements
7 366 1 366
2 1 2 40
1 1 3 47
2 17 1 47
3 4 2 48
4 2 9 48
5 3 26 47
6 18 4 48
7 9 10 49
8 9 18 48
9 18 9 49
10 10 11 51
11 10 19 49
12 19 10 51
13 11 12 45
14 20 11 45
15 11 20 51
16 12 13 52
17 12 21 45
18 21 12 52
19 13 14 50
20 13 50 52
21 14 15 46
22 14 46 50
23 15 16 53
24 15 24 46
25 24 15 53
26 16 17 54
27 53 16 54
28 26 17 47
29 17 26 54
30 19 18 49
31 20 19 51
32 21 20 45
33 22 21 52
34 23 22 50
35 50 22 52
36 24 23 46
37 46 23 50
38 25 24 53
39 26 25 54
40 25 53 54
2 2 2 40
41 5 57 7
42 35 57 5
43 8 58 6
44 6 58 27
45 7 57 44
46 36 58 8
47 27 61 28
48 27 58 36
49 36 61 27
50 28 59 29
51 37 59 28
52 28 61 37
53 29 55 30
54 38 55 29
55 29 59 38
56 30 60 31
57 30 55 39
58 39 60 30
59 31 62 32
60 60 62 31
61 32 56 33
62 32 62 56
63 33 63 34
64 33 56 42
65 42 63 33
66 34 64 35
67 63 64 34
68 44 57 35
69 35 64 44
70 37 61 36
71 38 59 37
72 39 55 38
73 40 60 39
74 41 62 40
75 40 62 60
76 42 56 41
77 56 62 41
78 43 63 42
79 44 64 43
80 43 64 63
2 3 2 40
81 5 1 74
82 1 17 74
83 2 6 68
84 9 2 68
85 35 5 74
86 6 27 68
87 10 9 71
88 27 9 68
89 9 27 71
90 11 10 69
91 10 28 69
92 28 10 71
93 12 11 66
94 11 29 66
95 29 11 69
96 13 12 70
97 30 12 66
98 12 30 70
99 14 13 72
100 13 70 72
101 15 14 67
102 67 14 72
103 16 15 73
104 33 15 67
105 15 33 73
106 17 16 65
107 65 16 73
108 35 17 65
109 17 35 74
110 27 28 71
111 28 29 69
112 29 30 66
113 30 31 70
114 31 32 72
115 70 31 72
116 32 33 67
117 32 67 72
118 33 34 73
119 34 35 65
120 34 65 73
2 4 2 40
121 7 84 3
122 3 84 26
123 4 78 8
124 18 78 4
125 44 84 7
126 8 78 36
127 19 79 18
128 36 78 18
129 18 79 36
130 20 80 19
131 37 79 19
132 19 80 37
133 21 76 20
134 20 76 38
135 38 80 20
136 22 81 21
137 39 76 21
138 21 81 39
139 23 82 22
140 22 82 81
141 24 77 23
142 77 82 23
143 25 83 24
144 24 83 77
145 26 75 25
146 75 83 25
147 44 75 26
148 26 84 44
149 36 79 37
150 37 80 38
151 38 76 39
152 39 81 40
153 40 82 41
154 81 82 40
155 41 77 42
156 41 82 77
157 42 83 43
158 77 83 42
159 43 75 44
160 43 83 75
2 5 2 4
161 2 4 85
162 6 2 85
163 4 8 85
164 8 6 85
2 6 2 4
165 1 86 3
166 5 86 1
167 3 86 7
168 7 86 5
3 1 4 198
169 74 47 84 44
170 84 57 74 44
171 68 61 36 79
172 79 9 48 68
173 9 61 68 79
174 36 68 79 48
175 69 51 59 28
176 80 51 19 59
177 36 48 78 58
178 38 76 45 55
179 36 68 48 58
180 55 45 11 66
181 59 38 51 69
182 10 49 79 71
183 79 49 9 71
184 61 10 79 71
185 9 61 79 71
186 51 80 38 59
187 39 45 76 55
188 12 55 66 45
189 47 26 84 44
190 74 17 47 35
191 57 35 74 44
192 47 74 35 44
193 27 9 61 68
194 36 18 48 79
195 27 36 68 61
196 9 18 79 48
197 36 27 68 58
198 69 10 51 28
199 37 80 19 59
200 79 49 10 19
201 76 45 20 38
202 61 10 71 28
203 59 38 69 29
204 11 55 66 29
205 18 36 48 78
206 18 9 79 49
207 11 51 38 69
208 10 79 19 61
209 37 61 19 79
210 45 11 38 55
211 9 27 61 71
212 12 45 39 55
213 59 51 19 28
214 30 12 55 66
215 21 45 76 39
216 80 20 51 38
217 39 30 70 55
218 12 30 55 70
219 26 17 35 47
220 26 35 44 47
221 39 12 55 70
222 51 10 19 28
223 61 19 10 28
224 28 37 61 19
225 69 38 11 29
226 28 37 19 59
227 55 11 38 29
228 11 20 38 51
229 20 11 38 45
230 12 21 39 45
231 54 53 83 16
232 73 53 16 83
233 64 54 43 65
234 35 65 54 64
235 54 64 43 75
236 54 64 75 44
237 65 73 16 63
238 64 63 65 43
239 83 16 73 63
240 54 17 65 35
241 54 35 64 44
242 43 54 75 83
243 75 26 54 44
244 83 77 42 63
245 81 60 22 70
246 33 42 77 63
247 81 22 52 70
248 52 72 70 22
249 83 73 33 63
250 15 53 73 83
251 62 56 41 72
252 65 16 54 83
253 26 35 54 44
254 17 26 35 54
255 22 82 72 62
256 52 50 72 22
257 82 81 60 22
258 82 60 62 22
259 60 81 39 70
260 43 54 83 65
261 39 81 52 70
262 82 50 22 72
263 72 82 41 62
264 14 46 67 56
265 82 72 41 50
266 83 65 16 63
267 86 57 74 84
268 22 72 70 60
269 15 33 83 73
270 83 43 65 63
271 72 67 56 14
272 82 46 50 41
273 56 50 72 14
274 22 72 60 62
275 46 56 33 67
276 74 47 86 84
277 50 56 72 41
278 56 46 33 77
279 41 77 46 56
280 33 77 46 83
281 50 56 46 14
282 50 56 41 46
283 53 15 24 83
284 46 33 83 15
285 62 56 72 32
286 46 33 15 67
287 82 77 46 41
288 39 12 70 52
289 30 39 70 60
290 42 33 77 56
291 33 77 83 63
292 52 21 81 39
293 72 67 32 56
294 46 77 24 83
295 77 82 46 23
296 54 53 25 83
297 24 15 46 83
298 82 46 23 50
299 52 72 13 70
300 58 48 85 68
301 54 25 75 83
302 78 48 85 58
303 60 31 72 70
304 21 12 39 52
305 81 82 60 40
306 50 52 72 13
307 73 65 34 63
308 62 31 72 60
309 82 60 40 62
310 64 63 34 65
311 74 1 5 86
312 47 3 1 86
313 19 79 49 18
314 78 4 48 18
315 68 6 58 27
316 37 79 36 61
317 9 2 48 68
318 49 10 9 71
319 45 12 11 66
320 37 38 80 59
321 36 78 8 58
322 21 45 20 76
323 76 38 39 55
324 19 20 51 80
325 30 66 55 29
326 51 11 10 69
327 27 61 71 28
328 5 7 57 86
329 86 3 7 84
330 29 69 59 28
331 85 6 8 58
332 85 4 2 48
333 17 47 1 74
334 35 74 5 57
335 47 26 3 84
336 84 7 57 44
337 85 2 6 68
338 85 8 4 78
339 57 74 5 86
340 74 47 1 86
341 78 85 8 58
342 2 85 48 68
343 58 85 6 68
344 48 85 4 78
345 86 47 3 84
346 7 57 86 84
347 34 65 35 64
348 43 75 64 44
349 54 25 26 75
350 17 16 54 65
351 16 15 53 73
352 34 33 73 63
353 83 42 43 63
354 24 25 53 83
355 41 42 77 56
356 46 15 14 67
357 32 31 72 62
358 60 31 70 30
359 77 24 23 46
360 14 13 50 72
361 40 41 82 62
362 22 52 21 81
363 22 50 82 23
364 40 60 81 39
365 33 32 67 56
366 52 13 12 70
$EndElements
Now the FEniCSx code:
from dolfinx.fem import (Constant, dirichletbc, Function, FunctionSpace, assemble_scalar, Expression,
form, locate_dofs_geometrical, locate_dofs_topological, VectorFunctionSpace)
from dolfinx.fem.petsc import NonlinearProblem
from dolfinx.io import gmshio, XDMFFile
from dolfinx.nls.petsc import NewtonSolver
import gmsh
import meshio
from mpi4py import MPI
import numpy as np
from petsc4py.PETSc import ScalarType, Options
from ufl import (SpatialCoordinate, TestFunction, Measure, dot,
dx, grad, inner, MixedElement, FiniteElement, FacetNormal)
import matplotlib.pyplot as plt
proc = MPI.COMM_WORLD.rank
def create_mesh(mesh, cell_type, prune_z=False):
cells = mesh.get_cells_type(cell_type)
cell_data = mesh.get_cell_data("gmsh:physical", cell_type)
points = mesh.points[:,:2] if prune_z else mesh.points
out_mesh = meshio.Mesh(points=points, cells={cell_type: cells}, cell_data={"name_to_read":[cell_data]})
return out_mesh
mesh, cell_markers, facet_markers = gmshio.read_from_msh("the_mesh.msh", MPI.COMM_WORLD, gdim=3)
if proc == 0:
# Read in mesh
msh = meshio.read('the_mesh.msh')
triangle_mesh = create_mesh(msh, "triangle", prune_z=False)
tetra_mesh = create_mesh(msh, "tetra", prune_z=False)
meshio.write('tetra.xdmf', tetra_mesh)
meshio.write('mt.xdmf', triangle_mesh)
with XDMFFile(MPI.COMM_WORLD, 'tetra.xdmf', "r") as xdmf:
mesh = xdmf.read_mesh(name="Grid")
ct = xdmf.read_meshtags(mesh, name="Grid")
mesh.topology.create_connectivity(mesh.topology.dim, mesh.topology.dim-1)
with XDMFFile(MPI.COMM_WORLD, 'mt.xdmf', "r") as xdmf:
ft = xdmf.read_meshtags(mesh, name="Grid")
# Define function space
V = FunctionSpace(mesh, ("CG", 1))
# Define the "unknown" variable of the equation.
Temp = Function(V)
heat_flux = VectorFunctionSpace(mesh, ("DG", 1))
JQ = Function(heat_flux)
# Physical parameters.
κ = 49.0
C_p = 120
density = 9.7e3 # kg / m^3.
T_amb = 0.0
σ_SB = 5.6704e-8
h = 10
T_fixed_surface = 21
convection_surface = 22
T_left = 100
# Define Dirichlet boundary conditions to the facets corresponding to the left end of the rod.
left_facets = ft.find(T_fixed_surface)
left_dofs = locate_dofs_topological(V, mesh.topology.dim-1, left_facets)
bc = dirichletbc(ScalarType(T_left), left_dofs, V)
bcs = [bc]
x = SpatialCoordinate(mesh)
dx = Measure("dx", domain=mesh,subdomain_data=ct)
ds = Measure("ds", domain=mesh, subdomain_data=ft)
# Initial temperature of the rod.
T_0 = 0.0
def temp_init(x):
values = np.full(x.shape[1], T_0, dtype = ScalarType)
return values
Temp.name = "Temp"
Temp.interpolate(temp_init)
# Simulation parameters.
t = 0 # Start time
t_final = 2.0 # Final time
num_steps = 260
dt = t_final / num_steps # time step size
T_n = Function(V)
T_n.name = "T_n"
T_n.interpolate(temp_init)
v = TestFunction(V)
F_T = density * C_p * (Temp - T_n )* v * dx + dt * dot(κ * grad(Temp), grad(v)) * dx + v * h * (Temp - T_amb) * ds(convection_surface)
# Define the problem.
problem = NonlinearProblem(F_T, Temp, bcs=bcs)
solver = NewtonSolver(MPI.COMM_WORLD, problem)
solver.convergence_criterion = "incremental"
solver.rtol = 1e-14
solver.report = True
ksp = solver.krylov_solver
opts = Options()
option_prefix = ksp.getOptionsPrefix()
opts[f"{option_prefix}ksp_type"] = "cg"
opts[f"{option_prefix}pc_type"] = "gamg"
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
opts[f"{option_prefix}ksp_max_it"]= 10000
ksp.setFromOptions()
times, Qs_ratios, spatial_average_temperatures = [], [], []
for time_step in np.linspace(t, t_final, num_steps):
times.append(t)
# Compute the heat flux.
JQ_expr = Expression(-κ * grad(Temp), heat_flux.element.interpolation_points())
JQ.interpolate(JQ_expr)
# Compute total heat convected away.
n = FacetNormal(mesh)
# Heat entering the rod from the left side.
Q_in = assemble_scalar(form(dot(JQ, n)*ds(T_fixed_surface)))
# Heat leaving the rod on all other surfaces.
Q_out = assemble_scalar(form(dot(JQ, n)*ds(convection_surface)))
if Q_in == 0:
Qs_ratio = 0
else:
Qs_ratio = abs(Q_out) / abs(Q_in)
Qs_ratios.append(Qs_ratio * 100)
t += dt
n, converged = solver.solve(Temp)
T_n.x.array[:] = Temp.x.array
spatial_average_temperature = assemble_scalar(form(Temp * dx(domain = mesh))) / assemble_scalar(form(1 * dx(domain=mesh)))
spatial_average_temperatures.append(spatial_average_temperature)
plt.plot(times, spatial_average_temperatures)
plt.plot(times, Qs_ratios)
plt.show()
plt.close()
This produces a solution to the heat equation that reaches steady state in about 0.5 s. However the ratio of the flux entering and the flux leaving the rod is about 0.195, which doesn’t make physical sense. If this was really true, then the rod would be heating at a high rate, whereas the correct computation of the temperature profile shows that temperature has stabilized quickly. The average temperature is near 30.5.
But if I do the single line modification, i.e. increase the degree of the function space to 2, the flux ratio reaches 0.945 which is much better (in my real code, it is closer to 100). Average T is near 30.5, same as before.
Graphically, you can see the behavior. Blue curve is average temperature, orange curve is the fluxes ratio which should converge to 100 (it’s in %).
vs