-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQ2.py
More file actions
211 lines (175 loc) · 5.35 KB
/
Q2.py
File metadata and controls
211 lines (175 loc) · 5.35 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
"""
111901030
Mayank Singla
Coding Assignment 7 - Q1
"""
# %%
# Uncomment below line: This line is required to make the animation work in VSCode (Using `ipympl` as the backend for matplotlib plots)
# %matplotlib ipympl
from matplotlib import projections
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
import numpy as np
# Below lines are to ignore the pylint warning in VSCode
# pylint: disable=abstract-method
# pylint: disable=pointless-string-statement
# pylint: disable=invalid-name
def get_tridiag_matrix(n, a, b, c):
"""
Returns a tri-diagonal matrix of size n x n with the given diagonal elements
"""
return np.eye(n, k=-1) * a + np.eye(n, k=0) * b + np.eye(n, k=1) * c
def solve2DHeatEquation(uT0, uB, f, mu, T, h, ht, xmin, xmax, ymin, ymax, xc, yc):
"""
Solves the 2D heat equation using the finite difference method
"""
N = int((xmax - xmin) // h) + 1 # Number of points on the sheet
xs = np.linspace(xmin, xmax, N + 1) # points on the x-axis
ys = np.linspace(ymin, ymax, N + 1) # points on the y-axis
Nt = int(T // ht) + 1 # Number of time steps
ts = np.linspace(0, T, Nt + 1) # Instances in time
# Initial conditions
us = np.array([[uT0(x, y) for y in ys] for x in xs])
# Initialize the tri-diagonal matrix A
A = get_tridiag_matrix(N + 1, 1, -2, 1)
# The values of u generated by the PDE at different times
result = [us]
# Solve the PDE for each time step
for t in ts[1:]:
# Calculate the values of f at different points
fMat = np.array([[f(x, y, t, xc, yc) for y in ys] for x in xs])
# Calculate the derivative of u
du = ((mu / (h**2)) * ((A @ us) + (us @ A))) + fMat
# Update the values of u
us = us + ht * du
# Update the values at the boundary points
for i in range(N + 1):
us[i][0] = uB(t)
us[i][-1] = uB(t)
for j in range(N + 1):
us[0][j] = uB(t)
us[-1][j] = uB(t)
result.append(us)
return result, xs, ys, ts
def plot2DHeatEquationAnimation(
usVals, xs, ys, xmin, xmax, ymin, ymax, mu, show_graph=False
):
"""
Plots the animation of the 2D Heat Equation
"""
# Figure and Axes of the plot
fig = plt.figure()
if not show_graph:
ax = plt.axes()
else:
ax = plt.axes(projection="3d")
# What should be plotted and updated at each animation frame
patches = []
# Plot the initial condition
if not show_graph:
plt1 = plt.imshow(
usVals[-1],
cmap="hot",
origin="lower",
extent=[xmin, xmax, ymin, ymax],
aspect=xmax,
animated=True,
)
cb = fig.colorbar(plt1) # Add colorbar
cb.set_label("Temperature") # Add label to colorbar
patches.append(plt1)
else:
X, Y = np.meshgrid(xs, ys)
ax.plot_surface(
X,
Y,
usVals[0],
cmap="hot",
linewidth=0,
antialiased=False,
)
def init():
"""
Initialization function for the animation.
"""
# Title for the plot
ax.set_title(
f"Heat conduction in a sheet\n with boundary [{xmin}, {xmax}]×[{ymin}, {ymax}] and μ = {mu}"
)
if not show_graph:
# Removing the ticks
ax.get_xaxis().set_ticks([])
ax.get_yaxis().set_ticks([])
# Return everything that must be plotted at the start of the animation
return patches
def animate(i):
"""
Update the animation at frame i
"""
# Update the plot
if not show_graph:
plt1.set_array(usVals[i])
else:
ax.plot_surface(
X,
Y,
usVals[i],
cmap="hot",
linewidth=0,
antialiased=False,
)
# Return everything that must be updated
return patches
numFrames = len(usVals) # Number of frames in the animation
interval = 1 # Interval between frames in milliseconds
# Setting up the animation
anim = FuncAnimation(
fig,
func=animate,
frames=numFrames,
init_func=init,
repeat=False,
interval=interval,
)
# Display the animation
plt.show()
return anim
if __name__ == "__main__":
# Required values
in_uT0 = lambda x, y: 0
in_uB = lambda t: 0
in_f = lambda x, y, t, xc, yc: np.exp(-np.sqrt(((x - xc) ** 2) + ((y - yc) ** 2)))
in_mu = 5 * (10 ** (-5))
in_T, in_h, in_ht = 2000, 0.01, 0.5
in_xmin, in_xmax, in_ymin, in_ymax = 0, 1, 0, 1
in_xc, in_yc = 0.5, 0.5
# Solving the Heat Equation
uVals, xVals, yVals, tVals = solve2DHeatEquation(
uT0=in_uT0,
uB=in_uB,
f=in_f,
mu=in_mu,
T=in_T,
h=in_h,
ht=in_ht,
xmin=in_xmin,
xmax=in_xmax,
ymin=in_ymin,
ymax=in_ymax,
xc=in_xc,
yc=in_yc,
)
# Plotting the animation
ani = plot2DHeatEquationAnimation(
usVals=uVals,
xs=xVals,
ys=yVals,
xmin=in_xmin,
xmax=in_xmax,
ymin=in_ymin,
ymax=in_ymax,
mu=in_mu,
# show_graph=False,
show_graph=True,
)