Numerical-Simulation/HW1/main.py

535 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# main.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import case1
import case2
import common
data_dict = {}
data_dict["a_values"] = np.array([0.29, 0.5, 1.35, 2.75, 4.75, 9.15])
def prob1():
'''Analytical solutions'''
print("Problem 1")
# Problem 1 - Analytical solution
data_dict["prob1"] = {}
data_dict["prob1"]["x_values"] = np.array([0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0])
data_dict["prob1"]["x_values_fine"] = np.linspace(0, 1)
# Case 1 temperature calculations
results = []
results_fine = []
for a_value in data_dict["a_values"]:
result = case1.analytical(a=a_value, x=data_dict["prob1"]["x_values"])
result_fine = case1.analytical(a=a_value, x=data_dict["prob1"]["x_values_fine"])
results.append(result)
results_fine.append(result_fine)
data_dict["prob1"]["case1_temp_results"] = np.array(results_fine)
df_case1 = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=[f'x = {x:.3f}' for x in data_dict["prob1"]["x_values"]])
# Pretty print DataFrame for Case 1 temperature
print("Analytical Case 1 Temperature Results:")
print(df_case1)
print("\n" * 2)
# Plotting Case 1 temperature
plt.figure(figsize=(10, 6))
for idx, a_value in enumerate(data_dict["a_values"]):
plt.plot(data_dict["prob1"]["x_values_fine"], data_dict["prob1"]["case1_temp_results"][idx], label=f'α = {a_value}')
plt.xlabel('Position (cm)')
plt.ylabel('Temperature (°C)')
plt.legend()
plt.grid(True)
plt.savefig('prob1_case1_analytical_temperature_vs_position.png', dpi=300)
#plt.show()
plt.close()
# Case 2 temperature calculations
results = []
results_fine = []
for a_value in data_dict["a_values"]:
result = case2.analytical(a=a_value, x=data_dict["prob1"]["x_values"])
result_fine = case2.analytical(a=a_value, x=data_dict["prob1"]["x_values_fine"])
results.append(result)
results_fine.append(result_fine)
data_dict["prob1"]["case2_temp_results"] = np.array(results_fine)
df_case2 = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=[f'x = {x:.3f}' for x in data_dict["prob1"]["x_values"]])
# Pretty print DataFrame for Case 2
print("Analytical Case 2 Temperature Results:")
print(df_case2)
print("\n" * 2)
# Plotting Case 2
plt.figure(figsize=(10, 6))
for idx, a_value in enumerate(data_dict["a_values"]):
plt.plot(data_dict["prob1"]["x_values_fine"], data_dict["prob1"]["case2_temp_results"][idx], label=f'α = {a_value}')
plt.xlabel('Position (cm)')
plt.ylabel('Temperature (°C)')
plt.legend()
plt.grid(True)
plt.savefig('prob1_case2_analytical_temperature_vs_position.png', dpi=300)
#plt.show()
plt.close()
# Comparison plots between cases for temperature distribution
fig, axes = plt.subplots(3, 2, figsize=(12, 12), sharex=True, sharey=True)
for idx, a_value in enumerate(data_dict["a_values"]):
ax = axes[idx // 2, idx % 2]
ax.plot(data_dict["prob1"]["x_values_fine"], data_dict["prob1"]["case1_temp_results"][idx], label='Case 1')
ax.plot(data_dict["prob1"]["x_values_fine"], data_dict["prob1"]["case2_temp_results"][idx], label='Case 2')
ax.set_title(f'α = {a_value}')
ax.set_xlabel('Position (cm)')
ax.set_ylabel('Temperature (°C)')
ax.legend()
ax.grid(True)
plt.tight_layout(rect=[0, 0, 1, 0.95]) # Adjust layout to make room for the main title
plt.savefig('prob1_comparison_cases.png', dpi=300)
#plt.show()
plt.close()
# Case 1 heat flux calculations
results = []
for a_value in data_dict["a_values"]:
result = case1.analytical_heat_loss(a=a_value)
results.append(result)
data_dict["prob1"]["case1_heat_flux_results"] = np.array(results)
# Create a DataFrame with alpha as the index and heat flux as the data
df_case1_heat_flux = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=['Heat Flux'])
# Pretty print DataFrame for Case 1 heat flux
print("Analytical Case 1 Heat Flux Results:")
print(df_case1_heat_flux)
print("\n" * 2)
# Case 2 heat flux calculations
results = []
for a_value in data_dict["a_values"]:
result = case2.analytical_heat_loss(a=a_value)
results.append(result)
data_dict["prob1"]["case2_heat_flux_results"] = np.array(results)
# Create a DataFrame with alpha as the index and heat flux as the data
df_case2_heat_flux = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=['Heat Flux'])
# Pretty print DataFrame for Case 2 heat flux
print("Analytical Case 2 Heat Flux Results:")
print(df_case2_heat_flux)
print("\n" * 2)
# Plotting heat flux vs alpha for both cases
plt.figure(figsize=(10, 6))
plt.plot(data_dict["a_values"], data_dict["prob1"]["case1_heat_flux_results"], label='Case 1')
plt.plot(data_dict["a_values"], data_dict["prob1"]["case2_heat_flux_results"], label='Case 2')
plt.xlabel('Alpha ($cm^{-1}$)')
plt.ylabel('Heat Flux (W)')
plt.legend()
plt.grid(True)
plt.savefig('prob1_heat_flux_comparison.png', dpi=300)
#plt.show()
plt.close()
def prob2():
'''FDM with dx = 0.125 and alpha varying'''
print("Problem 2")
data_dict["prob2"] = {}
data_dict["prob2"]["num_point"] = 8 # This does not consider the final T(L) point. So actually we have 9 points
data_dict["prob2"]["dx"] = 0.125
# Case 1
results = []
# num_point does not consider T(L). So "4" points is T0, T1, T2, T3, and then we add back T(L)
for a_value in data_dict["a_values"]:
fdm_array = case1.fdm_array(data_dict["prob2"]["num_point"], a = a_value)
fdm_array_inverse = np.linalg.inv(fdm_array)
right_array = case1.right_array(data_dict["prob2"]["num_point"])
unkown_temps_array = fdm_array_inverse @ right_array
solution = [0] # First point is 0 from BC
solution[1:] = unkown_temps_array
solution.append(100) # T(L) BC
results.append(solution)
data_dict["prob2"]["case1"] = {}
data_dict["prob2"]["case1"]["temp_results"] = np.array(results)
data_dict["prob2"]["x_values"] = np.array([0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0])
df_case1 = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=[f'x = {x:.3f}' for x in data_dict["prob2"]["x_values"]])
# Pretty print DataFrame for Case 1 temperature
print("FDM Case 1 Temperature Results:")
print(df_case1)
print("\n" * 2)
# Plotting Case 1 temperature
plt.figure(figsize=(10, 6))
for idx, a_value in enumerate(data_dict["a_values"]):
plt.plot(data_dict["prob2"]["x_values"], data_dict["prob2"]["case1"]["temp_results"][idx], label=f'α = {a_value}')
plt.xlabel('Position (cm)')
plt.ylabel('Temperature (°C)')
plt.legend()
plt.grid(True)
plt.savefig('prob2_case1_fdm_temperature_vs_position.png', dpi=300)
#plt.show()
plt.close()
# Case 2
results = []
# num_point does not consider T(L). So "4" points is T0, T1, T2, T3, and then we add back T(L)
for a_value in data_dict["a_values"]:
fdm_array = case2.fdm_array(data_dict["prob2"]["num_point"], a = a_value)
fdm_array_inverse = np.linalg.inv(fdm_array)
right_array = case2.right_array(data_dict["prob2"]["num_point"])
unkown_temps_array = fdm_array_inverse @ right_array
solution = unkown_temps_array.tolist()
solution.append(100) # T(L) BC
results.append(solution)
data_dict["prob2"]["case2"] = {}
data_dict["prob2"]["case2"]["temp_results"] = np.array(results)
data_dict["prob2"]["x_values"] = np.array([0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0])
df_case2 = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=[f'x = {x:.3f}' for x in data_dict["prob2"]["x_values"]])
# Pretty print DataFrame for Case 2 temperature
print("FDM Case 2 Temperature Results:")
print(df_case2)
print("\n" * 2)
# Plotting Case 2 temperature
plt.figure(figsize=(10, 6))
for idx, a_value in enumerate(data_dict["a_values"]):
plt.plot(data_dict["prob2"]["x_values"], data_dict["prob2"]["case2"]["temp_results"][idx], label=f'α = {a_value}')
plt.xlabel('Position (cm)')
plt.ylabel('Temperature (°C)')
plt.legend()
plt.grid(True)
plt.savefig('prob2_case2_fdm_temperature_vs_position.png', dpi=300)
#plt.show()
plt.close()
# Plot the comparisons similar to problem 1
# Comparison plots between cases for temperature distribution
fig, axes = plt.subplots(3, 2, figsize=(12, 12), sharex=True, sharey=True)
for idx, a_value in enumerate(data_dict["a_values"]):
ax = axes[idx // 2, idx % 2]
ax.plot(data_dict["prob2"]["x_values"], data_dict["prob2"]["case1"]["temp_results"][idx], label='Case 1')
ax.plot(data_dict["prob2"]["x_values"], data_dict["prob2"]["case2"]["temp_results"][idx], label='Case 2')
ax.set_title(f'α = {a_value}')
ax.set_xlabel('Position (cm)')
ax.set_ylabel('Temperature (°C)')
ax.legend()
ax.grid(True)
plt.tight_layout(rect=[0, 0, 1, 0.95]) # Adjust layout to make room for the main title
plt.savefig('prob2_comparison_cases.png', dpi=300)
#plt.show()
plt.close()
# Heat flux extraction
# Case 1
results = []
for i in range(len(data_dict["a_values"])):
a = data_dict["a_values"][i]
(t_0, t_1) = data_dict["prob2"]["case1"]["temp_results"][i][-2:]
dx = data_dict["prob2"]["dx"]
first_order = common.taylor_extraction(t_0, t_1, dx, a, 1)
second_order = common.taylor_extraction(t_0, t_1, dx, a, 2)
results.append([first_order, second_order])
data_dict["prob2"]["case1"]["heat_results"] = np.array(results)
# Create a DataFrame with alpha as the index and heat flux as the data
df_case1_heat_flux = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=['1st Order', '2nd Order'])
# Pretty print DataFrame for Case 1 heat flux
print("FDM Case 1 Heat Flux Results:")
print(df_case1_heat_flux)
print("\n" * 2)
# Plotting heat flux vs alpha for both extractions
plt.figure(figsize=(10, 6))
plt.plot(data_dict["a_values"], [i[0] for i in data_dict["prob2"]["case1"]["heat_results"]], label='1st Order Extraction')
plt.plot(data_dict["a_values"], [i[1] for i in data_dict["prob2"]["case1"]["heat_results"]], label='2nd Order Extraction')
plt.xlabel('Alpha ($cm^{-1}$)')
plt.ylabel('Heat Flux (W)')
plt.legend()
plt.grid(True)
plt.savefig('prob2_case1_heat_flux.png', dpi=300)
#plt.show()
plt.close()
# Case 2
results = []
for i in range(len(data_dict["a_values"])):
a = data_dict["a_values"][i]
(t_0, t_1) = data_dict["prob2"]["case2"]["temp_results"][i][-2:]
dx = data_dict["prob2"]["dx"]
first_order = common.taylor_extraction(t_0, t_1, dx, a, 1)
second_order = common.taylor_extraction(t_0, t_1, dx, a, 2)
results.append([first_order, second_order])
data_dict["prob2"]["case2"]["heat_results"] = np.array(results)
# Create a DataFrame with alpha as the index and heat flux as the data
df_case2_heat_flux = pd.DataFrame(results, index=[f'a = {a}' for a in data_dict["a_values"]], columns=['1st Order', '2nd Order'])
# Pretty print DataFrame for Case 1 heat flux
print("FDM Case 2 Heat Flux Results:")
print(df_case2_heat_flux)
print("\n" * 2)
# Plotting heat flux vs alpha for both extractions
plt.figure(figsize=(10, 6))
plt.plot(data_dict["a_values"], [i[0] for i in data_dict["prob2"]["case2"]["heat_results"]], label='1st Order Extraction')
plt.plot(data_dict["a_values"], [i[1] for i in data_dict["prob2"]["case2"]["heat_results"]], label='2nd Order Extraction')
plt.xlabel('Alpha ($cm^{-1}$)')
plt.ylabel('Heat Flux (W)')
plt.legend()
plt.grid(True)
plt.savefig('prob2_case2_heat_flux.png', dpi=300)
#plt.show()
plt.close()
def prob3():
'''Convergence analysis of the cases'''
print("Problem 3")
data_dict["prob3"] = {}
data_dict["prob3"]["num_points"] = [2**i for i in range(2, 8)] # This does not consider the final T(L) point. So actually we have n + 1 points
data_dict["prob3"]["dx_values"] = [1 / i for i in data_dict["prob3"]["num_points"]]
# Case 1
data_dict["prob3"]["case1"] = {}
data_dict["prob3"]["case1"]["temp_results"] = []
# num_point does not consider T(L). So "4" points is T0, T1, T2, T3, and then we add back T(L)
for num_point in data_dict["prob3"]["num_points"]:
fdm_array = case1.fdm_array(num_point)
fdm_array_inverse = np.linalg.inv(fdm_array)
right_array = case1.right_array(num_point)
unkown_temps_array = fdm_array_inverse @ right_array
solution = [0] # First point is 0 from BC
solution[1:] = unkown_temps_array
solution.append(100) # T(L) BC
data_dict["prob3"]["case1"]["temp_results"].append(solution)
#data_dict["prob3"]["x_values_fine"] = np.linspace(0, 1)
#data_dict["prob3"]["case1"]["true_temp_results"] = case1.analytical(a=2.75, x=data_dict["prob3"]["x_values_fine"])
# We have all of the temperature results for varying dx
# For each dx, calculate the 1st and 2nd order heat flux
results = []
for i in range(len(data_dict["prob3"]["dx_values"])):
a = 2.75
dx = data_dict["prob3"]["dx_values"][i]
(t_0, t_1) = data_dict["prob3"]["case1"]["temp_results"][i][-2:]
first_order = common.taylor_extraction(t_0, t_1, dx, a, 1)
second_order = common.taylor_extraction(t_0, t_1, dx, a, 2)
results.append([first_order, second_order])
data_dict["prob3"]["case1"]["heat_results"] = np.array(results)
data_dict["prob3"]["case1"]["heat_results_true"] = case1.analytical_heat_loss(a=2.75)
# Calculate % error and beta values
errors = []
betas = []
q_exact = data_dict["prob3"]["case1"]["heat_results_true"]
for i in range(0, len(results)):
# % Error calculation
q_1_curr, q_2_curr = results[i]
first_order_error = common.calc_error(q_exact, q_1_curr)
second_order_error = common.calc_error(q_exact, q_2_curr)
# Beta (convergence rate) calculation
if i != 0:
q_1_prev, q_2_prev = results[i-1]
dx_1 = data_dict["prob3"]["dx_values"][i-1]
dx_2 = data_dict["prob3"]["dx_values"][i]
first_order_beta = common.calc_beta(q_exact, q_1_curr, q_1_prev, dx_2, dx_1)
second_order_beta = common.calc_beta(q_exact, q_2_curr, q_2_prev, dx_2, dx_1)
else:
first_order_beta = 0
second_order_beta = 0
errors.append([first_order_error, second_order_error])
betas.append([first_order_beta, second_order_beta])
data_dict["prob3"]["case1"]["errors"] = errors
data_dict["prob3"]["case1"]["betas"] = betas
# Combine dx values, results, errors, and betas into a DataFrame for display
table_data = []
for i in range(len(data_dict["prob3"]["dx_values"])):
table_data.append([
results[i][0], # 1st order result
results[i][1], # 2nd order result
data_dict["prob3"]["case1"]["heat_results_true"], # True Q
errors[i][0], # 1st order % error
errors[i][1], # 2nd order % error
betas[i][0], # 1st order beta
betas[i][1] # 2nd order beta
])
columns = ['1st Q', '2nd Q', 'True Q', '1st % Error', '2nd % Error', '1st β', '2nd β']
df_case1 = pd.DataFrame(table_data, index=[f'dx = {i}' for i in data_dict["prob3"]["dx_values"]], columns=columns)
print("FDM Case 1 Heat Flux Convergence Results:")
print(df_case1)
print("\n" * 2)
# Plotting
plt.figure(figsize=(8, 6))
plt.plot(data_dict["prob3"]["dx_values"], [err[0] for err in data_dict["prob3"]["case1"]["errors"]], label='1st Order Error')
plt.plot(data_dict["prob3"]["dx_values"], [err[1] for err in data_dict["prob3"]["case1"]["errors"]], label='2nd Order Error')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Δx')
plt.ylabel('% Error')
plt.legend()
plt.grid(True)
plt.savefig("prob3_case1_convergence.png", dpi=300)
#plt.show()
plt.close()
# Case 2
data_dict["prob3"]["case2"] = {}
data_dict["prob3"]["case2"]["temp_results"] = []
# num_point does not consider T(L). So "4" points is T0, T1, T2, T3, and then we add back T(L)
for num_point in data_dict["prob3"]["num_points"]:
fdm_array = case2.fdm_array(num_point)
fdm_array_inverse = np.linalg.inv(fdm_array)
right_array = case2.right_array(num_point)
unkown_temps_array = fdm_array_inverse @ right_array
solution = []
solution[0:] = unkown_temps_array
solution.append(100) # T(L) BC
data_dict["prob3"]["case2"]["temp_results"].append(solution)
# We have all of the temperature results for varying dx
# For each dx, calculate the 1st and 2nd order heat flux
results = []
for i in range(len(data_dict["prob3"]["dx_values"])):
a = 2.75
dx = data_dict["prob3"]["dx_values"][i]
(t_0, t_1) = data_dict["prob3"]["case2"]["temp_results"][i][-2:]
first_order = common.taylor_extraction(t_0, t_1, dx, a, 1)
second_order = common.taylor_extraction(t_0, t_1, dx, a, 2)
results.append([first_order, second_order])
data_dict["prob3"]["case2"]["heat_results"] = np.array(results)
data_dict["prob3"]["case2"]["heat_results_true"] = case2.analytical_heat_loss(a=2.75)
# Calculate % error and beta values
errors = []
betas = []
q_exact = data_dict["prob3"]["case2"]["heat_results_true"]
for i in range(0, len(results)):
# % Error calculation
q_1_curr, q_2_curr = results[i]
first_order_error = common.calc_error(q_exact, q_1_curr)
second_order_error = common.calc_error(q_exact, q_2_curr)
# Beta (convergence rate) calculation
if i != 0:
q_1_prev, q_2_prev = results[i-1]
dx_1 = data_dict["prob3"]["dx_values"][i-1]
dx_2 = data_dict["prob3"]["dx_values"][i]
first_order_beta = common.calc_beta(q_exact, q_1_curr, q_1_prev, dx_2, dx_1)
second_order_beta = common.calc_beta(q_exact, q_2_curr, q_2_prev, dx_2, dx_1)
else:
first_order_beta = 0
second_order_beta = 0
errors.append([first_order_error, second_order_error])
betas.append([first_order_beta, second_order_beta])
data_dict["prob3"]["case2"]["errors"] = errors
data_dict["prob3"]["case2"]["betas"] = betas
# Combine dx values, results, errors, and betas into a DataFrame for display
table_data = []
for i in range(len(data_dict["prob3"]["dx_values"])):
table_data.append([
results[i][0], # 1st order result
results[i][1], # 2nd order result
data_dict["prob3"]["case2"]["heat_results_true"], # True Q
errors[i][0], # 1st order % error
errors[i][1], # 2nd order % error
betas[i][0], # 1st order beta
betas[i][1] # 2nd order beta
])
columns = ['1st Q', '2nd Q', 'True Q', '1st % Error', '2nd % Error', '1st β', '2nd β']
df_case2 = pd.DataFrame(table_data, index=[f'dx = {i}' for i in data_dict["prob3"]["dx_values"]], columns=columns)
print("FDM Case 2 Heat Flux Convergence Results:")
print(df_case2)
print("\n" * 2)
# Plotting
plt.figure(figsize=(8, 6))
plt.plot(data_dict["prob3"]["dx_values"], [err[0] for err in data_dict["prob3"]["case2"]["errors"]], label='1st Order Error')
plt.plot(data_dict["prob3"]["dx_values"], [err[1] for err in data_dict["prob3"]["case2"]["errors"]], label='2nd Order Error')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Δx')
plt.ylabel('% Error')
plt.legend()
plt.grid(True)
plt.savefig("prob3_case2_convergence.png", dpi=300)
#plt.show()
plt.close()
if __name__ == "__main__":
print("Homework 1 by Judson Upchurch")
print("Please note that some of the tables are transposed compared to the LaTeX equivalent")
print("")
prob1() # Analyitical temperature distribution
prob2() # FDM with dx = 0.125 and varying alpha
prob3() # Convergence analysis