.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/thermodynamics/properties/plot_05_antoine_equation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_thermodynamics_properties_plot_05_antoine_equation.py: Antoine's vapour-pressure equation (1888) ========================================= The integrated Clausius-Clapeyron relation makes :math:`\log p` linear in :math:`1/T`. Measured vapour pressures bend away from that line because the latent heat falls as the temperature rises. In 1888 Charles Antoine, a French naval engineer, added a third constant to the temperature, :math:`\log_{10} p = A - B/(C + T)` (:func:`~engineeringkit.thermodynamics.antoine_vapor_pressure`). It fits most liquids to within a fraction of a percent over a range of 100 K, and tables of Antoine constants are still standard in chemical engineering. The example fits both forms to IAPWS-IF97 water and compares them. .. GENERATED FROM PYTHON SOURCE LINES 17-22 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from engineeringkit.thermodynamics import antoine_vapor_pressure, clausius_clapeyron_pressure, saturation_pressure .. GENERATED FROM PYTHON SOURCE LINES 23-30 Fitting the constants --------------------- Multiplying through by :math:`C + T` gives :math:`T\log_{10}p = (AC - B) + AT - C\log_{10}p`, which is linear in :math:`AC - B`, :math:`A` and :math:`C`, so least squares fits all three at once. The two-constant Clausius-Clapeyron fit is a line in :math:`1/T`. .. GENERATED FROM PYTHON SOURCE LINES 30-49 .. code-block:: Python T = np.linspace(274.15, 373.15, 100) log_p = np.log10(saturation_pressure(T)) design = np.column_stack([np.ones_like(T), T, -log_p]) (k0, A, C), *_ = np.linalg.lstsq(design, T * log_p, rcond=None) B = A * C - k0 print(f"Antoine fit for p in Pa and T in K: A = {A:.4f}, B = {B:.2f} K, C = {C:.2f} K") slope, intercept = np.polyfit(1 / T, np.log(saturation_pressure(T)), 1) h_over_R = -slope T_ref = 323.15 p_ref = np.exp(intercept + slope / T_ref) p_antoine = antoine_vapor_pressure(T, A, B, C) p_cc = clausius_clapeyron_pressure(T, T_ref, p_ref, h_over_R * 461.526, 461.526) err_antoine = np.max(np.abs(p_antoine / saturation_pressure(T) - 1)) err_cc = np.max(np.abs(p_cc / saturation_pressure(T) - 1)) print(f"largest error from 1 to 100 °C: Antoine {err_antoine:.3%}, Clausius-Clapeyron {err_cc:.2%}") assert err_antoine < 0.003 < 0.03 < err_cc .. rst-class:: sphx-glr-script-out .. code-block:: none Antoine fit for p in Pa and T in K: A = 10.1989, B = 1732.62 K, C = -39.45 K largest error from 1 to 100 °C: Antoine 0.237%, Clausius-Clapeyron 3.95% .. GENERATED FROM PYTHON SOURCE LINES 50-56 Tabulated constants ------------------- The classic constants for water, 8.07131, 1730.63 and 233.426, are for mmHg and °C. Adding :math:`\log_{10}133.322` to :math:`A` and subtracting 273.15 from :math:`C` converts them to Pa and K. .. GENERATED FROM PYTHON SOURCE LINES 56-76 .. code-block:: Python A_tab, B_tab, C_tab = 8.07131 + np.log10(133.322), 1730.63, 233.426 - 273.15 p_tab = antoine_vapor_pressure(T, A_tab, B_tab, C_tab) p_boil = antoine_vapor_pressure(373.15, A_tab, B_tab, C_tab) print(f"tabulated constants at 100 °C: {p_boil:.0f} Pa (IF97 {float(saturation_pressure(373.15)):.0f} Pa)") assert np.max(np.abs(p_tab / saturation_pressure(T) - 1)) < 0.01 fig, axes = plt.subplots(1, 2, figsize=(10, 3.8)) axes[0].plot(T - 273.15, saturation_pressure(T) / 1e3, "k", label="IAPWS-IF97") axes[0].plot(T[::8] - 273.15, p_antoine[::8] / 1e3, "o", label="Antoine fit") axes[0].set(xlabel="temperature [°C]", ylabel="vapour pressure [kPa]", title="Water") axes[0].legend() for p_fit, label in ((p_cc, "Clausius-Clapeyron (2 constants)"), (p_antoine, "Antoine (3 constants)"), (p_tab, "Antoine, tabulated")): axes[1].plot(T - 273.15, (p_fit / saturation_pressure(T) - 1) * 100, label=label) axes[1].axhline(0, color="gray", lw=0.8) axes[1].set(xlabel="temperature [°C]", ylabel="error against IF97 [%]") axes[1].legend(fontsize=8) fig.tight_layout() plt.show() .. image-sg:: /api/gallery/thermodynamics/properties/images/sphx_glr_plot_05_antoine_equation_001.png :alt: Water :srcset: /api/gallery/thermodynamics/properties/images/sphx_glr_plot_05_antoine_equation_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none tabulated constants at 100 °C: 101336 Pa (IF97 101418 Pa) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.051 seconds) .. _sphx_glr_download_api_gallery_thermodynamics_properties_plot_05_antoine_equation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/thermodynamics/properties/plot_05_antoine_equation.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_05_antoine_equation.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_05_antoine_equation.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_05_antoine_equation.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_