def logP(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval of a chemical's octanol-water
    partition coefficient. 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.

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

    Returns
    -------
    logP : float
        Octanol-water partition coefficient, [-]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain logP with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The method name to use. Accepted methods are 'SYRRES', or 'CRC',
        All valid values are also held in the list logP_methods.
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        the logP for the desired chemical, and will return methods
        instead of the logP

    Notes
    -----
    .. math::
        \log P_{ oct/wat} = \log\left(\frac{\left[{solute}
        \right]_{ octanol}^{un-ionized}}{\left[{solute}
        \right]_{ water}^{ un-ionized}}\right)

    Examples
    --------
    >>> logP('67-56-1')
    -0.74

    References
    ----------
    .. [1] Syrres. 2006. KOWWIN Data, SrcKowData2.zip.
       http://esc.syrres.com/interkow/Download/SrcKowData2.zip
    .. [2] 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 CRClogPDict.index:
            methods.append(CRC)
        if CASRN in SyrresDict2.index:
            methods.append(SYRRES)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == CRC:
        return float(CRClogPDict.at[CASRN, 'logP'])
    elif Method == SYRRES:
        return float(SyrresDict2.at[CASRN, 'logP'])
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
logP
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
CRClogPDict
.
index
:
methods
.
append
(
CRC
)
if
CASRN
in
SyrresDict2
.
index
:
methods
.
append
(
SYRRES
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
CRC
:
return
float
(
CRClogPDict
.
at
[
CASRN
,
'logP'
]
)
elif
Method
==
SYRRES
:
return
float
(
SyrresDict2
.
at
[
CASRN
,
'logP'
]
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval of a chemical s octanol - water partition coefficient . 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 calculate(self, T, method):
        r'''Method to calculate vapor pressure of a fluid at temperature `T`
        with a given method.

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

        Parameters
        ----------
        T : float
            Temperature at calculate vapor pressure, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Psat : float
            Vapor pressure at T, [pa]
        '''
        if method == WAGNER_MCGARRY:
            Psat = Wagner_original(T, self.WAGNER_MCGARRY_Tc, self.WAGNER_MCGARRY_Pc, *self.WAGNER_MCGARRY_coefs)
        elif method == WAGNER_POLING:
            Psat = Wagner(T, self.WAGNER_POLING_Tc, self.WAGNER_POLING_Pc, *self.WAGNER_POLING_coefs)
        elif method == ANTOINE_EXTENDED_POLING:
            Psat = TRC_Antoine_extended(T, *self.ANTOINE_EXTENDED_POLING_coefs)
        elif method == ANTOINE_POLING:
            A, B, C = self.ANTOINE_POLING_coefs
            Psat = Antoine(T, A, B, C, base=10.0)
        elif method == DIPPR_PERRY_8E:
            Psat = EQ101(T, *self.Perrys2_8_coeffs)
        elif method == VDI_PPDS:
            Psat = Wagner(T, self.VDI_PPDS_Tc, self.VDI_PPDS_Pc, *self.VDI_PPDS_coeffs)
        elif method == COOLPROP:
            Psat = PropsSI('P','T', T,'Q',0, self.CASRN)
        elif method == BOILING_CRITICAL:
            Psat = boiling_critical_relation(T, self.Tb, self.Tc, self.Pc)
        elif method == LEE_KESLER_PSAT:
            Psat = Lee_Kesler(T, self.Tc, self.Pc, self.omega)
        elif method == AMBROSE_WALTON:
            Psat = Ambrose_Walton(T, self.Tc, self.Pc, self.omega)
        elif method == SANJARI:
            Psat = Sanjari(T, self.Tc, self.Pc, self.omega)
        elif method == EDALAT:
            Psat = Edalat(T, self.Tc, self.Pc, self.omega)
        elif method == EOS:
            Psat = self.eos[0].Psat(T)
        elif method in self.tabular_data:
            Psat = self.interpolate(T, method)
        return Psat

def calculate ( self , T , method ) : if method == WAGNER_MCGARRY : Psat = Wagner_original ( T , self . WAGNER_MCGARRY_Tc , self . WAGNER_MCGARRY_Pc , * self . WAGNER_MCGARRY_coefs ) elif method == WAGNER_POLING : Psat = Wagner ( T , self . WAGNER_POLING_Tc , self . WAGNER_POLING_Pc , * self . WAGNER_POLING_coefs ) elif method == ANTOINE_EXTENDED_POLING : Psat = TRC_Antoine_extended ( T , * self . ANTOINE_EXTENDED_POLING_coefs ) elif method == ANTOINE_POLING : A , B , C = self . ANTOINE_POLING_coefs Psat = Antoine ( T , A , B , C , base = 10.0 ) elif method == DIPPR_PERRY_8E : Psat = EQ101 ( T , * self . Perrys2_8_coeffs ) elif method == VDI_PPDS : Psat = Wagner ( T , self . VDI_PPDS_Tc , self . VDI_PPDS_Pc , * self . VDI_PPDS_coeffs ) elif method == COOLPROP : Psat = PropsSI ( 'P' , 'T' , T , 'Q' , 0 , self . CASRN ) elif method == BOILING_CRITICAL : Psat = boiling_critical_relation ( T , self . Tb , self . Tc , self . Pc ) elif method == LEE_KESLER_PSAT : Psat = Lee_Kesler ( T , self . Tc , self . Pc , self . omega ) elif method == AMBROSE_WALTON : Psat = Ambrose_Walton ( T , self . Tc , self . Pc , self . omega ) elif method == SANJARI : Psat = Sanjari ( T , self . Tc , self . Pc , self . omega ) elif method == EDALAT : Psat = Edalat ( T , self . Tc , self . Pc , self . omega ) elif method == EOS : Psat = self . eos [ 0 ] . Psat ( T ) elif method in self . tabular_data : Psat = self . interpolate ( T , method ) return Psat

r Method to calculate vapor pressure of a fluid at temperature T with a given method .


def solve(self):
        '''First EOS-generic method; should be called by all specific EOSs.
        For solving for `T`, the EOS must provide the method `solve_T`.
        For all cases, the EOS must provide `a_alpha_and_derivatives`.
        Calls `set_from_PT` once done.
        '''
        self.check_sufficient_inputs()

        if self.V:
            if self.P:
                self.T = self.solve_T(self.P, self.V)
                self.a_alpha, self.da_alpha_dT, self.d2a_alpha_dT2 = self.a_alpha_and_derivatives(self.T)
            else:
                self.a_alpha, self.da_alpha_dT, self.d2a_alpha_dT2 = self.a_alpha_and_derivatives(self.T)
                self.P = R*self.T/(self.V-self.b) - self.a_alpha/(self.V*self.V + self.delta*self.V + self.epsilon)
            Vs = [self.V, 1j, 1j]
        else:
            self.a_alpha, self.da_alpha_dT, self.d2a_alpha_dT2 = self.a_alpha_and_derivatives(self.T)
            Vs = self.volume_solutions(self.T, self.P, self.b, self.delta, self.epsilon, self.a_alpha)
        self.set_from_PT(Vs)

def solve ( self ) : self . check_sufficient_inputs ( ) if self . V : if self . P : self . T = self . solve_T ( self . P , self . V ) self . a_alpha , self . da_alpha_dT , self . d2a_alpha_dT2 = self . a_alpha_and_derivatives ( self . T ) else : self . a_alpha , self . da_alpha_dT , self . d2a_alpha_dT2 = self . a_alpha_and_derivatives ( self . T ) self . P = R * self . T / ( self . V - self . b ) - self . a_alpha / ( self . V * self . V + self . delta * self . V + self . epsilon ) Vs = [ self . V , 1j , 1j ] else : self . a_alpha , self . da_alpha_dT , self . d2a_alpha_dT2 = self . a_alpha_and_derivatives ( self . T ) Vs = self . volume_solutions ( self . T , self . P , self . b , self . delta , self . epsilon , self . a_alpha ) self . set_from_PT ( Vs )

First EOS - generic method ; should be called by all specific EOSs . For solving for T the EOS must provide the method solve_T . For all cases the EOS must provide a_alpha_and_derivatives . Calls set_from_PT once done .


def set_from_PT(self, Vs):
        '''Counts the number of real volumes in `Vs`, and determines what to do.
        If there is only one real volume, the method
        `set_properties_from_solution` is called with it. If there are
        two real volumes, `set_properties_from_solution` is called once with
        each volume. The phase is returned by `set_properties_from_solution`,
        and the volumes is set to either `V_l` or `V_g` as appropriate.

        Parameters
        ----------
        Vs : list[float]
            Three possible molar volumes, [m^3/mol]
        '''
        # All roots will have some imaginary component; ignore them if > 1E-9
        good_roots = []
        bad_roots = []
        for i in Vs:
            j = i.real
            if abs(i.imag) > 1E-9 or j < 0:
                bad_roots.append(i)
            else:
                good_roots.append(j)

        if len(bad_roots) == 2:
            V = good_roots[0]
            self.phase = self.set_properties_from_solution(self.T, self.P, V, self.b, self.delta, self.epsilon, self.a_alpha, self.da_alpha_dT, self.d2a_alpha_dT2)
            if self.phase == 'l':
                self.V_l = V
            else:
                self.V_g = V
        else:
            # Even in the case of three real roots, it is still the min/max that make sense
            self.V_l, self.V_g = min(good_roots), max(good_roots)
            [self.set_properties_from_solution(self.T, self.P, V, self.b, self.delta, self.epsilon, self.a_alpha, self.da_alpha_dT, self.d2a_alpha_dT2) for V in [self.V_l, self.V_g]]
            self.phase = 'l/g'

Counts the number of real volumes in Vs and determines what to do . If there is only one real volume the method set_properties_from_solution is called with it . If there are two real volumes set_properties_from_solution is called once with each volume . The phase is returned by set_properties_from_solution and the volumes is set to either V_l or V_g as appropriate .


def solve_T(self, P, V, quick=True):
        '''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
            Whether to use a SymPy cse-derived expression (3x faster) or
            individual formulas - not applicable where a numerical solver is
            used.

        Returns
        -------
        T : float
            Temperature, [K]
        '''
        def to_solve(T):
            a_alpha = self.a_alpha_and_derivatives(T, full=False)
            P_calc = R*T/(V-self.b) - a_alpha/(V*V + self.delta*V + self.epsilon)
            return P_calc - P
        return newton(to_solve, self.Tc*0.5)

def solve_T ( self , P , V , quick = True ) : def to_solve ( T ) : a_alpha = self . a_alpha_and_derivatives ( T , full = False ) P_calc = R * T / ( V - self . b ) - a_alpha / ( V * V + self . delta * V + self . epsilon ) return P_calc - P return newton ( to_solve , self . Tc * 0.5 )

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 a_alpha_and_derivatives(self, T, full=True, quick=True):
        r'''Method to calculate `a_alpha` and its first and second
        derivatives for this EOS. Returns `a_alpha`, `da_alpha_dT`, and
        `d2a_alpha_dT2`. See `GCEOS.a_alpha_and_derivatives` for more
        documentation. Uses the set values of `Tc`, `kappa`, and `a`.

        For use in `solve_T`, returns only `a_alpha` if full is False.

        .. math::
            a\alpha = a \left(\kappa \left(- \frac{T^{0.5}}{Tc^{0.5}}
            + 1\right) + 1\right)^{2}

            \frac{d a\alpha}{dT} = - \frac{1.0 a \kappa}{T^{0.5} Tc^{0.5}}
            \left(\kappa \left(- \frac{T^{0.5}}{Tc^{0.5}} + 1\right) + 1\right)

            \frac{d^2 a\alpha}{dT^2} = 0.5 a \kappa \left(- \frac{1}{T^{1.5}
            Tc^{0.5}} \left(\kappa \left(\frac{T^{0.5}}{Tc^{0.5}} - 1\right)
            - 1\right) + \frac{\kappa}{T^{1.0} Tc^{1.0}}\right)
        '''
        if not full:
            return self.a*(1 + self.kappa*(1-(T/self.Tc)**0.5))**2
        else:
            if quick:
                Tc, kappa = self.Tc, self.kappa
                x0 = T**0.5
                x1 = Tc**-0.5
                x2 = kappa*(x0*x1 - 1.) - 1.
                x3 = self.a*kappa

                a_alpha = self.a*x2*x2
                da_alpha_dT = x1*x2*x3/x0
                d2a_alpha_dT2 = x3*(-0.5*T**-1.5*x1*x2 + 0.5/(T*Tc)*kappa)
            else:
                a_alpha = self.a*(1 + self.kappa*(1-(T/self.Tc)**0.5))**2
                da_alpha_dT = -self.a*self.kappa*sqrt(T/self.Tc)*(self.kappa*(-sqrt(T/self.Tc) + 1.) + 1.)/T
                d2a_alpha_dT2 = self.a*self.kappa*(self.kappa/self.Tc - sqrt(T/self.Tc)*(self.kappa*(sqrt(T/self.Tc) - 1.) - 1.)/T)/(2.*T)
            return a_alpha, da_alpha_dT, d2a_alpha_dT2

def a_alpha_and_derivatives ( self , T , full = True , quick = True ) : if not full : return self . a * ( 1 + self . kappa * ( 1 - ( T / self . Tc ) ** 0.5 ) ) ** 2 else : if quick : Tc , kappa = self . Tc , self . kappa x0 = T ** 0.5 x1 = Tc ** - 0.5 x2 = kappa * ( x0 * x1 - 1. ) - 1. x3 = self . a * kappa a_alpha = self . a * x2 * x2 da_alpha_dT = x1 * x2 * x3 / x0 d2a_alpha_dT2 = x3 * ( - 0.5 * T ** - 1.5 * x1 * x2 + 0.5 / ( T * Tc ) * kappa ) else : a_alpha = self . a * ( 1 + self . kappa * ( 1 - ( T / self . Tc ) ** 0.5 ) ) ** 2 da_alpha_dT = - self . a * self . kappa * sqrt ( T / self . Tc ) * ( self . kappa * ( - sqrt ( T / self . Tc ) + 1. ) + 1. ) / T d2a_alpha_dT2 = self . a * self . kappa * ( self . kappa / self . Tc - sqrt ( T / self . Tc ) * ( self . kappa * ( sqrt ( T / self . Tc ) - 1. ) - 1. ) / T ) / ( 2. * T ) return a_alpha , da_alpha_dT , d2a_alpha_dT2

r Method to calculate a_alpha and its first and second derivatives for this EOS . Returns a_alpha da_alpha_dT and d2a_alpha_dT2 . See GCEOS . a_alpha_and_derivatives for more documentation . Uses the set values of Tc kappa and a . For use in solve_T returns only a_alpha if full is False .


def solve_T(self, P, V, quick=True):
        r'''Method to calculate `T` from a specified `P` and `V` for the PRSV
        EOS. Uses `Tc`, `a`, `b`, `kappa0`  and `kappa` as well, obtained from
        the class's namespace.

        Parameters
        ----------
        P : float
            Pressure, [Pa]
        V : float
            Molar volume, [m^3/mol]
        quick : bool, optional
            Whether to use a SymPy cse-derived expression (somewhat faster) or
            individual formulas.

        Returns
        -------
        T : float
            Temperature, [K]

        Notes
        -----
        Not guaranteed to produce a solution. There are actually two solution,
        one much higher than normally desired; it is possible the solver could
        converge on this.
        '''
        Tc, a, b, kappa0, kappa1 = self.Tc, self.a, self.b, self.kappa0, self.kappa1
        if quick:
            x0 = V - b
            R_x0 = R/x0
            x3 = (100.*(V*(V + b) + b*x0))
            x4 = 10.*kappa0
            kappa110 = kappa1*10.
            kappa17 = kappa1*7.
            def to_solve(T):
                x1 = T/Tc
                x2 = x1**0.5
                return (T*R_x0 - a*((x4 - (kappa110*x1 - kappa17)*(x2 + 1.))*(x2 - 1.) - 10.)**2/x3) - P
        else:
            def to_solve(T):
                P_calc = R*T/(V - b) - a*((kappa0 + kappa1*(sqrt(T/Tc) + 1)*(-T/Tc + 7/10))*(-sqrt(T/Tc) + 1) + 1)**2/(V*(V + b) + b*(V - b))
                return P_calc - P
        return newton(to_solve, Tc*0.5)

def solve_T ( self , P , V , quick = True ) : Tc , a , b , kappa0 , kappa1 = self . Tc , self . a , self . b , self . kappa0 , self . kappa1 if quick : x0 = V - b R_x0 = R / x0 x3 = ( 100. * ( V * ( V + b ) + b * x0 ) ) x4 = 10. * kappa0 kappa110 = kappa1 * 10. kappa17 = kappa1 * 7. def to_solve ( T ) : x1 = T / Tc x2 = x1 ** 0.5 return ( T * R_x0 - a * ( ( x4 - ( kappa110 * x1 - kappa17 ) * ( x2 + 1. ) ) * ( x2 - 1. ) - 10. ) ** 2 / x3 ) - P else : def to_solve ( T ) : P_calc = R * T / ( V - b ) - a * ( ( kappa0 + kappa1 * ( sqrt ( T / Tc ) + 1 ) * ( - T / Tc + 7 / 10 ) ) * ( - sqrt ( T / Tc ) + 1 ) + 1 ) ** 2 / ( V * ( V + b ) + b * ( V - b ) ) return P_calc - P return newton ( to_solve , Tc * 0.5 )

r Method to calculate T from a specified P and V for the PRSV EOS . Uses Tc a b kappa0 and kappa as well obtained from the class s namespace .


def solve_T(self, P, V):
        r'''Method to calculate `T` from a specified `P` and `V` for the VDW
        EOS. Uses `a`, and `b`, obtained from the class's namespace.

        .. math::
            T =  \frac{1}{R V^{2}} \left(P V^{2} \left(V - b\right)
            + V a - a b\right)

        Parameters
        ----------
        P : float
            Pressure, [Pa]
        V : float
            Molar volume, [m^3/mol]

        Returns
        -------
        T : float
            Temperature, [K]
        '''
        return (P*V**2*(V - self.b) + V*self.a - self.a*self.b)/(R*V**2)

def solve_T ( self , P , V ) : return ( P * V ** 2 * ( V - self . b ) + V * self . a - self . a * self . b ) / ( R * V ** 2 )

r Method to calculate T from a specified P and V for the VDW EOS . Uses a and b obtained from the class s namespace .


r'''Method to calculate `T` from a specified `P` and `V` for the RK
        EOS. Uses `a`, and `b`, obtained from the class's namespace.

        Parameters
        ----------
        P : float
            Pressure, [Pa]
        V : float
            Molar volume, [m^3/mol]
        quick : bool, optional
            Whether to use a SymPy cse-derived expression (3x faster) or
            individual formulas

        Returns
        -------
        T : float
            Temperature, [K]

        Notes
        -----
        The exact solution can be derived as follows; it is excluded for
        breviety.

        >>> from sympy import *
        >>> P, T, V, R = symbols('P, T, V, R')
        >>> Tc, Pc = symbols('Tc, Pc')
        >>> a, b = symbols('a, b')

        >>> RK = Eq(P, R*T/(V-b) - a/sqrt(T)/(V*V + b*V))
        >>> # solve(RK, T)

r Method to calculate T from a specified P and V for the RK EOS . Uses a and b obtained from the class s namespace .


def solve_T(self, P, V, quick=True):
        r'''Method to calculate `T` from a specified `P` and `V` for the API
        SRK EOS. Uses `a`, `b`, and `Tc` obtained from the class's namespace.

        Parameters
        ----------
        P : float
            Pressure, [Pa]
        V : float
            Molar volume, [m^3/mol]
        quick : bool, optional
            Whether to use a SymPy cse-derived expression (3x faster) or
            individual formulas

        Returns
        -------
        T : float
            Temperature, [K]

        Notes
        -----
        If S2 is set to 0, the solution is the same as in the SRK EOS, and that
        is used. Otherwise, newton's method must be used to solve for `T`.
        There are 8 roots of T in that case, six of them real. No guarantee can
        be made regarding which root will be obtained.
        '''
        if self.S2 == 0:
            self.m = self.S1
            return SRK.solve_T(self, P, V, quick=quick)
        else:
            # Previously coded method is  63 microseconds vs 47 here
#            return super(SRK, self).solve_T(P, V, quick=quick)
            Tc, a, b, S1, S2 = self.Tc, self.a, self.b, self.S1, self.S2
            if quick:
                x2 = R/(V-b)
                x3 = (V*(V + b))
                def to_solve(T):
                    x0 = (T/Tc)**0.5
                    x1 = x0 - 1.
                    return (x2*T - a*(S1*x1 + S2*x1/x0 - 1.)**2/x3) - P
            else:
                def to_solve(T):
                    P_calc = R*T/(V - b) - a*(S1*(-sqrt(T/Tc) + 1) + S2*(-sqrt(T/Tc) + 1)/sqrt(T/Tc) + 1)**2/(V*(V + b))
                    return P_calc - P
            return newton(to_solve, Tc*0.5)

r Method to calculate T from a specified P and V for the API SRK EOS . Uses a b and Tc obtained from the class s namespace .


def a_alpha_and_derivatives(self, T, full=True, quick=True):
        r'''Method to calculate `a_alpha` and its first and second
        derivatives for this EOS. Returns `a_alpha`, `da_alpha_dT`, and
        `d2a_alpha_dT2`. See `GCEOS.a_alpha_and_derivatives` for more
        documentation. Uses the set values of `Tc`, `omega`, and `a`.

        Because of its similarity for the TWUPR EOS, this has been moved to an
        external `TWU_a_alpha_common` function. See it for further
        documentation.
        '''
        return TWU_a_alpha_common(T, self.Tc, self.omega, self.a, full=full, quick=quick, method='SRK')

def a_alpha_and_derivatives ( self , T , full = True , quick = True ) : return TWU_a_alpha_common ( T , self . Tc , self . omega , self . a , full = full , quick = quick , method = 'SRK' )

r Method to calculate a_alpha and its first and second derivatives for this EOS . Returns a_alpha da_alpha_dT and d2a_alpha_dT2 . See GCEOS . a_alpha_and_derivatives for more documentation . Uses the set values of Tc omega and a . Because of its similarity for the TWUPR EOS this has been moved to an external TWU_a_alpha_common function . See it for further documentation .


def Tb(CASRN, AvailableMethods=False, Method=None, IgnoreMethods=[PSAT_DEFINITION]):
    r'''This function handles the retrieval of a chemical's boiling
    point. Lookup is based on CASRNs. Will automatically select a data
    source to use if no Method is provided; returns None if the data is not
    available.

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

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

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

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

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

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

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

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

    if Method == CRC_INORG:
        return float(CRC_inorganic_data.at[CASRN, 'Tb'])
    elif Method == CRC_ORG:
        return float(CRC_organic_data.at[CASRN, 'Tb'])
    elif Method == YAWS:
        return float(Yaws_data.at[CASRN, 'Tb'])
    elif Method == PSAT_DEFINITION:
        return VaporPressure(CASRN=CASRN).solve_prop(101325.)
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

r This function handles the retrieval of a chemical s boiling point . Lookup is based on CASRNs . Will automatically select a data source to use if no Method is provided ; returns None if the data is not available .


def Tm(CASRN, AvailableMethods=False, Method=None, IgnoreMethods=[]):
    r'''This function handles the retrieval of a chemical's melting
    point. Lookup is based on CASRNs. Will automatically select a data
    source to use if no Method is provided; returns None if the data is not
    available.

    Prefered sources are 'Open Notebook Melting Points', with backup sources
    'CRC Physical Constants, organic' for organic chemicals, and
    'CRC Physical Constants, inorganic' for inorganic chemicals. Function has
    data for approximately 14000 chemicals.

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

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

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

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

        * 'OPEN_NTBKM, a compillation of data on organics
          as published in [1]_ as Open Notebook Melting Points; Averaged
          (median) values were used when
          multiple points were available. For more information on this
          invaluable and excellent collection, see
          http://onswebservices.wikispaces.com/meltingpoint.
        * 'CRC_ORG', a compillation of data on organics
          as published in [2]_.
        * 'CRC_INORG', a compillation of data on
          inorganic as published in [2]_.

    Examples
    --------
    >>> Tm(CASRN='7732-18-5')
    273.15

    References
    ----------
    .. [1] Bradley, Jean-Claude, Antony Williams, and Andrew Lang.
       "Jean-Claude Bradley Open Melting Point Dataset", May 20, 2014.
       https://figshare.com/articles/Jean_Claude_Bradley_Open_Melting_Point_Datset/1031637.
    .. [2] 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 Tm_ON_data.index:
            methods.append(OPEN_NTBKM)
        if CASRN in CRC_inorganic_data.index and not np.isnan(CRC_inorganic_data.at[CASRN, 'Tm']):
            methods.append(CRC_INORG)
        if CASRN in CRC_organic_data.index and not np.isnan(CRC_organic_data.at[CASRN, 'Tm']):
            methods.append(CRC_ORG)
        if IgnoreMethods:
            for Method in IgnoreMethods:
                if Method in methods:
                    methods.remove(Method)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == OPEN_NTBKM:
        return float(Tm_ON_data.at[CASRN, 'Tm'])
    elif Method == CRC_INORG:
        return float(CRC_inorganic_data.at[CASRN, 'Tm'])
    elif Method == CRC_ORG:
        return float(CRC_organic_data.at[CASRN, 'Tm'])
    elif Method == NONE:
        return None
    else:
        raise Exception('Failure in in function')

def
Tm
(
CASRN
,
AvailableMethods
=
False
,
Method
=
,
IgnoreMethods
=
[
]
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
Tm_ON_data
.
index
:
methods
.
append
(
OPEN_NTBKM
)
if
CASRN
in
CRC_inorganic_data
.
index
and
not
np
.
isnan
(
CRC_inorganic_data
.
at
[
CASRN
,
'Tm'
]
)
:
methods
.
append
(
CRC_INORG
)
if
CASRN
in
CRC_organic_data
.
index
and
not
np
.
isnan
(
CRC_organic_data
.
at
[
CASRN
,
'Tm'
]
)
:
methods
.
append
(
CRC_ORG
)
if
IgnoreMethods
:
for
Method
in
IgnoreMethods
:
if
Method
in
methods
:
methods
.
remove
(
Method
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
OPEN_NTBKM
:
return
float
(
Tm_ON_data
.
at
[
CASRN
,
'Tm'
]
)
elif
Method
==
CRC_INORG
:
return
float
(
CRC_inorganic_data
.
at
[
CASRN
,
'Tm'
]
)
elif
Method
==
CRC_ORG
:
return
float
(
CRC_organic_data
.
at
[
CASRN
,
'Tm'
]
)
elif
Method
==
:
return
else
:
raise
Exception
(
'Failure in in function'
)

r This function handles the retrieval of a chemical s melting point . Lookup is based on CASRNs . Will automatically select a data source to use if no Method is provided ; returns None if the data is not available .


def Clapeyron(T, Tc, Pc, dZ=1, Psat=101325):
    r'''Calculates enthalpy of vaporization at arbitrary temperatures using the
    Clapeyron equation.

    The enthalpy of vaporization is given by:

    .. math::
        \Delta H_{vap} = RT \Delta Z \frac{\ln (P_c/Psat)}{(1-T_{r})}

    Parameters
    ----------
    T : float
        Temperature of fluid [K]
    Tc : float
        Critical temperature of fluid [K]
    Pc : float
        Critical pressure of fluid [Pa]
    dZ : float
        Change in compressibility factor between liquid and gas, []
    Psat : float
        Saturation pressure of fluid [Pa], optional

    Returns
    -------
    Hvap : float
        Enthalpy of vaporization, [J/mol]

    Notes
    -----
    No original source is available for this equation.
    [1]_ claims this equation overpredicts enthalpy by several percent.
    Under Tr = 0.8, dZ = 1 is a reasonable assumption.
    This equation is most accurate at the normal boiling point.

    Internal units are bar.

    WARNING: I believe it possible that the adjustment for pressure may be incorrect

    Examples
    --------
    Problem from Perry's examples.

    >>> Clapeyron(T=294.0, Tc=466.0, Pc=5.55E6)
    26512.354585061985

    References
    ----------
    .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition.
       New York: McGraw-Hill Professional, 2000.
    '''
    Tr = T/Tc
    return R*T*dZ*log(Pc/Psat)/(1. - Tr)

def Clapeyron ( T , Tc , Pc , dZ = 1 , Psat = 101325 ) : Tr = T / Tc return R * T * dZ * log ( Pc / Psat ) / ( 1. - Tr )

r Calculates enthalpy of vaporization at arbitrary temperatures using the Clapeyron equation .


def Watson(T, Hvap_ref, T_Ref, Tc, exponent=0.38):
    '''
    Adjusts enthalpy of vaporization of enthalpy for another temperature, for one temperature.
    '''
    Tr = T/Tc
    Trefr = T_Ref/Tc
    H2 = Hvap_ref*((1-Tr)/(1-Trefr))**exponent
    return H2

def Watson ( T , Hvap_ref , T_Ref , Tc , exponent = 0.38 ) : Tr = T / Tc Trefr = T_Ref / Tc H2 = Hvap_ref * ( ( 1 - Tr ) / ( 1 - Trefr ) ) ** exponent return H2

Adjusts enthalpy of vaporization of enthalpy for another temperature for one temperature .


def Hfus(T=298.15, P=101325, MW=None, AvailableMethods=False, Method=None, CASRN=''):  # pragma: no cover
    '''This function handles the calculation of a chemical's enthalpy of fusion.
    Generally this, is used by the chemical class, as all parameters are passed.
    Calling the function directly works okay.

    Enthalpy of fusion is a weak function of pressure, and its effects are
    neglected.

    This API is considered experimental, and is expected to be removed in a
    future release in favor of a more complete object-oriented interface.

    '''
    def list_methods():
        methods = []
        if CASRN in CRCHfus_data.index:
            methods.append('CRC, at melting point')
        methods.append('None')
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    # This is the calculate, given the method section
    if Method == 'CRC, at melting point':
        _Hfus = CRCHfus_data.at[CASRN, 'Hfus']
    elif Method == 'None' or not MW:
        _Hfus = None
    else:
        raise Exception('Failure in in function')
    _Hfus = property_molar_to_mass(_Hfus, MW)
    return _Hfus

This function handles the calculation of a chemical s enthalpy of fusion . Generally this is used by the chemical class as all parameters are passed . Calling the function directly works okay .


def Hsub(T=298.15, P=101325, MW=None, AvailableMethods=False, Method=None, CASRN=''):  # pragma: no cover
    '''This function handles the calculation of a chemical's enthalpy of sublimation.
    Generally this, is used by the chemical class, as all parameters are passed.

    This API is considered experimental, and is expected to be removed in a
    future release in favor of a more complete object-oriented interface.
    '''
    def list_methods():
        methods = []
#        if Hfus(T=T, P=P, MW=MW, CASRN=CASRN) and Hvap(T=T, P=P, MW=MW, CASRN=CASRN):
#            methods.append('Hfus + Hvap')
        if CASRN in GharagheiziHsub_data.index:
            methods.append('Ghazerati Appendix, at 298K')
        methods.append('None')
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    # This is the calculate, given the method section
#    if Method == 'Hfus + Hvap':
#        p1 = Hfus(T=T, P=P, MW=MW, CASRN=CASRN)
#        p2 = Hvap(T=T, P=P, MW=MW, CASRN=CASRN)
#        if p1 and p2:
#            _Hsub = p1 + p2
#        else:
#            _Hsub = None
    if Method == 'Ghazerati Appendix, at 298K':
        _Hsub = float(GharagheiziHsub_data.at[CASRN, 'Hsub'])
    elif Method == 'None' or not _Hsub or not MW:
        return None
    else:
        raise Exception('Failure in in function')
    _Hsub = property_molar_to_mass(_Hsub, MW)
    return _Hsub

#            methods.append('Hfus + Hvap')

This function handles the calculation of a chemical s enthalpy of sublimation . Generally this is used by the chemical class as all parameters are passed .


def Tliquidus(Tms=None, ws=None, xs=None, CASRNs=None, AvailableMethods=False,
              Method=None):  # pragma: no cover
    '''This function handles the retrival of a mixtures's liquidus point.

    This API is considered experimental, and is expected to be removed in a
    future release in favor of a more complete object-oriented interface.

    >>> Tliquidus(Tms=[250.0, 350.0], xs=[0.5, 0.5])
    350.0
    >>> Tliquidus(Tms=[250, 350], xs=[0.5, 0.5], Method='Simple')
    300.0
    >>> Tliquidus(Tms=[250, 350], xs=[0.5, 0.5], AvailableMethods=True)
    ['Maximum', 'Simple', 'None']
    '''
    def list_methods():
        methods = []
        if none_and_length_check([Tms]):
            methods.append('Maximum')
            methods.append('Simple')
        methods.append('None')
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    # This is the calculate, given the method section
    if Method == 'Maximum':
        _Tliq = max(Tms)
    elif Method == 'Simple':
        _Tliq = mixing_simple(xs, Tms)
    elif Method == 'None':
        return None
    else:
        raise Exception('Failure in in function')
    return _Tliq

This function handles the retrival of a mixtures s liquidus point .


def solubility_parameter(T=298.15, Hvapm=None, Vml=None,
                         CASRN='', AvailableMethods=False, Method=None):
    r'''This function handles the calculation of a chemical's solubility
    parameter. Calculation is a function of temperature, but is not always
    presented as such. No lookup values are available; either `Hvapm`, `Vml`,
    and `T` are provided or the calculation cannot be performed.

    .. math::
        \delta = \sqrt{\frac{\Delta H_{vap} - RT}{V_m}}

    Parameters
    ----------
    T : float
        Temperature of the fluid [k]
    Hvapm : float
        Heat of vaporization [J/mol/K]
    Vml : float
        Specific volume of the liquid [m^3/mol]
    CASRN : str, optional
        CASRN of the fluid, not currently used [-]

    Returns
    -------
    delta : float
        Solubility parameter, [Pa^0.5]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain the solubility parameter
        with the given inputs

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

    Notes
    -----
    Undefined past the critical point. For convenience, if Hvap is not defined,
    an error is not raised; None is returned instead. Also for convenience,
    if Hvapm is less than RT, None is returned to avoid taking the root of a
    negative number.

    This parameter is often given in units of cal/ml, which is 2045.48 times
    smaller than the value returned here.

    Examples
    --------
    Pentane at STP

    >>> solubility_parameter(T=298.2, Hvapm=26403.3, Vml=0.000116055)
    14357.681538173534

    References
    ----------
    .. [1] Barton, Allan F. M. CRC Handbook of Solubility Parameters and Other
       Cohesion Parameters, Second Edition. CRC Press, 1991.
    '''
    def list_methods():
        methods = []
        if T and Hvapm and Vml:
            methods.append(DEFINITION)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == DEFINITION:
        if (not Hvapm) or (not T) or (not Vml):
            delta = None
        else:
            if Hvapm < R*T or Vml < 0:  # Prevent taking the root of a negative number
                delta = None
            else:
                delta = ((Hvapm - R*T)/Vml)**0.5
    elif Method == NONE:
        delta = None
    else:
        raise Exception('Failure in in function')
    return delta

r This function handles the calculation of a chemical s solubility parameter . Calculation is a function of temperature but is not always presented as such . No lookup values are available ; either Hvapm Vml and T are provided or the calculation cannot be performed .


def solubility_eutectic(T, Tm, Hm, Cpl=0, Cps=0, gamma=1):
    r'''Returns the maximum solubility of a solute in a solvent.

    .. math::
        \ln x_i^L \gamma_i^L = \frac{\Delta H_{m,i}}{RT}\left(
        1 - \frac{T}{T_{m,i}}\right) - \frac{\Delta C_{p,i}(T_{m,i}-T)}{RT}
        + \frac{\Delta C_{p,i}}{R}\ln\frac{T_m}{T}

        \Delta C_{p,i} = C_{p,i}^L - C_{p,i}^S

    Parameters
    ----------
    T : float
        Temperature of the system [K]
    Tm : float
        Melting temperature of the solute [K]
    Hm : float
        Heat of melting at the melting temperature of the solute [J/mol]
    Cpl : float, optional
        Molar heat capacity of the solute as a liquid [J/mol/K]
    Cpls: float, optional
        Molar heat capacity of the solute as a solid [J/mol/K]
    gamma : float, optional
        Activity coefficient of the solute as a liquid [-]

    Returns
    -------
    x : float
        Mole fraction of solute at maximum solubility [-]

    Notes
    -----
    gamma is of the solute in liquid phase

    Examples
    --------
    From [1]_, matching example

    >>> solubility_eutectic(T=260., Tm=278.68, Hm=9952., Cpl=0, Cps=0, gamma=3.0176)
    0.24340068761677464

    References
    ----------
    .. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
       Weinheim, Germany: Wiley-VCH, 2012.
    '''
    dCp = Cpl-Cps
    x = exp(- Hm/R/T*(1-T/Tm) + dCp*(Tm-T)/R/T - dCp/R*log(Tm/T))/gamma
    return x

def solubility_eutectic ( T , Tm , Hm , Cpl = 0 , Cps = 0 , gamma = 1 ) : dCp = Cpl - Cps x = exp ( - Hm / R / T * ( 1 - T / Tm ) + dCp * ( Tm - T ) / R / T - dCp / R * log ( Tm / T ) ) / gamma return x

r Returns the maximum solubility of a solute in a solvent .


def Tm_depression_eutectic(Tm, Hm, x=None, M=None, MW=None):
    r'''Returns the freezing point depression caused by a solute in a solvent.
    Can use either the mole fraction of the solute or its molality and the
    molecular weight of the solvent. Assumes ideal system behavior.

    .. math::
        \Delta T_m = \frac{R T_m^2 x}{\Delta H_m}

        \Delta T_m = \frac{R T_m^2 (MW) M}{1000 \Delta H_m}

    Parameters
    ----------
    Tm : float
        Melting temperature of the solute [K]
    Hm : float
        Heat of melting at the melting temperature of the solute [J/mol]
    x : float, optional
        Mole fraction of the solute [-]
    M : float, optional
        Molality [mol/kg]
    MW: float, optional
        Molecular weight of the solvent [g/mol]

    Returns
    -------
    dTm : float
        Freezing point depression [K]

    Notes
    -----
    MW is the molecular weight of the solvent. M is the molality of the solute.

    Examples
    --------
    From [1]_, matching example.

    >>> Tm_depression_eutectic(353.35, 19110, .02)
    1.0864594900639515

    References
    ----------
    .. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
       Weinheim, Germany: Wiley-VCH, 2012.
    '''
    if x:
        dTm = R*Tm**2*x/Hm
    elif M and MW:
        MW = MW/1000. #g/mol to kg/mol
        dTm = R*Tm**2*MW*M/Hm
    else:
        raise Exception('Either molality or mole fraction of the solute must be specified; MW of the solvent is required also if molality is provided')
    return dTm

r Returns the freezing point depression caused by a solute in a solvent . Can use either the mole fraction of the solute or its molality and the molecular weight of the solvent . Assumes ideal system behavior .


def Rackett(T, Tc, Pc, Zc):
    r'''Calculates saturation liquid volume, using Rackett CSP method and
    critical properties.

    The molar volume of a liquid is given by:

    .. math::
        V_s = \frac{RT_c}{P_c}{Z_c}^{[1+(1-{T/T_c})^{2/7} ]}

    Units are all currently in m^3/mol - this can be changed to kg/m^3

    Parameters
    ----------
    T : float
        Temperature of fluid [K]
    Tc : float
        Critical temperature of fluid [K]
    Pc : float
        Critical pressure of fluid [Pa]
    Zc : float
        Critical compressibility of fluid, [-]

    Returns
    -------
    Vs : float
        Saturation liquid volume, [m^3/mol]

    Notes
    -----
    Units are dependent on gas constant R, imported from scipy
    According to Reid et. al, underpredicts volume for compounds with Zc < 0.22

    Examples
    --------
    Propane, example from the API Handbook

    >>> Vm_to_rho(Rackett(272.03889, 369.83, 4248000.0, 0.2763), 44.09562)
    531.3223212651092

    References
    ----------
    .. [1] Rackett, Harold G. "Equation of State for Saturated Liquids."
       Journal of Chemical & Engineering Data 15, no. 4 (1970): 514-517.
       doi:10.1021/je60047a012
    '''
    return R*Tc/Pc*Zc**(1 + (1 - T/Tc)**(2/7.))

def Rackett ( T , Tc , Pc , Zc ) : return R * Tc / Pc * Zc ** ( 1 + ( 1 - T / Tc ) ** ( 2 / 7. ) )

r Calculates saturation liquid volume using Rackett CSP method and critical properties .


def Yamada_Gunn(T, Tc, Pc, omega):
    r'''Calculates saturation liquid volume, using Yamada and Gunn CSP method
    and a chemical's critical properties and acentric factor.

    The molar volume of a liquid is given by:

    .. math::
        V_s = \frac{RT_c}{P_c}{(0.29056-0.08775\omega)}^{[1+(1-{T/T_c})^{2/7}]}

    Units are in m^3/mol.

    Parameters
    ----------
    T : float
        Temperature of fluid [K]
    Tc : float
        Critical temperature of fluid [K]
    Pc : float
        Critical pressure of fluid [Pa]
    omega : float
        Acentric factor for fluid, [-]

    Returns
    -------
    Vs : float
        saturation liquid volume, [m^3/mol]

    Notes
    -----
    This equation is an improvement on the Rackett equation.
    This is often presented as the Rackett equation.
    The acentric factor is used here, instead of the critical compressibility
    A variant using a reference fluid also exists

    Examples
    --------
    >>> Yamada_Gunn(300, 647.14, 22048320.0, 0.245)
    2.1882836429895796e-05

    References
    ----------
    .. [1] Gunn, R. D., and Tomoyoshi Yamada. "A Corresponding States
        Correlation of Saturated Liquid Volumes." AIChE Journal 17, no. 6
        (1971): 1341-45. doi:10.1002/aic.690170613
    .. [2] Yamada, Tomoyoshi, and Robert D. Gunn. "Saturated Liquid Molar
        Volumes. Rackett Equation." Journal of Chemical & Engineering Data 18,
        no. 2 (1973): 234-36. doi:10.1021/je60057a006
    '''
    return R*Tc/Pc*(0.29056 - 0.08775*omega)**(1 + (1 - T/Tc)**(2/7.))

r Calculates saturation liquid volume using Yamada and Gunn CSP method and a chemical s critical properties and acentric factor .


def Townsend_Hales(T, Tc, Vc, omega):
    r'''Calculates saturation liquid density, using the Townsend and Hales
    CSP method as modified from the original Riedel equation. Uses
    chemical critical volume and temperature, as well as acentric factor

    The density of a liquid is given by:

    .. math::
        Vs = V_c/\left(1+0.85(1-T_r)+(1.692+0.986\omega)(1-T_r)^{1/3}\right)

    Parameters
    ----------
    T : float
        Temperature of fluid [K]
    Tc : float
        Critical temperature of fluid [K]
    Vc : float
        Critical volume of fluid [m^3/mol]
    omega : float
        Acentric factor for fluid, [-]

    Returns
    -------
    Vs : float
        Saturation liquid volume, [m^3/mol]

    Notes
    -----
    The requirement for critical volume and acentric factor requires all data.

    Examples
    --------
    >>> Townsend_Hales(300, 647.14, 55.95E-6, 0.3449)
    1.8007361992619923e-05

    References
    ----------
    .. [1] Hales, J. L, and R Townsend. "Liquid Densities from 293 to 490 K of
       Nine Aromatic Hydrocarbons." The Journal of Chemical Thermodynamics
       4, no. 5 (1972): 763-72. doi:10.1016/0021-9614(72)90050-X
    '''
    Tr = T/Tc
    return Vc/(1 + 0.85*(1-Tr) + (1.692 + 0.986*omega)*(1-Tr)**(1/3.))

r Calculates saturation liquid density using the Townsend and Hales CSP method as modified from the original Riedel equation . Uses chemical critical volume and temperature as well as acentric factor


def COSTALD(T, Tc, Vc, omega):
    r'''Calculate saturation liquid density using the COSTALD CSP method.

    A popular and accurate estimation method. If possible, fit parameters are
    used; alternatively critical properties work well.

    The density of a liquid is given by:

    .. math::
        V_s=V^*V^{(0)}[1-\omega_{SRK}V^{(\delta)}]

        V^{(0)}=1-1.52816(1-T_r)^{1/3}+1.43907(1-T_r)^{2/3}
        - 0.81446(1-T_r)+0.190454(1-T_r)^{4/3}

        V^{(\delta)}=\frac{-0.296123+0.386914T_r-0.0427258T_r^2-0.0480645T_r^3}
        {T_r-1.00001}

    Units are that of critical or fit constant volume.

    Parameters
    ----------
    T : float
        Temperature of fluid [K]
    Tc : float
        Critical temperature of fluid [K]
    Vc : float
        Critical volume of fluid [m^3/mol].
        This parameter is alternatively a fit parameter
    omega : float
        (ideally SRK) Acentric factor for fluid, [-]
        This parameter is alternatively a fit parameter.

    Returns
    -------
    Vs : float
        Saturation liquid volume

    Notes
    -----
    196 constants are fit to this function in [1]_.
    Range: 0.25 < Tr < 0.95, often said to be to 1.0

    This function has been checked with the API handbook example problem.

    Examples
    --------
    Propane, from an example in the API Handbook

    >>> Vm_to_rho(COSTALD(272.03889, 369.83333, 0.20008161E-3, 0.1532), 44.097)
    530.3009967969841

    References
    ----------
    .. [1] Hankinson, Risdon W., and George H. Thomson. "A New Correlation for
       Saturated Densities of Liquids and Their Mixtures." AIChE Journal
       25, no. 4 (1979): 653-663. doi:10.1002/aic.690250412
    '''
    Tr = T/Tc
    V_delta = (-0.296123 + 0.386914*Tr - 0.0427258*Tr**2
        - 0.0480645*Tr**3)/(Tr - 1.00001)
    V_0 = 1 - 1.52816*(1-Tr)**(1/3.) + 1.43907*(1-Tr)**(2/3.) \
        - 0.81446*(1-Tr) + 0.190454*(1-Tr)**(4/3.)
    return Vc*V_0*(1-omega*V_delta)

r Calculate saturation liquid density using the COSTALD CSP method .


def Amgat(xs, Vms):
    r'''Calculate mixture liquid density using the Amgat mixing rule.
    Highly inacurate, but easy to use. Assumes idea liquids with
    no excess volume. Average molecular weight should be used with it to obtain
    density.

    .. math::
        V_{mix} = \sum_i x_i V_i

    or in terms of density:

    .. math::

        \rho_{mix} = \sum\frac{x_i}{\rho_i}

    Parameters
    ----------
    xs : array
        Mole fractions of each component, []
    Vms : array
        Molar volumes of each fluids at conditions [m^3/mol]

    Returns
    -------
    Vm : float
        Mixture liquid volume [m^3/mol]

    Notes
    -----
    Units are that of the given volumes.
    It has been suggested to use this equation with weight fractions,
    but the results have been less accurate.

    Examples
    --------
    >>> Amgat([0.5, 0.5], [4.057e-05, 5.861e-05])
    4.9590000000000005e-05
    '''
    if not none_and_length_check([xs, Vms]):
        raise Exception('Function inputs are incorrect format')
    return mixing_simple(xs, Vms)

def
Amgat
(
xs
,
Vms
)
:
if
not
none_and_length_check
(
[
xs
,
Vms
]
)
:
raise
Exception
(
'Function inputs are incorrect format'
)
return
mixing_simple
(
xs
,
Vms
)

r Calculate mixture liquid density using the Amgat mixing rule . Highly inacurate but easy to use . Assumes idea liquids with no excess volume . Average molecular weight should be used with it to obtain density .


def COSTALD_mixture(xs, T, Tcs, Vcs, omegas):
    r'''Calculate mixture liquid density using the COSTALD CSP method.

    A popular and accurate estimation method. If possible, fit parameters are
    used; alternatively critical properties work well.

    The mixing rules giving parameters for the pure component COSTALD
    equation are:

    .. math::
        T_{cm} = \frac{\sum_i\sum_j x_i x_j (V_{ij}T_{cij})}{V_m}

        V_m = 0.25\left[ \sum x_i V_i + 3(\sum x_i V_i^{2/3})(\sum_i x_i V_i^{1/3})\right]

        V_{ij}T_{cij} = (V_iT_{ci}V_{j}T_{cj})^{0.5}

        \omega = \sum_i z_i \omega_i

    Parameters
    ----------
    xs: list
        Mole fractions of each component
    T : float
        Temperature of fluid [K]
    Tcs : list
        Critical temperature of fluids [K]
    Vcs : list
        Critical volumes of fluids [m^3/mol].
        This parameter is alternatively a fit parameter
    omegas : list
        (ideally SRK) Acentric factor of all fluids, [-]
        This parameter is alternatively a fit parameter.

    Returns
    -------
    Vs : float
        Saturation liquid mixture volume

    Notes
    -----
    Range: 0.25 < Tr < 0.95, often said to be to 1.0
    No example has been found.
    Units are that of critical or fit constant volume.

    Examples
    --------
    >>> COSTALD_mixture([0.4576, 0.5424], 298.,  [512.58, 647.29],[0.000117, 5.6e-05], [0.559,0.344] )
    2.706588773271354e-05

    References
    ----------
    .. [1] Hankinson, Risdon W., and George H. Thomson. "A New Correlation for
       Saturated Densities of Liquids and Their Mixtures." AIChE Journal
       25, no. 4 (1979): 653-663. doi:10.1002/aic.690250412
    '''
    cmps = range(len(xs))
    if not none_and_length_check([xs, Tcs, Vcs, omegas]):
        raise Exception('Function inputs are incorrect format')
    sum1 = sum([xi*Vci for xi, Vci in zip(xs, Vcs)])
    sum2 = sum([xi*Vci**(2/3.) for xi, Vci in zip(xs, Vcs)])
    sum3 = sum([xi*Vci**(1/3.) for xi, Vci in zip(xs, Vcs)])
    Vm = 0.25*(sum1 + 3.*sum2*sum3)
    VijTcij = [[(Tcs[i]*Tcs[j]*Vcs[i]*Vcs[j])**0.5 for j in cmps] for i in cmps]
    omega = mixing_simple(xs, omegas)
    Tcm = sum([xs[i]*xs[j]*VijTcij[i][j]/Vm for j in cmps for i in cmps])
    return COSTALD(T, Tcm, Vm, omega)

def
COSTALD_mixture
(
xs
,
T
,
Tcs
,
Vcs
,
omegas
)
:
cmps
=
range
(
len
(
xs
)
)
if
not
none_and_length_check
(
[
xs
,
Tcs
,
Vcs
,
omegas
]
)
:
raise
Exception
(
'Function inputs are incorrect format'
)
sum1
=
sum
(
[
xi
*
Vci
for
xi
,
Vci
in
zip
(
xs
,
Vcs
)
]
)
sum2
=
sum
(
[
xi
*
Vci
**
(
2
/
3.
)
for
xi
,
Vci
in
zip
(
xs
,
Vcs
)
]
)
sum3
=
sum
(
[
xi
*
Vci
**
(
1
/
3.
)
for
xi
,
Vci
in
zip
(
xs
,
Vcs
)
]
)
Vm
=
0.25
*
(
sum1
+
3.
*
sum2
*
sum3
)
VijTcij
=
[
[
(
Tcs
[
i
]
*
Tcs
[
j
]
*
Vcs
[
i
]
*
Vcs
[
j
]
)
**
0.5
for
j
in
cmps
]
for
i
in
cmps
]
omega
=
mixing_simple
(
xs
,
omegas
)
Tcm
=
sum
(
[
xs
[
i
]
*
xs
[
j
]
*
VijTcij
[
i
]
[
j
]
/
Vm
for
j
in
cmps
for
i
in
cmps
]
)
return
COSTALD
(
T
,
Tcm
,
Vm
,
omega
)

r Calculate mixture liquid density using the COSTALD CSP method .


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

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

        Parameters
        ----------
        T : float
            Temperature at which to calculate molar volume, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Vm : float
            Molar volume of the liquid at T and a low pressure, [m^3/mol]
        '''
        if method == RACKETT:
            Vm = Rackett(T, self.Tc, self.Pc, self.Zc)
        elif method == YAMADA_GUNN:
            Vm = Yamada_Gunn(T, self.Tc, self.Pc, self.omega)
        elif method == BHIRUD_NORMAL:
            Vm = Bhirud_normal(T, self.Tc, self.Pc, self.omega)
        elif method == TOWNSEND_HALES:
            Vm = Townsend_Hales(T, self.Tc, self.Vc, self.omega)
        elif method == HTCOSTALD:
            Vm = COSTALD(T, self.Tc, self.Vc, self.omega)
        elif method == YEN_WOODS_SAT:
            Vm = Yen_Woods_saturation(T, self.Tc, self.Vc, self.Zc)
        elif method == MMSNM0:
            Vm = SNM0(T, self.Tc, self.Vc, self.omega)
        elif method == MMSNM0FIT:
            Vm = SNM0(T, self.Tc, self.Vc, self.omega, self.SNM0_delta_SRK)
        elif method == CAMPBELL_THODOS:
            Vm = Campbell_Thodos(T, self.Tb, self.Tc, self.Pc, self.MW, self.dipole)
        elif method == HTCOSTALDFIT:
            Vm = COSTALD(T, self.Tc, self.COSTALD_Vchar, self.COSTALD_omega_SRK)
        elif method == RACKETTFIT:
            Vm = Rackett(T, self.Tc, self.Pc, self.RACKETT_Z_RA)
        elif method == PERRYDIPPR:
            A, B, C, D = self.DIPPR_coeffs
            Vm = 1./EQ105(T, A, B, C, D)
        elif method == CRC_INORG_L:
            rho = CRC_inorganic(T, self.CRC_INORG_L_rho, self.CRC_INORG_L_k, self.CRC_INORG_L_Tm)
            Vm = rho_to_Vm(rho, self.CRC_INORG_L_MW)
        elif method == VDI_PPDS:
            A, B, C, D = self.VDI_PPDS_coeffs
            tau = 1. - T/self.VDI_PPDS_Tc
            rho = self.VDI_PPDS_rhoc + A*tau**0.35 + B*tau**(2/3.) + C*tau + D*tau**(4/3.)
            Vm = rho_to_Vm(rho, self.VDI_PPDS_MW)
        elif method == CRC_INORG_L_CONST:
            Vm = self.CRC_INORG_L_CONST_Vm
        elif method == COOLPROP:
            Vm = 1./CoolProp_T_dependent_property(T, self.CASRN, 'DMOLAR', 'l')
        elif method in self.tabular_data:
            Vm = self.interpolate(T, method)
        return Vm

def calculate ( self , T , method ) : if method == RACKETT : Vm = Rackett ( T , self . Tc , self . Pc , self . Zc ) elif method == YAMADA_GUNN : Vm = Yamada_Gunn ( T , self . Tc , self . Pc , self . omega ) elif method == BHIRUD_NORMAL : Vm = Bhirud_normal ( T , self . Tc , self . Pc , self . omega ) elif method == TOWNSEND_HALES : Vm = Townsend_Hales ( T , self . Tc , self . Vc , self . omega ) elif method == HTCOSTALD : Vm = COSTALD ( T , self . Tc , self . Vc , self . omega ) elif method == YEN_WOODS_SAT : Vm = Yen_Woods_saturation ( T , self . Tc , self . Vc , self . Zc ) elif method == MMSNM0 : Vm = SNM0 ( T , self . Tc , self . Vc , self . omega ) elif method == MMSNM0FIT : Vm = SNM0 ( T , self . Tc , self . Vc , self . omega , self . SNM0_delta_SRK ) elif method == CAMPBELL_THODOS : Vm = Campbell_Thodos ( T , self . Tb , self . Tc , self . Pc , self . MW , self . dipole ) elif method == HTCOSTALDFIT : Vm = COSTALD ( T , self . Tc , self . COSTALD_Vchar , self . COSTALD_omega_SRK ) elif method == RACKETTFIT : Vm = Rackett ( T , self . Tc , self . Pc , self . RACKETT_Z_RA ) elif method == PERRYDIPPR : A , B , C , D = self . DIPPR_coeffs Vm = 1. / EQ105 ( T , A , B , C , D ) elif method == CRC_INORG_L : rho = CRC_inorganic ( T , self . CRC_INORG_L_rho , self . CRC_INORG_L_k , self . CRC_INORG_L_Tm ) Vm = rho_to_Vm ( rho , self . CRC_INORG_L_MW ) elif method == VDI_PPDS : A , B , C , D = self . VDI_PPDS_coeffs tau = 1. - T / self . VDI_PPDS_Tc rho = self . VDI_PPDS_rhoc + A * tau ** 0.35 + B * tau ** ( 2 / 3. ) + C * tau + D * tau ** ( 4 / 3. ) Vm = rho_to_Vm ( rho , self . VDI_PPDS_MW ) elif method == CRC_INORG_L_CONST : Vm = self . CRC_INORG_L_CONST_Vm elif method == COOLPROP : Vm = 1. / CoolProp_T_dependent_property ( T , self . CASRN , 'DMOLAR' , 'l' ) elif method in self . tabular_data : Vm = self . interpolate ( T , method ) return Vm

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


def calculate_P(self, T, P, method):
        r'''Method to calculate pressure-dependent liquid molar volume 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 molar volume, [K]
        P : float
            Pressure at which to calculate molar volume, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Vm : float
            Molar volume of the liquid at T and P, [m^3/mol]
        '''
        if method == COSTALD_COMPRESSED:
            Vm = self.T_dependent_property(T)
            Psat = self.Psat(T) if hasattr(self.Psat, '__call__') else self.Psat
            Vm = COSTALD_compressed(T, P, Psat, self.Tc, self.Pc, self.omega, Vm)
        elif method == COOLPROP:
            Vm = 1./PropsSI('DMOLAR', 'T', T, 'P', P, self.CASRN)
        elif method == EOS:
            self.eos[0] = self.eos[0].to_TP(T=T, P=P)
            Vm = self.eos[0].V_l
        elif method in self.tabular_data:
            Vm = self.interpolate_P(T, P, method)
        return Vm

def calculate_P ( self , T , P , method ) : if method == COSTALD_COMPRESSED : Vm = self . T_dependent_property ( T ) Psat = self . Psat ( T ) if hasattr ( self . Psat , '__call__' ) else self . Psat Vm = COSTALD_compressed ( T , P , Psat , self . Tc , self . Pc , self . omega , Vm ) elif method == COOLPROP : Vm = 1. / PropsSI ( 'DMOLAR' , 'T' , T , 'P' , P , self . CASRN ) elif method == EOS : self . eos [ 0 ] = self . eos [ 0 ] . to_TP ( T = T , P = P ) Vm = self . eos [ 0 ] . V_l elif method in self . tabular_data : Vm = self . interpolate_P ( T , P , method ) return Vm

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


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate molar volume 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
        -------
        Vm : float
            Molar volume of the liquid mixture at the given conditions,
            [m^3/mol]
        '''
        if method == SIMPLE:
            Vms = [i(T, P) for i in self.VolumeLiquids]
            return Amgat(zs, Vms)
        elif method == COSTALD_MIXTURE:
            return COSTALD_mixture(zs, T, self.Tcs, self.Vcs, self.omegas)
        elif method == COSTALD_MIXTURE_FIT:
            return COSTALD_mixture(zs, T, self.Tcs, self.COSTALD_Vchars, self.COSTALD_omegas)
        elif method == RACKETT:
            return Rackett_mixture(T, zs, self.MWs, self.Tcs, self.Pcs, self.Zcs)
        elif method == RACKETT_PARAMETERS:
            return Rackett_mixture(T, zs, self.MWs, self.Tcs, self.Pcs, self.Z_RAs)
        elif method == LALIBERTE:
            ws = list(ws) ; ws.pop(self.index_w)
            rho = Laliberte_density(T, ws, self.wCASs)
            MW = mixing_simple(zs, self.MWs)
            return rho_to_Vm(rho, MW)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
if
method
==
SIMPLE
:
Vms
=
[
i
(
T
,
P
)
for
i
in
self
.
VolumeLiquids
]
return
Amgat
(
zs
,
Vms
)
elif
method
==
COSTALD_MIXTURE
:
return
COSTALD_mixture
(
zs
,
T
,
self
.
Tcs
,
self
.
Vcs
,
self
.
omegas
)
elif
method
==
COSTALD_MIXTURE_FIT
:
return
COSTALD_mixture
(
zs
,
T
,
self
.
Tcs
,
self
.
COSTALD_Vchars
,
self
.
COSTALD_omegas
)
elif
method
==
RACKETT
:
return
Rackett_mixture
(
T
,
zs
,
self
.
MWs
,
self
.
Tcs
,
self
.
Pcs
,
self
.
Zcs
)
elif
method
==
RACKETT_PARAMETERS
:
return
Rackett_mixture
(
T
,
zs
,
self
.
MWs
,
self
.
Tcs
,
self
.
Pcs
,
self
.
Z_RAs
)
elif
method
==
LALIBERTE
:
ws
=
list
(
ws
)
ws
.
pop
(
self
.
index_w
)
rho
=
Laliberte_density
(
T
,
ws
,
self
.
wCASs
)
MW
=
mixing_simple
(
zs
,
self
.
MWs
)
return
rho_to_Vm
(
rho
,
MW
)
else
:
raise
Exception
(
'Method not valid'
)

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


def calculate_P(self, T, P, method):
        r'''Method to calculate pressure-dependent gas molar volume 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 molar volume, [K]
        P : float
            Pressure at which to calculate molar volume, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Vm : float
            Molar volume of the gas at T and P, [m^3/mol]
        '''
        if method == EOS:
            self.eos[0] = self.eos[0].to_TP(T=T, P=P)
            Vm = self.eos[0].V_g
        elif method == TSONOPOULOS_EXTENDED:
            B = BVirial_Tsonopoulos_extended(T, self.Tc, self.Pc, self.omega, dipole=self.dipole)
            Vm = ideal_gas(T, P) + B
        elif method == TSONOPOULOS:
            B = BVirial_Tsonopoulos(T, self.Tc, self.Pc, self.omega)
            Vm = ideal_gas(T, P) + B
        elif method == ABBOTT:
            B = BVirial_Abbott(T, self.Tc, self.Pc, self.omega)
            Vm = ideal_gas(T, P) + B
        elif method == PITZER_CURL:
            B = BVirial_Pitzer_Curl(T, self.Tc, self.Pc, self.omega)
            Vm = ideal_gas(T, P) + B
        elif method == CRC_VIRIAL:
            a1, a2, a3, a4, a5 = self.CRC_VIRIAL_coeffs
            t = 298.15/T - 1.
            B = (a1 + a2*t + a3*t**2 + a4*t**3 + a5*t**4)/1E6
            Vm = ideal_gas(T, P) + B
        elif method == IDEAL:
            Vm = ideal_gas(T, P)
        elif method == COOLPROP:
            Vm = 1./PropsSI('DMOLAR', 'T', T, 'P', P, self.CASRN)
        elif method in self.tabular_data:
            Vm = self.interpolate_P(T, P, method)
        return Vm

def calculate_P ( self , T , P , method ) : if method == EOS : self . eos [ 0 ] = self . eos [ 0 ] . to_TP ( T = T , P = P ) Vm = self . eos [ 0 ] . V_g elif method == TSONOPOULOS_EXTENDED : B = BVirial_Tsonopoulos_extended ( T , self . Tc , self . Pc , self . omega , dipole = self . dipole ) Vm = ideal_gas ( T , P ) + B elif method == TSONOPOULOS : B = BVirial_Tsonopoulos ( T , self . Tc , self . Pc , self . omega ) Vm = ideal_gas ( T , P ) + B elif method == ABBOTT : B = BVirial_Abbott ( T , self . Tc , self . Pc , self . omega ) Vm = ideal_gas ( T , P ) + B elif method == PITZER_CURL : B = BVirial_Pitzer_Curl ( T , self . Tc , self . Pc , self . omega ) Vm = ideal_gas ( T , P ) + B elif method == CRC_VIRIAL : a1 , a2 , a3 , a4 , a5 = self . CRC_VIRIAL_coeffs t = 298.15 / T - 1. B = ( a1 + a2 * t + a3 * t ** 2 + a4 * t ** 3 + a5 * t ** 4 ) / 1E6 Vm = ideal_gas ( T , P ) + B elif method == IDEAL : Vm = ideal_gas ( T , P ) elif method == COOLPROP : Vm = 1. / PropsSI ( 'DMOLAR' , 'T' , T , 'P' , P , self . CASRN ) elif method in self . tabular_data : Vm = self . interpolate_P ( T , P , method ) return Vm

r Method to calculate pressure - dependent gas molar volume at temperature T and pressure P with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate molar volume of a gas 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
        -------
        Vm : float
            Molar volume of the gas mixture at the given conditions, [m^3/mol]
        '''
        if method == SIMPLE:
            Vms = [i(T, P) for i in self.VolumeGases]
            return mixing_simple(zs, Vms)
        elif method == IDEAL:
            return ideal_gas(T, P)
        elif method == EOS:
            self.eos[0] = self.eos[0].to_TP_zs(T=T, P=P, zs=zs)
            return self.eos[0].V_g
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
if
method
==
SIMPLE
:
Vms
=
[
i
(
T
,
P
)
for
i
in
self
.
VolumeGases
]
return
mixing_simple
(
zs
,
Vms
)
elif
method
==
IDEAL
:
return
ideal_gas
(
T
,
P
)
elif
method
==
EOS
:
self
.
eos
[
0
]
=
self
.
eos
[
0
]
.
to_TP_zs
(
T
=
T
,
P
=
P
,
zs
=
zs
)
return
self
.
eos
[
0
]
.
V_g
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate molar volume of a gas 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 the molar volume of a solid at tempearture `T`
        with a given method.

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

        Parameters
        ----------
        T : float
            Temperature at which to calculate molar volume, [K]
        method : str
            Name of the method to use

        Returns
        -------
        Vms : float
            Molar volume of the solid at T, [m^3/mol]
        '''
        if method == CRC_INORG_S:
            Vms = self.CRC_INORG_S_Vm
#        elif method == GOODMAN:
#            Vms = Goodman(T, self.Tt, self.rhol_Tt)
        elif method in self.tabular_data:
            Vms = self.interpolate(T, method)
        return Vms

r Method to calculate the molar volume of a solid at tempearture T with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate molar volume of a solid 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
        -------
        Vm : float
            Molar volume of the solid mixture at the given conditions,
            [m^3/mol]
        '''
        if method == SIMPLE:
            Vms = [i(T, P) for i in self.VolumeSolids]
            return mixing_simple(zs, Vms)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
if
method
==
SIMPLE
:
Vms
=
[
i
(
T
,
P
)
for
i
in
self
.
VolumeSolids
]
return
mixing_simple
(
zs
,
Vms
)
else
:
raise
Exception
(
'Method not valid'
)

r Method to calculate molar volume of a solid mixture at temperature T pressure P mole fractions zs and weight fractions ws with a given method .


def legal_status(CASRN, Method=None, AvailableMethods=False, CASi=None):
    r'''Looks up the legal status of a chemical according to either a specifc
    method or with all methods.

    Returns either the status as a string for a specified method, or the
    status of the chemical in all available data sources, in the format
    {source: status}.

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

    Returns
    -------
    status : str or dict
        Legal status information [-]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain legal status with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        A string for the method name to use, as defined by constants in
        legal_status_methods
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        the legal status for the desired chemical, and will return methods
        instead of the status
    CASi : int, optional
        CASRN as an integer, used internally [-]

    Notes
    -----

    Supported methods are:

        * **DSL**: Canada Domestic Substance List, [1]_. As extracted on Feb 11, 2015
          from a html list. This list is updated continuously, so this version
          will always be somewhat old. Strictly speaking, there are multiple
          lists but they are all bundled together here. A chemical may be
          'Listed', or be on the 'Non-Domestic Substances List (NDSL)',
          or be on the list of substances with 'Significant New Activity (SNAc)',
          or be on the DSL but with a 'Ministerial Condition pertaining to this
          substance', or have been removed from the DSL, or have had a
          Ministerial prohibition for the substance.
        * **TSCA**: USA EPA Toxic Substances Control Act Chemical Inventory, [2]_.
          This list is as extracted on 2016-01. It is believed this list is
          updated on a periodic basis (> 6 month). A chemical may simply be
          'Listed', or may have certain flags attached to it. All these flags
          are described in the dict TSCA_flags.
        * **EINECS**: European INventory of Existing Commercial chemical
          Substances, [3]_. As extracted from a spreadsheet dynamically
          generated at [1]_. This list was obtained March 2015; a more recent
          revision already exists.
        * **NLP**: No Longer Polymers, a list of chemicals with special
          regulatory exemptions in EINECS. Also described at [3]_.
        * **SPIN**: Substances Prepared in Nordic Countries. Also a boolean
          data type. Retrieved 2015-03 from [4]_.

    Other methods which could be added are:

        * Australia: AICS Australian Inventory of Chemical Substances
        * China: Inventory of Existing Chemical Substances Produced or Imported
          in China (IECSC)
        * Europe: REACH List of Registered Substances
        * India: List of Hazardous Chemicals
        * Japan: ENCS: Inventory of existing and new chemical substances
        * Korea: Existing Chemicals Inventory (KECI)
        * Mexico: INSQ National Inventory of Chemical Substances in Mexico
        * New Zealand:  Inventory of Chemicals (NZIoC)
        * Philippines: PICCS Philippines Inventory of Chemicals and Chemical
          Substances

    Examples
    --------
    >>> pprint(legal_status('64-17-5'))
    {'DSL': 'LISTED',
     'EINECS': 'LISTED',
     'NLP': 'UNLISTED',
     'SPIN': 'LISTED',
     'TSCA': 'LISTED'}

    References
    ----------
    .. [1] Government of Canada.. "Substances Lists" Feb 11, 2015.
       https://www.ec.gc.ca/subsnouvelles-newsubs/default.asp?n=47F768FE-1.
    .. [2] US EPA. "TSCA Chemical Substance Inventory." Accessed April 2016.
       https://www.epa.gov/tsca-inventory.
    .. [3] ECHA. "EC Inventory". Accessed March 2015.
       http://echa.europa.eu/information-on-chemicals/ec-inventory.
    .. [4] SPIN. "SPIN Substances in Products In Nordic Countries." Accessed
       March 2015. http://195.215.202.233/DotNetNuke/default.aspx.
    '''
    load_law_data()
    if not CASi:
        CASi = CAS2int(CASRN)
    methods = [COMBINED, DSL, TSCA, EINECS, NLP, SPIN]
    if AvailableMethods:
        return methods
    if not Method:
        Method = methods[0]
    if Method == DSL:
        if CASi in DSL_data.index:
            status = CAN_DSL_flags[DSL_data.at[CASi, 'Registry']]
        else:
            status = UNLISTED
    elif Method == TSCA:
        if CASi in TSCA_data.index:
            data = TSCA_data.loc[CASi].to_dict()
            if any(data.values()):
                status = sorted([TSCA_flags[i] for i in data.keys() if data[i]])
            else:
                status = LISTED
        else:
            status = UNLISTED
    elif Method == EINECS:
        if CASi in EINECS_data.index:
            status = LISTED
        else:
            status = UNLISTED
    elif Method == NLP:
        if CASi in NLP_data.index:
            status = LISTED
        else:
            status = UNLISTED
    elif Method == SPIN:
        if CASi in SPIN_data.index:
            status = LISTED
        else:
            status = UNLISTED
    elif Method == COMBINED:
        status = {}
        for method in methods[1:]:
            status[method] = legal_status(CASRN, Method=method, CASi=CASi)
    else:
        raise Exception('Failure in in function')
    return status

def
legal_status
(
CASRN
,
Method
=
,
AvailableMethods
=
False
,
CASi
=
)
:
load_law_data
(
)
if
not
CASi
:
CASi
=
CAS2int
(
CASRN
)
methods
=
[
COMBINED
,
DSL
,
TSCA
,
EINECS
,
NLP
,
SPIN
]
if
AvailableMethods
:
return
methods
if
not
Method
:
Method
=
methods
[
0
]
if
Method
==
DSL
:
if
CASi
in
DSL_data
.
index
:
status
=
CAN_DSL_flags
[
DSL_data
.
at
[
CASi
,
'Registry'
]
]
else
:
status
=
UNLISTED
elif
Method
==
TSCA
:
if
CASi
in
TSCA_data
.
index
:
data
=
TSCA_data
.
loc
[
CASi
]
.
to_dict
(
)
if
any
(
data
.
values
(
)
)
:
status
=
sorted
(
[
TSCA_flags
[
i
]
for
i
in
data
.
keys
(
)
if
data
[
i
]
]
)
else
:
status
=
LISTED
else
:
status
=
UNLISTED
elif
Method
==
EINECS
:
if
CASi
in
EINECS_data
.
index
:
status
=
LISTED
else
:
status
=
UNLISTED
elif
Method
==
NLP
:
if
CASi
in
NLP_data
.
index
:
status
=
LISTED
else
:
status
=
UNLISTED
elif
Method
==
SPIN
:
if
CASi
in
SPIN_data
.
index
:
status
=
LISTED
else
:
status
=
UNLISTED
elif
Method
==
COMBINED
:
status
=
{
}
for
method
in
methods
[
1
:
]
:
status
[
method
]
=
legal_status
(
CASRN
,
Method
=
method
,
CASi
=
CASi
)
else
:
raise
Exception
(
'Failure in in function'
)
return
status

r Looks up the legal status of a chemical according to either a specifc method or with all methods .


def economic_status(CASRN, Method=None, AvailableMethods=False):  # pragma: no cover
    '''Look up the economic status of a chemical.

    This API is considered experimental, and is expected to be removed in a
    future release in favor of a more complete object-oriented interface.

    >>> pprint(economic_status(CASRN='98-00-0'))
    ["US public: {'Manufactured': 0.0, 'Imported': 10272.711, 'Exported': 184.127}",
     u'10,000 - 100,000 tonnes per annum',
     'OECD HPV Chemicals']

    >>> economic_status(CASRN='13775-50-3')  # SODIUM SESQUISULPHATE
    []
    >>> economic_status(CASRN='98-00-0', Method='OECD high production volume chemicals')
    'OECD HPV Chemicals'
    >>> economic_status(CASRN='98-01-1', Method='European Chemicals Agency Total Tonnage Bands')
    [u'10,000 - 100,000 tonnes per annum']
    '''
    load_economic_data()
    CASi = CAS2int(CASRN)

    def list_methods():
        methods = []
        methods.append('Combined')
        if CASRN in _EPACDRDict:
            methods.append(EPACDR)
        if CASRN in _ECHATonnageDict:
            methods.append(ECHA)
        if CASi in HPV_data.index:
            methods.append(OECD)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    # This is the calculate, given the method section
    if Method == EPACDR:
        status = 'US public: ' + str(_EPACDRDict[CASRN])
    elif Method == ECHA:
        status = _ECHATonnageDict[CASRN]
    elif Method == OECD:
        status = 'OECD HPV Chemicals'
    elif Method == 'Combined':
        status = []
        if CASRN in _EPACDRDict:
            status += ['US public: ' + str(_EPACDRDict[CASRN])]
        if CASRN in _ECHATonnageDict:
            status += _ECHATonnageDict[CASRN]
        if CASi in HPV_data.index:
            status += ['OECD HPV Chemicals']
    elif Method == NONE:
        status = None
    else:
        raise Exception('Failure in in function')
    return status

Look up the economic status of a chemical .


def estimate(self):
        '''Method to compute all available properties with the Joback method;
        returns their results as a dict. For the tempearture dependent values
        Cpig and mul, both the coefficients and objects to perform calculations
        are returned.
        '''
        # Pre-generate the coefficients or they will not be returned
        self.mul(300)
        self.Cpig(300)
        estimates = {'Tb': self.Tb(self.counts),
                     'Tm': self.Tm(self.counts),
                     'Tc': self.Tc(self.counts, self.Tb_estimated),
                     'Pc': self.Pc(self.counts, self.atom_count),
                     'Vc': self.Vc(self.counts),
                     'Hf': self.Hf(self.counts),
                     'Gf': self.Gf(self.counts),
                     'Hfus': self.Hfus(self.counts),
                     'Hvap': self.Hvap(self.counts),
                     'mul': self.mul,
                     'mul_coeffs': self.calculated_mul_coeffs,
                     'Cpig': self.Cpig,
                     'Cpig_coeffs': self.calculated_Cpig_coeffs}
        return estimates

Method to compute all available properties with the Joback method ; returns their results as a dict . For the tempearture dependent values Cpig and mul both the coefficients and objects to perform calculations are returned .


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

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

    Returns
    -------
    kappa : float
        Electrical conductivity of the fluid, [S/m]
    T : float, only returned if full_info == True
        Temperature at which conductivity measurement 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
        conductivity_methods
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        conductivity for the desired chemical, and will return methods instead
        of conductivity
    full_info : bool, optional
        If True, function will return the temperature at which the conductivity
        reading was made

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

        * 'LANGE_COND' which is from Lange's Handbook, Table 8.34 Electrical
        Conductivity of Various Pure Liquids', a compillation of data in [1]_.

    Examples
    --------
    >>> conductivity('7732-18-5')
    (4e-06, 291.15)

    References
    ----------
    .. [1] Speight, James. Lange's Handbook of Chemistry. 16 edition.
       McGraw-Hill Professional, 2005.
    '''
    def list_methods():
        methods = []
        if CASRN in Lange_cond_pure.index:
            methods.append(LANGE_COND)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]
    if Method == LANGE_COND:
        kappa = float(Lange_cond_pure.at[CASRN, 'Conductivity'])
        if full_info:
            T = float(Lange_cond_pure.at[CASRN, 'T'])

    elif Method == NONE:
        kappa, T = None, None
    else:
        raise Exception('Failure in in function')

    if full_info:
        return kappa, T
    else:
        return kappa

def
conductivity
(
CASRN
=
,
AvailableMethods
=
False
,
Method
=
,
full_info
=
True
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
Lange_cond_pure
.
index
:
methods
.
append
(
LANGE_COND
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
LANGE_COND
:
kappa
=
float
(
Lange_cond_pure
.
at
[
CASRN
,
'Conductivity'
]
)
if
full_info
:
T
=
float
(
Lange_cond_pure
.
at
[
CASRN
,
'T'
]
)
elif
Method
==
:
kappa
,
T
=
,
else
:
raise
Exception
(
'Failure in in function'
)
if
full_info
:
return
kappa
,
T
else
:
return
kappa

r This function handles the retrieval of a chemical s conductivity . 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 ionic_strength(mis, zis):
    r'''Calculate the ionic strength of a solution in one of two ways,
    depending on the inputs only. For Pitzer and Bromley models,
    `mis` should be molalities of each component. For eNRTL models,
    `mis` should be mole fractions of each electrolyte in the solution.
    This will sum to be much less than 1.

    .. math::
        I = \frac{1}{2} \sum M_i z_i^2

        I = \frac{1}{2} \sum x_i z_i^2

    Parameters
    ----------
    mis : list
        Molalities of each ion, or mole fractions of each ion [mol/kg or -]
    zis : list
        Charges of each ion [-]

    Returns
    -------
    I : float
        ionic strength, [?]

    Examples
    --------
    >>> ionic_strength([0.1393, 0.1393], [1, -1])
    0.1393

    References
    ----------
    .. [1] Chen, Chau-Chyun, H. I. Britt, J. F. Boston, and L. B. Evans. "Local
       Composition Model for Excess Gibbs Energy of Electrolyte Systems.
       Part I: Single Solvent, Single Completely Dissociated Electrolyte
       Systems." AIChE Journal 28, no. 4 (July 1, 1982): 588-96.
       doi:10.1002/aic.690280410
    .. [2] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
       Weinheim, Germany: Wiley-VCH, 2012.
    '''
    return 0.5*sum([mi*zi*zi for mi, zi in zip(mis, zis)])

def ionic_strength ( mis , zis ) : return 0.5 * sum ( [ mi * zi * zi for mi , zi in zip ( mis , zis ) ] )

r Calculate the ionic strength of a solution in one of two ways depending on the inputs only . For Pitzer and Bromley models mis should be molalities of each component . For eNRTL models mis should be mole fractions of each electrolyte in the solution . This will sum to be much less than 1 .


def ion_balance_proportional(anion_charges, cation_charges, zs, n_anions,
                             n_cations, balance_error, method):
    '''Helper method for balance_ions for the proportional family of methods.
    See balance_ions for a description of the methods; parameters are fairly
    obvious.
    '''
    anion_zs = zs[0:n_anions]
    cation_zs = zs[n_anions:n_cations+n_anions]
    anion_balance_error = sum([zi*ci for zi, ci in zip(anion_zs, anion_charges)])
    cation_balance_error = sum([zi*ci for zi, ci in zip(cation_zs, cation_charges)])
    if method == 'proportional insufficient ions increase':
        if balance_error < 0:
            multiplier = -anion_balance_error/cation_balance_error
            cation_zs = [i*multiplier for i in cation_zs]
        else:
            multiplier = -cation_balance_error/anion_balance_error
            anion_zs = [i*multiplier for i in anion_zs]
    elif method == 'proportional excess ions decrease':
        if balance_error < 0:
            multiplier = -cation_balance_error/anion_balance_error
            anion_zs = [i*multiplier for i in anion_zs]
        else:
            multiplier = -anion_balance_error/cation_balance_error
            cation_zs = [i*multiplier for i in cation_zs]
    elif method == 'proportional cation adjustment':
        multiplier = -anion_balance_error/cation_balance_error
        cation_zs = [i*multiplier for i in cation_zs]
    elif method == 'proportional anion adjustment':
        multiplier = -cation_balance_error/anion_balance_error
        anion_zs = [i*multiplier for i in anion_zs]
    else:
        raise Exception('Allowable methods are %s' %charge_balance_methods)
    z_water = 1. - sum(anion_zs) - sum(cation_zs)
    return anion_zs, cation_zs, z_water

Helper method for balance_ions for the proportional family of methods . See balance_ions for a description of the methods ; parameters are fairly obvious .


def calculate(self, T, method):
        r'''Method to calculate permittivity of a liquid at temperature `T`
        with a given method.

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

        Parameters
        ----------
        T : float
            Temperature at which to calculate relative permittivity, [K]
        method : str
            Name of the method to use

        Returns
        -------
        epsilon : float
            Relative permittivity of the liquid at T, [-]
        '''
        if method == CRC:
            A, B, C, D = self.CRC_coeffs
            epsilon = A + B*T + C*T**2 + D*T**3
        elif method == CRC_CONSTANT:
            epsilon = self.CRC_permittivity
        elif method in self.tabular_data:
            epsilon = self.interpolate(T, method)
        return epsilon

def calculate ( self , T , method ) : if method == CRC : A , B , C , D = self . CRC_coeffs epsilon = A + B * T + C * T ** 2 + D * T ** 3 elif method == CRC_CONSTANT : epsilon = self . CRC_permittivity elif method in self . tabular_data : epsilon = self . interpolate ( T , method ) return epsilon

r Method to calculate permittivity of a liquid at temperature T with a given method .


def calculate(self, T, P, zs, ws, method):
        r'''Method to calculate surface tension 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
        -------
        sigma : float
            Surface tension of the liquid at given conditions, [N/m]
        '''
        if method == SIMPLE:
            sigmas = [i(T) for i in self.SurfaceTensions]
            return mixing_simple(zs, sigmas)
        elif method == DIGUILIOTEJA:
            return Diguilio_Teja(T=T, xs=zs, sigmas_Tb=self.sigmas_Tb,
                                 Tbs=self.Tbs, Tcs=self.Tcs)
        elif method == WINTERFELDSCRIVENDAVIS:
            sigmas = [i(T) for i in self.SurfaceTensions]
            rhoms = [1./i(T, P) for i in self.VolumeLiquids]
            return Winterfeld_Scriven_Davis(zs, sigmas, rhoms)
        else:
            raise Exception('Method not valid')

def
calculate
(
self
,
T
,
P
,
zs
,
ws
,
method
)
:
if
method
==
SIMPLE
:
sigmas
=
[
i
(
T
)
for
i
in
self
.
SurfaceTensions
]
return
mixing_simple
(
zs
,
sigmas
)
elif
method
==
DIGUILIOTEJA
:
return
Diguilio_Teja
(
T
=
T
,
xs
=
zs
,
sigmas_Tb
=
self
.
sigmas_Tb
,
Tbs
=
self
.
Tbs
,
Tcs
=
self
.
Tcs
)
elif
method
==
WINTERFELDSCRIVENDAVIS
:
sigmas
=
[
i
(
T
)
for
i
in
self
.
SurfaceTensions
]
rhoms
=
[
1.
/
i
(
T
,
P
)
for
i
in
self
.
VolumeLiquids
]
return
Winterfeld_Scriven_Davis
(
zs
,
sigmas
,
rhoms
)
else
:
raise
Exception
(
'Method not valid'
)

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


def load_group_assignments_DDBST():
    '''Data is stored in the format
    InChI key\tbool bool bool \tsubgroup count ...\tsubgroup count \tsubgroup count...
    where the bools refer to whether or not the original UNIFAC, modified
    UNIFAC, and PSRK group assignments were completed correctly.
    The subgroups and their count have an indefinite length.
    '''
    # Do not allow running multiple times
    if DDBST_UNIFAC_assignments:
        return None
    with open(os.path.join(folder, 'DDBST UNIFAC assignments.tsv')) as f:
        _group_assignments = [DDBST_UNIFAC_assignments, DDBST_MODIFIED_UNIFAC_assignments, DDBST_PSRK_assignments]
        for line in f.readlines():
            key, valids, original, modified, PSRK = line.split('\t')
            # list of whether or not each method was correctly identified or not
            valids = [True if i == '1' else False for i in valids.split(' ')]
            for groups, storage, valid in zip([original, modified, PSRK], _group_assignments, valids):
                if valid:
                    groups = groups.rstrip().split(' ')
                    d_data = {}
                    for i in range(int(len(groups)/2)):
                        d_data[int(groups[i*2])] = int(groups[i*2+1])
                    storage[key] = d_data

Data is stored in the format InChI key \ tbool bool bool \ tsubgroup count ... \ tsubgroup count \ tsubgroup count ... where the bools refer to whether or not the original UNIFAC modified UNIFAC and PSRK group assignments were completed correctly . The subgroups and their count have an indefinite length .


def dipole_moment(CASRN, AvailableMethods=False, Method=None):
    r'''This function handles the retrieval of a chemical's dipole moment.
    Lookup is based on CASRNs. Will automatically select a data source to use
    if no Method is provided; returns None if the data is not available.

    Prefered source is 'CCCBDB'. Considerable variation in reported data has
    found.

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

    Returns
    -------
    dipole : float
        Dipole moment, [debye]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to obtain dipole moment with the
        given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The method name to use. Accepted methods are 'CCCBDB', 'MULLER', or
        'POLING'. All valid values are also held in the list `dipole_methods`.
    AvailableMethods : bool, optional
        If True, function will determine which methods can be used to obtain
        the dipole moment for the desired chemical, and will return methods
        instead of the dipole moment

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

        * 'CCCBDB', a series of critically evaluated data for compounds in
          [1]_, intended for use in predictive modeling.
        * 'MULLER', a collection of data in a
          group-contribution scheme in [2]_.
        * 'POLING', in the appendix in [3].

    This function returns dipole moment in units of Debye. This is actually
    a non-SI unit; to convert to SI, multiply by 3.33564095198e-30 and its
    units will be in ampere*second^2 or equivalently and more commonly given,
    coulomb*second. The constant is the result of 1E-21/c, where c is the
    speed of light.

    Examples
    --------
    >>> dipole_moment(CASRN='64-17-5')
    1.44

    References
    ----------
    .. [1] NIST Computational Chemistry Comparison and Benchmark Database
       NIST Standard Reference Database Number 101 Release 17b, September 2015,
       Editor: Russell D. Johnson III http://cccbdb.nist.gov/
    .. [2] Muller, Karsten, Liudmila Mokrushina, and Wolfgang Arlt. "Second-
       Order Group Contribution Method for the Determination of the Dipole
       Moment." Journal of Chemical & Engineering Data 57, no. 4 (April 12,
       2012): 1231-36. doi:10.1021/je2013395.
    .. [3] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition.
       New York: McGraw-Hill Professional, 2000.
    '''
    def list_methods():
        methods = []
        if CASRN in _dipole_CCDB.index and not np.isnan(_dipole_CCDB.at[CASRN, 'Dipole']):
            methods.append(CCCBDB)
        if CASRN in _dipole_Muller.index and not np.isnan(_dipole_Muller.at[CASRN, 'Dipole']):
            methods.append(MULLER)
        if CASRN in _dipole_Poling.index and not np.isnan(_dipole_Poling.at[CASRN, 'Dipole']):
            methods.append(POLING)
        methods.append(NONE)
        return methods
    if AvailableMethods:
        return list_methods()
    if not Method:
        Method = list_methods()[0]

    if Method == CCCBDB:
        _dipole = float(_dipole_CCDB.at[CASRN, 'Dipole'])
    elif Method == MULLER:
        _dipole = float(_dipole_Muller.at[CASRN, 'Dipole'])
    elif Method == POLING:
        _dipole = float(_dipole_Poling.at[CASRN, 'Dipole'])
    elif Method == NONE:
        _dipole = None
    else:
        raise Exception('Failure in in function')
    return _dipole

def
dipole_moment
(
CASRN
,
AvailableMethods
=
False
,
Method
=
)
:
def
list_methods
(
)
:
methods
=
[
]
if
CASRN
in
_dipole_CCDB
.
index
and
not
np
.
isnan
(
_dipole_CCDB
.
at
[
CASRN
,
'Dipole'
]
)
:
methods
.
append
(
CCCBDB
)
if
CASRN
in
_dipole_Muller
.
index
and
not
np
.
isnan
(
_dipole_Muller
.
at
[
CASRN
,
'Dipole'
]
)
:
methods
.
append
(
MULLER
)
if
CASRN
in
_dipole_Poling
.
index
and
not
np
.
isnan
(
_dipole_Poling
.
at
[
CASRN
,
'Dipole'
]
)
:
methods
.
append
(
POLING
)
methods
.
append
(
)
return
methods
if
AvailableMethods
:
return
list_methods
(
)
if
not
Method
:
Method
=
list_methods
(
)
[
0
]
if
Method
==
CCCBDB
:
_dipole
=
float
(
_dipole_CCDB
.
at
[
CASRN
,
'Dipole'
]
)
elif
Method
==
MULLER
:
_dipole
=
float
(
_dipole_Muller
.
at
[
CASRN
,
'Dipole'
]
)
elif
Method
==
POLING
:
_dipole
=
float
(
_dipole_Poling
.
at
[
CASRN
,
'Dipole'
]
)
elif
Method
==
:
_dipole
=
else
:
raise
Exception
(
'Failure in in function'
)
return
_dipole

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