Example #1
0
 def list_methods():
     ''' List methods available for calculating a chemical's acentric
     factor, omega '''
     methods = []
     if (CASRN in _crit_PSRKR4.index
             and not np.isnan(_crit_PSRKR4.at[CASRN, 'omega'])):
         methods.append('PSRK')
     if (CASRN in _crit_PassutDanner.index
             and not np.isnan(_crit_PassutDanner.at[CASRN, 'omega'])):
         methods.append('PD')
     if (CASRN in _crit_Yaws.index
             and not np.isnan(_crit_Yaws.at[CASRN, 'omega'])):
         methods.append('YAWS')
     Tcrit, Pcrit = Tc(CASRN), Pc(CASRN)
     if Tcrit and Pcrit:
         if Tb(CASRN):
             methods.append('LK')
         if VaporPressure(CASRN=CASRN).T_dependent_property(Tcrit * 0.7):
             # TODO: better integration
             methods.append('DEFINITION')
     if IgnoreMethods:
         for Method in IgnoreMethods:
             if Method in methods:
                 methods.remove(Method)
     methods.append('NONE')
     return methods
Example #2
0
 def list_methods():
     methods = []
     if CASRN in Staveley_data.index and not np.isnan(
             Staveley_data.at[CASRN, 'Pt']):
         methods.append(STAVELEY)
     if Tt(CASRN) and VaporPressure(CASRN=CASRN).T_dependent_property(
             T=Tt(CASRN)):
         methods.append(DEFINITION)
     methods.append(NONE)
     return methods
Example #3
0
    def set_T_sources(self):
        # Tempearture and Pressure Denepdence
        # Get and choose initial methods
        self.VaporPressure = VaporPressure(Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, CASRN=self.CAS)
        self.Psat_298 = self.VaporPressure.T_dependent_property(298.15)


        self.VolumeLiquid = VolumeLiquid(MW=self.MW, Tb=self.Tb, Tc=self.Tc,
                          Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega,
                          dipole=self.dipole, Psat=self.VaporPressure.T_dependent_property, CASRN=self.CAS)

        self.Vml_Tb = self.VolumeLiquid.T_dependent_property(self.Tb) if self.Tb else None
        self.Vml_Tm = self.VolumeLiquid.T_dependent_property(self.Tm) if self.Tm else None
        self.Vml_STP = self.VolumeLiquid.T_dependent_property(298.15)

        # set molecular_diameter; depends on Vml_Tb, Vml_Tm
        self.molecular_diameter_sources = molecular_diameter(Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, Vm=self.Vml_Tm, Vb=self.Vml_Tb, AvailableMethods=True, CASRN=self.CAS)
        self.molecular_diameter_source = self.molecular_diameter_sources[0]
        self.molecular_diameter = molecular_diameter(Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, Vm=self.Vml_Tm, Vb=self.Vml_Tb, Method=self.molecular_diameter_source, CASRN=self.CAS)

        self.VolumeGas = VolumeGas(MW=self.MW, Tc=self.Tc, Pc=self.Pc, omega=self.omega, dipole=self.dipole, CASRN=self.CAS)

        self.VolumeSolid = VolumeSolid(CASRN=self.CAS, MW=self.MW, Tt=self.Tt)

        self.HeatCapacityGas = HeatCapacityGas(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable)

        self.HeatCapacitySolid = HeatCapacitySolid(MW=self.MW, similarity_variable=self.similarity_variable, CASRN=self.CAS)

        self.HeatCapacityLiquid = HeatCapacityLiquid(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable, Tc=self.Tc, omega=self.omega, Cpgm=self.HeatCapacityGas.T_dependent_property)

        self.EnthalpyVaporization = EnthalpyVaporization(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, similarity_variable=self.similarity_variable)
        self.HvapTbm = self.EnthalpyVaporization.T_dependent_property(self.Tb) if self.Tb else None
        self.HvapTb = property_molar_to_mass(self.HvapTbm, self.MW)

        self.Hsub_methods = Hsub(T=self.T, P=self.P, MW=self.MW, AvailableMethods=True, CASRN=self.CAS)
        self.Hsub_method = self.Hsub_methods[0]

        self.ViscosityLiquid = ViscosityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, omega=self.omega, Psat=self.VaporPressure.T_dependent_property, Vml=self.VolumeLiquid.T_dependent_property)
        
        vmg_calc = lambda T : self.VolumeGas.TP_dependent_property(T, 101325)
        self.ViscosityGas = ViscosityGas(CASRN=self.CAS, MW=self.MW, Tc=self.Tc, Pc=self.Pc, Zc=self.Zc, dipole=self.dipole, Vmg=vmg_calc)

        self.ThermalConductivityLiquid = ThermalConductivityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, Hfus=self.Hfusm)

        cvgm_calc = lambda T : self.HeatCapacityGas.T_dependent_property(T) - R
        self.ThermalConductivityGas = ThermalConductivityGas(CASRN=self.CAS, MW=self.MW, Tb=self.Tb, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, dipole=self.dipole, Vmg=vmg_calc, Cvgm=cvgm_calc, mug=self.ViscosityGas.T_dependent_property)

        self.SurfaceTension = SurfaceTension(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, StielPolar=self.StielPolar)

        self.Permittivity = Permittivity(CASRN=self.CAS)

        self.solubility_parameter_methods = solubility_parameter(T=self.T, Hvapm=self.HvapTbm, Vml=self.Vml_STP, AvailableMethods=True, CASRN=self.CAS)
        self.solubility_parameter_method = self.solubility_parameter_methods[0]
Example #4
0
    def set_T_sources(self):
        # Tempearture and Pressure Denepdence
        # Get and choose initial methods
        self.VaporPressure = VaporPressure(Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, CASRN=self.CAS)
        self.Psat_298 = self.VaporPressure.T_dependent_property(298.15)

        self.VolumeLiquid = VolumeLiquid(MW=self.MW, Tb=self.Tb, Tc=self.Tc,
                          Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega,
                          dipole=self.dipole, Psat=self.Psat, CASRN=self.CAS)
        if self.Tb:
            self.Vml_Tb = self.VolumeLiquid.T_dependent_property(self.Tb)
        else:
            self.Vml_Tb = None
        if self.Tm:
            self.Vml_Tm = self.VolumeLiquid.T_dependent_property(self.Tm)
        else:
            self.Vml_Tm = None
        self.Vml_STP = self.VolumeLiquid.T_dependent_property(298.15)

        self.VolumeGas = VolumeGas(MW=self.MW, Tc=self.Tc, Pc=self.Pc, omega=self.omega, dipole=self.dipole, CASRN=self.CAS)

        self.VolumeSolid = VolumeSolid(CASRN=self.CAS, MW=self.MW, Tt=self.Tt)

        self.HeatCapacitySolid = HeatCapacitySolid(MW=self.MW, similarity_variable=self.similarity_variable, CASRN=self.CAS)

        self.HeatCapacityLiquid = HeatCapacityLiquid(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable, Tc=self.Tc, omega=self.omega, Cpgm=self.Cpgm)

        self.HeatCapacityGas = HeatCapacityGas(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable)

        self.ViscosityLiquid = ViscosityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, omega=self.omega, Psat=self.Psat, Vml=self.Vml)

        self.ViscosityGas = ViscosityGas(CASRN=self.CAS, MW=self.MW, Tc=self.Tc, Pc=self.Pc, Zc=self.Zc, dipole=self.dipole, Vmg=self.Vmg)

        self.EnthalpyVaporization = EnthalpyVaporization(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, similarity_variable=self.similarity_variable)
        self.HvapTbm = self.EnthalpyVaporization.T_dependent_property(self.Tb)
        self.HvapTb = property_molar_to_mass(self.HvapTbm, self.MW)

        self.Hfus_methods = Hfus(T=self.T, P=self.P, MW=self.MW, AvailableMethods=True, CASRN=self.CAS)
        self.Hfus_method = self.Hfus_methods[0]

        self.Hsub_methods = Hsub(T=self.T, P=self.P, MW=self.MW, AvailableMethods=True, CASRN=self.CAS)
        self.Hsub_method = self.Hsub_methods[0]

        self.ThermalConductivityLiquid = ThermalConductivityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, Hfus=self.Hfusm)

        self.ThermalConductivityGas = ThermalConductivityGas(CASRN=self.CAS, MW=self.MW, Tb=self.Tb, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, dipole=self.dipole, Vmg=self.Vmg, Cvgm=self.Cvgm, mug=self.mug)

        self.SurfaceTension = SurfaceTension(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, StielPolar=self.StielPolar)

        self.Permittivity = Permittivity(CASRN=self.CAS)

        self.solubility_parameter_methods = solubility_parameter(T=self.T, Hvapm=self.Hvapm, Vml=self.Vml, AvailableMethods=True, CASRN=self.CAS)
        self.solubility_parameter_method = self.solubility_parameter_methods[0]
Example #5
0
 def list_methods():
     methods = []
     if CASRN in _crit_PSRKR4.index and not np.isnan(_crit_PSRKR4.at[CASRN, 'omega']):
         methods.append('PSRK')
     if CASRN in _crit_PassutDanner.index and not np.isnan(_crit_PassutDanner.at[CASRN, 'omega']):
         methods.append('PD')
     if CASRN in _crit_Yaws.index and not np.isnan(_crit_Yaws.at[CASRN, 'omega']):
         methods.append('YAWS')
     Tcrit, Pcrit = Tc(CASRN), Pc(CASRN)
     if Tcrit and Pcrit:
         if Tb(CASRN):
             methods.append('LK')
         if VaporPressure(CASRN=CASRN).T_dependent_property(Tcrit*0.7):
             methods.append('DEFINITION')  # TODO: better integration
     if IgnoreMethods:
         for Method in IgnoreMethods:
             if Method in methods:
                 methods.remove(Method)
     methods.append('NONE')
     return methods
Example #6
0
 def list_methods():
     methods = []
     if CASRN in CRC_inorganic_data.index and not np.isnan(CRC_inorganic_data.at[CASRN, 'Tb']):
         methods.append(CRC_INORG)
     if CASRN in CRC_organic_data.index and not np.isnan(CRC_organic_data.at[CASRN, 'Tb']):
         methods.append(CRC_ORG)
     if CASRN in Yaws_data.index:
         methods.append(YAWS)
     if PSAT_DEFINITION not in IgnoreMethods:
         try:
             # For some chemicals, vapor pressure range will exclude Tb
             VaporPressure(CASRN=CASRN).solve_prop(101325.)
             methods.append(PSAT_DEFINITION)
         except:  # pragma: no cover
             pass
     if IgnoreMethods:
         for Method in IgnoreMethods:
             if Method in methods:
                 methods.remove(Method)
     methods.append(NONE)
     return methods
Example #7
0
def omega(CASRN,
          AvailableMethods=False,
          Method=None,
          IgnoreMethods=['LK', 'DEFINITION']):
    r'''This function handles the retrieval of a chemical's acentric factor,
    `omega`, or its calculation from correlations or directly through the
    definition of acentric factor if possible. Requires a known boiling point,
    critical temperature and pressure for use of the correlations. Requires
    accurate vapor pressure data for direct calculation.

    Will automatically select a method to use if no Method is provided;
    returns None if the data is not available and cannot be calculated.

    .. math::
        \omega \equiv -\log_{10}\left[\lim_{T/T_c=0.7}(P^{sat}/P_c)\right]-1.0

    Examples
    --------
    >>> omega(CASRN='64-17-5')
    0.635

    Parameters
    ----------
    CASRN : string
        CASRN [-]

    Returns
    -------
    omega : float
        Acentric factor of compound
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain omega with the given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The method name to use. Accepted methods are 'PSRK', 'PD', 'YAWS',
        'LK', and 'DEFINITION'. All valid values are also held in the list
        omega_methods.
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        omega for the desired chemical, and will return methods instead of
        omega
    IgnoreMethods : list, optional
        A list of methods to ignore in obtaining the full list of methods,
        useful for for performance reasons and ignoring inaccurate methods

    Notes
    -----
    A total of five sources are available for this function. They are:

        * 'PSRK', a compillation of experimental and estimated data published
          in the Appendix of [15]_, the fourth revision of the PSRK model.
        * 'PD', an older compillation of
          data published in (Passut & Danner, 1973) [16]_.
        * 'YAWS', a large compillation of data from a
          variety of sources; no data points are sourced in the work of [17]_.
        * 'LK', a estimation method for hydrocarbons.
        * 'DEFINITION', based on the definition of omega as
          presented in [1]_, using vapor pressure data.

    References
    ----------
    .. [1] Pitzer, K. S., D. Z. Lippmann, R. F. Curl, C. M. Huggins, and
       D. E. Petersen: The Volumetric and Thermodynamic Properties of Fluids.
       II. Compressibility Factor, Vapor Pressure and Entropy of Vaporization.
       J. Am. Chem. Soc., 77: 3433 (1955).
    .. [2] Horstmann, Sven, Anna Jabłoniec, Jörg Krafczyk, Kai Fischer, and
       Jürgen Gmehling. "PSRK Group Contribution Equation of State:
       Comprehensive Revision and Extension IV, Including Critical Constants
       and Α-Function Parameters for 1000 Components." Fluid Phase Equilibria
       227, no. 2 (January 25, 2005): 157-64. doi:10.1016/j.fluid.2004.11.002.
    .. [3] Passut, Charles A., and Ronald P. Danner. "Acentric Factor. A
       Valuable Correlating Parameter for the Properties of Hydrocarbons."
       Industrial & Engineering Chemistry Process Design and Development 12,
       no. 3 (July 1, 1973): 365-68. doi:10.1021/i260047a026.
    .. [4] Yaws, Carl L. Thermophysical Properties of Chemicals and
       Hydrocarbons, Second Edition. Amsterdam Boston: Gulf Professional
       Publishing, 2014.
    '''
    def list_methods():
        ''' List methods available for calculating a chemical's acentric
        factor, omega '''
        methods = []
        if (CASRN in _crit_PSRKR4.index
                and not np.isnan(_crit_PSRKR4.at[CASRN, 'omega'])):
            methods.append('PSRK')
        if (CASRN in _crit_PassutDanner.index
                and not np.isnan(_crit_PassutDanner.at[CASRN, 'omega'])):
            methods.append('PD')
        if (CASRN in _crit_Yaws.index
                and not np.isnan(_crit_Yaws.at[CASRN, 'omega'])):
            methods.append('YAWS')
        Tcrit, Pcrit = Tc(CASRN), Pc(CASRN)
        if Tcrit and Pcrit:
            if Tb(CASRN):
                methods.append('LK')
            if VaporPressure(CASRN=CASRN).T_dependent_property(Tcrit * 0.7):
                # TODO: better integration
                methods.append('DEFINITION')
        if IgnoreMethods:
            for Method in IgnoreMethods:
                if Method in methods:
                    methods.remove(Method)
        methods.append('NONE')
        return methods

    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    # This is the calculate, given the method section
    if Method == 'PSRK':
        _omega = float(_crit_PSRKR4.at[CASRN, 'omega'])
    elif Method == 'PD':
        _omega = float(_crit_PassutDanner.at[CASRN, 'omega'])
    elif Method == 'YAWS':
        _omega = float(_crit_Yaws.at[CASRN, 'omega'])
    elif Method == 'LK':
        _omega = LK_omega(Tb(CASRN), Tc(CASRN), Pc(CASRN))
    elif Method == 'DEFINITION':
        P = VaporPressure(CASRN=CASRN).T_dependent_property(Tc(CASRN) * 0.7)
        _omega = -log10(P / Pc(CASRN)) - 1.0
    elif Method == 'NONE':
        _omega = None
    else:
        raise Exception('Failure in in function')
    return _omega
Example #8
0
def StielPolar(Tc=None,
               Pc=None,
               omega=None,
               CASRN='',
               Method=None,
               AvailableMethods=False):
    r'''This function handles the calculation of a chemical's Stiel Polar
    factor, directly through the definition of Stiel-polar factor if possible.
    Requires Tc, Pc, acentric factor, and a vapor pressure datum at Tr=0.6.

    Will automatically select a method to use if no Method is provided;
    returns None if the data is not available and cannot be calculated.

    .. math::
        x = \log P_r|_{T_r=0.6} + 1.70 \omega + 1.552

    Parameters
    ----------
    Tc : float
        Critical temperature of fluid [K]
    Pc : float
        Critical pressure of fluid [Pa]
    omega : float
        Acentric factor of the fluid [-]
    CASRN : string
        CASRN [-]

    Returns
    -------
    factor : float
        Stiel polar factor of compound
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain Stiel polar factor with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The method name to use. Only 'DEFINITION' is accepted so far.
        All valid values are also held in the list Stiel_polar_methods.
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        Stiel-polar factor for the desired chemical, and will return methods
        instead of stiel-polar factor

    Notes
    -----
    Only one source is available for this function. It is:

        * 'DEFINITION', based on the definition of
          Stiel Polar Factor presented in [1]_, using vapor pressure data.

    A few points have also been published in [2]_, which may be used for
    comparison. Currently this is only used for a surface tension correlation.

    Examples
    --------
    >>> StielPolar(647.3, 22048321.0, 0.344, CASRN='7732-18-5')
    0.024581140348734376

    References
    ----------
    .. [1] Halm, Roland L., and Leonard I. Stiel. "A Fourth Parameter for the
       Vapor Pressure and Entropy of Vaporization of Polar Fluids." AIChE
       Journal 13, no. 2 (1967): 351-355. doi:10.1002/aic.690130228.
    .. [2] D, Kukoljac Miloš, and Grozdanić Dušan K. "New Values of the
       Polarity Factor." Journal of the Serbian Chemical Society 65, no. 12
       (January 1, 2000).
       http://www.shd.org.rs/JSCS/Vol65/No12-Pdf/JSCS12-07.pdf
    '''
    def list_methods():
        ''' List methods available for Stiel's polar factor '''
        methods = []
        if Tc and Pc and omega:
            methods.append('DEFINITION')
        methods.append('NONE')
        return methods

    if AvailableMethods:
        return list_methods()

    if not Method:
        Method = list_methods()[0]

    if Method == 'DEFINITION':
        P = VaporPressure(CASRN=CASRN).T_dependent_property(Tc * 0.6)
        if not P:
            factor = None
        else:
            Pr = P / Pc
            factor = log10(Pr) + 1.70 * omega + 1.552
    elif Method == 'NONE':
        factor = None
    else:
        raise Exception('Failure in in function')
    return factor
Example #9
0
def Tb(CASRN='', AvailableMethods=False, Method=None, IgnoreMethods=[PSAT_DEFINITION]):
    r'''This function handles the retrieval of a chemical's boiling
    point. Lookup is based on CASRNs. Will automatically select a data
    source to use if no Method is provided; returns None if the data is not
    available.

    Prefered sources are 'CRC Physical Constants, organic' for organic
    chemicals, and 'CRC Physical Constants, inorganic' for inorganic
    chemicals. Function has data for approximately 13000 chemicals.

    Parameters
    ----------
    CASRN : string
        CASRN [-]

    Returns
    -------
    Tb : float
        Boiling temperature, [K]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain Tb with the given inputs

    Other Parameters
    ----------------
    Method : string, optional
        A string for the method name to use, as defined by constants in
        Tb_methods
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        Tb for the desired chemical, and will return methods instead of Tb
    IgnoreMethods : list, optional
        A list of methods to ignore in obtaining the full list of methods,
        useful for for performance reasons and ignoring inaccurate methods

    Notes
    -----
    A total of four methods are available for this function. They are:

        * 'CRC_ORG', a compillation of data on organics
          as published in [1]_.
        * 'CRC_INORG', a compillation of data on
          inorganic as published in [1]_.
        * 'YAWS', a large compillation of data from a
          variety of sources; no data points are sourced in the work of [2]_.
        * 'PSAT_DEFINITION', calculation of boiling point from a
          vapor pressure calculation. This is normally off by a fraction of a
          degree even in the best cases. Listed in IgnoreMethods by default
          for performance reasons.

    Examples
    --------
    >>> Tb('7732-18-5')
    373.124

    References
    ----------
    .. [1] Haynes, W.M., Thomas J. Bruno, and David R. Lide. CRC Handbook of
       Chemistry and Physics, 95E. Boca Raton, FL: CRC press, 2014.
    .. [2] Yaws, Carl L. Thermophysical Properties of Chemicals and
       Hydrocarbons, Second Edition. Amsterdam Boston: Gulf Professional
       Publishing, 2014.
    '''
    def list_methods():
        methods = []
        if CASRN in CRC_inorganic_data.index and not np.isnan(CRC_inorganic_data.at[CASRN, 'Tb']):
            methods.append(CRC_INORG)
        if CASRN in CRC_organic_data.index and not np.isnan(CRC_organic_data.at[CASRN, 'Tb']):
            methods.append(CRC_ORG)
        if CASRN in Yaws_data.index:
            methods.append(YAWS)
        if PSAT_DEFINITION not in IgnoreMethods:
            try:
                # For some chemicals, vapor pressure range will exclude Tb
                VaporPressure(CASRN=CASRN).solve_prop(101325.)
                methods.append(PSAT_DEFINITION)
            except:  # pragma: no cover
                pass
        if IgnoreMethods:
            for Method in IgnoreMethods:
                if Method in methods:
                    methods.remove(Method)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == CRC_INORG:
        _Tb = float(CRC_inorganic_data.at[CASRN, 'Tb'])
    elif Method == CRC_ORG:
        _Tb = float(CRC_organic_data.at[CASRN, 'Tb'])
    elif Method == YAWS:
        _Tb = float(Yaws_data.at[CASRN, 'Tb'])
    elif Method == PSAT_DEFINITION:
        _Tb = VaporPressure(CASRN=CASRN).solve_prop(101325.)
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')
    return _Tb
Example #10
0
class Chemical(object): # pragma: no cover
    '''Class for obtaining properties of chemicals.
    Considered somewhat stable, but changes to some mthods are expected.


    Default initialization is for 298.15 K, 1 atm.
    Goal is for, when a method fails, a warning is printed.
    '''

    def __init__(self, ID, T=298.15, P=101325):
        self.ID = ID
        self.P = P
        self.T = T

        # Identification
        self.CAS = CASfromAny(ID)
        self.PubChem = PubChem(self.CAS)
        self.MW = MW(self.CAS)
        self.formula = formula(self.CAS)
        self.smiles = smiles(self.CAS)
        self.InChI = InChI(self.CAS)
        self.InChI_Key = InChI_Key(self.CAS)
        self.IUPAC_name = IUPAC_name(self.CAS).lower()
        self.name = name(self.CAS).lower()
        self.synonyms = [i.lower() for i in synonyms(self.CAS)]

        self.set_structure()

        self.set_constant_sources()
        self.set_constants()
        self.set_T_sources()
        self.set_T(self.T)
        self.set_phase()


    def set_structure(self):
        try:
            self.rdkitmol = Chem.MolFromSmiles(self.smiles)
            self.rdkitmol_Hs = Chem.AddHs(self.rdkitmol)
            self.atoms = dict(Counter(atom.GetSymbol() for atom in self.rdkitmol_Hs.GetAtoms()))
            self.charge = Chem.GetFormalCharge(self.rdkitmol)
            self.rings = Chem.Descriptors.RingCount(self.rdkitmol)
            self.atom_fractions = atom_fractions(self.atoms)
            self.mass_fractions = mass_fractions(self.atoms, self.MW)
            self.similarity_variable = similarity_variable(self.atoms, self.MW)
            self.Hill = atoms_to_Hill(self.atoms)
        except:
            self.rdkitmol = None
            self.rdkitmol_Hs = None
            self.charge = None
            self.rings = None
            self.atoms = simple_formula_parser(self.formula)
            self.atom_fractions = atom_fractions(self.atoms)
            self.mass_fractions = mass_fractions(self.atoms, self.MW)
            self.similarity_variable = similarity_variable(self.atoms, self.MW)
            self.Hill = atoms_to_Hill(self.atoms)

    def draw_2d(self):
        try:
            return Draw.MolToImage(self.rdkitmol)
        except:
            return 'Rdkit required'

    def draw_3d(self):
        try:
            import py3Dmol
            AllChem.EmbedMultipleConfs(self.rdkitmol_Hs)
            mb = Chem.MolToMolBlock(self.rdkitmol_Hs)
            p = py3Dmol.view(width=300,height=300)
            p.addModel(mb,'sdf')
            p.setStyle({'stick':{}})
            # Styles: stick, line, cross, sphere
            p.zoomTo()
            p.show()
            return p
        except:
            return 'py3Dmol and rdkit required'

    def set_constant_sources(self):
        self.Tm_sources = Tm(CASRN=self.CAS, AvailableMethods=True)
        self.Tm_source = self.Tm_sources[0]
        self.Tb_sources = Tb(CASRN=self.CAS, AvailableMethods=True)
        self.Tb_source = self.Tb_sources[0]

        # Critical Point
        self.Tc_methods = Tc(self.CAS, AvailableMethods=True)
        self.Tc_method = self.Tc_methods[0]
        self.Pc_methods = Pc(self.CAS, AvailableMethods=True)
        self.Pc_method = self.Pc_methods[0]
        self.Vc_methods = Vc(self.CAS, AvailableMethods=True)
        self.Vc_method = self.Vc_methods[0]
        self.omega_methods = omega(CASRN=self.CAS, AvailableMethods=True)
        self.omega_method = self.omega_methods[0]

        # Triple point
        self.Tt_sources = Tt(self.CAS, AvailableMethods=True)
        self.Tt_source = self.Tt_sources[0]
        self.Pt_sources = Pt(self.CAS, AvailableMethods=True)
        self.Pt_source = self.Pt_sources[0]
        
        # Enthalpy
        self.Hfus_methods = Hfus(T=self.T, P=self.P, MW=self.MW, AvailableMethods=True, CASRN=self.CAS)
        self.Hfus_method = self.Hfus_methods[0]

        # Fire Safety Limits
        self.Tflash_sources = Tflash(self.CAS, AvailableMethods=True)
        self.Tflash_source = self.Tflash_sources[0]
        self.Tautoignition_sources = Tautoignition(self.CAS, AvailableMethods=True)
        self.Tautoignition_source = self.Tautoignition_sources[0]

        # Chemical Exposure Limits
        self.TWA_sources = TWA(self.CAS, AvailableMethods=True)
        self.TWA_source = self.TWA_sources[0]
        self.STEL_sources = STEL(self.CAS, AvailableMethods=True)
        self.STEL_source = self.STEL_sources[0]
        self.Ceiling_sources = Ceiling(self.CAS, AvailableMethods=True)
        self.Ceiling_source = self.Ceiling_sources[0]
        self.Skin_sources = Skin(self.CAS, AvailableMethods=True)
        self.Skin_source = self.Skin_sources[0]
        self.Carcinogen_sources = Carcinogen(self.CAS, AvailableMethods=True)
        self.Carcinogen_source = self.Carcinogen_sources[0]

        # Chemistry - currently molar
        self.Hf_sources = Hf(CASRN=self.CAS, AvailableMethods=True)
        self.Hf_source = self.Hf_sources[0]

        # Misc
        self.dipole_sources = dipole(CASRN=self.CAS, AvailableMethods=True)
        self.dipole_source = self.dipole_sources[0]

        # Environmental
        self.GWP_sources = GWP(CASRN=self.CAS, AvailableMethods=True)
        self.GWP_source = self.GWP_sources[0]
        self.ODP_sources = ODP(CASRN=self.CAS, AvailableMethods=True)
        self.ODP_source = self.ODP_sources[0]
        self.logP_sources = logP(CASRN=self.CAS, AvailableMethods=True)
        self.logP_source = self.logP_sources[0]

        # Legal
        self.legal_status_sources = legal_status(CASRN=self.CAS, AvailableMethods=True)
        self.legal_status_source = self.legal_status_sources[0]
        self.economic_status_sources = economic_status(CASRN=self.CAS, AvailableMethods=True)
        self.economic_status_source = self.economic_status_sources[0]

        # Analytical
        self.RI_sources = refractive_index(CASRN=self.CAS, AvailableMethods=True)
        self.RI_source = self.RI_sources[0]

        self.conductivity_sources = conductivity(CASRN=self.CAS, AvailableMethods=True)
        self.conductivity_source = self.conductivity_sources[0]


    def set_constants(self):
        self.Tm = Tm(self.CAS, Method=self.Tm_source)
        self.Tb = Tb(self.CAS, Method=self.Tb_source)

        # Critical Point
        self.Tc = Tc(self.CAS, Method=self.Tc_method)
        self.Pc = Pc(self.CAS, Method=self.Pc_method)
        self.Vc = Vc(self.CAS, Method=self.Vc_method)
        self.omega = omega(self.CAS, Method=self.omega_method)
        
        self.StielPolar_methods = StielPolar(Tc=self.Tc, Pc=self.Pc, omega=self.omega, CASRN=self.CAS, AvailableMethods=True)
        self.StielPolar_method = self.StielPolar_methods[0]
        self.StielPolar = StielPolar(Tc=self.Tc, Pc=self.Pc, omega=self.omega, CASRN=self.CAS, Method=self.StielPolar_method)

        self.Zc = Z(self.Tc, self.Pc, self.Vc) if all((self.Tc, self.Pc, self.Vc)) else None
        self.rhoC = Vm_to_rho(self.Vc, self.MW) if self.Vc else None
        self.rhoCm = 1./self.Vc if self.Vc else None

        # Triple point
        self.Pt = Pt(self.CAS, Method=self.Pt_source)
        self.Tt = Tt(self.CAS, Method=self.Tt_source)

        # Enthalpy
        self.Hfus = Hfus(T=self.T, P=self.P, MW=self.MW, Method=self.Hfus_method, CASRN=self.CAS)
        self.Hfusm = property_mass_to_molar(self.Hfus, self.MW) if self.Hfus else None
        
        # Chemistry
        self.Hf = Hf(CASRN=self.CAS, Method=self.Hf_source)
        self.Hc = Hcombustion(atoms=self.atoms, Hf=self.Hf)

        # Fire Safety Limits
        self.Tflash = Tflash(self.CAS, Method=self.Tflash_source)
        self.Tautoignition = Tautoignition(self.CAS, Method=self.Tautoignition_source)
        self.LFL_sources = LFL(atoms=self.atoms, Hc=self.Hc, CASRN=self.CAS, AvailableMethods=True)
        self.LFL_source = self.LFL_sources[0]
        self.UFL_sources = UFL(atoms=self.atoms, Hc=self.Hc, CASRN=self.CAS, AvailableMethods=True)
        self.UFL_source = self.UFL_sources[0]
        self.LFL = LFL(atoms=self.atoms, Hc=self.Hc, CASRN=self.CAS, Method=self.LFL_source)
        self.UFL = UFL(atoms=self.atoms, Hc=self.Hc, CASRN=self.CAS, Method=self.UFL_source)

        # Chemical Exposure Limits
        self.TWA = TWA(self.CAS, Method=self.TWA_source)
        self.STEL = STEL(self.CAS, Method=self.STEL_source)
        self.Ceiling = Ceiling(self.CAS, Method=self.Ceiling_source)
        self.Skin = Skin(self.CAS, Method=self.Skin_source)
        self.Carcinogen = Carcinogen(self.CAS, Method=self.Carcinogen_source)

        # Misc
        self.dipole = dipole(self.CAS, Method=self.dipole_source) # Units of Debye
        self.Stockmayer_sources = Stockmayer(Tc=self.Tc, Zc=self.Zc, omega=self.omega, AvailableMethods=True, CASRN=self.CAS)
        self.Stockmayer_source = self.Stockmayer_sources[0]
        self.Stockmayer = Stockmayer(Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Zc=self.Zc, omega=self.omega, Method=self.Stockmayer_source, CASRN=self.CAS)

        # Environmental
        self.GWP = GWP(CASRN=self.CAS, Method=self.GWP_source)
        self.ODP = ODP(CASRN=self.CAS, Method=self.ODP_source)
        self.logP = logP(CASRN=self.CAS, Method=self.logP_source)

        # Legal
        self.legal_status = legal_status(self.CAS, Method=self.legal_status_source)
        self.economic_status = economic_status(self.CAS, Method=self.economic_status_source)

        # Analytical
        self.RI, self.RIT = refractive_index(CASRN=self.CAS, Method=self.RI_source)
        self.conductivity, self.conductivityT = conductivity(CASRN=self.CAS, Method=self.conductivity_source)


    def set_T_sources(self):
        # Tempearture and Pressure Denepdence
        # Get and choose initial methods
        self.VaporPressure = VaporPressure(Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, CASRN=self.CAS)
        self.Psat_298 = self.VaporPressure.T_dependent_property(298.15)


        self.VolumeLiquid = VolumeLiquid(MW=self.MW, Tb=self.Tb, Tc=self.Tc,
                          Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega,
                          dipole=self.dipole, Psat=self.VaporPressure.T_dependent_property, CASRN=self.CAS)

        self.Vml_Tb = self.VolumeLiquid.T_dependent_property(self.Tb) if self.Tb else None
        self.Vml_Tm = self.VolumeLiquid.T_dependent_property(self.Tm) if self.Tm else None
        self.Vml_STP = self.VolumeLiquid.T_dependent_property(298.15)

        # set molecular_diameter; depends on Vml_Tb, Vml_Tm
        self.molecular_diameter_sources = molecular_diameter(Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, Vm=self.Vml_Tm, Vb=self.Vml_Tb, AvailableMethods=True, CASRN=self.CAS)
        self.molecular_diameter_source = self.molecular_diameter_sources[0]
        self.molecular_diameter = molecular_diameter(Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, Vm=self.Vml_Tm, Vb=self.Vml_Tb, Method=self.molecular_diameter_source, CASRN=self.CAS)

        self.VolumeGas = VolumeGas(MW=self.MW, Tc=self.Tc, Pc=self.Pc, omega=self.omega, dipole=self.dipole, CASRN=self.CAS)

        self.VolumeSolid = VolumeSolid(CASRN=self.CAS, MW=self.MW, Tt=self.Tt)

        self.HeatCapacityGas = HeatCapacityGas(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable)

        self.HeatCapacitySolid = HeatCapacitySolid(MW=self.MW, similarity_variable=self.similarity_variable, CASRN=self.CAS)

        self.HeatCapacityLiquid = HeatCapacityLiquid(CASRN=self.CAS, MW=self.MW, similarity_variable=self.similarity_variable, Tc=self.Tc, omega=self.omega, Cpgm=self.HeatCapacityGas.T_dependent_property)

        self.EnthalpyVaporization = EnthalpyVaporization(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, similarity_variable=self.similarity_variable)
        self.HvapTbm = self.EnthalpyVaporization.T_dependent_property(self.Tb) if self.Tb else None
        self.HvapTb = property_molar_to_mass(self.HvapTbm, self.MW)

        self.Hsub_methods = Hsub(T=self.T, P=self.P, MW=self.MW, AvailableMethods=True, CASRN=self.CAS)
        self.Hsub_method = self.Hsub_methods[0]

        self.ViscosityLiquid = ViscosityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, omega=self.omega, Psat=self.VaporPressure.T_dependent_property, Vml=self.VolumeLiquid.T_dependent_property)
        
        vmg_calc = lambda T : self.VolumeGas.TP_dependent_property(T, 101325)
        self.ViscosityGas = ViscosityGas(CASRN=self.CAS, MW=self.MW, Tc=self.Tc, Pc=self.Pc, Zc=self.Zc, dipole=self.dipole, Vmg=vmg_calc)

        self.ThermalConductivityLiquid = ThermalConductivityLiquid(CASRN=self.CAS, MW=self.MW, Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, omega=self.omega, Hfus=self.Hfusm)

        cvgm_calc = lambda T : self.HeatCapacityGas.T_dependent_property(T) - R
        self.ThermalConductivityGas = ThermalConductivityGas(CASRN=self.CAS, MW=self.MW, Tb=self.Tb, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, dipole=self.dipole, Vmg=vmg_calc, Cvgm=cvgm_calc, mug=self.ViscosityGas.T_dependent_property)

        self.SurfaceTension = SurfaceTension(CASRN=self.CAS, Tb=self.Tb, Tc=self.Tc, Pc=self.Pc, Vc=self.Vc, Zc=self.Zc, omega=self.omega, StielPolar=self.StielPolar)

        self.Permittivity = Permittivity(CASRN=self.CAS)

        self.solubility_parameter_methods = solubility_parameter(T=self.T, Hvapm=self.HvapTbm, Vml=self.Vml_STP, AvailableMethods=True, CASRN=self.CAS)
        self.solubility_parameter_method = self.solubility_parameter_methods[0]

    def set_T(self, T=None):
        if T:
            self.T = T
        self.Psat = self.VaporPressure.T_dependent_property(T=self.T)

        self.Vms = self.VolumeSolid.T_dependent_property(T=self.T)
        self.rhos = Vm_to_rho(self.Vms, self.MW) if self.Vms else None
        self.rhosm = 1/self.Vms if self.Vms else None
        self.Zs = Z(self.T, self.P, self.Vms) if self.Vms else None
                
        self.Vml = self.VolumeLiquid.TP_dependent_property(self.T, self.P)
#        self.Vml = self.VolumeLiquid.T_dependent_property(self.T) if not self.Vml else self.Vml
        
        # TODO: derivative
        self.isobaric_expansion_l = isobaric_expansion(V1=self.Vml, dT=0.01, V2=self.VolumeLiquid.TP_dependent_property(self.T+0.01, self.P))
        if not self.Vml:
            self.Vml = self.VolumeLiquid.T_dependent_property(self.T)
            self.isobaric_expansion_l = isobaric_expansion(V1=self.Vml, dT=0.01, V2=self.VolumeLiquid.T_dependent_property(self.T+0.01))

        self.rhol = Vm_to_rho(self.Vml, self.MW) if self.Vml else None
        self.Zl = Z(self.T, self.P, self.Vml) if self.Vml else None
        self.rholm = 1./self.Vml if self.Vml else None

        self.Vmg = self.VolumeGas.TP_dependent_property(T=self.T, P=self.P)
        self.rhog = Vm_to_rho(self.Vmg, self.MW) if self.Vmg else None
        self.Zg = Z(self.T, self.P, self.Vmg) if self.Vmg else None
        self.rhogm = 1./self.Vmg if self.Vmg else None
        self.Bvirial = B_from_Z(self.Zg, self.T, self.P) if self.Vmg else None

        self.isobaric_expansion_g = isobaric_expansion(V1=self.Vmg, dT=0.01, V2=self.VolumeGas.TP_dependent_property(T=self.T+0.01, P=self.P))

        self.Cpsm = self.HeatCapacitySolid.T_dependent_property(self.T)
        self.Cpgm = self.HeatCapacityGas.T_dependent_property(self.T)
        self.Cplm = self.HeatCapacityLiquid.T_dependent_property(self.T)
        
        self.Cpl = property_molar_to_mass(self.Cplm, self.MW) if self.Cplm else None
        self.Cps = property_molar_to_mass(self.Cpsm, self.MW) if self.Cpsm else None
        self.Cpg = property_molar_to_mass(self.Cpgm, self.MW) if self.Cpgm else None

        self.Cvgm = self.Cpgm - R if self.Cpgm else None
        self.Cvg = property_molar_to_mass(self.Cvgm, self.MW) if self.Cvgm else None

        self.isentropic_exponent = isentropic_exponent(self.Cpg, self.Cvg) if all((self.Cpg, self.Cvg)) else None

        self.Hvapm = self.EnthalpyVaporization.T_dependent_property(self.T)
        self.Hvap = property_molar_to_mass(self.Hvapm, self.MW)

        self.Hsub = Hsub(T=self.T, P=self.P, MW=self.MW, Method=self.Hsub_method, CASRN=self.CAS)
        self.Hsubm = property_mass_to_molar(self.Hsub, self.MW)

        self.mul = self.ViscosityLiquid.TP_dependent_property(self.T, self.P)
        if not self.mul:
            self.mul = self.ViscosityLiquid.T_dependent_property(self.T)

        self.mug = self.ViscosityGas.TP_dependent_property(self.T, self.P)
        if not self.mug:
            self.mug = self.ViscosityGas.T_dependent_property(self.T)

        self.kl = self.ThermalConductivityLiquid.TP_dependent_property(self.T, self.P)
        if not self.kl:
            self.kl = self.ThermalConductivityLiquid.T_dependent_property(self.T)

        self.kg = self.ThermalConductivityGas.TP_dependent_property(self.T, self.P)
        if not self.kg:
            self.kg = self.ThermalConductivityGas.T_dependent_property(self.T)


        self.sigma = self.SurfaceTension.T_dependent_property(self.T)
        self.permittivity = self.Permittivity.T_dependent_property(self.T)

        self.solubility_parameter = solubility_parameter(T=self.T, Hvapm=self.Hvapm, Vml=self.Vml, Method=self.solubility_parameter_method, CASRN=self.CAS)

        self.Parachor = Parachor(sigma=self.sigma, MW=self.MW, rhol=self.rhol, 
                                 rhog=self.rhog) if all((self.sigma, self.MW, self.rhol, self.rhog)) else None

        self.JTl = JT(T=self.T, V=self.Vml, Cp=self.Cplm, isobaric_expansion=self.isobaric_expansion_l)
        self.JTg = JT(T=self.T, V=self.Vmg, Cp=self.Cpgm, isobaric_expansion=self.isobaric_expansion_g)

        self.nul = nu_mu_converter(mu=self.mul, rho=self.rhol) if all([self.mul, self.rhol]) else None
        self.nug = nu_mu_converter(mu=self.mug, rho=self.rhog) if all([self.mug, self.rhog]) else None

        self.Prl = Prandtl(Cp=self.Cpl, mu=self.mul, k=self.kl) if all([self.Cpl, self.mul, self.kl]) else None
        self.Prg = Prandtl(Cp=self.Cpg, mu=self.mug, k=self.kg) if all([self.Cpg, self.mug, self.kg]) else None

        self.alphal = thermal_diffusivity(k=self.kl, rho=self.rhol, Cp=self.Cpl) if all([self.kl, self.rhol, self.Cpl]) else None
        self.alphag = thermal_diffusivity(k=self.kg, rho=self.rhog, Cp=self.Cpg) if all([self.kg, self.rhog, self.Cpg]) else None

        self.set_phase()

        return True

    def set_phase(self):
        self.phase_STP = identify_phase(T=298.15, P=101325., Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Psat=self.Psat_298)
        self.phase = identify_phase(T=self.T, P=self.P, Tm=self.Tm, Tb=self.Tb, Tc=self.Tc, Psat=self.Psat)
        self.k = phase_set_property(phase=self.phase, s=None, l=self.kl, g=self.kg) # ks not implemented
        self.rho = phase_set_property(phase=self.phase, s=self.rhos, l=self.rhol, g=self.rhog)
        self.Vm = phase_set_property(phase=self.phase, s=self.Vms, l=self.Vml, g=self.Vmg)
        self.Z = Z(self.T, self.P, self.Vm) if self.Vm else None
        self.Cp = phase_set_property(phase=self.phase, s=self.Cps, l=self.Cpl, g=self.Cpg)
        self.Cpm = phase_set_property(phase=self.phase, s=self.Cpsm, l=self.Cplm, g=self.Cpgm)
        self.mu = phase_set_property(phase=self.phase, l=self.mul, g=self.mug)
        self.nu = phase_set_property(phase=self.phase, l=self.nul, g=self.nug)
        self.Pr = phase_set_property(phase=self.phase, l=self.Prl, g=self.Prg)
        self.alpha = phase_set_property(phase=self.phase, l=self.alphal, g=self.alphag)
        self.isobaric_expansion = phase_set_property(phase=self.phase, l=self.isobaric_expansion_l, g=self.isobaric_expansion_g)
        self.JT = phase_set_property(phase=self.phase, l=self.JTl, g=self.JTg)
        # TODO
        self.H = 0
        self.Hm = 0


    def Tsat(self, P):
        return self.VaporPressure.solve_prop(P)


    def Reynolds(self, V=None, D=None):
        return Reynolds(V=V, D=D, rho=self.rho, mu=self.mu)

    def Capillary(self, V=None):
        return Capillary(V=V, mu=self.mu, sigma=self.sigma)

    def Weber(self, V=None, D=None):
        return Weber(V=V, L=D, rho=self.rho, sigma=self.sigma)

    def Bond(self, L=None):
        return Bond(rhol=self.rhol, rhog=self.rhog, sigma=self.sigma, L=L)

    def Jakob(self, Tw=None):
        return Jakob(Cp=self.Cp, Hvap=self.Hvap, Te=Tw-self.T)

    def Grashof(self, Tw=None, L=None):
        return Grashof(L=L, beta=self.isobaric_expansion, T1=Tw, T2=self.T,
                       rho=self.rho, mu=self.mu)

    def Peclet_heat(self, V=None, D=None):
        return Peclet_heat(V=V, L=D, rho=self.rho, Cp=self.Cp, k=self.k)
Example #11
0
def Pt(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval of a chemical's triple pressure.
    Lookup is based on CASRNs. Will automatically select a data source to use
    if no Method is provided; returns None if the data is not available.

    Returns data from [1]_, or attempts to calculate the vapor pressure at the
    triple temperature, if data is available.

    Parameters
    ----------
    CASRN : string
        CASRN [-]

    Returns
    -------
    Pt : float
        Triple point pressure, [Pa]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain Pt with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        A string for the method name to use, as defined by constants in
        Pt_methods
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        the Pt for the desired chemical, and will return methods
        instead of the Pt

    Notes
    -----

    Examples
    --------
    Ammonia

    >>> Pt('7664-41-7')
    6079.5

    References
    ----------
    .. [1] Staveley, L. A. K., L. Q. Lobo, and J. C. G. Calado. "Triple-Points
       of Low Melting Substances and Their Use in Cryogenic Work." Cryogenics
       21, no. 3 (March 1981): 131-144. doi:10.1016/0011-2275(81)90264-2.
    '''
    def list_methods():
        methods = []
        if CASRN in Staveley_data.index and not np.isnan(
                Staveley_data.at[CASRN, 'Pt']):
            methods.append(STAVELEY)
        if Tt(CASRN) and VaporPressure(CASRN=CASRN).T_dependent_property(
                T=Tt(CASRN)):
            methods.append(DEFINITION)
        methods.append(NONE)
        return methods

    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == STAVELEY:
        Pt = Staveley_data.at[CASRN, 'Pt']
    elif Method == DEFINITION:
        Pt = VaporPressure(CASRN=CASRN).T_dependent_property(T=Tt(CASRN))
    elif Method == NONE:
        Pt = None
    else:
        raise Exception('Failure in in function')
    return Pt
Example #12
0
def test_VolumeLiquidMixture_ExcessVolume():
    # Excess volume
    # Vs -7.5E-7 in ddbst http://www.ddbst.com/en/EED/VE/VE0%20Ethanol%3BWater.php
    T = 298.15
    P = 101325.0
    MWs = [18.01528, 46.06844]
    zs = [1 - 0.15600, 0.15600]
    ws = zs_to_ws(zs, MWs)

    VaporPressures = [
        VaporPressure(CASRN="7732-18-5",
                      Tb=373.124,
                      Tc=647.14,
                      Pc=22048320.0,
                      omega=0.344,
                      extrapolation="AntoineAB|DIPPR101_ABC",
                      method="WAGNER_MCGARRY"),
        VaporPressure(CASRN="64-17-5",
                      Tb=351.39,
                      Tc=514.0,
                      Pc=6137000.0,
                      omega=0.635,
                      extrapolation="AntoineAB|DIPPR101_ABC",
                      method="WAGNER_MCGARRY")
    ]

    drink = VolumeLiquidMixture(MWs=[18.01528, 46.06844],
                                Tcs=[647.14, 514.0],
                                Pcs=[22048320.0, 6137000.0],
                                Vcs=[5.6000000000000006e-05, 0.000168],
                                Zcs=[0.22947273972184645, 0.24125043269792065],
                                omegas=[0.344, 0.635],
                                CASs=['7732-18-5', '64-17-5'],
                                correct_pressure_pure=True,
                                method="LALIBERTE",
                                VolumeLiquids=[
                                    VolumeLiquid(
                                        CASRN="7732-18-5",
                                        MW=18.01528,
                                        Tb=373.124,
                                        Tc=647.14,
                                        Pc=22048320.0,
                                        Vc=5.6000000000000006e-05,
                                        Zc=0.22947273972184645,
                                        omega=0.344,
                                        dipole=1.85,
                                        Psat=VaporPressures[0],
                                        extrapolation="constant",
                                        method="VDI_PPDS",
                                        method_P="COSTALD_COMPRESSED"),
                                    VolumeLiquid(CASRN="64-17-5",
                                                 MW=46.06844,
                                                 Tb=351.39,
                                                 Tc=514.0,
                                                 Pc=6137000.0,
                                                 Vc=0.000168,
                                                 Zc=0.24125043269792065,
                                                 omega=0.635,
                                                 dipole=1.44,
                                                 Psat=VaporPressures[1],
                                                 extrapolation="constant",
                                                 method="DIPPR_PERRY_8E",
                                                 method_P="COSTALD_COMPRESSED")
                                ])
    V_Ex = drink.excess_property(T, P, zs, ws)
    assert_close(V_Ex, -7.242450496000289e-07, rtol=1e-12)
Example #13
0
def test_VolumeLiquidMixture():
    #    from thermo.mixture import Mixture
    #    m = Mixture(['benzene', 'toluene'], zs=[.5, .5], T=298.15, P=101325.)
    T, P, zs = 298.15, 101325.0, [0.5, 0.5]
    MWs = [78.11184, 92.13842]
    ws = zs_to_ws(zs, MWs=MWs)

    VaporPressures = [
        VaporPressure(CASRN="71-43-2",
                      Tb=353.23,
                      Tc=562.05,
                      Pc=4895000.0,
                      omega=0.212,
                      extrapolation="AntoineAB|DIPPR101_ABC",
                      method=POLY_FIT,
                      poly_fit=(278.68399999999997, 562.01, [
                          4.547344107145341e-20, -1.3312501882259186e-16,
                          1.6282983902136683e-13, -1.0498233680158312e-10,
                          3.535838362096064e-08, -3.6181923213017173e-06,
                          -0.001593607608896686, 0.6373679536454406,
                          -64.4285974110459
                      ])),
        VaporPressure(CASRN="108-88-3",
                      Tb=383.75,
                      Tc=591.75,
                      Pc=4108000.0,
                      omega=0.257,
                      extrapolation="AntoineAB|DIPPR101_ABC",
                      method=POLY_FIT,
                      poly_fit=(178.01, 591.74, [
                          -8.638045111752356e-20, 2.995512203611858e-16,
                          -4.5148088801006036e-13, 3.8761537879200513e-10,
                          -2.0856828984716705e-07, 7.279010846673517e-05,
                          -0.01641020023565049, 2.2758331029405516,
                          -146.04484159879843
                      ]))
    ]

    VolumeLiquids = [
        VolumeLiquid(CASRN="71-43-2",
                     MW=78.11184,
                     Tb=353.23,
                     Tc=562.05,
                     Pc=4895000.0,
                     Vc=0.000256,
                     Zc=0.2681535335844513,
                     omega=0.212,
                     dipole=0.0,
                     Psat=VaporPressures[0],
                     extrapolation="constant",
                     method=POLY_FIT,
                     poly_fit=(278.68399999999997, 552.02, [
                         2.5040222732960933e-22, -7.922607445206804e-19,
                         1.088548130214618e-15, -8.481605391952225e-13,
                         4.098451788397536e-10, -1.257577461969114e-07,
                         2.3927976459304723e-05, -0.0025810882828932375,
                         0.12092854717588034
                     ])),
        VolumeLiquid(CASRN="108-88-3",
                     MW=92.13842,
                     Tb=383.75,
                     Tc=591.75,
                     Pc=4108000.0,
                     Vc=0.000316,
                     Zc=0.2638426898300023,
                     omega=0.257,
                     dipole=0.33,
                     Psat=VaporPressures[1],
                     extrapolation="constant",
                     method=POLY_FIT,
                     poly_fit=(178.01, 581.75, [
                         2.2801490297347937e-23, -6.411956871696508e-20,
                         7.723152902379232e-17, -5.197203733189603e-14,
                         2.1348482785660093e-11, -5.476649499770259e-09,
                         8.564670053875876e-07, -7.455178589434267e-05,
                         0.0028545812080104068
                     ]))
    ]

    obj = VolumeLiquidMixture(MWs=MWs,
                              Tcs=[562.05, 591.75],
                              Pcs=[4895000.0, 4108000.0],
                              Vcs=[0.000256, 0.000316],
                              Zcs=[0.2681535335844513, 0.2638426898300023],
                              omegas=[0.212, 0.257],
                              CASs=['71-43-2', '108-88-3'],
                              VolumeLiquids=VolumeLiquids,
                              correct_pressure_pure=False)

    hash0 = hash(obj)
    obj2 = VolumeLiquidMixture.from_json(json.loads(json.dumps(obj.as_json())))
    assert obj == obj2
    assert hash(obj) == hash0
    assert hash(obj2) == hash0

    obj2 = eval(str(obj))
    assert obj == obj2
    assert hash(obj) == hash0
    assert hash(obj2) == hash0

    Vml = 9.858773618507427e-05
    assert_close(obj.calculate(T, P, zs, ws, COSTALD_MIXTURE), Vml, rtol=1e-11)
    obj.method = COSTALD_MIXTURE
    assert_close(obj(T, P, zs, ws), Vml, rtol=1e-11)

    Vml = 9.815400609778346e-05
    assert_close(obj.calculate(T, P, zs, ws, COSTALD_MIXTURE_FIT),
                 Vml,
                 rtol=1e-11)
    obj.method = COSTALD_MIXTURE_FIT
    assert_close(obj(T, P, zs, ws), Vml, rtol=1e-11)

    Vml = 9.814047221052766e-05
    assert_close(obj.calculate(T, P, zs, ws, LINEAR), Vml, rtol=1e-11)
    obj.method = LINEAR
    assert_close(obj(T, P, zs, ws), Vml, rtol=1e-11)

    Vml = 9.7377562180953e-05
    assert_close(obj.calculate(T, P, zs, ws, RACKETT), Vml, rtol=1e-11)
    obj.method = RACKETT
    assert_close(obj(T, P, zs, ws), Vml, rtol=1e-11)

    Vml = 9.810986651973312e-05
    assert_close(obj.calculate(T, P, zs, ws, RACKETT_PARAMETERS),
                 Vml,
                 rtol=1e-11)
    obj.method = RACKETT_PARAMETERS
    assert_close(obj(T, P, zs, ws), Vml, rtol=1e-11)

    # Unhappy paths
    with pytest.raises(Exception):
        obj.calculate(m.T, m.P, m.zs, m.ws, 'BADMETHOD')

    with pytest.raises(Exception):
        obj.test_method_validity(m.T, m.P, m.zs, m.ws, 'BADMETHOD')
Example #14
0
def test_two_eos_pure_flash_all_properties():
    # Methanol
    constants = ChemicalConstantsPackage(
        atom_fractions={
            'H': 0.6666666666666666,
            'C': 0.16666666666666666,
            'O': 0.16666666666666666
        },
        atomss=[{
            'H': 4,
            'C': 1,
            'O': 1
        }],
        CASs=['67-56-1'],
        charges=[0],
        conductivities=[4.4e-05],
        dipoles=[1.7],
        formulas=['CH4O'],
        Gfgs=[-162000.13000000003],
        Gfgs_mass=[-5055890.325967345],
        Hcs=[-764464.0],
        Hcs_lower=[-676489.1],
        Hcs_lower_mass=[-21112666.368306957],
        Hcs_mass=[-23858290.373904638],
        Hfgs=[-200700.0],
        Hfgs_mass=[-6263681.321870828],
        Hfus_Tms=[3215.0000000000005],
        Hfus_Tms_mass=[100337.49601302797],
        Hvap_298s=[37486.47944178592],
        Hvap_298s_mass=[1169922.078237216],
        Hvap_Tbs=[35170.873821707064],
        Hvap_Tbs_mass=[1097653.9383702152],
        LFLs=[0.06],
        logPs=[-0.74],
        molecular_diameters=[3.7995699999999997],
        MWs=[32.04186],
        names=['methanol'],
        omegas=[0.5589999999999999],
        Parachors=[1.574169046057019e-05],
        Pcs=[8084000.0],
        phase_STPs=['l'],
        Psat_298s=[16905.960312551426],
        PSRK_groups=[{
            15: 1
        }],
        Pts=[0.1758862695025245],
        PubChems=[887],
        rhocs=[8547.008547008547],
        rhocs_mass=[273.86205128205125],
        rhol_STPs=[24494.78614922483],
        rhol_STPs_mass=[784.8585085234012],
        RIs=[1.3288],
        S0gs=[239.9],
        S0gs_mass=[7487.080962216301],
        Sfgs=[-129.7999999999999],
        Sfgs_mass=[-4050.950849919446],
        similarity_variables=[0.18725504699165404],
        Skins=[True],
        smiless=['CO'],
        STELs=[(250.0, 'ppm')],
        StielPolars=[0.027243902847492674],
        Stockmayers=[685.96],
        Tautoignitions=[713.15],
        Tbs=[337.65],
        Tcs=[512.5],
        Tflashs=[282.15],
        Tms=[175.15],
        Tts=[175.59],
        UFLs=[0.36],
        UNIFAC_Dortmund_groups=[{
            15: 1
        }],
        UNIFAC_groups=[{
            15: 1
        }],
        Van_der_Waals_areas=[358000.0],
        Van_der_Waals_volumes=[2.1709787e-05],
        Vcs=[0.000117],
        Vml_STPs=[4.0825014511573776e-05],
        Vml_Tms=[3.541058756059562e-05],
        Zcs=[0.22196480200068586],
        UNIFAC_Rs=[1.4311],
        UNIFAC_Qs=[1.432],
        rhos_Tms=[1013.0221439813405],
        Vms_Tms=[3.162996997683616e-05],
        solubility_parameters=[29315.58469262365],
        Vml_60Fs=[4.033573571273147e-05],
        rhol_60Fs_mass=[794.3789652976724],
        rhol_60Fs=[24791.91174599953])

    VaporPressures = [
        VaporPressure(poly_fit=(175.7, 512.49, [
            -1.446088049406911e-19, 4.565038519454878e-16,
            -6.278051259204248e-13, 4.935674274379539e-10,
            -2.443464113936029e-07, 7.893819658700523e-05,
            -0.016615779444332356, 2.1842496316772264, -134.19766175812708
        ])),
    ]
    HeatCapacityGases = [
        HeatCapacityGas(poly_fit=(50.0, 1000.0, [
            2.3511458696647882e-21, -9.223721411371584e-18,
            1.3574178156001128e-14, -8.311274917169928e-12,
            4.601738891380102e-10, 1.78316202142183e-06,
            -0.0007052056417063217, 0.13263597297874355, 28.44324970462924
        ])),
    ]
    HeatCapacityLiquids = [
        HeatCapacityLiquid(poly_fit=(180.0, 503.1, [
            -5.042130764341761e-17, 1.3174414379504284e-13,
            -1.472202211288266e-10, 9.19934288272021e-08,
            -3.517841445216993e-05, 0.008434516406617465, -1.2381765320848312,
            101.71442569958393, -3508.6245143327947
        ])),
    ]
    VolumeLiquids = [
        VolumeLiquid(poly_fit=(175.7, 502.5, [
            3.5725079384600736e-23, -9.031033742820083e-20,
            9.819637959370411e-17, -5.993173551565636e-14,
            2.2442465416964825e-11, -5.27776114586072e-09,
            7.610461006178106e-07, -6.148574498547711e-05, 0.00216398089328537
        ])),
    ]
    EnthalpyVaporizations = [
        EnthalpyVaporization(poly_fit=(175.7, 512.499, 512.5, [
            -0.004536133852590396, -0.2817551666837462, -7.344529282245696,
            -104.02286881045083, -860.5796142607192, -4067.8897875259267,
            -8952.300062896637, 2827.0089241465225, 44568.12528999141
        ])),
    ]
    HeatCapacitySolids = [
        HeatCapacitySolid(poly_fit=(1.0, 5000.0, [
            -4.2547351607351175e-26, 9.58204543572984e-22,
            -8.928062818728625e-18, 4.438942190507877e-14,
            -1.2656161406049876e-10, 2.0651464217978594e-07,
            -0.0001691371394823046, 0.2038633833421581, -0.07254973910767148
        ])),
    ]
    SublimationPressures = [
        SublimationPressure(poly_fit=(61.5, 179.375, [
            -1.9972190661146383e-15, 2.1648606414769645e-12,
            -1.0255776193312338e-09, 2.7846062954442135e-07,
            -4.771529410705124e-05, 0.005347189071525987, -0.3916553642749777,
            18.072103851054266, -447.1556383160345
        ])),
    ]
    EnthalpySublimations = [
        EnthalpySublimation(poly_fit=(1.7515, 175.59, [
            2.3382707698778188e-17, -2.03890965442551e-12,
            1.5374109464154768e-09, -4.640933157748743e-07,
            6.931187040484687e-05, -0.004954625422589015, 0.045058888152305354,
            32.52432385785916, 42213.605713250145
        ])),
    ]
    VolumeSolids = [
        VolumeSolid(poly_fit=(52.677, 175.59, [
            3.9379562779372194e-30, 1.4859309728437516e-27,
            3.897856765862211e-24, 5.012758300685479e-21,
            7.115820892078097e-18, 9.987967202910477e-15,
            1.4030825662633013e-11, 1.970935889948393e-08,
            2.7686131179275174e-05
        ])),
    ]

    correlations = PropertyCorrelationsPackage(
        constants,
        VaporPressures=VaporPressures,
        HeatCapacityGases=HeatCapacityGases,
        HeatCapacityLiquids=HeatCapacityLiquids,
        VolumeLiquids=VolumeLiquids,
        EnthalpyVaporizations=EnthalpyVaporizations,
        HeatCapacitySolids=HeatCapacitySolids,
        SublimationPressures=SublimationPressures,
        EnthalpySublimations=EnthalpySublimations,
        VolumeSolids=VolumeSolids)

    eos_liquid = CEOSLiquid(PRMIX,
                            dict(Tcs=constants.Tcs,
                                 Pcs=constants.Pcs,
                                 omegas=constants.omegas),
                            HeatCapacityGases=HeatCapacityGases,
                            Hfs=constants.Hfgs,
                            Sfs=constants.Sfgs,
                            Gfs=constants.Gfgs)

    gas = CEOSGas(PRMIX,
                  dict(Tcs=constants.Tcs,
                       Pcs=constants.Pcs,
                       omegas=constants.omegas),
                  HeatCapacityGases=HeatCapacityGases,
                  Hfs=constants.Hfgs,
                  Sfs=constants.Sfgs,
                  Gfs=constants.Gfgs)

    # Pseudo vapor volume for eos gas?
    flasher = FlashPureVLS(constants, correlations, gas, [eos_liquid], [])

    # Test all the results
    T, VF = 300.0, 0.4
    eq = flasher.flash(T=T, VF=VF)

    # Meta
    assert eq.phases[0] is eq.gas
    assert eq.phases[1] is eq.liquid0
    assert eq.phase_count == 2
    assert eq.liquid_count == 1
    assert eq.gas_count == 1
    assert eq.solid_count == 0
    assert eq.zs == [1.0]

    # Phase fractions
    assert_close1d(eq.betas, [.4, .6], rtol=1e-12)
    assert_close1d(eq.betas_mass, [.4, .6], rtol=1e-12)
    assert_close1d(eq.betas_volume,
                   [0.9994907285990579, 0.0005092714009421547],
                   rtol=1e-12)

    assert_close(eq.T, T, rtol=1e-12)
    for phase in eq.phases:
        assert_close(phase.T, T, rtol=1e-12)

    P_eq_expect = 17641.849717291494  # Might change slightly in the future due to tolerance
    assert_close(eq.P, P_eq_expect, rtol=1e-9)
    for phase in eq.phases:
        assert_close(phase.P, eq.P, rtol=1e-12)

    # Mass and volume (liquid) fractions
    # Since liquid fraction does not make any sense, might as well use pure volumes.
    assert_close1d(eq.Vfls(), [1])
    assert_close1d(eq.bulk.Vfls(), [1])
    assert_close2d([eq.Vfls(phase) for phase in eq.phases], [[1], [1]])

    assert_close1d(eq.Vfgs(), [1])
    assert_close1d(eq.bulk.Vfgs(), [1])
    assert_close2d([eq.Vfgs(phase) for phase in eq.phases], [[1], [1]])

    assert_close1d(eq.ws(), [1])
    assert_close1d(eq.bulk.ws(), [1])
    assert_close2d([eq.ws(phase) for phase in eq.phases], [[1], [1]])

    # H S G U A
    assert_close(eq.H(), -24104.760566193883, rtol=1e-12)
    assert_close(eq.bulk.H(), -24104.760566193883, rtol=1e-12)
    assert_close1d([i.H() for i in eq.phases],
                   [51.18035762282534, -40208.72118207169],
                   rtol=1e-12)

    assert_close(eq.S(), -65.77742662151137, rtol=1e-12)
    assert_close(eq.bulk.S(), -65.77742662151137, rtol=1e-12)
    assert_close1d([i.S() for i in eq.phases],
                   [14.742376457877638, -119.45729534110404],
                   rtol=1e-12)

    assert_close(eq.G(), -4371.532579740473, rtol=1e-12)
    assert_close(eq.bulk.G(), -4371.532579740473, rtol=1e-12)
    assert_close1d([i.G() for i in eq.phases],
                   [-4371.532579740466, -4371.53257974048],
                   rtol=1e-12)

    assert_close(eq.U(), -25098.583314964242, rtol=1e-12)
    assert_close(eq.bulk.U(), -25098.583314964242, rtol=1e-12)
    assert_close1d([i.U() for i in eq.phases],
                   [-2432.11120054419, -40209.56472457761],
                   rtol=1e-12)

    assert_close(eq.A(), -5365.355328510832, rtol=1e-12)
    assert_close(eq.bulk.A(), -5365.355328510832, rtol=1e-12)
    assert_close1d([i.A() for i in eq.phases],
                   [-6854.824137907482, -4372.376122246402],
                   rtol=1e-12)

    # Reactive H S G U A
    assert_close(eq.H_reactive(), -224804.7605661939, rtol=1e-12)
    assert_close(eq.bulk.H_reactive(), -224804.7605661939, rtol=1e-12)
    assert_close1d([i.H_reactive() for i in eq.phases],
                   [-200648.81964237717, -240908.7211820717],
                   rtol=1e-12)

    assert_close(eq.S_reactive(), -195.57742662151128, rtol=1e-12)
    assert_close(eq.bulk.S_reactive(), -195.57742662151128, rtol=1e-12)
    assert_close1d([i.S_reactive() for i in eq.phases],
                   [-115.05762354212226, -249.25729534110394],
                   rtol=1e-12)

    assert_close(eq.G_reactive(), -166131.5325797405, rtol=1e-12)
    assert_close(eq.bulk.G_reactive(), -166131.5325797405, rtol=1e-12)
    assert_close1d([i.G_reactive() for i in eq.phases],
                   [-166131.5325797405] * 2,
                   rtol=1e-12)

    assert_close(eq.U_reactive(), -225798.58331496426, rtol=1e-12)
    assert_close(eq.bulk.U_reactive(), -225798.58331496426, rtol=1e-12)
    assert_close1d([i.U_reactive() for i in eq.phases],
                   [-203132.1112005442, -240909.56472457762],
                   rtol=1e-12)

    assert_close(eq.A_reactive(), -167125.35532851086, rtol=1e-12)
    assert_close(eq.bulk.A_reactive(), -167125.35532851086, rtol=1e-12)
    assert_close1d([i.A_reactive() for i in eq.phases],
                   [-168614.82413790753, -166132.37612224644],
                   rtol=1e-12)

    # Mass H S G U A
    assert_close(eq.H_mass(), -752289.6787575341, rtol=1e-12)
    assert_close(eq.bulk.H_mass(), -752289.6787575341, rtol=1e-12)
    assert_close1d([i.H_mass() for i in eq.phases],
                   [1597.2967119519697, -1254880.9957371918],
                   rtol=1e-12)

    assert_close(eq.S_mass(), -2052.859185500198, rtol=1e-12)
    assert_close(eq.bulk.S_mass(), -2052.859185500198, rtol=1e-12)
    assert_close1d([i.S_mass() for i in eq.phases],
                   [460.0973993980886, -3728.163575432389],
                   rtol=1e-12)

    assert_close(eq.G_mass(), -136431.9231074748, rtol=1e-12)
    assert_close(eq.bulk.G_mass(), -136431.9231074748, rtol=1e-12)
    assert_close1d([i.G_mass() for i in eq.phases], [-136431.92310747458] * 2,
                   rtol=1e-12)

    assert_close(eq.A_mass(), -167448.31069453622, rtol=1e-12)
    assert_close(eq.bulk.A_mass(), -167448.31069453622, rtol=1e-12)
    assert_close1d([i.A_mass() for i in eq.phases],
                   [-213933.40267723164, -136458.24937273934],
                   rtol=1e-12)

    assert_close(eq.U_mass(), -783306.0663445955, rtol=1e-12)
    assert_close(eq.bulk.U_mass(), -783306.0663445955, rtol=1e-12)
    assert_close1d([i.U_mass() for i in eq.phases],
                   [-75904.18285780508, -1254907.322002456],
                   rtol=1e-12)

    # Other
    assert_close(eq.MW(), 32.04186, rtol=1e-12)
    assert_close(eq.bulk.MW(), 32.04186, rtol=1e-12)
    assert_close1d([i.MW() for i in eq.phases], [32.04186, 32.04186],
                   rtol=1e-12)

    # Volumetric
    assert_close(eq.rho_mass(), 0.568791245201322, rtol=1e-12)
    assert_close(eq.bulk.rho_mass(), 0.568791245201322, rtol=1e-12)
    assert_close1d([i.rho_mass() for i in eq.phases],
                   [0.2276324247643884, 670.1235264525617],
                   rtol=1e-12)

    assert_close(eq.V(), 0.05633325103071669, rtol=1e-12)
    assert_close(eq.bulk.V(), 0.05633325103071669, rtol=1e-12)
    assert_close1d([i.V() for i in eq.phases],
                   [0.1407614052926116, 4.781485612006529e-05],
                   rtol=1e-12)

    assert_close(eq.rho(), 17.75150522476916, rtol=1e-12)
    assert_close(eq.bulk.rho(), 17.75150522476916, rtol=1e-12)
    assert_close1d([i.rho() for i in eq.phases],
                   [7.104220066013285, 20914.002072681225],
                   rtol=1e-12)

    assert_close(eq.Z(), 0.3984313416321555, rtol=1e-12)
    assert_close(eq.bulk.Z(), 0.3984313416321555, rtol=1e-12)
    assert_close1d([i.Z() for i in eq.phases],
                   [0.9955710798615588, 0.00033818281255378383],
                   rtol=1e-12)

    assert_close(eq.V_mass(), 1.7581142614915828, rtol=1e-12)
    assert_close(eq.bulk.V_mass(), 1.7581142614915828, rtol=1e-12)
    assert_close1d([i.V_mass() for i in eq.phases],
                   [4.393047260446541, 0.0014922621882770006],
                   rtol=1e-12)

    # MW air may be adjusted in the future
    SG_gas_expect = 1.10647130731458
    assert_close(eq.SG_gas(), SG_gas_expect, rtol=1e-5)
    assert_close(eq.bulk.SG_gas(), SG_gas_expect, rtol=1e-5)
    assert_close1d([i.SG_gas() for i in eq.phases], [SG_gas_expect] * 2,
                   rtol=1e-5)

    assert_close(eq.SG(), 0.7951605425835767, rtol=1e-5)
    assert_close(eq.bulk.SG(), 0.7951605425835767, rtol=1e-5)
    assert_close1d([i.SG() for i in eq.phases], [0.7951605425835767] * 2,
                   rtol=1e-5)

    # Cp and Cv related
    assert_close(eq.Cp(), 85.30634675113457, rtol=1e-12)
    assert_close(eq.bulk.Cp(), 85.30634675113457, rtol=1e-12)
    assert_close1d([i.Cp() for i in eq.phases],
                   [44.63182543018587, 112.42269429843371],
                   rtol=1e-12)

    assert_close(eq.Cp_mass(), 2662.340661595006, rtol=1e-12)
    assert_close(eq.bulk.Cp_mass(), 2662.340661595006, rtol=1e-12)
    assert_close1d([i.Cp_mass() for i in eq.phases],
                   [1392.9224280421258, 3508.6194839635937],
                   rtol=1e-12)

    assert_close(eq.Cv(), 65.77441970078021, rtol=1e-12)
    assert_close(eq.bulk.Cv(), 65.77441970078021, rtol=1e-12)
    assert_close1d([i.Cv() for i in eq.phases],
                   [36.18313355107219, 79.87072617335762],
                   rtol=1e-12)

    assert_close(eq.Cp_Cv_ratio(), 1.2969532401685737, rtol=1e-12)
    assert_close(eq.bulk.Cp_Cv_ratio(), 1.2969532401685737, rtol=1e-12)
    assert_close1d([i.Cp_Cv_ratio() for i in eq.phases],
                   [1.2334980707845113, 1.4075581841389895],
                   rtol=1e-12)

    assert_close(eq.Cv_mass(), 2052.765341986396, rtol=1e-12)
    assert_close(eq.bulk.Cv_mass(), 2052.765341986396, rtol=1e-12)
    assert_close1d([i.Cv_mass() for i in eq.phases],
                   [1129.2457289018862, 2492.699430474936],
                   rtol=1e-12)

    # ideal gas properties
    assert_close(eq.V_ideal_gas(), 0.14138759968016104, rtol=1e-12)
    assert_close(eq.bulk.V_ideal_gas(), 0.14138759968016104, rtol=1e-12)
    assert_close1d([i.V_ideal_gas() for i in eq.phases],
                   [0.14138759968016104] * 2,
                   rtol=1e-12)

    assert_close(eq.Cp_ideal_gas(), 44.47452555993428, rtol=1e-12)
    assert_close(eq.bulk.Cp_ideal_gas(), 44.47452555993428, rtol=1e-12)
    assert_close1d([i.Cp_ideal_gas() for i in eq.phases],
                   [44.47452555993428] * 2,
                   rtol=1e-12)

    assert_close(eq.Cv_ideal_gas(), 36.160062941781035, rtol=1e-12)
    assert_close(eq.bulk.Cv_ideal_gas(), 36.160062941781035, rtol=1e-12)
    assert_close1d([i.Cv_ideal_gas() for i in eq.phases],
                   [36.160062941781035] * 2,
                   rtol=1e-12)

    assert_close(eq.Cp_Cv_ratio_ideal_gas(), 1.229934959779794, rtol=1e-12)
    assert_close(eq.bulk.Cp_Cv_ratio_ideal_gas(),
                 1.229934959779794,
                 rtol=1e-12)
    assert_close1d([i.Cp_Cv_ratio_ideal_gas() for i in eq.phases],
                   [1.229934959779794] * 2,
                   rtol=1e-12)

    assert_close(eq.H_ideal_gas(), 82.17715909331491, rtol=1e-12)
    assert_close(eq.bulk.H_ideal_gas(), 82.17715909331491, rtol=1e-12)
    assert_close1d([i.H_ideal_gas() for i in eq.phases],
                   [82.17715909331491] * 2,
                   rtol=1e-12)

    assert_close(eq.S_ideal_gas(), 14.808945043469695, rtol=1e-12)
    assert_close(eq.bulk.S_ideal_gas(), 14.808945043469695, rtol=1e-12)
    assert_close1d([i.S_ideal_gas() for i in eq.phases],
                   [14.808945043469695] * 2,
                   rtol=1e-12)

    assert_close(eq.G_ideal_gas(), -4360.506353947593, rtol=1e-12)
    assert_close(eq.bulk.G_ideal_gas(), -4360.506353947593, rtol=1e-12)
    assert_close1d([i.G_ideal_gas() for i in eq.phases],
                   [-4360.506353947593] * 2,
                   rtol=1e-12)

    assert_close(eq.A_ideal_gas(), -6854.845139393565, rtol=1e-12)
    assert_close(eq.bulk.A_ideal_gas(), -6854.845139393565, rtol=1e-12)
    assert_close1d([i.A_ideal_gas() for i in eq.phases],
                   [-6854.845139393565] * 2,
                   rtol=1e-12)

    assert_close(eq.U_ideal_gas(), -2412.161626352657, rtol=1e-12)
    assert_close(eq.bulk.U_ideal_gas(), -2412.161626352657, rtol=1e-12)
    assert_close1d([i.U_ideal_gas() for i in eq.phases],
                   [-2412.161626352657] * 2,
                   rtol=1e-12)

    # Ideal formation basis

    assert_close(eq.H_formation_ideal_gas(), -200700.0, rtol=1e-12)
    assert_close(eq.bulk.H_formation_ideal_gas(), -200700.0, rtol=1e-12)
    assert_close1d([i.H_formation_ideal_gas() for i in eq.phases],
                   [-200700.0] * 2,
                   rtol=1e-12)

    assert_close(eq.S_formation_ideal_gas(), -129.8, rtol=1e-12)
    assert_close(eq.bulk.S_formation_ideal_gas(), -129.8, rtol=1e-12)
    assert_close1d([i.S_formation_ideal_gas() for i in eq.phases],
                   [-129.8] * 2,
                   rtol=1e-12)

    assert_close(eq.G_formation_ideal_gas(), -162000.13, rtol=1e-12)
    assert_close(eq.bulk.G_formation_ideal_gas(), -162000.13, rtol=1e-12)
    assert_close1d([i.G_formation_ideal_gas() for i in eq.phases],
                   [-162000.13] * 2,
                   rtol=1e-12)

    assert_close(eq.U_formation_ideal_gas(), -215026.0985375923, rtol=1e-12)
    assert_close(eq.bulk.U_formation_ideal_gas(),
                 -215026.0985375923,
                 rtol=1e-12)
    assert_close1d([i.U_formation_ideal_gas() for i in eq.phases],
                   [-215026.0985375923] * 2,
                   rtol=1e-12)

    assert_close(eq.A_formation_ideal_gas(), -176326.22853759234, rtol=1e-12)
    assert_close(eq.bulk.A_formation_ideal_gas(),
                 -176326.22853759234,
                 rtol=1e-12)
    assert_close1d([i.A_formation_ideal_gas() for i in eq.phases],
                   [-176326.22853759234] * 2,
                   rtol=1e-12)

    # Pseudo critical properties
    assert_close(eq.pseudo_Tc(), constants.Tcs[0], rtol=1e-12)
    assert_close(eq.bulk.pseudo_Tc(), constants.Tcs[0], rtol=1e-12)
    assert_close1d([i.pseudo_Tc() for i in eq.phases], [constants.Tcs[0]] * 2,
                   rtol=1e-12)

    assert_close(eq.pseudo_Pc(), constants.Pcs[0], rtol=1e-12)
    assert_close(eq.bulk.pseudo_Pc(), constants.Pcs[0], rtol=1e-12)
    assert_close1d([i.pseudo_Pc() for i in eq.phases], [constants.Pcs[0]] * 2,
                   rtol=1e-12)

    assert_close(eq.pseudo_Vc(), constants.Vcs[0], rtol=1e-12)
    assert_close(eq.bulk.pseudo_Vc(), constants.Vcs[0], rtol=1e-12)
    assert_close1d([i.pseudo_Vc() for i in eq.phases], [constants.Vcs[0]] * 2,
                   rtol=1e-12)

    assert_close(eq.pseudo_Zc(), constants.Zcs[0], rtol=1e-12)
    assert_close(eq.bulk.pseudo_Zc(), constants.Zcs[0], rtol=1e-12)
    assert_close1d([i.pseudo_Zc() for i in eq.phases], [constants.Zcs[0]] * 2,
                   rtol=1e-12)

    # Standard volumes
    V_std_expect = 0.023690417461829063
    assert_close(eq.V_gas_standard(), V_std_expect, rtol=1e-12)
    assert_close(eq.bulk.V_gas_standard(), V_std_expect, rtol=1e-12)
    assert_close1d([i.V_gas_standard() for i in eq.phases], [V_std_expect] * 2,
                   rtol=1e-12)

    V_std_expect = 0.02364483003622853
    assert_close(eq.V_gas_normal(), V_std_expect, rtol=1e-12)
    assert_close(eq.bulk.V_gas_normal(), V_std_expect, rtol=1e-12)
    assert_close1d([i.V_gas_normal() for i in eq.phases], [V_std_expect] * 2,
                   rtol=1e-12)

    # Combustion properties
    Hc_expect = -764464.0
    assert_close(eq.Hc(), Hc_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc(), Hc_expect, rtol=1e-12)
    assert_close1d([i.Hc() for i in eq.phases], [Hc_expect] * 2, rtol=1e-12)

    Hc_mass_expect = -23858290.373904638
    assert_close(eq.Hc_mass(), Hc_mass_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_mass(), Hc_mass_expect, rtol=1e-12)
    assert_close1d([i.Hc_mass() for i in eq.phases], [Hc_mass_expect] * 2,
                   rtol=1e-12)

    Hc_lower_expect = -676489.1
    assert_close(eq.Hc_lower(), Hc_lower_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_lower(), Hc_lower_expect, rtol=1e-12)
    assert_close1d([i.Hc_lower() for i in eq.phases], [Hc_lower_expect] * 2,
                   rtol=1e-12)

    Hc_lower_mass_expect = -21112666.368306957
    assert_close(eq.Hc_lower_mass(), Hc_lower_mass_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_lower_mass(), Hc_lower_mass_expect, rtol=1e-12)
    assert_close1d([i.Hc_lower_mass() for i in eq.phases],
                   [Hc_lower_mass_expect] * 2,
                   rtol=1e-12)

    # Volume combustion properties
    Hc_normal_expect = -32331126.881804217
    assert_close(eq.Hc_normal(), Hc_normal_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_normal(), Hc_normal_expect, rtol=1e-12)
    assert_close1d([i.Hc_normal() for i in eq.phases], [Hc_normal_expect] * 2,
                   rtol=1e-12)

    Hc_standard_expect = -32268912.155378208
    assert_close(eq.Hc_standard(), Hc_standard_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_standard(), Hc_standard_expect, rtol=1e-12)
    assert_close1d([i.Hc_standard() for i in eq.phases],
                   [Hc_standard_expect] * 2,
                   rtol=1e-12)

    Hc_lower_normal_expect = -28610444.607277177
    assert_close(eq.Hc_lower_normal(), Hc_lower_normal_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_lower_normal(), Hc_lower_normal_expect, rtol=1e-12)
    assert_close1d([i.Hc_lower_normal() for i in eq.phases],
                   [Hc_lower_normal_expect] * 2,
                   rtol=1e-12)

    Hc_lower_standard_expect = -28555389.582728375
    assert_close(eq.Hc_lower_standard(), Hc_lower_standard_expect, rtol=1e-12)
    assert_close(eq.bulk.Hc_lower_standard(),
                 Hc_lower_standard_expect,
                 rtol=1e-12)
    assert_close1d([i.Hc_lower_standard() for i in eq.phases],
                   [Hc_lower_standard_expect] * 2,
                   rtol=1e-12)

    # Wobbe index
    Wobbe_index_expect = 726753.2127139702
    assert_close(eq.Wobbe_index(), Wobbe_index_expect, rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index(), Wobbe_index_expect, rtol=1e-12)
    assert_close1d([i.Wobbe_index() for i in eq.phases],
                   [Wobbe_index_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_lower_expect = 643118.0890022058
    assert_close(eq.Wobbe_index_lower(), Wobbe_index_lower_expect, rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_lower(),
                 Wobbe_index_lower_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_lower() for i in eq.phases],
                   [Wobbe_index_lower_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_mass_expect = 22681367.83301501
    assert_close(eq.Wobbe_index_mass(), Wobbe_index_mass_expect, rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_mass(),
                 Wobbe_index_mass_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_mass() for i in eq.phases],
                   [Wobbe_index_mass_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_lower_mass_expect = 20071184.6628818
    assert_close(eq.Wobbe_index_lower_mass(),
                 Wobbe_index_lower_mass_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_lower_mass(),
                 Wobbe_index_lower_mass_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_lower_mass() for i in eq.phases],
                   [Wobbe_index_lower_mass_expect] * 2,
                   rtol=1e-12)

    # Wobbe index volume properties
    Wobbe_index_standard_expect = 30677096.082622595
    assert_close(eq.Wobbe_index_standard(),
                 Wobbe_index_standard_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_standard(),
                 Wobbe_index_standard_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_standard() for i in eq.phases],
                   [Wobbe_index_standard_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_normal_expect = 30736241.774647623
    assert_close(eq.Wobbe_index_normal(),
                 Wobbe_index_normal_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_normal(),
                 Wobbe_index_normal_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_normal() for i in eq.phases],
                   [Wobbe_index_normal_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_lower_standard_expect = 27146760.50088282
    assert_close(eq.Wobbe_index_lower_standard(),
                 Wobbe_index_lower_standard_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_lower_standard(),
                 Wobbe_index_lower_standard_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_lower_standard() for i in eq.phases],
                   [Wobbe_index_lower_standard_expect] * 2,
                   rtol=1e-12)

    Wobbe_index_lower_normal_expect = 27199099.677046627
    assert_close(eq.Wobbe_index_lower_normal(),
                 Wobbe_index_lower_normal_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.Wobbe_index_lower_normal(),
                 Wobbe_index_lower_normal_expect,
                 rtol=1e-12)
    assert_close1d([i.Wobbe_index_lower_normal() for i in eq.phases],
                   [Wobbe_index_lower_normal_expect] * 2,
                   rtol=1e-12)

    # Mechanical critical point - these have an inner solver
    Tmc_expect = 512.5
    assert_close(eq.Tmc(), Tmc_expect, rtol=1e-12)
    assert_close(eq.bulk.Tmc(), Tmc_expect, rtol=1e-12)
    assert_close1d([i.Tmc() for i in eq.phases], [Tmc_expect] * 2, rtol=1e-12)

    Pmc_expect = 8084000.0
    assert_close(eq.Pmc(), Pmc_expect, rtol=1e-12)
    assert_close(eq.bulk.Pmc(), Pmc_expect, rtol=1e-12)
    assert_close1d([i.Pmc() for i in eq.phases], [Pmc_expect] * 2, rtol=1e-12)

    # The solver tolerance here is loose
    Vmc_expect = 0.00016203642168563802
    assert_close(eq.Vmc(), Vmc_expect, rtol=1e-4)
    assert_close(eq.bulk.Vmc(), Vmc_expect, rtol=1e-4)
    assert_close1d([i.Vmc() for i in eq.phases], [Vmc_expect] * 2, rtol=1e-4)

    # The solver tolerance here is loose
    Zmc_expect = 0.30740497655001947
    assert_close(eq.Zmc(), Zmc_expect, rtol=1e-4)
    assert_close(eq.bulk.Zmc(), Zmc_expect, rtol=1e-4)
    assert_close1d([i.Zmc() for i in eq.phases], [Zmc_expect] * 2, rtol=1e-4)

    # Properties calculated form derivatives
    assert_close(eq.isobaric_expansion(), 0.002008218029645217, rtol=1e-12)
    assert_close(eq.bulk.isobaric_expansion(),
                 0.002008218029645217,
                 rtol=1e-12)
    assert_close1d([i.isobaric_expansion() for i in eq.phases],
                   [0.0033751089225799308, 0.0010969574343554077],
                   rtol=1e-12)

    assert_close(eq.kappa(), 2.277492845010776e-05, rtol=1e-12)
    assert_close(eq.bulk.kappa(), 2.277492845010776e-05, rtol=1e-12)
    assert_close1d([i.kappa() for i in eq.phases],
                   [5.693652573977374e-05, 5.302569971013028e-10],
                   rtol=1e-12)

    assert_close(eq.Joule_Thomson(), 1.563918814309498e-05, rtol=1e-12)
    assert_close(eq.bulk.Joule_Thomson(), 1.563918814309498e-05, rtol=1e-12)
    assert_close1d([i.Joule_Thomson() for i in eq.phases],
                   [3.9525992445522226e-05, -2.853480585231828e-07],
                   rtol=1e-12)

    assert_close(eq.speed_of_sound(), 235.8471087474984, rtol=1e-12)
    assert_close(eq.bulk.speed_of_sound(), 235.8471087474984, rtol=1e-12)
    assert_close1d([i.speed_of_sound() for i in eq.phases],
                   [55.22243501081154, 356.26355790528964],
                   rtol=1e-12)

    assert_close(eq.speed_of_sound_mass(), 1317.5639311230432, rtol=1e-12)
    assert_close(eq.bulk.speed_of_sound_mass(), 1317.5639311230432, rtol=1e-12)
    assert_close1d([i.speed_of_sound_mass() for i in eq.phases],
                   [308.5010833731638, 1990.2724962896298],
                   rtol=1e-12)

    # Departure properties
    assert_close(eq.H_dep(), -24186.9377252872, rtol=1e-12)
    assert_close(eq.bulk.H_dep(), -24186.9377252872, rtol=1e-12)
    assert_close1d([i.H_dep() for i in eq.phases],
                   [-30.99680147049139, -40290.898341165004],
                   rtol=1e-12)

    assert_close(eq.S_dep(), -80.58637166498106, rtol=1e-12)
    assert_close(eq.bulk.S_dep(), -80.58637166498106, rtol=1e-12)
    assert_close1d([i.S_dep() for i in eq.phases],
                   [-0.0665685855920503, -134.26624038457373],
                   rtol=1e-12)

    assert_close(eq.G_dep(), -11.026225792880723, rtol=1e-9)
    assert_close(eq.bulk.G_dep(), -11.026225792880723, rtol=1e-9)
    assert_close1d([i.G_dep() for i in eq.phases],
                   [-11.026225792876303, -11.026225792884361],
                   rtol=1e-9)

    assert_close(eq.U_dep(), -22686.421688611586, rtol=1e-9)
    assert_close(eq.bulk.U_dep(), -22686.421688611586, rtol=1e-9)
    assert_close1d([i.U_dep() for i in eq.phases],
                   [-19.949574191534843, -37797.40309822495],
                   rtol=1e-9)

    assert_close(eq.A_dep(), 1489.4898108827329, rtol=1e-9)
    assert_close(eq.bulk.A_dep(), 1489.4898108827329, rtol=1e-9)
    assert_close1d([i.A_dep() for i in eq.phases],
                   [0.021001486080244547, 2482.4690171471666],
                   rtol=1e-9)

    assert_close(eq.Cp_dep(), 40.83182119120029, rtol=1e-9)
    assert_close(eq.bulk.Cp_dep(), 40.83182119120029, rtol=1e-9)
    assert_close1d([i.Cp_dep() for i in eq.phases],
                   [0.1572998702515953, 67.94816873849943],
                   rtol=1e-9)

    assert_close(eq.Cv_dep(), 29.61435675899918, rtol=1e-12)
    assert_close(eq.bulk.Cv_dep(), 29.61435675899918, rtol=1e-12)
    assert_close1d([i.Cv_dep() for i in eq.phases],
                   [0.023070609291153232, 43.71066323157659],
                   rtol=1e-12)

    # Standard liquid density
    rho_mass_liquid_ref_expect = 784.8585085234012
    assert_close(eq.rho_mass_liquid_ref(),
                 rho_mass_liquid_ref_expect,
                 rtol=1e-12)
    assert_close(eq.bulk.rho_mass_liquid_ref(),
                 rho_mass_liquid_ref_expect,
                 rtol=1e-12)
    assert_close1d([i.rho_mass_liquid_ref() for i in eq.phases],
                   [rho_mass_liquid_ref_expect] * 2,
                   rtol=1e-12)

    V_liquid_ref_expect = 4.0825014511573776e-05
    assert_close(eq.V_liquid_ref(), V_liquid_ref_expect, rtol=1e-12)
    assert_close(eq.bulk.V_liquid_ref(), V_liquid_ref_expect, rtol=1e-12)
    assert_close1d([i.V_liquid_ref() for i in eq.phases],
                   [V_liquid_ref_expect] * 2,
                   rtol=1e-12)

    # Water contect
    assert_close(eq.molar_water_content(), 0, atol=0)
    assert_close(eq.bulk.molar_water_content(), 0, atol=0)
    assert_close1d([i.molar_water_content() for i in eq.phases], [0] * 2,
                   atol=0)

    assert_close1d(eq.zs_no_water(), [1], atol=0)
    assert_close1d(eq.bulk.zs_no_water(), [1], atol=0)
    assert_close2d([i.zs_no_water() for i in eq.phases], [[1.0]] * 2, atol=0)

    assert_close1d(eq.ws_no_water(), [1], atol=0)
    assert_close1d(eq.bulk.ws_no_water(), [1], atol=0)
    assert_close2d([i.ws_no_water() for i in eq.phases], [[1.0]] * 2, atol=0)

    # H/C ratio
    assert_close(eq.H_C_ratio(), 4, atol=0)
    assert_close(eq.bulk.H_C_ratio(), 4, atol=0)
    assert_close1d([i.H_C_ratio() for i in eq.phases], [4] * 2, atol=0)

    assert_close(eq.H_C_ratio_mass(), 0.3356806847227889, rtol=1e-12)
    assert_close(eq.bulk.H_C_ratio_mass(), 0.3356806847227889, rtol=1e-12)
    assert_close1d([i.H_C_ratio_mass() for i in eq.phases],
                   [0.3356806847227889] * 2,
                   rtol=1e-12)