codex/past-exam-of-the-mphil-in-micro-and-nanotechnology-enterprise-course-of-the-university-of-cambridge/2022/paper-1-thermoelectric.py

past-exam-of-the-mphil-in-micro-and-nanotechnology-enterprise-course-of-the-university-of-cambridge/2022/paper-1-thermoelectric.py
"""Original thermoelectric trade-off/circuit models; Python 3.14/numpy/matplotlib.

Carrier curves are illustrative normalized functions, not fitted measurements.
Output is a PNG basename in the current working directory.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np

fig = plt.figure(figsize=(10.6, 6.7), layout='constrained')
gs = fig.add_gridspec(2, 2)
a0 = fig.add_subplot(gs[0, 0])
n = np.geomspace(.01, 100, 500)
sigma = n
seebeck = 1/(1+n**.4)
kappa = .5+.2*n
powerfactor = seebeck**2*sigma
z = powerfactor/kappa
for values, label, color in [(seebeck, r'$|S|$', '#286a85'),
                             (sigma, r'$\sigma$', '#b65c38'),
                             (kappa, r'$\kappa$', '#91709b')]:
    a0.semilogx(n, values/np.max(values), color=color, label=label)
a0.semilogx(n, z/np.max(z), 'k--', label='Z (separate normalization)')
a0.set(xlabel='Carrier concentration (normalized)', ylabel='Individually normalized value',
       title='Competing transport trends')
a0.legend(ncol=2, fontsize=8)
a0.grid(alpha=.15)
a1 = fig.add_subplot(gs[1, 0])
r = np.linspace(.001, 6, 600)
a1.plot(r, 4*r/(1+r)**2, color='#286a85', lw=2)
a1.scatter([1], [1], color='#b65c38', zorder=3)
a1.axvline(1, color='.65', ls=':')
a1.set(xlabel=r'Load ratio $R_L/R$', ylabel=r'$P/P_{\max}$',
       title='Fixed junction temperatures: maximum power at RL = R', ylim=(0, 1.12))
a1.grid(alpha=.15)
ax = fig.add_subplot(gs[:, 1])
ax.set(xlim=(0, 10), ylim=(0, 11), aspect='equal')
ax.axis('off')
ax.add_patch(Rectangle((1, 7.95), 8, .65, color='#e9b29d'))
ax.add_patch(Rectangle((1, 2.6), 8, .5, color='#b7d9e7'))
ax.text(5, 9.25, 'Hot source; TH', ha='center', fontsize=12)
ax.text(5, 1.95, 'Cold sink; TC', ha='center', fontsize=12)
for x, label, color in [(2, 'p-type', '#e5c4b5'), (6.2, 'n-type', '#b9d9e4')]:
    ax.add_patch(Rectangle((x, 3.1), 1.8, 4.5, facecolor=color, edgecolor='.3'))
    ax.text(x+.9, 5.35, label, ha='center', rotation=90, fontsize=12)
ax.plot([2.9, 2.9, 7.1, 7.1], [7.6, 8.05, 8.05, 7.6], color='.25', lw=3)
ax.plot([2.9, 2.9, 1.1, 1.1, 4.0], [3.1, 3.0, 3.0, .8, .8], color='.25', lw=2)
ax.plot([7.1, 7.1, 8.9, 8.9, 6], [3.1, 3.0, 3.0, .8, .8], color='.25', lw=2)
ax.add_patch(Rectangle((4, .45), 2, .7, facecolor='white', edgecolor='.25', lw=1.5))
ax.text(5, .8, 'Load RL', ha='center', va='center', fontsize=10)
for x in [1.3, 8.7]:
    ax.annotate('', (x, 3.25), (x, 7.8), arrowprops={'arrowstyle': '->', 'color': '#b65c38', 'lw': 1.5})
ax.text(5, 6.6, 'Heat', ha='center', color='#b65c38', fontsize=10)
ax.text(5, 4.45, 'Electrical series\nThermal parallel', ha='center', fontsize=10)
ax.text(5, 10.25, 'Ideal thermoelectric generator couple', ha='center', fontsize=13)
ax.annotate('', (3.4, .8), (1.7, .8), arrowprops={'arrowstyle': '->', 'color': '#286a85', 'lw': 1.6})
ax.text(2.6, .35, 'I', ha='center', color='#286a85', fontsize=11)
ax.text(5, -.05, 'Plates insulate electrically and conduct heat.', ha='center', fontsize=9)
fig.savefig('paper-1-thermoelectric.png', dpi=150, facecolor='white')
plt.close(fig)