-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathIntegrEffectQ4.py
174 lines (153 loc) · 6.21 KB
/
IntegrEffectQ4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Finite Element Modeling with Abaqus and Python for Thermal and
# Stress Analysis
# (C) 2017, Petr Krysl
#
"""
Square domain with partial temperature boundary condition
and partial insulated boundary condition. Finite element mesh
that consists of four-node quadrilaterals.
"""
import math
from numpy import array, zeros, ones, arange, linspace
from numpy import unique, dot, linalg
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import time
tstart = time.clock()
# Input parameters
kappa = 0.2 # thermal conductivity
Q = 0.005 # uniform heat source
sidel = 48 # length of the side of the square domain
nes = 18 # number of elements per side
Dz = 1.0 # thickness of the slice
# Generate the nodes and the connectivities of the quadrilaterals
xs = linspace(0, sidel, nes+1) # grid in the X direction
ys = linspace(0, sidel, nes+1) # grid in the Y direction
nx = len(xs) - 1 # number of element edges in the X direction
ny = len(ys) - 1 # number of element edges in the Y direction
nnodes = (nx+1) * (ny+1) # Number of nodes
nfes = nx * ny # Number of elements
# Generate the nodes
x = zeros((nnodes, 2)) # Coordinates of nodes: initialized to all zeros
k = 0
for j in arange(0, (ny+1)):
for i in arange(0, (nx+1)):
x[k, :] = [xs[i], ys[j]]
k = k + 1
# Generate the elements: note that the nodes are numbered from 1
conn = zeros((nfes, 4), dtype=int)
k = 0
for i in arange(0, (nx)):
for j in arange(0, (ny)):
f = int(j * (nx+1) + i) + 1
conn[k, :] = [f, f+1, f+(nx+1)+1, f+(nx+1)]
k = k + 1
# Define the degrees of freedom
# Fixed temperature at the nodes on the boundary, except for a few
# in the lower-left corner. The node numbers are one-based
Fixed = [int(i)+1 for i in arange(nx/2, nx+1)]
Fixed = Fixed + [int(j*(nx+1))+1 for j in arange(ny/2, ny+1)]
Fixed = Fixed + [int(i+ny*(nx+1))+1 for i in arange(0, nx+1)]
Fixed = Fixed + [int(j*(nx+1)+ny)+1 for j in arange(0, ny+1)]
Fixed = unique(Fixed)
dof = zeros((nnodes,1), dtype=int)
N_f = nnodes-len(Fixed)
# Number the degrees of freedom: First we will number the prescribed
# degrees of freedom starting from the number of free degrees of freedom
k = N_f # first we number the prescribed degrees of freedom
for index in Fixed:
dof[index-1] = k+1 # the DOF are 1-based
k = k + 1
k = 0 # next we number the free degrees of freedom
for index in range(0, nnodes):
if (dof[index] == 0):
dof[index] = k+1 # the DOF are 1-based
k = k + 1
def gradNpar(xi, eta):
"""
A one-liner to calculate the matrix of the basis function gradients
in the parametric coordinates.
"""
return array([
[eta / 4 - 1. / 4, xi / 4 - 1. / 4],
[1. / 4 - eta / 4, - xi / 4 - 1. / 4],
[eta / 4 + 1. / 4, xi / 4 + 1. / 4],
[- eta / 4 - 1. / 4, 1. / 4 - xi / 4]])
def N(xi, eta):
"""
A one-liner to calculate the matrix of the basis function values.
"""
return array([(xi - 1) * (eta - 1) / 4,
(xi + 1) * (eta - 1) / -4,
(xi + 1) * (eta + 1) / 4,
(xi - 1) * (eta + 1) / -4]).reshape(4, 1)
# These are the integration point data for four-point quadrature rule
xe = array([[-0.577350269189626, -0.577350269189626],
[-0.577350269189626, +0.577350269189626],
[+0.577350269189626, -0.577350269189626],
[+0.577350269189626, +0.577350269189626]])
W = array([1, 1, 1, 1])
# These are the integration point data for one-point quadrature rule
#xe = array([[+0., +0]])
#W = array([4.0])
Kg = zeros((N_f, N_f))
Lg = zeros((N_f, 1))
nnpe = conn.shape[1] # number of nodes per element
zconn = conn - 1
for index in arange(conn.shape[0]):
# Element degree-of-freedom array, converted to zero base
zedof = dof[zconn[index, :]]-1
# Initialize the elementwise conductivity matrix.
Ke = zeros((nnpe, nnpe))
# Initialize the elementwise heat load vector
LQe = zeros((nnpe, 1))
# Loop over the quadrature points.
for qp in range(xe.shape[0]):
xi, eta = xe[qp, 0], xe[qp, 1]
lx = x[zconn[index, :], :]
# Compute the Jacobian matrix
J = dot(lx.T, gradNpar(xi, eta))
# The Jacobian
detJ = linalg.det(J)
# The gradient of the basis functions with respect to x,y
gradN = dot(gradNpar(xi, eta), linalg.inv(J))
# Add the contribution to the conductivity matrix
Ke = Ke + kappa * Dz * dot(gradN, gradN.T) * detJ * W[qp]
# At the contribution to the elementwise heat load vector
LQe = LQe + Q * Dz * N(xi, eta) * ones((nnpe, 1)) * detJ * W[qp]
# Assemble elementwise conductivity matrix
for ro in range(len(zedof)):
for co in range(len(zedof)):
if (zedof[ro] < N_f) and (zedof[co] < N_f):
Kg[zedof[ro], zedof[co]] = Kg[zedof[ro], zedof[co]] + Ke[ro, co]
# Assemble the elementwise heat load vector
for ro in range(len(zedof)):
if (zedof[ro] < N_f):
Lg[zedof[ro]] = Lg[zedof[ro]] + LQe[ro]
# Solve for the global temperatures at the free degrees of freedom
Tg = linalg.solve(Kg, Lg)
tend = time.clock()
print( 'Time =', tend-tstart)
print('Tg=', Tg)
# Set up an array of the temperatures at all the degrees of freedom
T = zeros((nnodes, 1))
T[0:N_f] = Tg # insert the computed values of the free degrees of freedom
# Plot contours
plt.figure()
plt.gca().set_aspect('equal')
# setup three 1-d arrays for the x-coordinate, the y-coordinate, and the
# z-coordinate
xs = x[:, 0].reshape(nnodes,) # one value per node
ys = x[:, 1].reshape(nnodes,) # one value per node
ix = dof[arange(nnodes)] - 1
zs = (T[ix]).reshape(nnodes,) # one value per node
triangles = conn[:, (0, 1, 2)] - 1 # the triangles are defined by the connectivity arrays
plt.tricontour(xs, ys, triangles, zs, linewidths=3)
triangles = conn[:, (0, 2, 3)] - 1 # the triangles are defined by the connectivity arrays
plt.tricontour(xs, ys, triangles, zs, linewidths=3)
plt.colorbar()
plt.title('Contour plot of temperature')
plt.xlabel('x (m)')
plt.ylabel('y (m)')
plt.show()