codexfourier-conduction-steady-bar.py
fourier-conduction-steady-bar.py
"""Plot the stipulated steady bar and distinguish heat flux from heat rate.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
Writes fourier-conduction-steady-bar.png in the current working directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
length, area, conductivity = 0.10, 0.010, 2.0
hot, cold = 40.0, 20.0 # Celsius; differences have the same size in kelvin.
x = np.linspace(0.0, length, 201)
gradient = (cold - hot) / length
temperature = hot + gradient * x
flux = -conductivity * gradient
rate = area * flux
assert np.allclose([gradient, flux, rate], [-200.0, 400.0, 4.0])
plt.rcParams.update({"font.size": 11, "figure.facecolor": "white",
"axes.facecolor": "white", "savefig.facecolor": "white",
"axes.spines.top": False, "axes.spines.right": False})
fig, (tax, qax) = plt.subplots(2, 1, figsize=(8.2, 6.4), dpi=120,
sharex=True, height_ratios=[1.4, 1])
fig.subplots_adjust(left=0.12, right=0.96, bottom=0.18, top=0.84, hspace=0.22)
fig.suptitle("Steady conduction: falling temperature, constant heat flux", fontsize=14)
fig.text(0.5, 0.91, "L = 0.10 m | A = 0.010 m² | k = 2 W/(m K)",
ha="center", fontsize=11)
tax.plot(x, temperature, color="#c44e28", lw=3)
tax.fill_between(x, 18, temperature, color="#c44e28", alpha=0.08)
tax.plot([0, length], [hot, cold], "o", color="#c44e28", ms=6)
tax.annotate("40°C", (0, hot), xytext=(6, 8), textcoords="offset points")
tax.annotate("20°C", (length, cold), xytext=(-6, 8),
textcoords="offset points", ha="right")
tax.text(0.058, 32, "dT/dx = −200 K/m", color="#9a3e20", ha="center")
tax.annotate("", xy=(0.087, 45), xytext=(0.013, 45),
arrowprops={"arrowstyle": "->", "lw": 2, "color": "#216a99"})
tax.text(0.05, 46.3, "Heat flows from hot to cold", ha="center", color="#216a99")
tax.set_ylabel("Temperature T (°C)")
tax.set_ylim(18, 50)
tax.set_yticks([20, 30, 40])
qax.plot(x, np.full_like(x, flux), color="#216a99", lw=3)
qax.text(0.05, 440, "q = −k dT/dx = 400 W/m²", ha="center", color="#216a99")
qax.text(0.05, 115, "Rate through the whole cross section:\n"
"Q̇ = A q = 0.010 m² × 400 W/m² = 4 W", ha="center", va="center",
bbox={"facecolor": "white", "edgecolor": "#b8c3cc", "pad": 7})
qax.set_ylabel("Heat flux q (W/m²)")
qax.set_ylim(0, 520)
qax.set_yticks([0, 200, 400])
qax.set_xlabel("Position x (m): hot end → cold end", labelpad=8)
for ax in (tax, qax):
ax.set_xlim(-0.002, 0.102)
ax.set_xticks([0, 0.025, 0.050, 0.075, 0.100],
["0", "0.025", "0.050", "0.075", "0.100"])
ax.grid(alpha=0.18)
fig.text(0.5, 0.075, "One-dimensional steady state; constant k and A; fixed end temperatures",
ha="center", fontsize=10)
fig.text(0.5, 0.035, "No internal sources or side losses; stipulated isotropic material",
ha="center", fontsize=10)
fig.savefig(Path(__file__).with_suffix(".png").name, transparent=False)
plt.close(fig)
print(f"gradient={gradient:g} K/m; q={flux:g} W/m²; Qdot={rate:g} W")
if __name__ == "__main__":
main()