def Tautoignition(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval or calculation of a chemical's
    autoifnition temperature. Lookup is based on CASRNs. No predictive methods
    are currently implemented. Will automatically select a data source to use
    if no Method is provided; returns None if the data is not available.

    Prefered source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
    'NFPA 497 (2008)' [2]_ having very similar data.

    Examples
    --------
    >>> Tautoignition(CASRN='71-43-2')
    771.15

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

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

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

    Notes
    -----

    References
    ----------
    .. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
       Material characteristics for gas and vapour classification - Test
       methods and data.” https://webstore.iec.ch/publication/635. See also
       https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
    .. [2] National Fire Protection Association. NFPA 497: Recommended
       Practice for the Classification of Flammable Liquids, Gases, or Vapors
       and of Hazardous. NFPA, 2008.
    '''
    def list_methods():
        methods = []
        if CASRN in IEC_2010.index and not np.isnan(IEC_2010.at[CASRN, 'Tautoignition']):
            methods.append(IEC)
        if CASRN in NFPA_2008.index and not np.isnan(NFPA_2008.at[CASRN, 'Tautoignition']):
            methods.append(NFPA)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == IEC:
        return float(IEC_2010.at[CASRN, 'Tautoignition'])
    elif Method == NFPA:
        return float(NFPA_2008.at[CASRN, 'Tautoignition'])
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
Tautoignition
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
IEC_2010
.
index
and
not
np
.
isnan
(
IEC_2010
.
at
[
CASRN
,
'Tautoignition'
]
)
:
methods
.
append
(
IEC
)
if
CASRN
in
NFPA_2008
.
index
and
not
np
.
isnan
(
NFPA_2008
.
at
[
CASRN
,
'Tautoignition'
]
)
:
methods
.
append
(
NFPA
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
IEC
:
return
float
(
IEC_2010
.
at
[
CASRN
,
'Tautoignition'
]
)
elif
Method
==
NFPA
:
return
float
(
NFPA_2008
.
at
[
CASRN
,
'Tautoignition'
]
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval or calculation of a chemical s autoifnition temperature . Lookup is based on CASRNs . No predictive methods are currently implemented . Will automatically select a data source to use if no Method is provided ; returns None if the data is not available .


def LFL(Hc=None, atoms={}, CASRN='', AvailableMethods=False, Method=None):
    r'''This function handles the retrieval or calculation of a chemical's
    Lower Flammability Limit. Lookup is based on CASRNs. Two predictive methods
    are currently implemented. Will automatically select a data source to use
    if no Method is provided; returns None if the data is not available.

    Prefered source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
    'NFPA 497 (2008)' [2]_ having very similar data. If the heat of combustion
    is provided, the estimation method `Suzuki_LFL` can be used. If the atoms
    of the molecule are available, the method `Crowl_Louvar_LFL` can be used.

    Examples
    --------
    >>> LFL(CASRN='71-43-2')
    0.012

    Parameters
    ----------
    Hc : float, optional
        Heat of combustion of gas [J/mol]
    atoms : dict, optional
        Dictionary of atoms and atom counts
    CASRN : string, optional
        CASRN [-]

    Returns
    -------
    LFL : float
        Lower flammability limit of the gas in an atmosphere at STP, [mole fraction]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain LFL with the
        given inputs

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

    Notes
    -----

    References
    ----------
    .. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
       Material characteristics for gas and vapour classification - Test
       methods and data.” https://webstore.iec.ch/publication/635. See also
       https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
    .. [2] National Fire Protection Association. NFPA 497: Recommended
       Practice for the Classification of Flammable Liquids, Gases, or Vapors
       and of Hazardous. NFPA, 2008.
    '''
    def list_methods():
        methods = []
        if CASRN in IEC_2010.index and not np.isnan(IEC_2010.at[CASRN, 'LFL']):
            methods.append(IEC)
        if CASRN in NFPA_2008.index and not np.isnan(NFPA_2008.at[CASRN, 'LFL']):
            methods.append(NFPA)
        if Hc:
            methods.append(SUZUKI)
        if atoms:
            methods.append(CROWLLOUVAR)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == IEC:
        return float(IEC_2010.at[CASRN, 'LFL'])
    elif Method == NFPA:
        return float(NFPA_2008.at[CASRN, 'LFL'])
    elif Method == SUZUKI:
        return Suzuki_LFL(Hc=Hc)
    elif Method == CROWLLOUVAR:
        return Crowl_Louvar_LFL(atoms=atoms)
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
LFL
(
Hc
=
,
atoms
=
{
}
,
CASRN
=
''
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
IEC_2010
.
index
and
not
np
.
isnan
(
IEC_2010
.
at
[
CASRN
,
'LFL'
]
)
:
methods
.
append
(
IEC
)
if
CASRN
in
NFPA_2008
.
index
and
not
np
.
isnan
(
NFPA_2008
.
at
[
CASRN
,
'LFL'
]
)
:
methods
.
append
(
NFPA
)
if
Hc
:
methods
.
append
(
SUZUKI
)
if
atoms
:
methods
.
append
(
CROWLLOUVAR
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
IEC
:
return
float
(
IEC_2010
.
at
[
CASRN
,
'LFL'
]
)
elif
Method
==
NFPA
:
return
float
(
NFPA_2008
.
at
[
CASRN
,
'LFL'
]
)
elif
Method
==
SUZUKI
:
return
Suzuki_LFL
(
Hc
=
Hc
)
elif
Method
==
CROWLLOUVAR
:
return
Crowl_Louvar_LFL
(
atoms
=
atoms
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval or calculation of a chemical s Lower Flammability Limit . Lookup is based on CASRNs . Two predictive methods are currently implemented . Will automatically select a data source to use if no Method is provided ; returns None if the data is not available .


def UFL(Hc=None, atoms={}, CASRN='', AvailableMethods=False, Method=None):
    r'''This function handles the retrieval or calculation of a chemical's
    Upper Flammability Limit. Lookup is based on CASRNs. Two predictive methods
    are currently implemented. Will automatically select a data source to use
    if no Method is provided; returns None if the data is not available.

    Prefered source is 'IEC 60079-20-1 (2010)' [1]_, with the secondary source
    'NFPA 497 (2008)' [2]_ having very similar data. If the heat of combustion
    is provided, the estimation method `Suzuki_UFL` can be used. If the atoms
    of the molecule are available, the method `Crowl_Louvar_UFL` can be used.

    Examples
    --------
    >>> UFL(CASRN='71-43-2')
    0.086

    Parameters
    ----------
    Hc : float, optional
        Heat of combustion of gas [J/mol]
    atoms : dict, optional
        Dictionary of atoms and atom counts
    CASRN : string, optional
        CASRN [-]

    Returns
    -------
    UFL : float
        Upper flammability limit of the gas in an atmosphere at STP, [mole fraction]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain UFL with the
        given inputs

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

    Notes
    -----

    References
    ----------
    .. [1] IEC. “IEC 60079-20-1:2010 Explosive atmospheres - Part 20-1:
       Material characteristics for gas and vapour classification - Test
       methods and data.” https://webstore.iec.ch/publication/635. See also
       https://law.resource.org/pub/in/bis/S05/is.iec.60079.20.1.2010.pdf
    .. [2] National Fire Protection Association. NFPA 497: Recommended
       Practice for the Classification of Flammable Liquids, Gases, or Vapors
       and of Hazardous. NFPA, 2008.
    '''
    def list_methods():
        methods = []
        if CASRN in IEC_2010.index and not np.isnan(IEC_2010.at[CASRN, 'UFL']):
            methods.append(IEC)
        if CASRN in NFPA_2008.index and not np.isnan(NFPA_2008.at[CASRN, 'UFL']):
            methods.append(NFPA)
        if Hc:
            methods.append(SUZUKI)
        if atoms:
            methods.append(CROWLLOUVAR)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == IEC:
        return float(IEC_2010.at[CASRN, 'UFL'])
    elif Method == NFPA:
        return float(NFPA_2008.at[CASRN, 'UFL'])
    elif Method == SUZUKI:
        return Suzuki_UFL(Hc=Hc)
    elif Method == CROWLLOUVAR:
        return Crowl_Louvar_UFL(atoms=atoms)
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
UFL
(
Hc
=
,
atoms
=
{
}
,
CASRN
=
''
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
IEC_2010
.
index
and
not
np
.
isnan
(
IEC_2010
.
at
[
CASRN
,
'UFL'
]
)
:
methods
.
append
(
IEC
)
if
CASRN
in
NFPA_2008
.
index
and
not
np
.
isnan
(
NFPA_2008
.
at
[
CASRN
,
'UFL'
]
)
:
methods
.
append
(
NFPA
)
if
Hc
:
methods
.
append
(
SUZUKI
)
if
atoms
:
methods
.
append
(
CROWLLOUVAR
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
IEC
:
return
float
(
IEC_2010
.
at
[
CASRN
,
'UFL'
]
)
elif
Method
==
NFPA
:
return
float
(
NFPA_2008
.
at
[
CASRN
,
'UFL'
]
)
elif
Method
==
SUZUKI
:
return
Suzuki_UFL
(
Hc
=
Hc
)
elif
Method
==
CROWLLOUVAR
:
return
Crowl_Louvar_UFL
(
atoms
=
atoms
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval or calculation of a chemical s Upper Flammability Limit . Lookup is based on CASRNs . Two predictive methods are currently implemented . Will automatically select a data source to use if no Method is provided ; returns None if the data is not available .


def atom_fractions(self):
        r'''Dictionary of atomic fractions for each atom in the mixture.

        Examples
        --------
        >>> Mixture(['CO2', 'O2'], zs=[0.5, 0.5]).atom_fractions
        {'C': 0.2, 'O': 0.8}
        '''
        things = dict()
        for zi, atoms in zip(self.zs, self.atomss):
            for atom, count in atoms.iteritems():
                if atom in things:
                    things[atom] += zi*count
                else:
                    things[atom] = zi*count

        tot = sum(things.values())
        return {atom : value/tot for atom, value in things.iteritems()}

def atom_fractions ( self ) : things = dict ( ) for zi , atoms in zip ( self . zs , self . atomss ) : for atom , count in atoms . iteritems ( ) : if atom in things : things [ atom ] += zi * count else : things [ atom ] = zi * count tot = sum ( things . values ( ) ) return { atom : value / tot for atom , value in things . iteritems ( ) }

r Dictionary of atomic fractions for each atom in the mixture .


def mass_fractions(self):
        r'''Dictionary of mass fractions for each atom in the mixture.

        Examples
        --------
        >>> Mixture(['CO2', 'O2'], zs=[0.5, 0.5]).mass_fractions
        {'C': 0.15801826905745822, 'O': 0.8419817309425419}
        '''
        things = dict()
        for zi, atoms in zip(self.zs, self.atomss):
            for atom, count in atoms.iteritems():
                if atom in things:
                    things[atom] += zi*count
                else:
                    things[atom] = zi*count
        return mass_fractions(things)

def mass_fractions ( self ) : things = dict ( ) for zi , atoms in zip ( self . zs , self . atomss ) : for atom , count in atoms . iteritems ( ) : if atom in things : things [ atom ] += zi * count else : things [ atom ] = zi * count return mass_fractions ( things )

r Dictionary of mass fractions for each atom in the mixture .


def draw_2d(self,  Hs=False): # pragma: no cover
        r'''Interface for drawing a 2D image of all the molecules in the
        mixture. Requires an HTML5 browser, and the libraries RDKit and
        IPython. An exception is raised if either of these libraries is
        absent.

        Parameters
        ----------
        Hs : bool
            Whether or not to show hydrogen

        Examples
        --------
        Mixture(['natural gas']).draw_2d()
        '''
        try:
            from rdkit.Chem import Draw
            from rdkit.Chem.Draw import IPythonConsole
            if Hs:
                mols = [i.rdkitmol_Hs for i in self.Chemicals]
            else:
                mols = [i.rdkitmol for i in self.Chemicals]
            return Draw.MolsToImage(mols)
        except:
            return 'Rdkit is required for this feature.'

def
draw_2d
(
self
,
Hs
=
False
)
:
# pragma: no cover
try
:
from
rdkit
.
Chem
import
Draw
from
rdkit
.
Chem
.
Draw
import
IPythonConsole
if
Hs
:
mols
=
[
i
.
rdkitmol_Hs
for
i
in
self
.
Chemicals
]
else
:
mols
=
[
i
.
rdkitmol
for
i
in
self
.
Chemicals
]
return
Draw
.
MolsToImage
(
mols
)
except
:
return
'Rdkit is required for this feature.'

r Interface for drawing a 2D image of all the molecules in the mixture . Requires an HTML5 browser and the libraries RDKit and IPython . An exception is raised if either of these libraries is absent .


def Tt(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval of a chemical's triple temperature.
    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 a chemical's melting point if available.

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

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

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

    Notes
    -----
    Median difference between melting points and triple points is 0.02 K.
    Accordingly, this should be more than good enough for engineering
    applications.

    Temperatures are on the ITS-68 scale.

    Examples
    --------
    Ammonia

    >>> Tt('7664-41-7')
    195.47999999999999

    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:
            methods.append(STAVELEY)
        if Tm(CASRN):
            methods.append(MELTING)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == STAVELEY:
        Tt = Staveley_data.at[CASRN, "Tt68"]
    elif Method == MELTING:
        Tt = Tm(CASRN)
    elif Method == NONE:
        Tt = None
    else:
        raise Exception('Failure in in function')
    return Tt

def
Tt
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
Staveley_data
.
index
:
methods
.
append
(
STAVELEY
)
if
Tm
(
CASRN
)
:
methods
.
append
(
MELTING
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
STAVELEY
:
Tt
=
Staveley_data
.
at
[
CASRN
,
"Tt68"
]
elif
Method
==
MELTING
:
Tt
=
Tm
(
CASRN
)
elif
Method
==
:
Tt
=
else
:
raise
Exception
(
'Failure in in function'
)
return
Tt

r This function handles the retrieval of a chemical s triple temperature . 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 .


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

def
Pt
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
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
(
)
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
==
:
Pt
=
else
:
raise
Exception
(
'Failure in in function'
)
return
Pt

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 .


def Parachor(MW, rhol, rhog, sigma):
    r'''Calculate Parachor for a pure species, using its density in the
    liquid and gas phases, surface tension, and molecular weight.

    .. math::
        P = \frac{\sigma^{0.25} MW}{\rho_L - \rho_V}

    Parameters
    ----------
    MW : float
        Molecular weight, [g/mol]
    rhol : float
        Liquid density [kg/m^3]
    rhog : float
        Gas density [kg/m^3]
    sigma : float
        Surface tension, [N/m]

    Returns
    -------
    P : float
        Parachor, [N^0.25*m^2.75/mol]

    Notes
    -----
    To convert the output of this function to units of [mN^0.25*m^2.75/kmol],
    multiply by 5623.4132519.

    Values in group contribution tables for Parachor are often listed as
    dimensionless, in which they are multiplied by 5623413 and the appropriate
    units to make them dimensionless.

    Examples
    --------
    Calculating Parachor from a known surface tension for methyl isobutyl
    ketone at 293.15 K

    >>> Parachor(100.15888, 800.8088185536124, 4.97865317223119, 0.02672166960656005)
    5.088443542210164e-05

    Converting to the `dimensionless` form:

    >>> 5623413*5.088443542210164e-05
    286.14419565030687

    Compared to 274.9 according to a group contribution method described in
    [3]_.

    References
    ----------
    .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition.
       New York: McGraw-Hill Professional, 2000.
    .. [2] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,
       8E. McGraw-Hill Professional, 2007.
    .. [3] Danner, Ronald P, and Design Institute for Physical Property Data.
       Manual for Predicting Chemical Process Design Data. New York, N.Y, 1982.
    '''
    rhol, rhog = rhol*1000., rhog*1000. # Convert kg/m^3 to g/m^3
    return sigma**0.25*MW/(rhol-rhog)

def
Parachor
(
MW
,
rhol
,
rhog
,
sigma
)
:
rhol
,
rhog
=
rhol
*
1000.
,
rhog
*
1000.
# Convert kg/m^3 to g/m^3
return
sigma
**
0.25
*
MW
/
(
rhol
rhog
)

r Calculate Parachor for a pure species using its density in the liquid and gas phases surface tension and molecular weight .


def Joule_Thomson(T, V, Cp, dV_dT=None, beta=None):
    r'''Calculate a real fluid's Joule Thomson coefficient. The required
    derivative should be calculated with an equation of state, and `Cp` is the
    real fluid versions. This can either be calculated with `dV_dT` directly,
    or with `beta` if it is already known.

    .. math::
        \mu_{JT} = \left(\frac{\partial T}{\partial P}\right)_H = \frac{1}{C_p}
        \left[T \left(\frac{\partial V}{\partial T}\right)_P - V\right]
        = \frac{V}{C_p}\left(\beta T-1\right)

    Parameters
    ----------
    T : float
        Temperature of fluid, [K]
    V : float
        Molar volume of fluid, [m^3/mol]
    Cp : float
        Real fluid heat capacity at constant pressure, [J/mol/K]
    dV_dT : float, optional
        Derivative of `V` with respect to `T`, [m^3/mol/K]
    beta : float, optional
        Isobaric coefficient of a thermal expansion, [1/K]

    Returns
    -------
    mu_JT : float
        Joule-Thomson coefficient [K/Pa]

    Examples
    --------
    Example from [2]_:

    >>> Joule_Thomson(T=390, V=0.00229754, Cp=153.235, dV_dT=1.226396e-05)
    1.621956080529905e-05

    References
    ----------
    .. [1] Walas, Stanley M. Phase Equilibria in Chemical Engineering.
       Butterworth-Heinemann, 1985.
    .. [2] Pratt, R. M. "Thermodynamic Properties Involving Derivatives: Using
       the Peng-Robinson Equation of State." Chemical Engineering Education 35,
       no. 2 (March 1, 2001): 112-115.
    '''
    if dV_dT:
        return (T*dV_dT - V)/Cp
    elif beta:
        return V/Cp*(beta*T - 1.)
    else:
        raise Exception('Either dV_dT or beta is needed')

def
Joule_Thomson
(
T
,
V
,
Cp
,
dV_dT
=
,
beta
=
)
:
if
dV_dT
:
return
(
T
*
dV_dT
V
)
/
Cp
elif
beta
:
return
V
/
Cp
*
(
beta
*
T
1.
)
else
:
raise
Exception
(
'Either dV_dT or beta is needed'
)

r Calculate a real fluid s Joule Thomson coefficient . The required derivative should be calculated with an equation of state and Cp is the real fluid versions . This can either be calculated with dV_dT directly or with beta if it is already known .


def Z_from_virial_pressure_form(P, *args):
    r'''Calculates the compressibility factor of a gas given its pressure, and
    pressure-form virial coefficients. Any number of coefficients is supported.

    .. math::
        Z = \frac{Pv}{RT} = 1 + B'P + C'P^2 + D'P^3 + E'P^4 \dots

    Parameters
    ----------
    P : float
        Pressure, [Pa]
    B to Z : float, optional
        Pressure form Virial coefficients, [various]

    Returns
    -------
    Z : float
        Compressibility factor at P, and with given virial coefficients, [-]

    Notes
    -----
    Note that although this function does not require a temperature input, it
    is still dependent on it because the coefficients themselves normally are
    regressed in terms of temperature.

    The use of this form is less common than the density form. Its coefficients
    are normally indicated with the "'" suffix.

    If no virial coefficients are given, returns 1, as per the ideal gas law.

    The units of each virial coefficient are as follows, where for B, n=1, and
    C, n=2, and so on.

    .. math::
        \left(\frac{1}{\text{Pa}}\right)^n

    Examples
    --------
    >>> Z_from_virial_pressure_form(102919.99946855308, 4.032286555169439e-09, 1.6197059494442215e-13, 6.483855042486911e-19)
    1.00283753944

    References
    ----------
    .. [1] Prausnitz, John M., Rudiger N. Lichtenthaler, and Edmundo Gomes de
       Azevedo. Molecular Thermodynamics of Fluid-Phase Equilibria. 3rd
       edition. Upper Saddle River, N.J: Prentice Hall, 1998.
    .. [2] Walas, Stanley M. Phase Equilibria in Chemical Engineering.
       Butterworth-Heinemann, 1985.
    '''
    return 1 + P*sum([coeff*P**i for i, coeff in enumerate(args)])

def Z_from_virial_pressure_form ( P , * args ) : return 1 + P * sum ( [ coeff * P ** i for i , coeff in enumerate ( args ) ] )

r Calculates the compressibility factor of a gas given its pressure and pressure - form virial coefficients . Any number of coefficients is supported .


def zs_to_ws(zs, MWs):
    r'''Converts a list of mole fractions to mass fractions. Requires molecular
    weights for all species.

    .. math::
        w_i = \frac{z_i MW_i}{MW_{avg}}

        MW_{avg} = \sum_i z_i MW_i

    Parameters
    ----------
    zs : iterable
        Mole fractions [-]
    MWs : iterable
        Molecular weights [g/mol]

    Returns
    -------
    ws : iterable
        Mass fractions [-]

    Notes
    -----
    Does not check that the sums add to one. Does not check that inputs are of
    the same length.

    Examples
    --------
    >>> zs_to_ws([0.5, 0.5], [10, 20])
    [0.3333333333333333, 0.6666666666666666]
    '''
    Mavg = sum(zi*MWi for zi, MWi in zip(zs, MWs))
    ws = [zi*MWi/Mavg for zi, MWi in zip(zs, MWs)]
    return ws

def zs_to_ws ( zs , MWs ) : Mavg = sum ( zi * MWi for zi , MWi in zip ( zs , MWs ) ) ws = [ zi * MWi / Mavg for zi , MWi in zip ( zs , MWs ) ] return ws

r Converts a list of mole fractions to mass fractions . Requires molecular weights for all species .


def zs_to_Vfs(zs, Vms):
    r'''Converts a list of mole fractions to volume fractions. Requires molar
    volumes for all species.

    .. math::
        \text{Vf}_i = \frac{z_i V_{m,i}}{\sum_i z_i V_{m,i}}

    Parameters
    ----------
    zs : iterable
        Mole fractions [-]
    VMs : iterable
        Molar volumes of species [m^3/mol]

    Returns
    -------
    Vfs : list
        Molar volume fractions [-]

    Notes
    -----
    Does not check that the sums add to one. Does not check that inputs are of
    the same length.

    Molar volumes are specified in terms of pure components only. Function
    works with any phase.

    Examples
    --------
    Acetone and benzene example

    >>> zs_to_Vfs([0.637, 0.363], [8.0234e-05, 9.543e-05])
    [0.5960229712956298, 0.4039770287043703]
    '''
    vol_is = [zi*Vmi for zi, Vmi in zip(zs, Vms)]
    tot = sum(vol_is)
    return [vol_i/tot for vol_i in vol_is]

def zs_to_Vfs ( zs , Vms ) : vol_is = [ zi * Vmi for zi , Vmi in zip ( zs , Vms ) ] tot = sum ( vol_is ) return [ vol_i / tot for vol_i in vol_is ]

r Converts a list of mole fractions to volume fractions . Requires molar volumes for all species .


def none_and_length_check(all_inputs, length=None):
    r'''Checks inputs for suitability of use by a mixing rule which requires
    all inputs to be of the same length and non-None. A number of variations
    were attempted for this function; this was found to be the quickest.

    Parameters
    ----------
    all_inputs : array-like of array-like
        list of all the lists of inputs, [-]
    length : int, optional
        Length of the desired inputs, [-]

    Returns
    -------
    False/True : bool
        Returns True only if all inputs are the same length (or length `length`)
        and none of the inputs contain None [-]

    Notes
    -----
    Does not check for nan values.

    Examples
    --------
    >>> none_and_length_check(([1, 1], [1, 1], [1, 30], [10,0]), length=2)
    True
    '''
    if not length:
        length = len(all_inputs[0])
    for things in all_inputs:
        if None in things or len(things) != length:
            return False
    return True

def none_and_length_check ( all_inputs , length = None ) : if not length : length = len ( all_inputs [ 0 ] ) for things in all_inputs : if None in things or len ( things ) != length : return False return True

r Checks inputs for suitability of use by a mixing rule which requires all inputs to be of the same length and non - None . A number of variations were attempted for this function ; this was found to be the quickest .


def mixing_simple(fracs, props):
    r'''Simple function calculates a property based on weighted averages of
    properties. Weights could be mole fractions, volume fractions, mass
    fractions, or anything else.

    .. math::
        y = \sum_i \text{frac}_i \cdot \text{prop}_i

    Parameters
    ----------
    fracs : array-like
        Fractions of a mixture
    props: array-like
        Properties

    Returns
    -------
    prop : value
        Calculated property

    Notes
    -----
    Returns None if any fractions or properties are missing or are not of the
    same length.

    Examples
    --------
    >>> mixing_simple([0.1, 0.9], [0.01, 0.02])
    0.019000000000000003
    '''
    if not none_and_length_check([fracs, props]):
        return None
    result = sum(frac*prop for frac, prop in zip(fracs, props))
    return result

def mixing_simple ( fracs , props ) : if not none_and_length_check ( [ fracs , props ] ) : return None result = sum ( frac * prop for frac , prop in zip ( fracs , props ) ) return result

r Simple function calculates a property based on weighted averages of properties . Weights could be mole fractions volume fractions mass fractions or anything else .


def mixing_logarithmic(fracs, props):
    r'''Simple function calculates a property based on weighted averages of
    logarithmic properties.

    .. math::
        y = \sum_i \text{frac}_i \cdot \log(\text{prop}_i)

    Parameters
    ----------
    fracs : array-like
        Fractions of a mixture
    props: array-like
        Properties

    Returns
    -------
    prop : value
        Calculated property

    Notes
    -----
    Does not work on negative values.
    Returns None if any fractions or properties are missing or are not of the
    same length.

    Examples
    --------
    >>> mixing_logarithmic([0.1, 0.9], [0.01, 0.02])
    0.01866065983073615
    '''
    if not none_and_length_check([fracs, props]):
        return None
    return exp(sum(frac*log(prop) for frac, prop in zip(fracs, props)))

def mixing_logarithmic ( fracs , props ) : if not none_and_length_check ( [ fracs , props ] ) : return None return exp ( sum ( frac * log ( prop ) for frac , prop in zip ( fracs , props ) ) )

r Simple function calculates a property based on weighted averages of logarithmic properties .


def phase_select_property(phase=None, s=None, l=None, g=None, V_over_F=None):
    r'''Determines which phase's property should be set as a default, given
    the phase a chemical is, and the property values of various phases. For the
    case of liquid-gas phase, returns None. If the property is not available
    for the current phase, or if the current phase is not known, returns None.

    Parameters
    ----------
    phase : str
        One of {'s', 'l', 'g', 'two-phase'}
    s : float
        Solid-phase property
    l : float
        Liquid-phase property
    g : float
        Gas-phase property
    V_over_F : float
        Vapor phase fraction

    Returns
    -------
    prop : float
        The selected/calculated property for the relevant phase

    Notes
    -----
    Could calculate mole-fraction weighted properties for the two phase regime.
    Could also implement equilibria with solid phases.

    Examples
    --------
    >>> phase_select_property(phase='g', l=1560.14, g=3312.)
    3312.0
    '''
    if phase == 's':
        return s
    elif phase == 'l':
        return l
    elif phase == 'g':
        return g
    elif phase == 'two-phase':
        return None  #TODO: all two-phase properties?
    elif phase is None:
        return None
    else:
        raise Exception('Property not recognized')

def
phase_select_property
(
phase
=
,
s
=
,
l
=
,
g
=
,
V_over_F
=
)
:
if
phase
==
's'
:
return
s
elif
phase
==
'l'
:
return
l
elif
phase
==
'g'
:
return
g
elif
phase
==
'two-phase'
:
return
#TODO: all two-phase properties?
elif
phase
is
:
return
else
:
raise
Exception
(
'Property not recognized'
)

r Determines which phase s property should be set as a default given the phase a chemical is and the property values of various phases . For the case of liquid - gas phase returns None . If the property is not available for the current phase or if the current phase is not known returns None .


def set_user_methods(self, user_methods, forced=False):
        r'''Method used to select certain property methods as having a higher
        priority than were set by default. If `forced` is true, then methods
        which were not specified are excluded from consideration.

        As a side effect, `method` is removed to ensure than the new methods
        will be used in calculations afterwards.

        An exception is raised if any of the methods specified aren't available
        for the chemical. An exception is raised if no methods are provided.

        Parameters
        ----------
        user_methods : str or list
            Methods by name to be considered or prefered
        forced : bool, optional
            If True, only the user specified methods will ever be considered;
            if False other methods will be considered if no user methods
            suceed
        '''
        # Accept either a string or a list of methods, and whether
        # or not to only consider the false methods
        if isinstance(user_methods, str):
            user_methods = [user_methods]

        # The user's order matters and is retained for use by select_valid_methods
        self.user_methods = user_methods
        self.forced = forced

        # Validate that the user's specified methods are actual methods
        if set(self.user_methods).difference(self.all_methods):
            raise Exception("One of the given methods is not available for this chemical")
        if not self.user_methods and self.forced:
            raise Exception('Only user specified methods are considered when forced is True, but no methods were provided')

        # Remove previously selected methods
        self.method = None
        self.sorted_valid_methods = []
        self.T_cached = None

r Method used to select certain property methods as having a higher priority than were set by default . If forced is true then methods which were not specified are excluded from consideration .


def select_valid_methods(self, T):
        r'''Method to obtain a sorted list of methods which are valid at `T`
        according to `test_method_validity`. Considers either only user methods
        if forced is True, or all methods. User methods are first tested
        according to their listed order, and unless forced is True, then all
        methods are tested and sorted by their order in `ranked_methods`.

        Parameters
        ----------
        T : float
            Temperature at which to test methods, [K]

        Returns
        -------
        sorted_valid_methods : list
            Sorted lists of methods valid at T according to
            `test_method_validity`
        '''
        # Consider either only the user's methods or all methods
        # Tabular data will be in both when inserted
        if self.forced:
            considered_methods = list(self.user_methods)
        else:
            considered_methods = list(self.all_methods)

        # User methods (incl. tabular data); add back later, after ranking the rest
        if self.user_methods:
            [considered_methods.remove(i) for i in self.user_methods]

        # Index the rest of the methods by ranked_methods, and add them to a list, sorted_methods
        preferences = sorted([self.ranked_methods.index(i) for i in considered_methods])
        sorted_methods = [self.ranked_methods[i] for i in preferences]

        # Add back the user's methods to the top, in order.
        if self.user_methods:
            [sorted_methods.insert(0, i) for i in reversed(self.user_methods)]

        sorted_valid_methods = []
        for method in sorted_methods:
            if self.test_method_validity(T, method):
                sorted_valid_methods.append(method)

        return sorted_valid_methods

r Method to obtain a sorted list of methods which are valid at T according to test_method_validity . Considers either only user methods if forced is True or all methods . User methods are first tested according to their listed order and unless forced is True then all methods are tested and sorted by their order in ranked_methods .


def solve_prop(self, goal, reset_method=True):
        r'''Method to solve for the temperature at which a property is at a
        specified value. `T_dependent_property` is used to calculate the value
        of the property as a function of temperature; if `reset_method` is True,
        the best method is used at each temperature as the solver seeks a
        solution. This slows the solution moderately.

        Checks the given property value with `test_property_validity` first
        and raises an exception if it is not valid. Requires that Tmin and
        Tmax have been set to know what range to search within.

        Search is performed with the brenth solver from SciPy.

        Parameters
        ----------
        goal : float
            Propoerty value desired, [`units`]
        reset_method : bool
            Whether or not to reset the method as the solver searches

        Returns
        -------
        T : float
            Temperature at which the property is the specified value [K]
        '''
        if self.Tmin is None or self.Tmax is None:
            raise Exception('Both a minimum and a maximum value are not present indicating there is not enough data for temperature dependency.')
        if not self.test_property_validity(goal):
            raise Exception('Input property is not considered plausible; no method would calculate it.')

        def error(T):
            if reset_method:
                self.method = None
            return self.T_dependent_property(T) - goal
        try:
            return brenth(error, self.Tmin, self.Tmax)
        except ValueError:
            raise Exception('To within the implemented temperature range, it is not possible to calculate the desired value.')

r Method to solve for the temperature at which a property is at a specified value . T_dependent_property is used to calculate the value of the property as a function of temperature ; if reset_method is True the best method is used at each temperature as the solver seeks a solution . This slows the solution moderately .


def T_dependent_property_derivative(self, T, order=1):
        r'''Method to obtain a derivative of a property with respect to
        temperature, of a given order. Methods found valid by
        `select_valid_methods` are attempted until a method succeeds. If no
        methods are valid and succeed, None is returned.

        Calls `calculate_derivative` internally to perform the actual
        calculation.

        .. math::
            \text{derivative} = \frac{d (\text{property})}{d T}

        Parameters
        ----------
        T : float
            Temperature at which to calculate the derivative, [K]
        order : int
            Order of the derivative, >= 1

        Returns
        -------
        derivative : float
            Calculated derivative property, [`units/K^order`]
        '''
        if self.method:
            # retest within range
            if self.test_method_validity(T, self.method):
                try:
                    return self.calculate_derivative(T, self.method, order)
                except:  # pragma: no cover
                    pass
        sorted_valid_methods = self.select_valid_methods(T)
        for method in sorted_valid_methods:
            try:
                return self.calculate_derivative(T, method, order)
            except:
                pass
        return None

def
T_dependent_property_derivative
(
self
,
T
,
order
=
1
)
:
if
self
.
method
:
# retest within range
if
self
.
test_method_validity
(
T
,
self
.
method
)
:
try
:
return
self
.
calculate_derivative
(
T
,
self
.
method
,
order
)
except
:
# pragma: no cover
pass
sorted_valid_methods
=
self
.
select_valid_methods
(
T
)
for
method
in
sorted_valid_methods
:
try
:
return
self
.
calculate_derivative
(
T
,
method
,
order
)
except
:
pass
return

r Method to obtain a derivative of a property with respect to temperature of a given order . Methods found valid by select_valid_methods are attempted until a method succeeds . If no methods are valid and succeed None is returned .


def calculate_integral(self, T1, T2, method):
        r'''Method to calculate the integral of a property with respect to
        temperature, using a specified method. Uses SciPy's `quad` function
        to perform the integral, with no options.

        This method can be overwritten by subclasses who may perfer to add
        analytical methods for some or all methods as this is much faster.

        If the calculation does not succeed, returns the actual error
        encountered.

        Parameters
        ----------
        T1 : float
            Lower limit of integration, [K]
        T2 : float
            Upper limit of integration, [K]
        method : str
            Method for which to find the integral

        Returns
        -------
        integral : float
            Calculated integral of the property over the given range,
            [`units*K`]
        '''
        return float(quad(self.calculate, T1, T2, args=(method))[0])

def calculate_integral ( self , T1 , T2 , method ) : return float ( quad ( self . calculate , T1 , T2 , args = ( method ) ) [ 0 ] )

r Method to calculate the integral of a property with respect to temperature using a specified method . Uses SciPy s quad function to perform the integral with no options . This method can be overwritten by subclasses who may perfer to add analytical methods for some or all methods as this is much faster .


def T_dependent_property_integral(self, T1, T2):
        r'''Method to calculate the integral of a property with respect to
        temperature, using a specified method. Methods found valid by
        `select_valid_methods` are attempted until a method succeeds. If no
        methods are valid and succeed, None is returned.

        Calls `calculate_integral` internally to perform the actual
        calculation.

        .. math::
            \text{integral} = \int_{T_1}^{T_2} \text{property} \; dT

        Parameters
        ----------
        T1 : float
            Lower limit of integration, [K]
        T2 : float
            Upper limit of integration, [K]
        method : str
            Method for which to find the integral

        Returns
        -------
        integral : float
            Calculated integral of the property over the given range,
            [`units*K`]
        '''
        Tavg = 0.5*(T1+T2)
        if self.method:
            # retest within range
            if self.test_method_validity(Tavg, self.method):
                try:
                    return self.calculate_integral(T1, T2, self.method)
                except:  # pragma: no cover
                    pass

        sorted_valid_methods = self.select_valid_methods(Tavg)
        for method in sorted_valid_methods:
            try:
                return self.calculate_integral(T1, T2, method)
            except:
                pass
        return None

def
T_dependent_property_integral
(
self
,
T1
,
T2
)
:
Tavg
=
0.5
*
(
T1
+
T2
)
if
self
.
method
:
# retest within range
if
self
.
test_method_validity
(
Tavg
,
self
.
method
)
:
try
:
return
self
.
calculate_integral
(
T1
,
T2
,
self
.
method
)
except
:
# pragma: no cover
pass
sorted_valid_methods
=
self
.
select_valid_methods
(
Tavg
)
for
method
in
sorted_valid_methods
:
try
:
return
self
.
calculate_integral
(
T1
,
T2
,
method
)
except
:
pass
return

r Method to calculate the integral of a property with respect to temperature using a specified method . Methods found valid by select_valid_methods are attempted until a method succeeds . If no methods are valid and succeed None is returned . Calls calculate_integral internally to perform the actual calculation .


def calculate_integral_over_T(self, T1, T2, method):
        r'''Method to calculate the integral of a property over temperature
        with respect to temperature, using a specified method. Uses SciPy's
        `quad` function to perform the integral, with no options.

        This method can be overwritten by subclasses who may perfer to add
        analytical methods for some or all methods as this is much faster.

        If the calculation does not succeed, returns the actual error
        encountered.

        Parameters
        ----------
        T1 : float
            Lower limit of integration, [K]
        T2 : float
            Upper limit of integration, [K]
        method : str
            Method for which to find the integral

        Returns
        -------
        integral : float
            Calculated integral of the property over the given range,
            [`units`]
        '''
        return float(quad(lambda T: self.calculate(T, method)/T, T1, T2)[0])

def calculate_integral_over_T ( self , T1 , T2 , method ) : return float ( quad ( lambda T : self . calculate ( T , method ) / T , T1 , T2 ) [ 0 ] )

r Method to calculate the integral of a property over temperature with respect to temperature using a specified method . Uses SciPy s quad function to perform the integral with no options . This method can be overwritten by subclasses who may perfer to add analytical methods for some or all methods as this is much faster .


def load_all_methods(self):
        r'''Method to load all data, and set all_methods based on the available
        data and properties. Demo function for testing only; must be
        implemented according to the methods available for each individual
        method.
        '''
        methods = []
        Tmins, Tmaxs = [], []
        if self.CASRN in ['7732-18-5', '67-56-1', '64-17-5']:
            methods.append(TEST_METHOD_1)
            self.TEST_METHOD_1_Tmin = 200.
            self.TEST_METHOD_1_Tmax = 350
            self.TEST_METHOD_1_coeffs = [1, .002]
            Tmins.append(self.TEST_METHOD_1_Tmin); Tmaxs.append(self.TEST_METHOD_1_Tmax)
        if self.CASRN in ['67-56-1']:
            methods.append(TEST_METHOD_2)
            self.TEST_METHOD_2_Tmin = 300.
            self.TEST_METHOD_2_Tmax = 400
            self.TEST_METHOD_2_coeffs = [1, .003]
            Tmins.append(self.TEST_METHOD_2_Tmin); Tmaxs.append(self.TEST_METHOD_2_Tmax)
        self.all_methods = set(methods)
        if Tmins and Tmaxs:
            self.Tmin = min(Tmins)
            self.Tmax = max(Tmaxs)

def load_all_methods ( self ) : methods = [ ] Tmins , Tmaxs = [ ] , [ ] if self . CASRN in [ '7732-18-5' , '67-56-1' , '64-17-5' ] : methods . append ( TEST_METHOD_1 ) self . TEST_METHOD_1_Tmin = 200. self . TEST_METHOD_1_Tmax = 350 self . TEST_METHOD_1_coeffs = [ 1 , .002 ] Tmins . append ( self . TEST_METHOD_1_Tmin ) Tmaxs . append ( self . TEST_METHOD_1_Tmax ) if self . CASRN in [ '67-56-1' ] : methods . append ( TEST_METHOD_2 ) self . TEST_METHOD_2_Tmin = 300. self . TEST_METHOD_2_Tmax = 400 self . TEST_METHOD_2_coeffs = [ 1 , .003 ] Tmins . append ( self . TEST_METHOD_2_Tmin ) Tmaxs . append ( self . TEST_METHOD_2_Tmax ) self . all_methods = set ( methods ) if Tmins and Tmaxs : self . Tmin = min ( Tmins ) self . Tmax = max ( Tmaxs )

r Method to load all data and set all_methods based on the available data and properties . Demo function for testing only ; must be implemented according to the methods available for each individual method .


def calculate(self, T, method):
        r'''Method to calculate a property with a specified method, with no
        validity checking or error handling. Demo function for testing only;
        must be implemented according to the methods available for each
        individual method. Include the interpolation call here.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        method : str
            Method name to use

        Returns
        -------
        prop : float
            Calculated property, [`units`]
        '''
        if method == TEST_METHOD_1:
            prop = self.TEST_METHOD_1_coeffs[0] + self.TEST_METHOD_1_coeffs[1]*T
        elif method == TEST_METHOD_2:
            prop = self.TEST_METHOD_2_coeffs[0] + self.TEST_METHOD_2_coeffs[1]*T
        elif method in self.tabular_data:
            prop = self.interpolate(T, method)
        return prop

def calculate ( self , T , method ) : if method == TEST_METHOD_1 : prop = self . TEST_METHOD_1_coeffs [ 0 ] + self . TEST_METHOD_1_coeffs [ 1 ] * T elif method == TEST_METHOD_2 : prop = self . TEST_METHOD_2_coeffs [ 0 ] + self . TEST_METHOD_2_coeffs [ 1 ] * T elif method in self . tabular_data : prop = self . interpolate ( T , method ) return prop

r Method to calculate a property with a specified method with no validity checking or error handling . Demo function for testing only ; must be implemented according to the methods available for each individual method . Include the interpolation call here .


def set_user_methods_P(self, user_methods_P, forced_P=False):
        r'''Method to set the pressure-dependent property methods desired for
        consideration by the user. Can be used to exclude certain methods which
        might have unacceptable accuracy.

        As a side effect, the previously selected method is removed when
        this method is called to ensure user methods are tried in the desired
        order.

        Parameters
        ----------
        user_methods_P : str or list
            Methods by name to be considered or preferred for pressure effect.
        forced : bool, optional
            If True, only the user specified methods will ever be considered;
            if False other methods will be considered if no user methods
            suceed.
        '''
        # Accept either a string or a list of methods, and whether
        # or not to only consider the false methods
        if isinstance(user_methods_P, str):
            user_methods_P = [user_methods_P]

        # The user's order matters and is retained for use by select_valid_methods
        self.user_methods_P = user_methods_P
        self.forced_P = forced_P

        # Validate that the user's specified methods are actual methods
        if set(self.user_methods_P).difference(self.all_methods_P):
            raise Exception("One of the given methods is not available for this chemical")
        if not self.user_methods_P and self.forced:
            raise Exception('Only user specified methods are considered when forced is True, but no methods were provided')

        # Remove previously selected methods
        self.method_P = None
        self.sorted_valid_methods_P = []
        self.TP_cached = None

r Method to set the pressure - dependent property methods desired for consideration by the user . Can be used to exclude certain methods which might have unacceptable accuracy .


def select_valid_methods_P(self, T, P):
        r'''Method to obtain a sorted list methods which are valid at `T`
        according to `test_method_validity`. Considers either only user methods
        if forced is True, or all methods. User methods are first tested
        according to their listed order, and unless forced is True, then all
        methods are tested and sorted by their order in `ranked_methods`.

        Parameters
        ----------
        T : float
            Temperature at which to test methods, [K]
        P : float
            Pressure at which to test methods, [Pa]

        Returns
        -------
        sorted_valid_methods_P : list
            Sorted lists of methods valid at T and P according to
            `test_method_validity`
        '''
        # Same as select_valid_methods but with _P added to variables
        if self.forced_P:
            considered_methods = list(self.user_methods_P)
        else:
            considered_methods = list(self.all_methods_P)

        if self.user_methods_P:
            [considered_methods.remove(i) for i in self.user_methods_P]

        preferences = sorted([self.ranked_methods_P.index(i) for i in considered_methods])
        sorted_methods = [self.ranked_methods_P[i] for i in preferences]

        if self.user_methods_P:
            [sorted_methods.insert(0, i) for i in reversed(self.user_methods_P)]

        sorted_valid_methods_P = []
        for method in sorted_methods:
            if self.test_method_validity_P(T, P, method):
                sorted_valid_methods_P.append(method)

        return sorted_valid_methods_P

r Method to obtain a sorted list methods which are valid at T according to test_method_validity . Considers either only user methods if forced is True or all methods . User methods are first tested according to their listed order and unless forced is True then all methods are tested and sorted by their order in ranked_methods .


def TP_dependent_property(self, T, P):
        r'''Method to calculate the property with sanity checking and without
        specifying a specific method. `select_valid_methods_P` is used to obtain
        a sorted list of methods to try. Methods are then tried in order until
        one succeeds. The methods are allowed to fail, and their results are
        checked with `test_property_validity`. On success, the used method
        is stored in the variable `method_P`.

        If `method_P` is set, this method is first checked for validity with
        `test_method_validity_P` for the specified temperature, and if it is
        valid, it is then used to calculate the property. The result is checked
        for validity, and returned if it is valid. If either of the checks fail,
        the function retrieves a full list of valid methods with
        `select_valid_methods_P` and attempts them as described above.

        If no methods are found which succeed, returns None.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        P : float
            Pressure at which to calculate the property, [Pa]

        Returns
        -------
        prop : float
            Calculated property, [`units`]
        '''
        # Optimistic track, with the already set method
        if self.method_P:
            # retest within range
            if self.test_method_validity_P(T, P, self.method_P):
                try:
                    prop = self.calculate_P(T, P, self.method_P)
                    if self.test_property_validity(prop):
                        return prop
                except:  # pragma: no cover
                    pass

        # get valid methods at T, and try them until one yields a valid
        # property; store the method_P and return the answer
        self.sorted_valid_methods_P = self.select_valid_methods_P(T, P)
        for method_P in self.sorted_valid_methods_P:
            try:
                prop = self.calculate_P(T, P, method_P)
                if self.test_property_validity(prop):
                    self.method_P = method_P
                    return prop
            except:  # pragma: no cover
                pass
        # Function returns None if it does not work.
        return None

r Method to calculate the property with sanity checking and without specifying a specific method . select_valid_methods_P is used to obtain a sorted list of methods to try . Methods are then tried in order until one succeeds . The methods are allowed to fail and their results are checked with test_property_validity . On success the used method is stored in the variable method_P .


def interpolate_P(self, T, P, name):
        r'''Method to perform interpolation on a given tabular data set
        previously added via `set_tabular_data_P`. This method will create the
        interpolators the first time it is used on a property set, and store
        them for quick future use.

        Interpolation is cubic-spline based if 5 or more points are available,
        and linearly interpolated if not. Extrapolation is always performed
        linearly. This function uses the transforms `interpolation_T`,
        `interpolation_P`,
        `interpolation_property`, and `interpolation_property_inv` if set. If
        any of these are changed after the interpolators were first created,
        new interpolators are created with the new transforms.
        All interpolation is performed via the `interp2d` function.

        Parameters
        ----------
        T : float
            Temperature at which to interpolate the property, [K]
        T : float
            Pressure at which to interpolate the property, [Pa]
        name : str
            The name assigned to the tabular data set

        Returns
        -------
        prop : float
            Calculated property, [`units`]
        '''
        key = (name, self.interpolation_T, self.interpolation_P, self.interpolation_property, self.interpolation_property_inv)

        # If the interpolator and extrapolator has already been created, load it
        if key in self.tabular_data_interpolators:
            extrapolator, spline = self.tabular_data_interpolators[key]
        else:
            Ts, Ps, properties = self.tabular_data[name]

            if self.interpolation_T:  # Transform ths Ts with interpolation_T if set
                Ts2 = [self.interpolation_T(T2) for T2 in Ts]
            else:
                Ts2 = Ts
            if self.interpolation_P:  # Transform ths Ts with interpolation_T if set
                Ps2 = [self.interpolation_P(P2) for P2 in Ps]
            else:
                Ps2 = Ps
            if self.interpolation_property:  # Transform ths props with interpolation_property if set
                properties2 = [self.interpolation_property(p) for p in properties]
            else:
                properties2 = properties
            # Only allow linear extrapolation, but with whatever transforms are specified
            extrapolator = interp2d(Ts2, Ps2, properties2)  # interpolation if fill value is missing
            # If more than 5 property points, create a spline interpolation
            if len(properties) >= 5:
                spline = interp2d(Ts2, Ps2, properties2, kind='cubic')
            else:
                spline = None
            self.tabular_data_interpolators[key] = (extrapolator, spline)

        # Load the stores values, tor checking which interpolation strategy to
        # use.
        Ts, Ps, properties = self.tabular_data[name]

        if T < Ts[0] or T > Ts[-1] or not spline or P < Ps[0] or P > Ps[-1]:
            tool = extrapolator
        else:
            tool = spline

        if self.interpolation_T:
            T = self.interpolation_T(T)
        if self.interpolation_P:
            P = self.interpolation_T(P)
        prop = tool(T, P)  # either spline, or linear interpolation

        if self.interpolation_property:
            prop = self.interpolation_property_inv(prop)

        return float(prop)

r Method to perform interpolation on a given tabular data set previously added via set_tabular_data_P . This method will create the interpolators the first time it is used on a property set and store them for quick future use .


def TP_dependent_property_derivative_T(self, T, P, order=1):
        r'''Method to calculate a derivative of a temperature and pressure
        dependent property with respect to temperature at constant pressure,
        of a given order. Methods found valid by `select_valid_methods_P` are
        attempted until a method succeeds. If no methods are valid and succeed,
        None is returned.

        Calls `calculate_derivative_T` internally to perform the actual
        calculation.

        .. math::
            \text{derivative} = \frac{d (\text{property})}{d T}|_{P}

        Parameters
        ----------
        T : float
            Temperature at which to calculate the derivative, [K]
        P : float
            Pressure at which to calculate the derivative, [Pa]
        order : int
            Order of the derivative, >= 1

        Returns
        -------
        d_prop_d_T_at_P : float
            Calculated derivative property, [`units/K^order`]
        '''
        sorted_valid_methods_P = self.select_valid_methods_P(T, P)
        for method in sorted_valid_methods_P:
            try:
                return self.calculate_derivative_T(T, P, method, order)
            except:
                pass
        return None

def TP_dependent_property_derivative_T ( self , T , P , order = 1 ) : sorted_valid_methods_P = self . select_valid_methods_P ( T , P ) for method in sorted_valid_methods_P : try : return self . calculate_derivative_T ( T , P , method , order ) except : pass return None

r Method to calculate a derivative of a temperature and pressure dependent property with respect to temperature at constant pressure of a given order . Methods found valid by select_valid_methods_P are attempted until a method succeeds . If no methods are valid and succeed None is returned .


def TP_dependent_property_derivative_P(self, T, P, order=1):
        r'''Method to calculate a derivative of a temperature and pressure
        dependent property with respect to pressure at constant temperature,
        of a given order. Methods found valid by `select_valid_methods_P` are
        attempted until a method succeeds. If no methods are valid and succeed,
        None is returned.

        Calls `calculate_derivative_P` internally to perform the actual
        calculation.

        .. math::
            \text{derivative} = \frac{d (\text{property})}{d P}|_{T}

        Parameters
        ----------
        T : float
            Temperature at which to calculate the derivative, [K]
        P : float
            Pressure at which to calculate the derivative, [Pa]
        order : int
            Order of the derivative, >= 1

        Returns
        -------
        d_prop_d_P_at_T : float
            Calculated derivative property, [`units/Pa^order`]
        '''
        sorted_valid_methods_P = self.select_valid_methods_P(T, P)
        for method in sorted_valid_methods_P:
            try:
                return self.calculate_derivative_P(P, T, method, order)
            except:
                pass
        return None

def TP_dependent_property_derivative_P ( self , T , P , order = 1 ) : sorted_valid_methods_P = self . select_valid_methods_P ( T , P ) for method in sorted_valid_methods_P : try : return self . calculate_derivative_P ( P , T , method , order ) except : pass return None

r Method to calculate a derivative of a temperature and pressure dependent property with respect to pressure at constant temperature of a given order . Methods found valid by select_valid_methods_P are attempted until a method succeeds . If no methods are valid and succeed None is returned .


def set_user_method(self, user_methods, forced=False):
        r'''Method to set the T, P, and composition dependent property methods
        desired for consideration by the user. Can be used to exclude certain
        methods which might have unacceptable accuracy.

        As a side effect, the previously selected method is removed when
        this method is called to ensure user methods are tried in the desired
        order.

        Parameters
        ----------
        user_methods : str or list
            Methods by name to be considered for calculation of the mixture
            property, ordered by preference.
        forced : bool, optional
            If True, only the user specified methods will ever be considered;
            if False, other methods will be considered if no user methods
            suceed.
        '''
        # Accept either a string or a list of methods, and whether
        # or not to only consider the false methods
        if isinstance(user_methods, str):
            user_methods = [user_methods]

        # The user's order matters and is retained for use by select_valid_methods
        self.user_methods = user_methods
        self.forced = forced

        # Validate that the user's specified methods are actual methods
        if set(self.user_methods).difference(self.all_methods):
            raise Exception("One of the given methods is not available for this mixture")
        if not self.user_methods and self.forced:
            raise Exception('Only user specified methods are considered when forced is True, but no methods were provided')

        # Remove previously selected methods
        self.method = None
        self.sorted_valid_methods = []
        self.TP_zs_ws_cached = (None, None, None, None)

r Method to set the T P and composition dependent property methods desired for consideration by the user . Can be used to exclude certain methods which might have unacceptable accuracy .


def property_derivative_T(self, T, P, zs, ws, order=1):
        r'''Method to calculate a derivative of a mixture property with respect
        to temperature at constant pressure and composition,
        of a given order. Methods found valid by `select_valid_methods` are
        attempted until a method succeeds. If no methods are valid and succeed,
        None is returned.

        Calls `calculate_derivative_T` internally to perform the actual
        calculation.

        .. math::
            \text{derivative} = \frac{d (\text{property})}{d T}|_{P, z}

        Parameters
        ----------
        T : float
            Temperature at which to calculate the derivative, [K]
        P : float
            Pressure at which to calculate the derivative, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        order : int
            Order of the derivative, >= 1

        Returns
        -------
        d_prop_d_T_at_P : float
            Calculated derivative property, [`units/K^order`]
        '''
        sorted_valid_methods = self.select_valid_methods(T, P, zs, ws)
        for method in sorted_valid_methods:
            try:
                return self.calculate_derivative_T(T, P, zs, ws, method, order)
            except:
                pass
        return None

def property_derivative_T ( self , T , P , zs , ws , order = 1 ) : sorted_valid_methods = self . select_valid_methods ( T , P , zs , ws ) for method in sorted_valid_methods : try : return self . calculate_derivative_T ( T , P , zs , ws , method , order ) except : pass return None

r Method to calculate a derivative of a mixture property with respect to temperature at constant pressure and composition of a given order . Methods found valid by select_valid_methods are attempted until a method succeeds . If no methods are valid and succeed None is returned .


def property_derivative_P(self, T, P, zs, ws, order=1):
        r'''Method to calculate a derivative of a mixture property with respect
        to pressure at constant temperature and composition,
        of a given order. Methods found valid by `select_valid_methods` are
        attempted until a method succeeds. If no methods are valid and succeed,
        None is returned.

        Calls `calculate_derivative_P` internally to perform the actual
        calculation.

        .. math::
            \text{derivative} = \frac{d (\text{property})}{d P}|_{T, z}

        Parameters
        ----------
        T : float
            Temperature at which to calculate the derivative, [K]
        P : float
            Pressure at which to calculate the derivative, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        order : int
            Order of the derivative, >= 1

        Returns
        -------
        d_prop_d_P_at_T : float
            Calculated derivative property, [`units/Pa^order`]
        '''
        sorted_valid_methods = self.select_valid_methods(T, P, zs, ws)
        for method in sorted_valid_methods:
            try:
                return self.calculate_derivative_P(P, T, zs, ws, method, order)
            except:
                pass
        return None

def property_derivative_P ( self , T , P , zs , ws , order = 1 ) : sorted_valid_methods = self . select_valid_methods ( T , P , zs , ws ) for method in sorted_valid_methods : try : return self . calculate_derivative_P ( P , T , zs , ws , method , order ) except : pass return None

r Method to calculate a derivative of a mixture property with respect to pressure at constant temperature and composition of a given order . Methods found valid by select_valid_methods are attempted until a method succeeds . If no methods are valid and succeed None is returned .


def refractive_index(CASRN, T=None, AvailableMethods=False, Method=None,
                     full_info=True):
    r'''This function handles the retrieval of a chemical's refractive
    index. 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.

    Function has data for approximately 4500 chemicals.

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

    Returns
    -------
    RI : float
        Refractive Index on the Na D line, [-]
    T : float, only returned if full_info == True
        Temperature at which refractive index reading was made
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain RI with the given inputs

    Other Parameters
    ----------------
    Method : string, optional
        A string for the method name to use, as defined by constants in
        RI_methods
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        RI for the desired chemical, and will return methods instead of RI
    full_info : bool, optional
        If True, function will return the temperature at which the refractive
        index reading was made

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

        * 'CRC', a compillation of Organic RI data in [1]_.

    Examples
    --------
    >>> refractive_index(CASRN='64-17-5')
    (1.3611, 293.15)

    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.
    '''
    def list_methods():
        methods = []
        if CASRN in CRC_RI_organic.index:
            methods.append(CRC)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == CRC:
        _RI = float(CRC_RI_organic.at[CASRN, 'RI'])
        if full_info:
            _T = float(CRC_RI_organic.at[CASRN, 'RIT'])
    elif Method == NONE:
        _RI, _T = None, None
    else:
        raise Exception('Failure in in function')
    if full_info:
        return _RI, _T
    else:
        return _RI

def
refractive_index
(
CASRN
,
T
=
,
AvailableMethods
=
False
,
Method
=
,
full_info
=
True
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
CRC_RI_organic
.
index
:
methods
.
append
(
CRC
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
CRC
:
_RI
=
float
(
CRC_RI_organic
.
at
[
CASRN
,
'RI'
]
)
if
full_info
:
_T
=
float
(
CRC_RI_organic
.
at
[
CASRN
,
'RIT'
]
)
elif
Method
==
:
_RI
,
_T
=
,
else
:
raise
Exception
(
'Failure in in function'
)
if
full_info
:
return
_RI
,
_T
else
:
return
_RI

r This function handles the retrieval of a chemical s refractive index . 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 .


def solve_T(self, P, V, quick=True):
        r'''Generic method to calculate `T` from a specified `P` and `V`.
        Provides SciPy's `newton` solver, and iterates to solve the general
        equation for `P`, recalculating `a_alpha` as a function of temperature
        using `a_alpha_and_derivatives` each iteration.

        Parameters
        ----------
        P : float
            Pressure, [Pa]
        V : float
            Molar volume, [m^3/mol]
        quick : bool, optional
            Unimplemented, although it may be possible to derive explicit
            expressions as done for many pure-component EOS

        Returns
        -------
        T : float
            Temperature, [K]
        '''
        self.Tc = sum(self.Tcs)/self.N
        # -4 goes back from object, GCEOS
        return super(type(self).__mro__[-3], self).solve_T(P=P, V=V, quick=quick)

def
solve_T
(
self
,
P
,
V
,
quick
=
True
)
:
self
.
Tc
=
sum
(
self
.
Tcs
)
/
self
.
N
# -4 goes back from object, GCEOS
return
super
(
type
(
self
)
.
__mro__
[
3
]
,
self
)
.
solve_T
(
P
=
P
,
V
=
V
,
quick
=
quick
)

r Generic method to calculate T from a specified P and V . Provides SciPy s newton solver and iterates to solve the general equation for P recalculating a_alpha as a function of temperature using a_alpha_and_derivatives each iteration .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `kappa`, and `Tc` for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        self.a, self.kappa, self.Tc = self.ais[i], self.kappas[i], self.Tcs[i]

def setup_a_alpha_and_derivatives ( self , i , T = None ) : self . a , self . kappa , self . Tc = self . ais [ i ] , self . kappas [ i ] , self . Tcs [ i ]

r Sets a kappa and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `m`, and `Tc` for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        self.a, self.m, self.Tc = self.ais[i], self.ms[i], self.Tcs[i]

def setup_a_alpha_and_derivatives ( self , i , T = None ) : self . a , self . m , self . Tc = self . ais [ i ] , self . ms [ i ] , self . Tcs [ i ]

r Sets a m and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `kappa0`, `kappa1`, and `Tc` for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        if not hasattr(self, 'kappas'):
            self.kappas = [kappa0 + kappa1*(1 + (T/Tc)**0.5)*(0.7 - (T/Tc)) for kappa0, kappa1, Tc in zip(self.kappa0s, self.kappa1s, self.Tcs)]
        self.a, self.kappa, self.kappa0, self.kappa1, self.Tc = self.ais[i], self.kappas[i], self.kappa0s[i], self.kappa1s[i], self.Tcs[i]

def setup_a_alpha_and_derivatives ( self , i , T = None ) : if not hasattr ( self , 'kappas' ) : self . kappas = [ kappa0 + kappa1 * ( 1 + ( T / Tc ) ** 0.5 ) * ( 0.7 - ( T / Tc ) ) for kappa0 , kappa1 , Tc in zip ( self . kappa0s , self . kappa1s , self . Tcs ) ] self . a , self . kappa , self . kappa0 , self . kappa1 , self . Tc = self . ais [ i ] , self . kappas [ i ] , self . kappa0s [ i ] , self . kappa1s [ i ] , self . Tcs [ i ]

r Sets a kappa0 kappa1 and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `kappa`, `kappa0`, `kappa1`, `kappa2`, `kappa3` and `Tc`
        for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        if not hasattr(self, 'kappas'):
            self.kappas = []
            for Tc, kappa0, kappa1, kappa2, kappa3 in zip(self.Tcs, self.kappa0s, self.kappa1s, self.kappa2s, self.kappa3s):
                Tr = T/Tc
                kappa = kappa0 + ((kappa1 + kappa2*(kappa3 - Tr)*(1. - Tr**0.5))*(1. + Tr**0.5)*(0.7 - Tr))
                self.kappas.append(kappa)

        (self.a, self.kappa, self.kappa0, self.kappa1, self.kappa2,
         self.kappa3, self.Tc) = (self.ais[i], self.kappas[i], self.kappa0s[i],
         self.kappa1s[i], self.kappa2s[i], self.kappa3s[i], self.Tcs[i])

def setup_a_alpha_and_derivatives ( self , i , T = None ) : if not hasattr ( self , 'kappas' ) : self . kappas = [ ] for Tc , kappa0 , kappa1 , kappa2 , kappa3 in zip ( self . Tcs , self . kappa0s , self . kappa1s , self . kappa2s , self . kappa3s ) : Tr = T / Tc kappa = kappa0 + ( ( kappa1 + kappa2 * ( kappa3 - Tr ) * ( 1. - Tr ** 0.5 ) ) * ( 1. + Tr ** 0.5 ) * ( 0.7 - Tr ) ) self . kappas . append ( kappa ) ( self . a , self . kappa , self . kappa0 , self . kappa1 , self . kappa2 , self . kappa3 , self . Tc ) = ( self . ais [ i ] , self . kappas [ i ] , self . kappa0s [ i ] , self . kappa1s [ i ] , self . kappa2s [ i ] , self . kappa3s [ i ] , self . Tcs [ i ] )

r Sets a kappa kappa0 kappa1 kappa2 kappa3 and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `omega`, and `Tc` for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        self.a, self.Tc, self.omega  = self.ais[i], self.Tcs[i], self.omegas[i]

def setup_a_alpha_and_derivatives ( self , i , T = None ) : self . a , self . Tc , self . omega = self . ais [ i ] , self . Tcs [ i ] , self . omegas [ i ]

r Sets a omega and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def setup_a_alpha_and_derivatives(self, i, T=None):
        r'''Sets `a`, `S1`, `S2` and `Tc` for a specific component before the
        pure-species EOS's `a_alpha_and_derivatives` method is called. Both are
        called by `GCEOSMIX.a_alpha_and_derivatives` for every component.'''
        self.a, self.Tc, self.S1, self.S2  = self.ais[i], self.Tcs[i], self.S1s[i], self.S2s[i]

def setup_a_alpha_and_derivatives ( self , i , T = None ) : self . a , self . Tc , self . S1 , self . S2 = self . ais [ i ] , self . Tcs [ i ] , self . S1s [ i ] , self . S2s [ i ]

r Sets a S1 S2 and Tc for a specific component before the pure - species EOS s a_alpha_and_derivatives method is called . Both are called by GCEOSMIX . a_alpha_and_derivatives for every component .


def Bahadori_liquid(T, M):
    r'''Estimates the thermal conductivity of parafin liquid hydrocarbons.
    Fits their data well, and is useful as only MW is required.
    X is the Molecular weight, and Y the temperature.

    .. math::
        K = a + bY + CY^2 + dY^3

        a = A_1 + B_1 X + C_1 X^2 + D_1 X^3

        b = A_2 + B_2 X + C_2 X^2 + D_2 X^3

        c = A_3 + B_3 X + C_3 X^2 + D_3 X^3

        d = A_4 + B_4 X + C_4 X^2 + D_4 X^3

    Parameters
    ----------
    T : float
        Temperature of the fluid [K]
    M : float
        Molecular weight of the fluid [g/mol]

    Returns
    -------
    kl : float
        Estimated liquid thermal conductivity [W/m/k]

    Notes
    -----
    The accuracy of this equation has not been reviewed.

    Examples
    --------
    Data point from [1]_.

    >>> Bahadori_liquid(273.15, 170)
    0.14274278108272603

    References
    ----------
    .. [1] Bahadori, Alireza, and Saeid Mokhatab. "Estimating Thermal
       Conductivity of Hydrocarbons." Chemical Engineering 115, no. 13
       (December 2008): 52-54
    '''
    A = [-6.48326E-2, 2.715015E-3, -1.08580E-5, 9.853917E-9]
    B = [1.565612E-2, -1.55833E-4, 5.051114E-7, -4.68030E-10]
    C = [-1.80304E-4, 1.758693E-6, -5.55224E-9, 5.201365E-12]
    D = [5.880443E-7, -5.65898E-9, 1.764384E-11, -1.65944E-14]
    X, Y = M, T
    a = A[0] + B[0]*X + C[0]*X**2 + D[0]*X**3
    b = A[1] + B[1]*X + C[1]*X**2 + D[1]*X**3
    c = A[2] + B[2]*X + C[2]*X**2 + D[2]*X**3
    d = A[3] + B[3]*X + C[3]*X**2 + D[3]*X**3
    return a + b*Y + c*Y**2 + d*Y**3

r Estimates the thermal conductivity of parafin liquid hydrocarbons . Fits their data well and is useful as only MW is required . X is the Molecular weight and Y the temperature .


r'''Estimates the thermal conductivity of hydrocarbons gases at low P.
    Fits their data well, and is useful as only MW is required.
    Y is the Molecular weight, and X the temperature.

    .. math::
        K = a + bY + CY^2 + dY^3

        a = A_1 + B_1 X + C_1 X^2 + D_1 X^3

        b = A_2 + B_2 X + C_2 X^2 + D_2 X^3

        c = A_3 + B_3 X + C_3 X^2 + D_3 X^3

        d = A_4 + B_4 X + C_4 X^2 + D_4 X^3

    Parameters
    ----------
    T : float
        Temperature of the gas [K]
    MW : float
        Molecular weight of the gas [g/mol]

    Returns
    -------
    kg : float
        Estimated gas thermal conductivity [W/m/k]

    Notes
    -----
    The accuracy of this equation has not been reviewed.

    Examples
    --------
    >>> Bahadori_gas(40+273.15, 20) # Point from article
    0.031968165337873326

    References
    ----------
    .. [1] Bahadori, Alireza, and Saeid Mokhatab. "Estimating Thermal
       Conductivity of Hydrocarbons." Chemical Engineering 115, no. 13
       (December 2008): 52-54

r Estimates the thermal conductivity of hydrocarbons gases at low P . Fits their data well and is useful as only MW is required . Y is the Molecular weight and X the temperature .


def calculate(self, T, method):
        r'''Method to calculate low-pressure liquid thermal conductivity at
        tempearture `T` with a given method.

        This method has no exception handling; see `T_dependent_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature of the liquid, [K]
        method : str
            Name of the method to use

        Returns
        -------
        kl : float
            Thermal conductivity of the liquid at T and a low pressure, [W/m/K]
        '''
        if method == SHEFFY_JOHNSON:
            kl = Sheffy_Johnson(T, self.MW, self.Tm)
        elif method == SATO_RIEDEL:
            kl = Sato_Riedel(T, self.MW, self.Tb, self.Tc)
        elif method == GHARAGHEIZI_L:
            kl = Gharagheizi_liquid(T, self.MW, self.Tb, self.Pc, self.omega)
        elif method == NICOLA:
            kl = Nicola(T, self.MW, self.Tc, self.Pc, self.omega)
        elif method == NICOLA_ORIGINAL:
            kl = Nicola_original(T, self.MW, self.Tc, self.omega, self.Hfus)
        elif method == LAKSHMI_PRASAD:
            kl = Lakshmi_Prasad(T, self.MW)
        elif method == BAHADORI_L:
            kl = Bahadori_liquid(T, self.MW)
        elif method == DIPPR_PERRY_8E:
            kl = EQ100(T, *self.Perrys2_315_coeffs)
        elif method == VDI_PPDS:
            kl = horner(self.VDI_PPDS_coeffs, T)
        elif method == COOLPROP:
            kl = CoolProp_T_dependent_property(T, self.CASRN, 'L', 'l')
        elif method in self.tabular_data:
            kl = self.interpolate(T, method)
        return kl

def calculate ( self , T , method ) : if method == SHEFFY_JOHNSON : kl = Sheffy_Johnson ( T , self . MW , self . Tm ) elif method == SATO_RIEDEL : kl = Sato_Riedel ( T , self . MW , self . Tb , self . Tc ) elif method == GHARAGHEIZI_L : kl = Gharagheizi_liquid ( T , self . MW , self . Tb , self . Pc , self . omega ) elif method == NICOLA : kl = Nicola ( T , self . MW , self . Tc , self . Pc , self . omega ) elif method == NICOLA_ORIGINAL : kl = Nicola_original ( T , self . MW , self . Tc , self . omega , self . Hfus ) elif method == LAKSHMI_PRASAD : kl = Lakshmi_Prasad ( T , self . MW ) elif method == BAHADORI_L : kl = Bahadori_liquid ( T , self . MW ) elif method == DIPPR_PERRY_8E : kl = EQ100 ( T , * self . Perrys2_315_coeffs ) elif method == VDI_PPDS : kl = horner ( self . VDI_PPDS_coeffs , T ) elif method == COOLPROP : kl = CoolProp_T_dependent_property ( T , self . CASRN , 'L' , 'l' ) elif method in self . tabular_data : kl = self . interpolate ( T , method ) return kl

r Method to calculate low - pressure liquid thermal conductivity at tempearture T with a given method .


def calculate_P(self, T, P, method):
        r'''Method to calculate pressure-dependent liquid thermal conductivity
        at temperature `T` and pressure `P` with a given method.

        This method has no exception handling; see `TP_dependent_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate liquid thermal conductivity, [K]
        P : float
            Pressure at which to calculate liquid thermal conductivity, [K]
        method : str
            Name of the method to use

        Returns
        -------
        kl : float
            Thermal conductivity of the liquid at T and P, [W/m/K]
        '''
        if method == DIPPR_9G:
            kl = self.T_dependent_property(T)
            kl = DIPPR9G(T, P, self.Tc, self.Pc, kl)
        elif method == MISSENARD:
            kl = self.T_dependent_property(T)
            kl = Missenard(T, P, self.Tc, self.Pc, kl)
        elif method == COOLPROP:
            kl = PropsSI('L', 'T', T, 'P', P, self.CASRN)
        elif method in self.tabular_data:
            kl = self.interpolate_P(T, P, method)
        return kl

def calculate_P ( self , T , P , method ) : if method == DIPPR_9G : kl = self . T_dependent_property ( T ) kl = DIPPR9G ( T , P , self . Tc , self . Pc , kl ) elif method == MISSENARD : kl = self . T_dependent_property ( T ) kl = Missenard ( T , P , self . Tc , self . Pc , kl ) elif method == COOLPROP : kl = PropsSI ( 'L' , 'T' , T , 'P' , P , self . CASRN ) elif method in self . tabular_data : kl = self . interpolate_P ( T , P , method ) return kl

r Method to calculate pressure - dependent liquid thermal conductivity at temperature T and pressure P with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate thermal conductivity of a liquid mixture at
        temperature `T`, pressure `P`, mole fractions `zs` and weight fractions
        `ws` with a given method.

        This method has no exception handling; see `mixture_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature at which to calculate the property, [K]
        P : float
            Pressure at which to calculate the property, [Pa]
        zs : list[float]
            Mole fractions of all species in the mixture, [-]
        ws : list[float]
            Weight fractions of all species in the mixture, [-]
        method : str
            Name of the method to use

        Returns
        -------
        k : float
            Thermal conductivity of the liquid mixture, [W/m/K]
        '''
        if method == SIMPLE:
            ks = [i(T, P) for i in self.ThermalConductivityLiquids]
            return mixing_simple(zs, ks)
        elif method == DIPPR_9H:
            ks = [i(T, P) for i in self.ThermalConductivityLiquids]
            return DIPPR9H(ws, ks)
        elif method == FILIPPOV:
            ks = [i(T, P) for i in self.ThermalConductivityLiquids]
            return Filippov(ws, ks)
        elif method == MAGOMEDOV:
            k_w = self.ThermalConductivityLiquids[self.index_w](T, P)
            ws = list(ws) ; ws.pop(self.index_w)
            return thermal_conductivity_Magomedov(T, P, ws, self.wCASs, k_w)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
if
method
==
SIMPLE
:
ks
=
[
i
(
T
,
P
)
for
i
in
self
.
ThermalConductivityLiquids
]
return
mixing_simple
(
zs
,
ks
)
elif
method
==
DIPPR_9H
:
ks
=
[
i
(
T
,
P
)
for
i
in
self
.
ThermalConductivityLiquids
]
return
DIPPR9H
(
ws
,
ks
)
elif
method
==
FILIPPOV
:
ks
=
[
i
(
T
,
P
)
for
i
in
self
.
ThermalConductivityLiquids
]
return
Filippov
(
ws
,
ks
)
elif
method
==
MAGOMEDOV
:
k_w
=
self
.
ThermalConductivityLiquids
[
self
.
index_w
]
(
T
,
P
)
ws
=
list
(
ws
)
ws
.
pop
(
self
.
index_w
)
return
thermal_conductivity_Magomedov
(
T
,
P
,
ws
,
self
.
wCASs
,
k_w
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate thermal conductivity of a liquid mixture at temperature T pressure P mole fractions zs and weight fractions ws with a given method .


def calculate(self, T, method):
        r'''Method to calculate low-pressure gas thermal conductivity at
        tempearture `T` with a given method.

        This method has no exception handling; see `T_dependent_property`
        for that.

        Parameters
        ----------
        T : float
            Temperature of the gas, [K]
        method : str
            Name of the method to use

        Returns
        -------
        kg : float
            Thermal conductivity of the gas at T and a low pressure, [W/m/K]
        '''
        if method == GHARAGHEIZI_G:
            kg = Gharagheizi_gas(T, self.MW, self.Tb, self.Pc, self.omega)
        elif method == DIPPR_9B:
            Cvgm = self.Cvgm(T) if hasattr(self.Cvgm, '__call__') else self.Cvgm
            mug = self.mug(T) if hasattr(self.mug, '__call__') else self.mug
            kg = DIPPR9B(T, self.MW, Cvgm, mug, self.Tc)
        elif method == CHUNG:
            Cvgm = self.Cvgm(T) if hasattr(self.Cvgm, '__call__') else self.Cvgm
            mug = self.mug(T) if hasattr(self.mug, '__call__') else self.mug
            kg = Chung(T, self.MW, self.Tc, self.omega, Cvgm, mug)
        elif method == ELI_HANLEY:
            Cvgm = self.Cvgm(T) if hasattr(self.Cvgm, '__call__') else self.Cvgm
            kg = eli_hanley(T, self.MW, self.Tc, self.Vc, self.Zc, self.omega, Cvgm)
        elif method == EUCKEN_MOD:
            Cvgm = self.Cvgm(T) if hasattr(self.Cvgm, '__call__') else self.Cvgm
            mug = self.mug(T) if hasattr(self.mug, '__call__') else self.mug
            kg = Eucken_modified(self.MW, Cvgm, mug)
        elif method == EUCKEN:
            Cvgm = self.Cvgm(T) if hasattr(self.Cvgm, '__call__') else self.Cvgm
            mug = self.mug(T) if hasattr(self.mug, '__call__') else self.mug
            kg = Eucken(self.MW, Cvgm, mug)
        elif method == DIPPR_PERRY_8E:
            kg = EQ102(T, *self.Perrys2_314_coeffs)
        elif method == VDI_PPDS:
            kg = horner(self.VDI_PPDS_coeffs, T)
        elif method == BAHADORI_G:
            kg = Bahadori_gas(T, self.MW)
        elif method == COOLPROP:
            kg = CoolProp_T_dependent_property(T, self.CASRN, 'L', 'g')
        elif method in self.tabular_data:
            kg = self.interpolate(T, method)
        return kg

def calculate ( self , T , method ) : if method == GHARAGHEIZI_G : kg = Gharagheizi_gas ( T , self . MW , self . Tb , self . Pc , self . omega ) elif method == DIPPR_9B : Cvgm = self . Cvgm ( T ) if hasattr ( self . Cvgm , '__call__' ) else self . Cvgm mug = self . mug ( T ) if hasattr ( self . mug , '__call__' ) else self . mug kg = DIPPR9B ( T , self . MW , Cvgm , mug , self . Tc ) elif method == CHUNG : Cvgm = self . Cvgm ( T ) if hasattr ( self . Cvgm , '__call__' ) else self . Cvgm mug = self . mug ( T ) if hasattr ( self . mug , '__call__' ) else self . mug kg = Chung ( T , self . MW , self . Tc , self . omega , Cvgm , mug ) elif method == ELI_HANLEY : Cvgm = self . Cvgm ( T ) if hasattr ( self . Cvgm , '__call__' ) else self . Cvgm kg = eli_hanley ( T , self . MW , self . Tc , self . Vc , self . Zc , self . omega , Cvgm ) elif method == EUCKEN_MOD : Cvgm = self . Cvgm ( T ) if hasattr ( self . Cvgm , '__call__' ) else self . Cvgm mug = self . mug ( T ) if hasattr ( self . mug , '__call__' ) else self . mug kg = Eucken_modified ( self . MW , Cvgm , mug ) elif method == EUCKEN : Cvgm = self . Cvgm ( T ) if hasattr ( self . Cvgm , '__call__' ) else self . Cvgm mug = self . mug ( T ) if hasattr ( self . mug , '__call__' ) else self . mug kg = Eucken ( self . MW , Cvgm , mug ) elif method == DIPPR_PERRY_8E : kg = EQ102 ( T , * self . Perrys2_314_coeffs ) elif method == VDI_PPDS : kg = horner ( self . VDI_PPDS_coeffs , T ) elif method == BAHADORI_G : kg = Bahadori_gas ( T , self . MW ) elif method == COOLPROP : kg = CoolProp_T_dependent_property ( T , self . CASRN , 'L' , 'g' ) elif method in self . tabular_data : kg = self . interpolate ( T , method ) return kg

r Method to calculate low - pressure gas thermal conductivity at tempearture T with a given method .