Chris Parmer — home

Van der Waals equation P-V-T surface for CO₂

Physical Chemistry

Example from the compendium of canonical charts

Physical Chemistry — Van der Waals equation P-V-T surface for CO₂

Python Code

"""Physical Chemistry — Van der Waals equation P-V-T surface for CO₂."""


import numpy as np
import plotly.graph_objects as go


# Van der Waals constants for CO₂
# P = RT/(V-b) - a/V²
A_CO2 = 3.658   # L²·atm/mol²
B_CO2 = 0.04286  # L/mol
R_GAS = 0.08206  # L·atm/(mol·K)

# Critical point: Tc = 8a/(27Rb), Vc = 3b, Pc = a/(27b²)
T_c = 8 * A_CO2 / (27 * R_GAS * B_CO2)  # ≈ 304 K
V_c = 3 * B_CO2                            # ≈ 0.129 L/mol
P_c = A_CO2 / (27 * B_CO2**2)             # ≈ 72.8 atm


def generate():
    print(f"computing CO₂ Van der Waals P-V-T surface (Tc={T_c:.1f}K, Vc={V_c:.3f}L, Pc={P_c:.1f}atm) …")

    # Grid: V from just above b to 3 L/mol, T from 250 K to 420 K
    V = np.linspace(B_CO2 + 0.01, 3.0, 80)
    T = np.linspace(250, 420, 60)
    VV, TT = np.meshgrid(V, T)

    PP = R_GAS * TT / (VV - B_CO2) - A_CO2 / VV**2

    # Clip to physical pressure range and mask unphysical region
    PP = np.clip(PP, -5, 120)

    # Isothermal colorscale — color by temperature
    colorscale = [
        [0.0, "#52B3D0"],    # low T: teal
        [0.35, "#845EEE"],   # mid-low: violet
        [0.65, "#E9A23B"],   # mid-high: orange
        [1.0,  "#DA5597"],   # high T: pink
    ]

    fig = go.Figure(data=go.Surface(
        x=V,
        y=T,
        z=PP,
        surfacecolor=TT,
        colorscale=colorscale,
        colorbar=dict(title="T (K)", len=0.6),
        hovertemplate="V=%{x:.3f} L/mol<br>T=%{y:.0f} K<br>P=%{z:.1f} atm<extra></extra>",
        cmin=250,
        cmax=420,
    ))

    # Critical point marker
    fig.add_trace(go.Scatter3d(
        x=[V_c], y=[T_c], z=[P_c],
        mode="markers",
        marker=dict(color="white", size=6, symbol="circle",
                    line=dict(color="#333", width=1)),
        name=f"Critical point ({T_c:.0f} K, {P_c:.1f} atm)",
        hovertemplate=f"Critical point<br>Tc={T_c:.0f} K, Vc={V_c:.3f} L/mol, Pc={P_c:.1f} atm<extra></extra>",
    ))

    fig.update_layout(
        scene=dict(
            xaxis_title="Molar Volume (L/mol)",
            yaxis_title="Temperature (K)",
            zaxis_title="Pressure (atm)",
            camera=dict(eye=dict(x=1.8, y=-1.8, z=0.8)),
        ),
        legend=dict(x=0.0, y=1.0),
        margin=dict(t=20, b=20, l=20, r=20),
        height=620,
    )
    return fig


if __name__ == "__main__":
    generate()

Made with Plotly