Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

2.2. Canonical Ensemble

Course-wide Conventions & Notation

Overview and Learning Objectives

The canonical ensemble describes a closed system in thermal contact with a large heat bath at fixed temperature. Its central result is the Boltzmann assignment pi∝e−βEip_i \propto e^{-\beta E_i}, normalized by the partition function. This section derives and interprets that probability distribution and introduces a two-state system as a concrete model.

In a closed system (energy exchange allowed, matter exchange forbidden) in thermal contact with a heat bath, the appropriate statistical description is the canonical ensemble.

Source
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from myst_nb import glue

# Helper function to plot a system
def plot_system(ax, title, annotations, boundary_color='b'):
    box = mpatches.FancyBboxPatch((0, 0), 1, 1, boxstyle='roundtooth', ec=boundary_color, fc='w')
    ax.add_patch(box)
    ax.set_title(title, fontsize=14)
    ax.text(0.5, 0.5, 'System', ha='center', va='center', fontsize=12)
    ax.text(0.5, -0.65, 'Surroundings', ha='center', va='center', fontsize=12)
    ax.text(0.5, 1.3, 'Boundary', ha='center', va='bottom', fontsize=12, color=boundary_color)
    for annotation in annotations:
        if "arrowprops" in annotation:  # Arrow annotations
            ax.annotate('', **annotation)
        else:  # Text annotations
            ax.text(**annotation)
    ax.set_xlim(-1, 2)
    ax.set_ylim(-1, 2)
    ax.set_aspect('equal')
    ax.axis('off')

# Define annotations for each system
annotations = [
        dict(xy=(-0.6, 0.15), xytext=(0.15, 0.15), arrowprops=dict(arrowstyle='<->', color='r')),
        dict(x=-1, y=0.3, s='Energy', ha='left', va='bottom', fontsize=12, color='r'),
]

fig, ax = plt.subplots(1, 1, figsize=(4, 4))
plot_system(ax, "", annotations)

plt.show()
plt.close(fig)
<Figure size 400x400 with 1 Axes>

A closed system exchanges energy—but not matter—with its surroundings.

Learning objectives:

Core Ideas and Derivations

Probability of a Microstate in the Canonical Ensemble

Consider an ensemble of A\mathcal{A} identical closed systems in thermal contact with a heat bath at temperature TT. A heat bath is an environment so large that it can absorb or release energy with negligible change in temperature.

Population ratios depend only on energy differences

Intuition tells us that a system is more likely to be found in lower-energy microstates.

Let a1a_1 and a2a_2 denote the numbers of systems in microstates 1 and 2. We assume the population ratio depends only on the energy difference:

a2a1=f(E1,E2)=f(E1−E2),\frac{a_2}{a_1} = f \left( E_1, E_2 \right) = f \left( E_1 - E_2 \right),

where E1E_1 and E2E_2 are the corresponding microstate energies.

Finding an Acceptable Form for ff

Because ratios multiply, we can write

a3a1=a2a1 a3a2f(E1−E3)=f(E1−E2) f(E2−E3).\begin{align*} \frac{a_3}{a_1} &= \frac{a_2}{a_1}\,\frac{a_3}{a_2} \\ f \left( E_1 - E_3 \right) &= f \left( E_1 - E_2 \right)\, f \left( E_2 - E_3 \right). \end{align*}

If ff is well behaved (e.g., continuous, measurable), it must be of the form

f(Em−En)=eβ(Em−En),f \left( E_m - E_n \right) = e^{\beta \left( E_m - E_n \right)},

where β\beta is an undetermined constant. We will later identify β=1kBT\beta = \frac{1}{k_\text{B} T}.

Converting ff to a Probability

Separating the indices mm and nn,

ameβEm=aneβEn=C,a_m e^{\beta E_m} = a_n e^{\beta E_n} = \mathcal{C},

where C\mathcal{C} is a constant. Therefore, the number of systems in a microstate with energy EmE_m is

am=Ce−βEm.a_m = \mathcal{C} e^{-\beta E_m}.

The constant C\mathcal{C} is determined by the normalization condition

∑mam=A=C∑me−βEm.\sum_m a_m = \mathcal{A} = \mathcal{C} \sum_m e^{-\beta E_m}.

Solving for C\mathcal{C} and substituting into the expression for ama_m gives

pm=amA=e−βEm∑me−βEm=e−βEmQ,p_m = \frac{a_m}{\mathcal{A}} = \frac{e^{-\beta E_m}}{\sum_m e^{-\beta E_m}} = \frac{e^{-\beta E_m}}{Q},

where pmp_m is the probability of finding the system in microstate mm and QQ is the partition function.

Two-State System

Consider a system with two microstates (two “levels”): state 1 with energy E1E_1 and state 2 with energy E2E_2.

Table 1:Chemical Contexts Where a Two-State Approximation Might be Appropriate

Chemical Context

State 1

State 2

Electronic transitions in atoms or molecules

Ground state

Excited state

Donor–acceptor electron transfer

Reduced state

Oxidized state

Molecular isomerization

Reactant

Product

Defects in solids

Defect-free

Defective

Protein folding

Unfolded

Folded

Partition Function for a Two-State System

The partition function Qtwo-stateQ_\text{two-state} for a two-state system is

Qtwo-state=e−βE1+e−βE2=e−βE1(1+e−βΔE),\begin{align*} Q_\text{two-state} &= e^{-\beta E_1} + e^{-\beta E_2} \\ &= e^{-\beta E_1} \left( 1 + e^{-\beta \Delta E} \right), \end{align*}

where ΔE=E2−E1\Delta E = E_2 - E_1 is the energy difference between the two states.

Probability of Finding the System in State 1

The probability of finding the system in state 1 is

p1=e−βE1Qtwo-state=11+e−βΔE=11+e−ΔEkBT.p_1 = \frac{e^{-\beta E_1}}{Q_\text{two-state}} = \frac{1}{1 + e^{-\beta \Delta E}} = \frac{1}{1 + e^{-\frac{\Delta E}{k_\text{B} T}}}.

Probability of Finding the System in State 2

The probability of finding the system in state 2 is

p2=1−p1.p_2 = 1 - p_1.

Partition Function as the Effective Number of Thermally Accessible Microstates

Source
import numpy as np
import matplotlib.pyplot as plt
from scipy.constants import k, eV
from labellines import labelLines
from myst_nb import glue
from matplotlib.patches import Rectangle

k_B = k / eV  # Boltzmann constant in eV/K

# Define the partition function for a two-state system
def partition_function_two_state(E1, E2, T):
    beta = 1 / (k_B * T)
    return np.exp(-beta * E1) + np.exp(-beta * E2)

# Calculate the partition function for a two-state system
E1 = 0
E2 = 0.01  # Energy difference between the two states in eV
T_values = np.linspace(1, 1000, 1000)
Q_values = [partition_function_two_state(E1, E2, T) for T in T_values]

# Calculate the probabilities of finding the system in each state for a two-state system
p1_values = [np.exp(-1 / (k_B * T) * E1) / Q for T, Q in zip(T_values, Q_values)]
p2_values = [np.exp(-1 / (k_B * T) * E2) / Q for T, Q in zip(T_values, Q_values)]

# Plot the partition function and the probabilities of finding the system in each state
fig, axs = plt.subplots(1, 2, figsize=(8, 4))

# Plot the partition function on axs[0]
axs[0].plot(T_values, Q_values, 'k-')
axs[0].set_xlabel('Temperature (K)')
axs[0].set_ylabel('$Q_{\\text{two-state}}$')
axs[0].grid(True)
axs[0].annotate(
    '$\\rightarrow 1$ accessible\nmicrostate', xy=(40, Q_values[0] + 0.01), xytext=(300, 1.1),
    arrowprops=dict(arrowstyle='->', color='b'),
    bbox=dict(boxstyle='round,pad=0.3', fc='w', ec='b'),
    ha='center', va='center', color='b'
)
axs[0].annotate(
    '$\\rightarrow 2$ accessible\nmicrostates', xy=(T_values[-1], Q_values[-1]), xytext=(750, 1.7),
    arrowprops=dict(arrowstyle='->', color='m'),
    bbox=dict(boxstyle='round,pad=0.3', fc='w', ec='m'),
    ha='center', va='center', color='m'
)
axs[0].set_xlim(0, 1000)
axs[0].set_ylim(1, 2)

# Plot the probabilities of finding the system in each state on axs[1]
p1_line, = axs[1].plot(T_values, p1_values, 'b-', label='State 1')
p2_line, = axs[1].plot(T_values, p2_values, 'r-', label='State 2')
labelLines([p1_line, p2_line], zorder=2.5)
axs[1].set_xlabel('Temperature (K)')
axs[1].set_ylabel('Probability')
axs[1].grid(True)
axs[1].set_ylim(0, 1)  # ensure y-axis spans from 0 to 1

# Add tall outlined rectangles around the probabilities at low and high temperatures.
# For T -> 0: highlight T from 1 to 50 K.
# For T = 1000: highlight T from 950 to 1000 K.
rect_low = Rectangle((1, 0), 50 - 1, 1, edgecolor='b', facecolor='b', linestyle='-', alpha=0.2)
rect_high = Rectangle((950, 0), 1000 - 950, 1, edgecolor='m', facecolor='m', linestyle='-', alpha=0.2)
axs[1].add_patch(rect_low)
axs[1].add_patch(rect_high)
axs[1].annotate(
    'Only state 1 is accessed', xy=(50, 0.95), xytext=(100, 0.95),
    arrowprops=dict(arrowstyle='-', color='b'),
    ha='left', va='center', color='b'
)
axs[1].annotate(
    'Both states are accessed', xy=(950, 0.05), xytext=(900, 0.05),
    arrowprops=dict(arrowstyle='-', color='m'),
    ha='right', va='center', color='m'
)

plt.tight_layout()
plt.show()
plt.close(fig)
<Figure size 800x400 with 2 Axes>

Partition function and state probabilities for a two-state system as a function of temperature (ΔE=0.01 eV\Delta E = 0.01\ \mathrm{eV}).

Computational Studio: Two-State System

Explore how the canonical probabilities, partition function, and heat capacity respond to changes in the energy gap and temperature range.

You can open the studio in a new tab: Two-Level System Studio.

Worked Example

Two-level system probabilities

A single particle has two energy levels: E0=0E_0=0 and E1=εE_1=\varepsilon, with ε=0.010 eV\varepsilon=0.010\ \mathrm{eV}. Find p0p_0 and p1p_1 at T=300 KT=300\ \mathrm{K}.

Use pi=e−βEi/Qp_i = e^{-\beta E_i}/Q, Q=1+e−βεQ=1+e^{-\beta\varepsilon}, and kB=8.617×10−5 eV/Kk_\text{B}=8.617\times 10^{-5}\ \mathrm{eV/K}.

  1. Compute βε\beta\varepsilon

    βε=εkBT=0.010(8.617×10−5)(300)=0.387.\beta\varepsilon=\frac{\varepsilon}{k_\text{B}T} =\frac{0.010}{(8.617\times10^{-5})(300)}=0.387.
  2. Compute the Boltzmann factor

    e−βε=e−0.387=0.679.e^{-\beta\varepsilon}=e^{-0.387}=0.679.
  3. Normalize

    Q=1+0.679=1.679,p0=1Q=0.596,p1=0.679Q=0.404.Q=1+0.679=1.679, \qquad p_0=\frac{1}{Q}=0.596, \qquad p_1=\frac{0.679}{Q}=0.404.

Result. At 300 K300\ \mathrm{K}, about 40%40\% of systems occupy the excited state for this energy gap.

Concept Checks

  1. Why must the argument of the exponential in e−βEe^{-\beta E} be dimensionless?

  2. What happens to p1/p0p_1/p_0 as T→0T\to 0? As T→∞T\to\infty?

  3. Which part of the canonical derivation relies on the reservoir being much larger than the system?

  4. How does shifting all energies by a constant affect pip_i, and why?

Key Takeaways