sigma_SB = 5.670374419e-8
eps_c = 0.85
h_c = 12.0 # W/m2K
A_c = 0.03 # m^2
m_c = 0.4 # kg
c_c = 460.0 # J/kgK
Tenv_c = 293.0 # K
T0_c = 900.0 # K
def f_comb(t, T):
return -(h_c*A_c/(m_c*c_c))*(T-Tenv_c) - (eps_c*sigma_SB*A_c/(m_c*c_c))*(T**4 - Tenv_c**4)
def euler_step(f, T0, t0, t_end, dt):
n = int(round((t_end-t0)/dt))
t, T = t0, T0
for _ in range(n):
T = T + dt*f(t, T); t += dt
return T
def heun_step(f, T0, t0, t_end, dt):
n = int(round((t_end-t0)/dt))
t, T = t0, T0
for _ in range(n):
k1 = f(t, T)
k2 = f(t+dt, T+dt*k1)
T = T + dt/2*(k1+k2); t += dt
return T
def rk4_step(f, T0, t0, t_end, dt):
n = int(round((t_end-t0)/dt))
t, T = t0, T0
for _ in range(n):
k1 = f(t, T)
k2 = f(t+dt/2, T+dt/2*k1)
k3 = f(t+dt/2, T+dt/2*k2)
k4 = f(t+dt, T+dt*k3)
T = T + dt/6*(k1+2*k2+2*k3+k4); t += dt
return T
# Reference solution (very fine tolerance)
t_check = 200.0
ref = solve_ivp(f_comb, (0, t_check), [T0_c], max_step=0.01, rtol=1e-13, atol=1e-12, dense_output=True)
T_ref = ref.sol(t_check)[0]
t_plot = np.linspace(0, 3000, 600)
ref_full = solve_ivp(f_comb, (0, 3000), [T0_c], t_eval=t_plot, max_step=0.1)
dt_values = np.array([20, 10, 5, 2.5, 1.25])
errors = {'Euler': [], 'Heun': [], 'RK4': []}
for dt in dt_values:
errors['Euler'].append(abs(euler_step(f_comb, T0_c, 0, t_check, dt) - T_ref))
errors['Heun'].append(abs(heun_step(f_comb, T0_c, 0, t_check, dt) - T_ref))
errors['RK4'].append(abs(rk4_step(f_comb, T0_c, 0, t_check, dt) - T_ref))
fig, axes = plt.subplots(1, 2, figsize=(11, 4.5))
axes[0].plot(ref_full.t, ref_full.y[0], color='crimson', lw=2.2)
axes[0].axhline(Tenv_c, color='gray', ls=':', lw=1, label='$T_{env}=293$ K')
axes[0].axvline(t_check, color='k', ls='--', lw=1, label='$t=200$ s (comparison point)')
axes[0].set_xlabel('$t$ (s)'); axes[0].set_ylabel('$T(t)$ (K)')
axes[0].set_title('Combined convection + radiation cooling')
axes[0].legend(fontsize=8.5)
colors_m = {'Euler':'steelblue', 'Heun':'darkorange', 'RK4':'seagreen'}
for name in errors:
axes[1].loglog(dt_values, errors[name], 'o-', color=colors_m[name], lw=2, label=name)
# Reference slope lines
dt_ref = dt_values
for order, style, lbl in [(1, ':', '$O(\\Delta t)$'), (2, '--', '$O(\\Delta t^2)$'), (4, '-.', '$O(\\Delta t^4)$')]:
scale = errors['Euler'][-1] / dt_ref[-1]**1 if order == 1 else \
errors['Heun'][-1] / dt_ref[-1]**2 if order == 2 else \
errors['RK4'][-1] / dt_ref[-1]**4
axes[1].loglog(dt_ref, scale*dt_ref**order, color='gray', ls=style, lw=1, label=lbl)
axes[1].set_xlabel('Step size $\\Delta t$ (s)'); axes[1].set_ylabel('Error in $T$ at $t=200$ s (K)')
axes[1].set_title('Convergence: Euler $O(\\Delta t)$, Heun $O(\\Delta t^2)$, RK4 $O(\\Delta t^4)$')
axes[1].legend(fontsize=7.5)
plt.tight_layout()
plt.show()