Course-wide Conventions & Notation
Overview and Learning Objectives¶
Real gases deviate from ideal behavior when finite molecular size and intermolecular forces become important. This section introduces the compressibility factor as a quantitative measure of nonideality and develops the van der Waals equation of state (EOS), including its critical constants and the principle of corresponding states.
At sufficiently high pressures (high densities) or low temperatures, we can no longer treat gases as collections of noninteracting point particles. High pressure/density brings molecules closer together, increasing collision frequency and making both excluded volume and intermolecular interactions more consequential. Lower temperature reduces kinetic energy, so these interactions more strongly perturb behavior. This section develops practical ways to quantify deviations from ideality and introduces the van der Waals EOS—one of the simplest real-gas models and the work recognized by the Nobel Prize in Physics 1910.
Learning objectives:
Define the compressibility factor and interpret vs. in terms of net attractions/repulsions.
Write the van der Waals EOS in particle and molar forms and interpret the parameters and .
Derive (or use) the van der Waals critical constants , , .
Non-dimensionalize the van der Waals EOS to obtain the corresponding-states form in reduced variables.
Core Ideas and Derivations¶
Deviations from Ideal Behavior¶
Compressibility Factor¶
Source
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.constants import R
from labellines import labelLines
from myst_nb import glue
from scipy.interpolate import interp1d
# Load the experimental data for water at 300 K
df = pd.read_csv("../_static/section-04/isothermal-properties-for-water-T=300.csv").iloc[:, [0, 1, 2, 3]]
df.columns = ["T", "P", "rho_m", "V_m"] # Rename columns
# Calculate the compressibility factor
df["P_Pa"] = df["P"] * 1e5 # Convert pressure from bar to Pa
df["Z"] = df["P_Pa"] * df["V_m"] / (R * df["T"])
# Set up figure and axis
fig, ax = plt.subplots(figsize=(4, 4))
ax.set_xlim(0, 1000)
ax.set_ylim(0, 2)
ax.set_xlabel("Pressure (bar)")
ax.set_ylabel(r"$Z$")
ax.grid(True, linestyle="--", alpha=0.7)
# Plot experimental compressibility factor
data_line = ax.plot(df["P"], df["Z"], "b-", label="$Z_\\text{water}$")
labelLines(data_line, xvals=[400], zorder=2.5)
# Plot ideal gas line
x_values = np.linspace(0, 1000, 100)
ideal_line = ax.plot(x_values, np.ones_like(x_values), "r--", label="$Z_\\text{ideal}$")
labelLines(ideal_line, xvals=[400], zorder=2.5)
# Interpolate to find intersection with ideal gas line
interp_Z = interp1d(df["P"], df["Z"], kind='linear', fill_value="extrapolate")
intersection_pressure = interp1d(df["Z"] - 1, df["P"], kind='linear')(0)
intersection_Z = interp_Z(intersection_pressure)
# Find pressure and Z value at minimum Z
min_Z_index = df["Z"].idxmin()
min_pressure = df.loc[min_Z_index, "P"]
min_Z = df.loc[min_Z_index, "Z"]
# Annotate ideal and coincidentally ideal points
ax.annotate("Ideal",
xy=(0, 1), xytext=(200, 1.25),
arrowprops=dict(arrowstyle="->"),
ha='center', va='center', zorder=4)
ax.annotate("Coincidentally\nideal",
xy=(intersection_pressure, 1), xytext=(800, 0.75),
arrowprops=dict(arrowstyle="->"),
ha='center', va='center', zorder=4)
# Draw vertical lines for reference
ax.axvline(x=min_pressure, color="black", linestyle=":")
ax.axvline(x=intersection_pressure, color="black", linestyle=":")
# Highlight regions of attractive and repulsive behavior
ax.fill_between([min_pressure, intersection_pressure], 0, 2, color="magenta", alpha=0.2, label="Attractive")
ax.fill_between([intersection_pressure, 1000], 0, 2, color="gray", alpha=0.2, label="Repulsive")
# Annotate regions
x_values_for_attractive = np.linspace(min_pressure, intersection_pressure, 100)
attractive_line = ax.plot(x_values_for_attractive, np.ones_like(x_values_for_attractive) * min_Z, "m-", label="Attractive", alpha=0.0)
labelLines(attractive_line, xvals=np.mean([min_pressure, intersection_pressure]), zorder=2.5)
x_values_for_repulsive = np.linspace(intersection_pressure, 1000, 100)
repulsive_line = ax.plot(x_values_for_repulsive, np.ones_like(x_values_for_repulsive) * min_Z, "gray", label="Repulsive", alpha=0.0)
labelLines(repulsive_line, xvals=800, zorder=2.5)
# Adjust layout and display
plt.tight_layout()
plt.show()
plt.close(fig)
Compressibility factor for water at 300 K as a function of pressure, with the ideal-gas line () included for comparison. The dip below indicates net attractive forces (most pronounced at the minimum in ), while the rise above at higher pressures reflects repulsive interactions. The intersection with marks a “coincidentally ideal” state.
One convenient measure of nonideality is the compressibility factor :
Table 1:Behavior of Water at Different Pressures
Pressure | Volume | Analysis | Water | |
|---|---|---|---|---|
High | Repulsive interactions | Pauli (steric) repulsion | ||
Medium | Attractive interactions | H-bonding and van der Waals interactions | ||
Low | Ideal-gas behavior | — |
Van der Waals Fluid¶
Van der Waals Equation of State¶
The van der Waals equation of state is among the simplest real-gas models (and was central to the work recognized by the Nobel Prize in Physics 1910):
Table 2:Forms of the van der Waals Equation of State
where and are substance-dependent parameters capturing two departures from ideality:
: Net attractive interactions between particles.
: Volume associated with finite particle size (excluded volume).
Van der Waals Isotherm¶
Source
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import numpy as np
import pandas as pd
from scipy.constants import R
from labellines import labelLines
from myst_nb import glue
# van der Waals constants for carbon dioxide
a_m_L_bar = 3.6551 # L^2 bar / mol^2
b_m_L = 0.042816 # L / mol
L_to_m3 = 1e-3 # m^3 / L
bar_to_Pa = 1e5 # Pa / bar
a_m = a_m_L_bar * L_to_m3**2 * bar_to_Pa # m^6 Pa / mol^2
b_m = b_m_L * L_to_m3 # m^3 / mol
# van der Waals critical properties for carbon dioxide
Tc_vdW = 8 * a_m / (27 * b_m * R) # K
Pc_vdW = a_m / (27 * b_m**2) # Pa
Vc_vdW = 3 * b_m # m^3 / mol
# Experimental phase change data for carbon dioxide
Tc_exp = 304.18 # K
Pc_exp = 73.80 * bar_to_Pa # Pa
Vc_exp = 0.0919 * L_to_m3 # m^3 / mol
# van der Waals pressure function
def van_der_waals_pressure(a, b, T, V):
return R * T / (V - b) - a / V**2
# Load experimental data
def load_experimental_data(filename):
df = pd.read_csv(filename).iloc[:, [0, 1, 2, 3]]
df.columns = ["Tc", "P", "rho_m", "V_m"]
return df
df_lt_Tc = load_experimental_data("../_static/section-04/isothermal-properties-for-carbon-dioxide-Tr=0.9.csv")
df_at_Tc = load_experimental_data("../_static/section-04/isothermal-properties-for-carbon-dioxide-Tr=1.0.csv")
df_gt_Tc = load_experimental_data("../_static/section-04/isothermal-properties-for-carbon-dioxide-Tr=1.1.csv")
# Set up figure
fig, ax = plt.subplots(figsize=(4, 4))
Vm_vdW = np.linspace(0.5 * Vc_vdW, 20 * Vc_vdW, 1000)
# Plot van der Waals isotherms
colors = ["b", "r", "m"]
temps = [0.9 * Tc_vdW, Tc_vdW, 1.1 * Tc_vdW]
labels = ["$T < T_c$", "$T = T_c$", "$T > T_c$"]
lines = []
for T, color, label in zip(temps, colors, labels):
P_vdW = van_der_waals_pressure(a_m, b_m, T, Vm_vdW)
line = ax.plot(Vm_vdW / L_to_m3, P_vdW / bar_to_Pa, color + "-", label=label)
lines.append(line)
labelLines(line, xvals=[0.3], zorder=2.5)
# Plot experimental isotherms
for df, color in zip([df_lt_Tc, df_at_Tc, df_gt_Tc], colors):
ax.plot(df["V_m"] / L_to_m3, df["P"], color + "-", alpha=0.5)
# Legend and labels
legend_elements = [Line2D([0], [0], c='k', label='van der Waals', ls="-"),
Line2D([0], [0], c='k', label='Experimental', ls="-", alpha=0.5)]
ax.set_xlim(0, 1)
ax.set_ylim(0, 100)
ax.set_xlabel("Molar Volume (L/mol)")
ax.set_ylabel("Pressure (bar)")
ax.legend(handles=legend_elements, loc='lower left')
ax.grid(True, linestyle="--", alpha=0.7)
# Adjust layout and display
plt.tight_layout()
plt.show()
plt.close(fig)
Comparison of experimental and van der Waals isotherms for CO at temperatures below, at, and above the critical temperature . For , the van der Waals EOS exhibits the characteristic loop associated with phase separation; at the isotherm has an inflection point; and for the liquid–vapor transition disappears.
Critical Point¶
Source
# Reference: https://scipython.com/blog/the-maxwell-construction/
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from scipy.constants import R as R_SI
from scipy.integrate import quad
from scipy.optimize import curve_fit, newton
from scipy.signal import argrelextrema
from scipy import stats
from labellines import labelLines
from myst_nb import glue
R = R_SI / 100 # Gas constant in L bar / mol K
# van der Waals constants for carbon dioxide
a_m = 3.6551 # L^2 bar/mol^2
b_m = 0.042816 # L/mol
# van der Waals critical properties for carbon dioxide
Tc_vdW = 8 * a_m / (27 * b_m * R) # K
Pc_vdW = a_m / (27 * b_m**2) # bar
Vc_vdW = 3 * b_m # L/mol
# Reduced-pressure form of the van der Waals equation of state
def vdw(Tr, Vr):
"""Van der Waals equation of state.
Return the reduced pressure from the reduced temperature and volume.
"""
pr = 8*Tr/(3*Vr-1) - 3/Vr**2
return pr
# Maxwell construction of the reduced-pressure form of the van der Waals equation of state
def vdw_maxwell(Tr, Vr):
"""Van der Waals equation of state with Maxwell construction.
Return the reduced pressure from the reduced temperature and volume,
applying the Maxwell construction correction to the unphysical region
if necessary.
"""
pr = vdw(Tr, Vr)
if Tr >= 1:
# No unphysical region above the critical temperature.
return pr
if min(pr) < 0:
raise ValueError('Negative pressure results from van der Waals'
' equation of state with Tr = {} K.'.format(Tr))
# Initial guess for the position of the Maxwell construction line:
# the volume corresponding to the mean pressure between the minimum and
# maximum in reduced pressure, pr.
iprmin = argrelextrema(pr, np.less)
iprmax = argrelextrema(pr, np.greater)
Vr0 = np.mean([Vr[iprmin], Vr[iprmax]])
def get_Vlims(pr0):
"""Solve the inverted van der Waals equation for reduced volume.
Return the lowest and highest reduced volumes such that the reduced
pressure is pr0. It only makes sense to call this function for
T<Tc, ie below the critical temperature where there are three roots.
"""
eos = np.poly1d( (3*pr0, -(pr0+8*Tr), 9, -3) )
roots = eos.r
roots.sort()
Vrmin, _, Vrmax = roots
return Vrmin, Vrmax
def get_area_difference(Vr0):
"""Return the difference in areas of the van der Waals loops.
Return the difference between the areas of the loops from Vr0 to Vrmax
and from Vrmin to Vr0 where the reduced pressure from the van der Waals
equation is the same at Vrmin, Vr0 and Vrmax. This difference is zero
when the straight line joining Vrmin and Vrmax at pr0 is the Maxwell
construction.
"""
pr0 = vdw(Tr, Vr0)
Vrmin, Vrmax = get_Vlims(pr0)
return quad(lambda vr: vdw(Tr, vr) - pr0, Vrmin, Vrmax)[0]
# Root finding by Newton's method determines Vr0 corresponding to
# equal loop areas for the Maxwell construction.
Vr0 = newton(get_area_difference, Vr0)
pr0 = vdw(Tr, Vr0)
Vrmin, Vrmax = get_Vlims(pr0)
# Set the pressure in the Maxwell construction region to constant pr0.
pr[(Vr >= Vrmin) & (Vr <= Vrmax)] = pr0
return pr, Vrmin, Vrmax
# Reduced volume range
Vr = np.linspace(0.5, 20, 1000)
fig, axs = plt.subplot_mosaic([[0, 1]], figsize=(8, 4), sharex=True, sharey=True)
# Plot the van der Waals isotherm below the critical temperature
line1 = axs[0].plot(Vr * Vc_vdW,
vdw(0.9, Vr) * Pc_vdW,
'b-', label='$T = 0.9 T_c$')
labelLines(line1, xvals=0.4, zorder=2.5)
Pr_max, Vr_liq, Vr_vap = vdw_maxwell(0.9, Vr)
Pr_equ = Pr_max[np.argwhere(np.diff(Pr_max) == 0).flatten().mean().astype(int)]
Vr_int = 0.140076 / Vc_vdW # https://www.wolframalpha.com/input?i=V%5E3-%28b%2BR*T%2FP%29*V%5E2%2Ba%2FP*V-a*b%2FP%3D0+for+a%3D3.6551%2C+b%3D0.042816%2C+R%3D8.314462618%2F100%2C+T%3D0.9*8*a%2F%2827*b*R%29%2C+P%3D0.64699835*a%2F%2827*b%5E2%29
# print(f"At Tr = 0.90, the molar volume of the liquid phase is {Vr_liq * Vc_vdW:.4f} L/mol, the molar volume of the vapor phase is {Vr_vap * Vc_vdW:.4f} L/mol, and the equilibrium pressure is {Pr_equ * Pc_vdW:.4f} bar.")
# Calculate the molar volume of the liquid and vapor phases at Tr = 0.85
Pr_max_85, Vr_liq_85, Vr_vap_85 = vdw_maxwell(0.85, Vr)
Pr_equ_85 = Pr_max_85[np.argwhere(np.diff(Pr_max_85) == 0).flatten().mean().astype(int)]
# print(f"At Tr = 0.85, the molar volume of the liquid phase is {Vr_liq_85 * Vc_vdW:.4f} L/mol, the molar volume of the vapor phase is {Vr_vap_85 * Vc_vdW:.4f} L/mol, and the equilibrium pressure is {Pr_equ_85 * Pc_vdW:.4f} bar.")
# Calculate the molar volume of the liquid and vapor phases at Tr = 0.8
# Plot the van der Waals isotherm at the critical temperature
line2 = axs[0].plot(Vr * Vc_vdW,
vdw(1.0, Vr) * Pc_vdW,
'r-', label='$T = T_c$')
labelLines(line2, xvals=0.4, zorder=2.5)
# Fill the Maxwell construction region
Vr_vals_fill_l = np.linspace(Vr_liq, Vr_int, 100) # Range of volumes for filling
Pr_vals_fill_l = vdw(0.9, Vr_vals_fill_l) * Pc_vdW # Calculate pressures along the curve
Vr_vals_fill_r = np.linspace(Vr_int, Vr_vap, 100) # Range of volumes for filling
Pr_vals_fill_r = vdw(0.9, Vr_vals_fill_r) * Pc_vdW # Calculate pressures along the curve
# Fill the area between the vdw curve and the phase transition pressure Pr_equ
axs[0].fill_between(
Vr_vals_fill_l * Vc_vdW, # Scaled volume
Pr_vals_fill_l, # Pressure from vdw curve
np.ones_like(Vr_vals_fill_l) * Pr_equ * Pc_vdW, # Constant transition pressure
color='blue', # Styling for the fill
)
axs[0].fill_between(
Vr_vals_fill_r * Vc_vdW, # Scaled volume
Pr_vals_fill_r, # Pressure from vdw curve
np.ones_like(Vr_vals_fill_r) * Pr_equ * Pc_vdW, # Constant transition pressure
color='blue', # Styling for the fill
)
# Plot the molar volume of the liquid and vapor phases at Tr = 0.9
axs[0].plot(Vr_liq * Vc_vdW, Pr_equ * Pc_vdW, 'wo', mec='b')
axs[0].plot(Vr_vap * Vc_vdW, Pr_equ * Pc_vdW, 'wo', mec='b')
# Annotate the Maxwell construction
x_maxwell = np.mean([Vc_vdW, 0.3])
axs[0].annotate("Maxwell\nconstruction",
xy=(x_maxwell, Pr_equ * Pc_vdW),
xytext=(x_maxwell, 40),
arrowprops=dict(arrowstyle="->"),
ha='center', va='center',
zorder=4)
# Plot and annotate the critical point
axs[0].plot(Vc_vdW, Pc_vdW, 'wo', mec='r')
Vm_vals_Vc = np.linspace(1e-3, 0.5, 100)
y_supercritical = np.mean([Pc_vdW, 80])
line3 = axs[0].plot(Vm_vals_Vc, np.ones_like(Vm_vals_Vc) * y_supercritical, 'r-', alpha=0, label='$V_{\\text{m},c}$')
labelLines(line3, xvals=Vc_vdW, zorder=2.5)
Vm_vals_Pc = np.linspace(0, 0.5, 100)
line4 = axs[0].plot(Vm_vals_Pc, np.ones_like(Vm_vals_Pc) * Pc_vdW, 'r-', alpha=0, label='$P_c$')
labelLines(line4, xvals=0.035, zorder=2.5)
axs[0].axvline(Vc_vdW, color='r', linestyle=':', zorder=-200)
axs[0].axhline(Pc_vdW, color='r', linestyle=':', zorder=-200)
# Approximate the coexistence curve with a function
# Define the functional form: A * ln(B * Vm) * exp(-C * Vm ** 0.25)
def fit_function(Vm, A, B, C):
return A * np.log(B * Vm) * np.exp(-C * Vm ** 0.25)
# Extract data points: (Vm_liq, P_eq), (Vc, Pc), (Vm_vap, P_eq)
Vm_data = np.array([Vr_liq * Vc_vdW,
Vr_liq_85 * Vc_vdW,
Vc_vdW,
Vr_vap_85 * Vc_vdW,
Vr_vap * Vc_vdW])
P_data = np.array([Pr_equ * Pc_vdW,
Pr_equ_85 * Pc_vdW,
Pc_vdW,
Pr_equ_85 * Pc_vdW,
Pr_equ * Pc_vdW])
# Provide an initial guess for the parameters A, B, C
initial_guess = [100, 10, 1]
# Fit the curve to the data
params, covariance = curve_fit(fit_function, Vm_data, P_data, p0=initial_guess)
# Extract fitted parameters
A_fit, B_fit, C_fit = params
# print(f"Fitted parameters: A = {A_fit}, B = {B_fit}, C = {C_fit}")
# Generate data for plotting the fitted curve
P_fit = fit_function(Vm_vals_Vc, A_fit, B_fit, C_fit)
# Fitted curve
axs[0].fill_between(Vm_vals_Vc, P_fit, 0, color='magenta', alpha=0.2, zorder=-100)
axs[1].fill_between(Vm_vals_Vc, P_fit, 0, color='magenta', alpha=0.2, zorder=-100)
# Annotate the coexistence curve
line5 = axs[1].plot(Vm_vals_Vc - 0.04, P_fit, 'b-', label='Liquid', alpha=0)
labelLines(line5, xvals=0.04, zorder=2.5)
axs[1].fill_between(Vm_vals_Vc[Vm_vals_Vc <= Vc_vdW],
np.ones_like(Vm_vals_Vc[Vm_vals_Vc <= Vc_vdW]) * Pc_vdW,
P_fit[Vm_vals_Vc <= Vc_vdW],
color='blue',
alpha=0.2)
line6 = axs[1].plot(Vm_vals_Vc + 0.04, P_fit, 'r-', label='Vapor', alpha=0)
labelLines(line6, xvals=0.32, zorder=2.5)
axs[1].fill_between(Vm_vals_Vc[Vm_vals_Vc >= Vc_vdW],
np.ones_like(Vm_vals_Vc[Vm_vals_Vc >= Vc_vdW]) * Pc_vdW,
P_fit[Vm_vals_Vc >= Vc_vdW],
color='red',
alpha=0.2)
line7 = axs[1].plot(Vm_vals_Pc, np.ones_like(Vm_vals_Pc) * y_supercritical, '-', c="gray", alpha=0, label='Supercritical fluid')
labelLines(line7, xvals=Vc_vdW, zorder=2.5)
axs[1].fill_between(Vm_vals_Pc,
np.ones_like(Vm_vals_Pc) * Pc_vdW,
80,
color='gray',
alpha=0.2)
line8 = axs[1].plot(Vm_vals_Pc, np.ones_like(Vm_vals_Pc) * 40, 'm-', alpha=0, label='Liquid-vapor\nmixture')
labelLines(line8, xvals=x_maxwell, zorder=2.5)
axs[0].set_xlim(0, 0.5)
axs[0].set_ylim(30, 80)
axs[0].set_xlabel("Molar Volume (L/mol)")
axs[1].set_xlabel("Molar Volume (L/mol)")
axs[0].set_ylabel("Pressure (bar)")
axs[0].grid(True, linestyle="--", alpha=0.7)
# Adjust layout and display
plt.tight_layout()
plt.show()
plt.close(fig)
Van der Waals isotherm for CO at , with the Maxwell construction illustrating how the unphysical loop is replaced by a horizontal tie line defining liquid–vapor coexistence. The critical point at is also shown, where the liquid and vapor phases merge.
Expanding Equation (5) and rearranging terms gives a cubic equation for :
Complete Derivation of the Cubic Equation in
At the critical point, the cubic in Equation (6) has a triple root at , so it can be written as
Matching coefficients yields
Complete Derivation of the Critical Point
Corresponding States¶
Source
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from labellines import labelLines
from scipy.constants import R
from myst_nb import glue
# Define styles for species
style_for_species = {"Ar": 'o', "O2": '^', "H2O": 's', "CO2": 'p'}
label_for_species = {"Ar": "Ar", "O2": "O$_2$", "H2O": "H$_2$O", "CO2": "CO$_2$"}
line_style_for_species = {"Ar": "-", "O2": "--", "H2O": "-.", "CO2": ":"}
color_for_temperature = {0.9: "blue", 1.0: "blue", 1.1: "red", 1.2: "magenta", 2.0: "red"}
color_for_species = {"Ar": "black", "O2": "blue", "H2O": "red", "CO2": "magenta"}
# Paths to data files
paths = [
f"../_static/section-04/isothermal-properties-for-{species}-Tr={T_r}.csv"
for species in ["argon", "oxygen", "water", "carbon-dioxide"]
for T_r in [1.0, 1.2, 2.0]
]
# Create figure
fig, ax = plt.subplots(figsize=(4, 4))
# Load and plot data
for i, path in enumerate(paths):
df = pd.read_csv(path)
df.rename(columns={"Temperature (K)": "T", "Pressure (bar)": "P_bar", "Volume (m3/mol)": "Vm"}, inplace=True)
df["P"] = df["P_bar"] * 1e5 # Convert bar to Pa
df["Z"] = df["P"] * df["Vm"] / (R * df["T"])
species = df["substance"].values[0]
T_r = df["Tr"].values[0].round(1)
color = color_for_temperature[T_r]
linestyle = line_style_for_species[species]
label = f"$T_r = {T_r}$" if i % 4 == 0 else None
line = ax.plot(df["Pr"], df["Z"], color=color, linestyle=linestyle, alpha=0.5, label=label)
if label:
labelLines(line, align=False, xvals=[2], zorder=2.5)
# Create legend
legend_elements = [Line2D([0], [0], c='k', label=label_for_species[s], ls=line_style_for_species[s], alpha=0.5)
for s in line_style_for_species]
ax.legend(handles=legend_elements, loc='lower right')
# Set labels and grid
ax.set_xlim(0, 8)
ax.set_ylim(0, 1.25)
ax.set_xlabel("Reduced Pressure ($P_r = P / P_c$)")
ax.set_ylabel("$Z$")
ax.grid(True, linestyle="--", alpha=0.7)
plt.tight_layout()
plt.show()
plt.close(fig)
Compressibility factor for argon, oxygen, water, and carbon dioxide plotted over a range of reduced pressures for different reduced temperatures. These data illustrate how real gases exhibit similar trends when expressed in terms of their critical properties, consistent with the principle of corresponding states.
Introduce reduced variables , , and via
and substitute into Equation (5) to obtain
This corresponding-states form shows that all van der Waals fluids obey the same reduced EOS when expressed relative to their critical properties.
Complete Derivation of the Corresponding States Equation
Computational Studio: Real Gas¶
Explore deviations from ideal behavior by dynamically comparing the ideal-gas, van der Waals (vdW), and Peng–Robinson (PR) equations of state. Adjust temperature and pressure to visualize how intermolecular forces impact the compressibility factor () and – isotherms, particularly near the critical point.
You can open the studio in a new tab: Real Gas Computational Studio.
Worked Example¶
van der Waals critical constants and for CO¶
Use the van der Waals parameters used in the section plots: , , and .
The van der Waals critical constants are
Critical volume
Critical pressure
Critical temperature
Critical compressibility factor
Result. The van der Waals model predicts , , , and .
Concept Checks¶
Why can a gas be “coincidentally ideal” (i.e., ) even when interactions are not negligible?
What physical effects are represented by the and corrections in the van der Waals EOS?
At fixed , how does typically change as increases, and why?
Why does the reduced-variable form imply similar behavior across different substances at corresponding reduced conditions?
Key Takeaways¶
Nonideality is quantified by ; suggests net attractions and suggests net repulsions.
The van der Waals EOS introduces an attraction parameter and an excluded-volume parameter .
Critical constants follow directly from the cubic form of the van der Waals EOS, with .
Using reduced variables yields the corresponding-states form shared by all van der Waals fluids.