244 lines
9.3 KiB
Python
244 lines
9.3 KiB
Python
# case1.py
|
|
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
from Bar import Bar, set_k_ratio
|
|
|
|
def get_analytical_constants(bar1:'Bar', bar2:'Bar', x_bar=2/np.pi, l=1):
|
|
'''Solve for C1, D1, C2, and D2
|
|
Returns np.array([C1, D1, C2, D2])'''
|
|
epsilon = (bar1.k*bar1.area*bar1.alpha) / (bar2.k*bar2.area*bar2.alpha)
|
|
A = np.array([
|
|
#C1 D1 C2 D2
|
|
[0, 1, 0, 0],
|
|
[0, 0, np.sinh(bar2.alpha*l), np.cosh(bar2.alpha*l)],
|
|
[np.sinh(bar1.alpha*x_bar), 0, -1*np.sinh(bar2.alpha*x_bar), -1*np.cosh(bar2.alpha*x_bar)],
|
|
[epsilon*np.cosh(bar1.alpha*x_bar), 0, -1*np.cosh(bar2.alpha*x_bar), -1*np.sinh(bar2.alpha*x_bar)]
|
|
])
|
|
|
|
B = np.array([
|
|
0,
|
|
100,
|
|
0,
|
|
0
|
|
])
|
|
|
|
return np.linalg.solve(A, B)
|
|
|
|
def get_analytical_datapoints(x_points, bar1:'Bar', bar2:'Bar', x_bar=2/np.pi, l=1):
|
|
'''Generates the temperature distribution given x_points.
|
|
Returns np.array of tempature values'''
|
|
constants = get_analytical_constants(bar1=bar1,bar2=bar2,x_bar=x_bar,l=1)
|
|
C1, D1, C2, D2 = constants[0], constants[1], constants[2], constants[3]
|
|
|
|
# Two temp functions for the left and right side of the interface
|
|
left_temp = lambda x: C1*np.sinh(bar1.alpha*x) + D1*np.cosh(bar1.alpha*x)
|
|
right_temp = lambda x: C2*np.sinh(bar2.alpha*x) + D2*np.cosh(bar2.alpha*x)
|
|
|
|
temp_values = np.array([])
|
|
for x in x_points:
|
|
if x <= x_bar:
|
|
temp = left_temp(x)
|
|
else:
|
|
temp = right_temp(x)
|
|
temp_values = np.append(temp_values, temp)
|
|
|
|
return temp_values
|
|
|
|
def get_analytical_heat_convection(x, bar1:'Bar', bar2:'Bar', x_bar=2/np.pi, l=1):
|
|
'''Gets the analytical heat convection at x from heat flux conservation'''
|
|
constants = get_analytical_constants(bar1=bar1,bar2=bar2,x_bar=x_bar,l=1)
|
|
C1, D1, C2, D2 = constants[0], constants[1], constants[2], constants[3]
|
|
|
|
t_prime = C2*bar2.alpha*np.cosh(bar2.alpha*x) + D2*bar2.alpha*np.sinh(bar2.alpha*x)
|
|
|
|
q_dot = -bar2.k*bar2.area*t_prime
|
|
return q_dot
|
|
|
|
def fdm_array(bar1:'Bar', bar2:'Bar', num_sections: int=6, x_bar=2/np.pi, l=1):
|
|
'''num_sections = total sections to cut the bar. Note that this is NOT evenly distributed over the entire
|
|
bar. Half of the sections are left of x_bar, half are to the right.
|
|
Returns the A matrix of the FDM equation Ax = B'''
|
|
dx1 = x_bar / (num_sections / 2)
|
|
dx2 = (l - x_bar) / (num_sections / 2)
|
|
k1 = 2 + bar1.alpha**2 * dx1**2
|
|
k2 = 2 + bar2.alpha**2 * dx2**2
|
|
|
|
beta1 = (bar1.k * bar1.area) / (dx1)
|
|
beta2 = (bar2.k * bar2.area) / (dx2)
|
|
|
|
#rho = beta1 - beta2 - (bar1.k * bar1.area * dx1 * bar1.alpha**2) / 2 + (bar2.k * bar2.area * dx2 * bar2.alpha**2) / 2
|
|
rho = beta1 + beta2 + (bar1.k * bar1.area * dx1 * bar1.alpha**2) / 2 + (bar2.k * bar2.area * dx2 * bar2.alpha**2) / 2
|
|
# Making the matrix
|
|
# There are num_sections - 1 rows and columns
|
|
# row 0, row n - 2, and row num_sections/2 - 1 are unique
|
|
# the rest are -1, k, -1 where k changes from k1 to k2 at num_sections/2
|
|
|
|
# Initialize matrix A with zeros
|
|
A = np.zeros((num_sections - 1, num_sections - 1))
|
|
|
|
# Fill the matrix A
|
|
for row in range(num_sections - 1):
|
|
if row == 0:
|
|
# First row for boundary at x = 0 (for example Dirichlet or Neumann condition)
|
|
A[row, row] = k1
|
|
A[row, row+1] = -1
|
|
elif row == num_sections // 2 - 1:
|
|
# Special row at the interface between bar1 and bar2
|
|
A[row, row-1] = -beta1
|
|
A[row, row] = rho # This is the rho value you computed
|
|
A[row, row+1] = -beta2
|
|
elif row == num_sections - 2:
|
|
# Last row for boundary at x = l (again assuming Dirichlet or Neumann condition)
|
|
A[row, row-1] = -1
|
|
A[row, row] = k2
|
|
else:
|
|
# Interior rows for bar1 and bar2 (uniform grid)
|
|
if row < num_sections // 2 - 1:
|
|
# In bar1 region
|
|
A[row, row-1] = -1
|
|
A[row, row] = k1
|
|
A[row, row+1] = -1
|
|
else:
|
|
# In bar2 region
|
|
A[row, row-1] = -1
|
|
A[row, row] = k2
|
|
A[row, row+1] = -1
|
|
return A
|
|
|
|
def fem_array(bar1:'Bar', bar2:'Bar', num_sections: int=6, x_bar=2/np.pi, l=1):
|
|
'''num_sections = total sections to cut the bar. Note that this is NOT evenly distributed over the entire
|
|
bar. Half of the sections are left of x_bar, half are to the right.
|
|
Returns the A matrix of the FEM equation Ax = B'''
|
|
dx1 = x_bar / (num_sections / 2)
|
|
dx2 = (l - x_bar) / (num_sections / 2)
|
|
k1 = (2/dx1 + 4*bar1.alpha**2*dx1/6) / (1/dx1 - bar1.alpha**2*dx1/6)
|
|
k2 = (2/dx2 + 4*bar2.alpha**2*dx2/6) / (1/dx2 - bar2.alpha**2*dx2/6)
|
|
|
|
beta1 = (bar1.k * bar1.area) / (dx1)
|
|
beta2 = (bar2.k * bar2.area) / (dx2)
|
|
|
|
rho = beta1 + beta2 + (bar1.k * bar1.area * dx1 * bar1.alpha**2) / 2 + (bar2.k * bar2.area * dx2 * bar2.alpha**2) / 2
|
|
# Making the matrix
|
|
# There are num_sections - 1 rows and columns
|
|
# row 0, row n - 2, and row num_sections/2 - 1 are unique
|
|
# the rest are -1, k, -1 where k changes from k1 to k2 at num_sections/2
|
|
|
|
# Initialize matrix A with zeros
|
|
A = np.zeros((num_sections - 1, num_sections - 1))
|
|
|
|
# Fill the matrix A
|
|
for row in range(num_sections - 1):
|
|
if row == 0:
|
|
# First row for boundary at x = 0 (for example Dirichlet or Neumann condition)
|
|
A[row, row] = k1
|
|
A[row, row+1] = -1
|
|
elif row == num_sections // 2 - 1:
|
|
# Special row at the interface between bar1 and bar2
|
|
A[row, row-1] = -beta1
|
|
A[row, row] = rho # This is the rho value you computed
|
|
A[row, row+1] = -beta2
|
|
elif row == num_sections - 2:
|
|
# Last row for boundary at x = l (again assuming Dirichlet or Neumann condition)
|
|
A[row, row-1] = -1
|
|
A[row, row] = k2
|
|
else:
|
|
# Interior rows for bar1 and bar2 (uniform grid)
|
|
if row < num_sections // 2 - 1:
|
|
# In bar1 region
|
|
A[row, row-1] = -1
|
|
A[row, row] = k1
|
|
A[row, row+1] = -1
|
|
else:
|
|
# In bar2 region
|
|
A[row, row-1] = -1
|
|
A[row, row] = k2
|
|
A[row, row+1] = -1
|
|
return A
|
|
|
|
def solve(bar1:'Bar', bar2:'Bar', num_sections: int=6, x_bar=2/np.pi, l=1, method="FDM"):
|
|
'''Solves using FDM or FEM as specified. Returns (temps, x_values)'''
|
|
if method == "FDM":
|
|
A = fdm_array(bar1,
|
|
bar2,
|
|
num_sections=num_sections,
|
|
x_bar=x_bar,
|
|
l=l)
|
|
elif method == "FEM":
|
|
A = fem_array(bar1,
|
|
bar2,
|
|
num_sections=num_sections,
|
|
x_bar=x_bar,
|
|
l=l)
|
|
|
|
B = np.zeros((num_sections - 1))
|
|
B[-1] = 100
|
|
|
|
# Add boundary conditions
|
|
interior_temps = np.linalg.solve(A, B)
|
|
all_temps = np.array([0])
|
|
all_temps = np.append(all_temps, interior_temps)
|
|
all_temps = np.append(all_temps, 100)
|
|
|
|
# Generate the x_values to return along with the temps
|
|
dx2 = (l - x_bar) / (num_sections / 2)
|
|
x_values = np.linspace(0, x_bar, num_sections // 2 + 1) # [0, x_bar]
|
|
x_values = np.append(x_values, np.linspace(x_bar+dx2, l, num_sections // 2))
|
|
return all_temps, x_values
|
|
|
|
|
|
if __name__ == "__main__":
|
|
bar1 = Bar(
|
|
radius=0.1,
|
|
k=0.5,
|
|
h=0.25
|
|
)
|
|
bar2 = Bar(
|
|
radius=0.1,
|
|
k=2,
|
|
h=0.25
|
|
)
|
|
|
|
set_k_ratio(0.5, bar1, bar2)
|
|
|
|
x_bar = 0.5
|
|
|
|
x_values = np.linspace(0, 1, 1000)
|
|
temp_values = get_analytical_datapoints(x_points=x_values,
|
|
bar1=bar1,
|
|
bar2=bar2,
|
|
x_bar=x_bar)
|
|
|
|
|
|
# fdm tests
|
|
l = 1
|
|
num_sections = 4
|
|
dx1 = x_bar / (num_sections / 2)
|
|
dx2 = (l - x_bar) / (num_sections / 2)
|
|
fdm_temps, x_fdm = solve(bar1=bar1,
|
|
bar2=bar2,
|
|
num_sections=num_sections,
|
|
x_bar=x_bar,
|
|
l=1,
|
|
method="FDM")
|
|
fem_temps, x_fem = solve(bar1=bar1,
|
|
bar2=bar2,
|
|
num_sections=num_sections,
|
|
x_bar=x_bar,
|
|
l=1,
|
|
method="FEM")
|
|
|
|
# Plot the data
|
|
plt.plot(x_values, temp_values, label='Temperature Distribution')
|
|
plt.axvline(x=x_bar, color='r', linestyle='--', label='x_bar')
|
|
plt.plot(x_fdm, fdm_temps, 'o-', label='Temperature Distribution (FDM)', color='g')
|
|
plt.plot(x_fem, fem_temps, 'o-', label='Temperature Distribution (FEM)', color='r')
|
|
plt.xlabel('x')
|
|
plt.ylabel('Temperature')
|
|
plt.title('Temperature Distribution Along the Bar')
|
|
plt.legend()
|
|
plt.grid(True)
|
|
|
|
# Show plot
|
|
plt.show() |