Grand Canonical Ensemble¶
Consider small system in thermal and particle exchange with a large reservoir .
The total system is isolated: total energy , total particle number .
Total volume is constant, and the reservoir is much larger: , .

Grand Canonical Probability¶
The probability that the system has energy and particle number is proportional to the number of microstates of the reservoir with , :
Define entropy of the reservoir . Then:
Expand to first order:
Use thermodynamic definitions:
Grand Canonical Distribution and Partition Function¶
Define the grand canonical partition function:
where:
is called the fugacity.
is the canonical partition function at fixed
The microstate probability in grand canonical ensemble is:
The macrostate probability over different energy values in grand canonical ensemble is:
Connections with and ¶
Each ensemble arises from a different choice of what the system exchanges with its surroundings. The table below summarizes how the three ensembles we have encountered so far are related:
| Property | (Microcanonical) | (Canonical) | (Grand Canonical) |
|---|---|---|---|
| Fixed variables | |||
| Fluctuating quantities | — | ||
| Exchange with reservoir | Nothing (isolated) | Energy | Energy + Particles |
| Partition function | |||
| Thermodynamic potential | |||
| Fluctuation-response | — |
Each successive ensemble is obtained by “opening up” one more variable: .
The corresponding partition function is a Laplace transform of the previous one, and the thermodynamic potential is related by a Legendre transform.
Statistical Dominance of Average Energy and Particle Number¶
Recall that the canonical ensemble emerges by weighting microcanonical contributions at different energies with an exponential factor .
Similarly, the grand canonical ensemble arises by further summing over all particle numbers , each weighted by the fugacity factor . This yields the grand canonical partition function:
In the thermodynamic limit, the sum is dominated by the most probable energy and particle number, giving:
We identify a new thermodynamic potential for the grand canonical ensemble that plays same role as free energy in canonical ensemble:
:class: - Unknown Directive
:class: - Unknown Directive$$ \Psi(T, V, \mu) = E - T S - \mu N $$
Thermodynamics and Legendre transform¶
In thermodynamics grand potential is derived from the internal energy via a Legendre transform that replaces the natural variables and :
Grand Potential and Pressure¶
Using Euler’s relation for extensive thermodynamic variables:
Substituting into the definition of , we find:
Hence, the grand potential is directly related to the pressure and volume:
Fluctuations in particle numbers¶
We once again find that the relative fluctuation of an extensive quantity scales as , a consequence of extensivity and the law of large numbers:
Using thermodynamics we could also link number fluctuations with isothermal compressibility
The relationship is analogous to what we had established in between energy fluctuations and heat capacity.
It takes a bit more work manipulating variables to get there in this case. See below for derivation:
Number fluctuations and isothermal compressibility
Let (average particle number) and (number density)
Define isothermal compressibility:
We’ll now recast this in terms of quantities more natural in the grand canonical ensemble — like and .
We start from grand canonical potential:
Take the total differential:
This identity is valid generally in the grand canonical ensemble and is a key link between statistical mechanics and thermodynamics.
This tells us: if you increase the chemical potential, the pressure increases, and so does particle density.
Now we differentiate again:
That’s great, but we still want to connect this to compressibility, which involves how volume or density responds to pressure.
From chain rule we get
Now recall:
And plugging into the fluctuation formula:
Intuition for Chemical Potential¶
In the canonical ensemble, temperature controls energy flow: energy flows from hot to cold until temperatures equalize. Chemical potential plays the exact same role for particle flow: particles flow from regions of high to regions of low until chemical potentials equalize across the system.
For an ideal gas, , which reveals two competing effects:
increases with density : a crowded system has high chemical potential and tends to “push” particles out
decreases with temperature (through ): thermal agitation makes adding a particle less costly in free energy
In the classical regime (), the chemical potential is always negative. This means adding a particle to a dilute gas at fixed and always lowers the free energy: the entropy gain from having more accessible states outweighs the (zero) interaction energy cost.
The chemical potential becomes zero and eventually positive only in the quantum regime (), where quantum statistics (Fermi-Dirac or Bose-Einstein) become important.
Source
import numpy as np
import matplotlib.pyplot as plt
n_lambda3 = np.linspace(0.001, 0.8, 500) # classical regime n*lambda^3 << 1
mu_over_kT = np.log(n_lambda3)
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(n_lambda3, mu_over_kT, lw=2, color='steelblue')
ax.axhline(0, color='gray', ls='--', lw=1)
ax.fill_between(n_lambda3, mu_over_kT, 0, where=(n_lambda3 < 0.3), alpha=0.15, color='steelblue')
ax.set_xlabel(r'$n\lambda^3$ (dimensionless density)', fontsize=12)
ax.set_ylabel(r'$\mu / k_BT$', fontsize=12)
ax.set_title('Chemical Potential of Classical Ideal Gas', fontsize=14, weight='bold')
ax.annotate('Classical regime\n' + r'($n\lambda^3 \ll 1$, $\mu < 0$)',
xy=(0.1, np.log(0.1)), fontsize=11,
xytext=(0.4, -4), arrowprops=dict(arrowstyle='->', color='red', lw=1.5))
ax.annotate(r'$\mu = 0$ at $n\lambda^3 = 1$' + '\n(quantum degeneracy)',
xy=(0.75, np.log(0.75)), fontsize=10,
xytext=(0.4, -1), arrowprops=dict(arrowstyle='->', color='darkgreen', lw=1.5))
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 0.8)
ax.set_ylim(-7, 0.5)
plt.tight_layout()
plt.show()
Ideal Gas in the Grand Canonical Ensemble¶
We begin by considering an ideal gas of indistinguishable, non-interacting particles in a volume , in thermal and chemical equilibrium with a reservoir at temperature and chemical potential .
The canonical partition function for particles is:
Where the thermal de Broglie wavelength is:
Grand Canonical Partition Function¶
To account for fluctuations in particle number, we compute the grand canonical partition function:
Fugacity: , a dimensionless measure of how favorable it is to add a particle to the system.
The average particle number is then obtained by taking first derivative with respect to
Chemical Potential in Terms of Pressure and Density¶
We can invert the relation for to express the chemical potential:
Noting that for an ideal gas , this becomes:
Number Fluctuations¶
In the grand canonical ensemble, number fluctuations are given by:
So the standard deviation , and relative fluctuations vanish as in the thermodynamic limit.
Isothermal Compressibility¶
We relate number fluctuations to the isothermal compressibility :
This is the well-known result for the ideal gas compressibility:
, a positive quantity ensuring mechanical stability.
Molecular Adsorption of Ideal Gas on Surfaces¶

One Site–One Molecule Model¶
We consider a simple model where each adsorption site can hold at most one molecule. The surface is in thermal and chemical equilibrium with a gas reservoir at temperature and chemical potential .
Each site has two possible states:
Empty: energy
Occupied: energy
Then the grand partition function for a single site is:
Independent Sites¶
If there are independent and identical adsorption sites, then the total grand partition function is:
Since the sites do not interact, their contributions multiply.
Average Number of Adsorbed Molecules¶
The average occupation number per site is:
The total number of adsorbed molecules is:
Average Energy¶
The average energy per site is:
The total energy of the system is:
Connecting to Pressure¶
For an ideal gas in the reservoir, the chemical potential is related to pressure via:
where is a reference pressure determined by the internal partition function of the gas.
Substituting this into the expression for :
and thus the total number of adsorbed molecules becomes:
This is the Langmuir adsorption isotherm, describing how the fraction of occupied adsorption sites depends on gas pressure. It captures saturation behavior as , where .
Source
import matplotlib.pyplot as plt
import numpy as np
# Use dimensionless units: energies in units of epsilon
epsilon = 1.0 # binding energy (reference unit)
p0 = 1.0 # reference pressure
p = np.linspace(0, 10, 500)
fig, ax = plt.subplots(figsize=(8, 5))
for kT in [0.2, 0.5, 1.0, 2.0, 5.0]:
n_avg = p / (p0 * np.exp(epsilon / kT) + p)
ax.plot(p, n_avg, lw=2, label=rf'$k_BT/\epsilon = {kT}$')
ax.set_xlabel(r'Pressure $p / p_0$', fontsize=12)
ax.set_ylabel(r'Average Occupancy $\langle n \rangle$', fontsize=12)
ax.set_title('Langmuir Adsorption Isotherm', fontsize=14, weight='bold')
ax.legend(fontsize=11)
ax.set_ylim(0, 1.05)
ax.set_xlim(0, 10)
ax.axhline(1.0, color='gray', ls='--', lw=1, alpha=0.5)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Chemical Equilibrium in gas mixtures¶
For each species , the canonical partition function is:
where:
is the thermal wavelength,
is the internal partition function (rotations, vibrations, etc.),
is the number of molecules of species .
For convenience lets use the Helmholtz free energy (same result with Gibbs Free energy):
Using Stirling’s approximation :
Equilibrium via minimization of free energy¶
Now, we consider a chemical reaction:
We introduce an extent of reaction which measures how far reaction has progressed from reactants to products:
We minimize at constant by setting:
Computing the derivative:
with the stoichiometric coefficient ( for reactants, for products). Or we can write it in terms of positive stoichiometric coefficients:
So the equilibrium condition is:
Exponentiating both sides we relate ratio of equilibrium numbers or concentrations to partition functions
Example: Chemical Equilibrium
Simple example using the reaction of
Step 1: Write equilibrium constant in terms of partition functions
Notice that all volume terms coming from translational part of partition function cancel out!
Each , so .
Step 2: Plug into expression for
This gives in terms of molecular properties at temperature . No volume dependence remains.
Grand Canonical Monte Carlo: Particle Number Fluctuations in Action¶
The formulas above predict that particle number fluctuates in the grand canonical ensemble with . We can see this directly using a simple Grand Canonical Monte Carlo (GCMC) simulation on a lattice. At each step, we randomly attempt to insert or delete a particle, accepting moves with probability determined by .
How the GCMC algorithm works
We are going to learn how to simulate lattice systems using Monte-Carlo algorithm in subsequent sections. But we the idea is simple enough that we can state it here. At each step we do three things:
Pick a random site on the lattice.
If the site is empty, attempt to insert a particle:
Compute the energy change from adding the particle
Accept with probability
If the site is occupied, attempt to delete the particle:
Compute the energy change from removing it
Accept with probability
For a non-interacting lattice gas (), the acceptance simplifies to:
Insert:
Delete:
Why it works: After many steps, the system samples the correct equilibrium distribution of , and we can directly measure , , and any other observable. The reason is that we engineered acceptance rule to satisfy the so called detailed balance with respect to the grand canonical distribution .
Intuition for :
: insertions are rarely accepted, deletions are easy low density
: insertions and deletions equally likely half-filled
: insertions are easy, deletions are rarely accepted high density
Source
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.colors import ListedColormap
from IPython.display import HTML
def gcmc_animation_frames(beta_mu, L=25, n_steps=30000, n_frames=80):
"""Run GCMC and collect frames for animation."""
grid = np.zeros((L, L), dtype=int)
N = 0
p_ins = min(1.0, np.exp(beta_mu))
p_del = min(1.0, np.exp(-beta_mu))
steps_per_frame = n_steps // n_frames
frames = []
N_vals = []
for step in range(n_steps):
x, y = np.random.randint(0, L, 2)
if grid[x, y] == 0:
if np.random.rand() < p_ins:
grid[x, y] = 1; N += 1
else:
if np.random.rand() < p_del:
grid[x, y] = 0; N -= 1
if (step + 1) % steps_per_frame == 0:
frames.append(grid.copy())
N_vals.append(N)
return frames, N_vals
# Generate frames for low and high mu
np.random.seed(42)
frames_low, N_low = gcmc_animation_frames(-2, L=25, n_steps=30000, n_frames=80)
frames_high, N_high = gcmc_animation_frames(2, L=25, n_steps=30000, n_frames=80)
cmap = ListedColormap(['#f0f0f0', '#2c7bb6'])
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4.5))
im1 = ax1.imshow(frames_low[0], cmap=cmap, vmin=0, vmax=1, interpolation='nearest')
im2 = ax2.imshow(frames_high[0], cmap=cmap, vmin=0, vmax=1, interpolation='nearest')
ax1.set_title(r'Low $\mu$: $\beta\mu = -2$', fontsize=13, fontweight='bold')
ax2.set_title(r'High $\mu$: $\beta\mu = +2$', fontsize=13, fontweight='bold')
for ax in [ax1, ax2]:
ax.set_xticks([]); ax.set_yticks([])
for spine in ax.spines.values():
spine.set_linewidth(2)
txt1 = ax1.text(0.5, -0.07, '', transform=ax1.transAxes, ha='center', fontsize=11)
txt2 = ax2.text(0.5, -0.07, '', transform=ax2.transAxes, ha='center', fontsize=11)
fig.suptitle('GCMC Animation: Lattice Filling at Different Chemical Potentials',
fontsize=14, fontweight='bold')
plt.tight_layout()
def update(frame):
im1.set_data(frames_low[frame])
im2.set_data(frames_high[frame])
L = 25
txt1.set_text(rf'$N = {N_low[frame]}$, $\theta = {N_low[frame]/(L*L):.2f}$')
txt2.set_text(rf'$N = {N_high[frame]}$, $\theta = {N_high[frame]/(L*L):.2f}$')
return [im1, im2, txt1, txt2]
plt.close(fig)
ani = animation.FuncAnimation(fig, update, frames=len(frames_low),
interval=80, blit=True)
HTML(ani.to_jshtml())
Source
import numpy as np
import matplotlib.pyplot as plt
def gcmc_lattice_gas(beta_mu, n_steps=50000, L=20):
"""Simple GCMC for non-interacting lattice gas.
Each lattice site is either empty (0) or occupied (1).
Acceptance probability for insertion/deletion depends on beta*mu.
"""
grid = np.zeros((L, L), dtype=int)
N = 0
N_history = []
p_accept_insert = min(1.0, np.exp(beta_mu))
p_accept_delete = min(1.0, np.exp(-beta_mu))
for _ in range(n_steps):
x, y = np.random.randint(0, L, 2)
if grid[x, y] == 0: # try to insert
if np.random.rand() < p_accept_insert:
grid[x, y] = 1
N += 1
else: # try to delete
if np.random.rand() < p_accept_delete:
grid[x, y] = 0
N -= 1
N_history.append(N)
return np.array(N_history)
# Run GCMC at different chemical potentials
fig, axes = plt.subplots(1, 2, figsize=(13, 4.5))
colors = ['#1f77b4', '#ff7f0e', '#2ca02c']
beta_mu_values = [-2, 0, 1.5]
for beta_mu, color in zip(beta_mu_values, colors):
N_hist = gcmc_lattice_gas(beta_mu, n_steps=50000)
burn_in = 5000
N_eq = N_hist[burn_in:]
# Time series (last 10000 steps)
axes[0].plot(N_hist[-10000:], alpha=0.7, color=color,
label=rf'$\beta\mu = {beta_mu}$')
# Histogram
rel_fluct = np.std(N_eq) / np.mean(N_eq) if np.mean(N_eq) > 0 else 0
axes[1].hist(N_eq, bins=30, alpha=0.5, density=True, color=color,
label=rf'$\beta\mu={beta_mu}$, $\sigma_N/\langle N\rangle={rel_fluct:.3f}$')
axes[0].set_xlabel('MC Step', fontsize=12)
axes[0].set_ylabel('N (particle number)', fontsize=12)
axes[0].set_title('Particle Number Fluctuations (GCMC)', fontsize=13, weight='bold')
axes[0].legend(fontsize=10)
axes[0].grid(True, alpha=0.3)
axes[1].set_xlabel('N', fontsize=12)
axes[1].set_ylabel('P(N)', fontsize=12)
axes[1].set_title('Distribution of Particle Number', fontsize=13, weight='bold')
axes[1].legend(fontsize=9)
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Isothermal-Isobaric (NPT) Ensemble¶
Most experiments in chemistry and biology are performed at constant temperature and pressure (e.g., reactions in open flasks, protein folding in solution). The appropriate statistical ensemble is the NPT ensemble, where the system exchanges energy and volume with a reservoir while keeping particle number fixed.
Derivation¶
Consider a system in thermal and mechanical contact with a large reservoir . The total system is isolated with fixed total energy and total volume .
The probability of finding the system in a state with energy and volume is:
Expanding the reservoir entropy to first order (same logic as for NVT and VT):
where we used:
This gives the NPT probability distribution:
Partition Function and Gibbs Free Energy¶
The thermodynamic potential is the Gibbs free energy:
where is the enthalpy.
The Gibbs free energy arises from the internal energy via Legendre transform replacing and :
Volume Fluctuations¶
Just as energy fluctuates in NVT and particle number fluctuates in VT, volume fluctuates in NPT:
The relative volume fluctuation follows the same scaling:
Complete Ensemble Comparison¶
| Property | ||||
|---|---|---|---|---|
| Fixed | ||||
| Fluctuating | — | |||
| Partition fn | ||||
| Potential | ||||
| Fluctuation-response | — |
Problems¶
¶
Consider a three level single particle system with five microstates with energies 0, ε, ε, ε, and 2ε. What is n=0,1,2 for this system? What is the mean energy of the system if it is in equilibrium with a heat bath at temperature T ?
Derive an expression for the chemical potential of an ideal gas using classical mechanics model for energy in the ensemble evaluate the fluctuations in particle number.
Consider a system in equilibrium with a heat bath at temperature and a particle reservoir at chemical potential . The system can have a minimum of one and a maximum of four distinguishable particles. The particles in the system do not interact and can be in one of two states with energies zero or . Determine the (grand) partition function of the system.
Combine the Gibbs formula of Entropy with the Grand canonical probability distribution to show that
Derive partition function for a pressure ensemble and show its connection with microcanonical ensemble
At a given temperature T a surface with adsorption centers has on average number of adsorbed molecules. Suppose that there are no interactions between molecules.
Show that the chemical potential of adsorbed gas is given by:
What is the meaning of