thermo Documentation

repository·master·Indexed 20 days ago

https://github.com/calebbell/thermo

An open-source library for engineers and scientists to retrieve chemical constants and calculate temperature/pressure dependent chemical properties for pure components and mixtures. Part of the Chemical Engineering Design Library (ChEDL), version 0.6.1, it provides tools for activity coefficient models (NRTL, Wilson, UNIQUAC, UNIFAC), cubic equations of state (EOS) for pure components and mixtures, and management of chemical constants and property correlations.

Tokens
69.2K
Snippets
184
Records
221
Agent score
72%

What's inside thermo

  1. Overview of Activity Coefficient Models

    master

    Thermo provides several models to predict excess Gibbs energy and activity coefficients, which are used to correct Raoult's law for non-ideal phase equilibria (vapor-liquid or liquid-liquid).

    All activity coefficient models inherit from the GibbsExcess base class. The available models include:

    • Regression-based models (require literature or regressed coefficients):
      • NRTL (thermo.nrtl.NRTL)
      • Wilson (thermo.wilson.Wilson)
      • UNIQUAC (thermo.uniquac.UNIQUAC)
    • Predictive models:
      • RegularSolution (thermo.regular_solution.RegularSolution): Based on solubility parameters and liquid molar volumes; does not implement temperature dependence.
      • UNIFAC (thermo.unifac.UNIFAC): A group-contribution scheme that fragments molecules into interacting sections.
    • Ideal model:
      • IdealSolution (thermo.activity.IdealSolution): A dummy class predicting zero excess Gibbs energy and activity coefficients of 1.
  2. Understand Cubic Equations of State (EOS) in thermo

    master

    Cubic equations of state provide thermodynamically-consistent and fast models for gases and liquids. The library provides two primary interfaces:

    1. thermo.eos: Used for pure component modeling. This interface is faster because it avoids the $N^2$ operations required for mixing rules.
    2. thermo.eos_mix: Used for multicomponent (mixture) modeling.

    Important Notes:

    • Units: All calculations in thermo.eos and thermo.eos_mix are performed on a molar basis. All outputs are in base SI units (K, Pa, m³, mole, etc.).
    • Mass-based units: If you need to work with mass-based units, use the Phase interface instead.
    • State Specification: You can specify the state of an EOS object using any two of T (temperature), P (pressure), or V (molar volume).
  3. How GibbsExcess objects interact with phase equilibria

    master

    The GibbsExcess objects are modular and focused strictly on excess Gibbs energy calculations. They do not handle phase equilibria, vapor pressure, or flash routines directly.

    To use them in phase equilibria calculations, they are typically used in one of two ways:

    1. As arguments to Equations of State (EOS): For example, a GibbsExcess object can be passed to a cubic EOS like PSRK (thermo.eos_mix.PSRK).
    2. Wrapped in GibbsExcessLiquid objects: The GibbsExcessLiquid class (thermo.phases.GibbsExcessLiquid) wraps the model to construct a thermodynamically consistent phase that Flash algorithms (thermo.flash.Flash) can process.
  4. How the Simple Interface handles phases and conditions

    master

    The Simple Interface uses a stateful approach for Chemical objects. When you create a Chemical instance, it loads all constant and temperature/pressure dependent coefficients.

    To change the conditions under which properties are reported, you must call the .calculate(T, P) method. Once called, subsequent property accessors (like .rho, .Cp, .k, .mu) will return values calculated for those specific conditions.

    To access properties in a specific hypothetical phase (even if the current state is different), append a phase suffix to the property name:

    • l: liquid phase
    • g: gas phase
    • s: solid phase

    Example: tol.rhog retrieves the gas density of toluene.

  5. How chemical constants and property correlations are configured

    master

    Thermo separates thermodynamic data from algorithms to ensure stability and testability. To configure a flash algorithm, you must manage five distinct configuration areas:

    1. ChemicalConstantsPackage: Immutable object containing constant chemical data (e.g., melting point, boiling point, UNIFAC groups).
    2. PropertyCorrelationsPackage: Contains temperature-dependent data (e.g., Antoine coefficients, Tait pressure-dependent volume parameters) stored in TDependentProperty, TPDependentProperty, or MixtureProperty objects.
    3. Phase-specific parameters: Parameters that depend on a specific phase configuration (e.g., volume translation coefficients), provided when configuring each Phase object.
    4. BulkSettings: Configuration for bulk mixing rules or bulk property calculation methods.
    5. Flash settings: Configuration for the Flash object itself (e.g., adjusting tolerances or algorithms).

    This tutorial focuses on the first two: ChemicalConstantsPackage and PropertyCorrelationsPackage.

  6. Mixture Equilibrium in Cubic EOS

    master
    Determining the equilibrium state for mixtures is more complex than for pure components. It typically requires algorithms like sequential substitution or Gibbs minimization, which often need initial guesses from simpler thermodynamic models. For detailed implementation and usage of equilibrium calculations, refer to the thermo.flash module.
  7. Understand the hierarchy of Thermo Property Objects

    master

    Thermo implements chemical properties using an object-oriented approach to allow easy experimentation with different calculation methods. Properties are categorized into three main types based on their physical dependencies. When selecting a property class, identify which physical variables (Temperature, Pressure, or Composition) your calculation requires.

    Property Categories

    1. Temperature Dependent Properties: Properties that depend primarily on temperature. Some may have weak pressure dependence (e.g., surface tension), while others have none (e.g., vapor pressure).
      • Base Class: thermo.utils.TDependentProperty
    2. Temperature and Pressure Dependent Properties: Properties that depend on both temperature and pressure (e.g., gas volume or thermal conductivity).
      • Base Class: thermo.utils.TPDependentProperty
    3. Mixture Properties: Properties of mixtures that depend on temperature, pressure, and composition (e.g., gas mixture heat capacity).
      • Base Class: thermo.utils.MixtureProperty

    Note: The underlying functional algorithms are provided by the chemicals library, while thermo provides these object-oriented wrappers.

  8. How Phase objects work in Thermo

    master

    A Phase object represents a single thermodynamic state and contains all information needed to compute phase-specific properties.

    Key Principles:

    • Immutability: Phase objects are designed to be immutable.
    • Independence: Calculations are independent of external databases; all required inputs must be provided during initialization.
    • State Management: A phase is initialized with a molar composition zs, temperature T, and pressure P. To move to a new state, use the .to() method (or .to_TP_zs() for faster performance when working strictly in the T-P domain).

    Properties: While T and P are stored as attributes, other thermodynamic properties are methods that must be called. Examples include:

    • V (Volume)
    • H (Enthalpy)
    • S (Entropy)
    • Cp (Heat Capacity)
    • fugacities
    • lnphis (Natural log of fugacity coefficients)
    • dlnphis_dT and dlnphis_dP (Derivatives of fugacity coefficients)
    # Example of creating a new phase from an existing one
    new_phase = phase.to(T=350, P=1e5)
    # Or faster if only T and P change
    new_phase = phase.to_TP_zs(T=350, P=1e5)
  9. Create pressure-dependent property objects

    master

    Pressure-dependent property objects (subclassing TDependentProperty) use a two-part correlation system: a low-pressure component and a high-pressure component.

    Important: Dependency Management Many properties require other property objects to be calculated first. You must create these dependency objects and pass them into the constructor of the dependent object. Common dependencies include:

    • Liquid molar volume: Requires VaporPressure
    • Gas viscosity: Requires VolumeGas
    • Liquid viscosity: Requires VaporPressure
    • Gas thermal conductivity: Requires VolumeGas, HeatCapacityGas, and ViscosityGas

    To avoid searching for external data files (like DIPPR coefficients) during initialization, set load_data=False in the constructor.

    >>> water_psat = VaporPressure(Tb=373.124, Tc=647.14, Pc=22048320.0, omega=0.344, CASRN='7732-18-5')
    >>> water_mu = ViscosityLiquid(CASRN="7732-18-5", MW=18.01528, Tm=273.15, Tc=647.14, Pc=22048320.0, Vc=5.6e-05, omega=0.344, method="DIPPR_PERRY_8E", Psat=water_psat, method_P="LUCAS")
  10. Use pint Quantities with thermo.units

    master

    The thermo.units module provides a wrapper around thermo functions and classes to enable compatibility with the pint unit handling library. This allows you to pass physical quantities with units (e.g., 400.0*u.degC) directly into thermo constructors.

    Key constraints:

    • Numpy Arrays: When using this interface, values that would normally accept Python lists or numpy arrays must be provided as numpy arrays.
    • Unsupported Objects: This wrapper does not support all thermo objects. Specifically, the following types are not supported via the thermo.units interface:
      • TDependentProperty, TPDependentProperty, MixtureProperty
      • Phase objects
      • Flash objects
      • ChemicalConstantsPackage
      • PropertyCorrelationsPackage
    import thermo
    import pint
    
    # Assuming u is a pint UnitRegistry
    u = pint.UnitRegistry()
    
    kwargs = dict(
        T=400.0*u.degC, 
        P=30*u.psi, 
        Tcs=[126.1, 190.6]*u.K, 
        Pcs=[33.94E5, 46.04E5]*u.Pa, 
        omegas=[0.04, 0.011]*u.dimensionless, 
        zs=[0.5, 0.5]*u.dimensionless, 
        kijs=[[0.0, 0.0289], [0.0289, 0.0]]*u.dimensionless
    )
    
    # Initialize a class like PRMIX using unit-aware kwargs
    mix = thermo.units.PRMIX(**kwargs)
  11. Perform flash calculations for pure compounds

    master

    For pure components, use the FlashPureVLS interface. This is highly optimized and reliable because pure component flashes have no composition dependence.

    Workflow:

    1. Define a HeatCapacityGas object.
    2. Create a ChemicalConstantsPackage with critical properties (Tcs, Pcs, omegas, MWs, CASs).
    3. Create a PropertyCorrelationsPackage (set skip_missing=True to avoid database lookups).
    4. Initialize liquid and gas phase objects (e.g., using CEOSLiquid and CEOSGas with a specific EOS like PRMIX).
    5. Initialize FlashPureVLS with the constants, correlations, and phase objects.
    6. Call .flash() with the desired intensive variables.

    Supported Flash Combinations: You can combine T, P, V with H (Enthalpy), S (Entropy), or U (Internal Energy). Note: Flashes using two of {H, S, U} are not currently implemented.

    Supported Variables:

    • T (Temperature)
    • P (Pressure)
    • V (Volume)
    • VF (Vapor Fraction)
    • H (Enthalpy)
    • S (Entropy)
    • U (Internal Energy)
    from thermo import ( 
        ChemicalConstantsPackage, PropertyCorrelationsPackage, 
        PRMIX, CEOSLiquid, CEOSGas, FlashPureVLS, HeatCapacityGas 
    )
    
    # 1. Heat Capacity
    CpObj = HeatCapacityGas(CASRN='67-56-1')
    HeatCapacityGases = [CpObj]
    
    # 2. Constants
    constants = ChemicalConstantsPackage(Tcs=[512.5], Pcs=[8084000.0], omegas=[0.559], MWs=[32.04186], CASs=['67-56-1'])
    
    # 3. Correlations
    correlations = PropertyCorrelationsPackage(constants, HeatCapacityGases=HeatCapacityGases, skip_missing=True)
    
    # 4. Phase Objects
    eos_kwargs = dict(Tcs=constants.Tcs, Pcs=constants.Pcs, omegas=constants.omegas)
    liquid = CEOSLiquid(PRMIX, HeatCapacityGases=HeatCapacityGases, eos_kwargs=eos_kwargs)
    gas = CEOSGas(PRMIX, HeatCapacityGases=HeatCapacityGases, eos_kwargs=eos_kwargs)
    
    # 5. Flasher
    flasher = FlashPureVLS(constants, correlations, gas=gas, liquids=[liquid], solids=[])
    
    # 6. Execute Flash (e.g., T-P flash)
    res = flasher.flash(T=300, P=1e5)
    print(res.phase, res.liquid0)