r'''This function handles the calculation of nucleate boiling
    heat flux and chooses the best method for performing the calculation
    based on the provided information.

    One of `Te` and `q` are always required.

    Parameters
    ----------
    Te : float, optional
        Excess wall temperature, [K]
    q : float, optional
        Heat flux, [W/m^2]
    Tsat : float, optional
        Saturation temperature at operating pressure [Pa]
    P : float, optional
        Saturation pressure of fluid, [Pa]
    dPsat : float, optional
        Difference in saturation pressure of the fluid at Te and T, [Pa]
    Cpl : float, optional
        Heat capacity of liquid [J/kg/K]
    kl : float, optional
        Thermal conductivity of liquid [W/m/K]
    mul : float, optional
        Viscosity of liquid [Pa*s]
    rhol : float, optional
        Density of the liquid [kg/m^3]
    sigma : float, optional
        Surface tension of liquid [N/m]
    Hvap : float, optional
        Heat of vaporization of the fluid at P, [J/kg]
    rhog : float, optional
        Density of the produced gas [kg/m^3]
    MW : float, optional
        Molecular weight of fluid, [g/mol]
    Pc : float, optional
        Critical pressure of fluid, [Pa]
    CAS : str, optional
        CAS of fluid

    Returns
    -------
    h : float
        Nucleate boiling heat flux [W/m^2]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to calculate `h` with the given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The name of the method to use; one of ['Gorenflo (1993)', 
        'Stephan-Abdelsalam water', 'Stephan-Abdelsalam cryogenic', 
        'Stephan-Abdelsalam', 'HEDH-Taborek', 'Forster-Zuber', 'Rohsenow', 
        'Cooper', 'Bier', 'Montinsky', 'McNelly']
    AvailableMethods : bool, optional
        If True, function will consider which methods which can be used to
        calculate `h` with the given inputs
        
    Notes
    -----
    The methods Stephan-Abdelsalam, Cooper, and Gorenflo all take other 
    arguments as well such as surface roughness or the thermal properties of
    the wall material. See them for their documentation. These parameters
    can also be passed as keyword arguments.
    
    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5', Ra=1E-6)
    3437.7726419934147
    
    Examples
    --------
    Water boiling at 3 bar and a heat flux of 2E4 W/m^2/K.

    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5')
    3043.344595525422
    
    Water, known excess temperature of 4.9 K, Rohsenow method

    >>> h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217,
    ... Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26, 
    ... Method='Rohsenow')
    3723.655267067467

def h_nucleic(Te=None, q=None, Tsat=None, P=None, dPsat=None, Cpl=None, 
              kl=None, mul=None, rhol=None, sigma=None, Hvap=None, rhog=None, 
              MW=None, Pc=None, CAS=None, Method=None, AvailableMethods=False, 
              **kwargs):
    r'''This function handles the calculation of nucleate boiling
    heat flux and chooses the best method for performing the calculation
    based on the provided information.

    One of `Te` and `q` are always required.

    Parameters
    ----------
    Te : float, optional
        Excess wall temperature, [K]
    q : float, optional
        Heat flux, [W/m^2]
    Tsat : float, optional
        Saturation temperature at operating pressure [Pa]
    P : float, optional
        Saturation pressure of fluid, [Pa]
    dPsat : float, optional
        Difference in saturation pressure of the fluid at Te and T, [Pa]
    Cpl : float, optional
        Heat capacity of liquid [J/kg/K]
    kl : float, optional
        Thermal conductivity of liquid [W/m/K]
    mul : float, optional
        Viscosity of liquid [Pa*s]
    rhol : float, optional
        Density of the liquid [kg/m^3]
    sigma : float, optional
        Surface tension of liquid [N/m]
    Hvap : float, optional
        Heat of vaporization of the fluid at P, [J/kg]
    rhog : float, optional
        Density of the produced gas [kg/m^3]
    MW : float, optional
        Molecular weight of fluid, [g/mol]
    Pc : float, optional
        Critical pressure of fluid, [Pa]
    CAS : str, optional
        CAS of fluid

    Returns
    -------
    h : float
        Nucleate boiling heat flux [W/m^2]
    methods : list, only returned if AvailableMethods == True
        List of methods which can be used to calculate `h` with the given inputs

    Other Parameters
    ----------------
    Method : string, optional
        The name of the method to use; one of ['Gorenflo (1993)', 
        'Stephan-Abdelsalam water', 'Stephan-Abdelsalam cryogenic', 
        'Stephan-Abdelsalam', 'HEDH-Taborek', 'Forster-Zuber', 'Rohsenow', 
        'Cooper', 'Bier', 'Montinsky', 'McNelly']
    AvailableMethods : bool, optional
        If True, function will consider which methods which can be used to
        calculate `h` with the given inputs
        
    Notes
    -----
    The methods Stephan-Abdelsalam, Cooper, and Gorenflo all take other 
    arguments as well such as surface roughness or the thermal properties of
    the wall material. See them for their documentation. These parameters
    can also be passed as keyword arguments.
    
    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5', Ra=1E-6)
    3437.7726419934147
    
    Examples
    --------
    Water boiling at 3 bar and a heat flux of 2E4 W/m^2/K.

    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5')
    3043.344595525422
    
    Water, known excess temperature of 4.9 K, Rohsenow method

    >>> h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217,
    ... Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26, 
    ... Method='Rohsenow')
    3723.655267067467
    '''
    def list_methods():
        methods = []
        if all((P, Pc)):
            if CAS and CAS in h0_Gorenflow_1993:
                methods.append('Gorenflo (1993)')
        if all((Te, Tsat, Cpl, kl, mul, sigma, Hvap, rhol, rhog)):
            if CAS and CAS == '7732-18-5':
                methods.append('Stephan-Abdelsalam water')
            if CAS and CAS in cryogenics:
                methods.append('Stephan-Abdelsalam cryogenic')
            methods.append('Stephan-Abdelsalam')
        if all((Te, P, Pc)):
            methods.append('HEDH-Taborek')
        if all((Te, dPsat, Cpl, kl, mul, sigma, Hvap, rhol, rhog)):
            methods.append('Forster-Zuber')
        if all((Te, Cpl, kl, mul, sigma, Hvap, rhol, rhog)):
            methods.append('Rohsenow')
        if all((Te, P, Pc, MW)):
            methods.append('Cooper')
        if all((Te, P, Pc)):
            methods.append('Bier')
        if all((Te, P, Pc)):
            methods.append('Montinsky')
        if all((Te, P, Cpl, kl, sigma, Hvap, rhol, rhog)):
            methods.append('McNelly')
        return methods

    if AvailableMethods:
        return list_methods()
    if not Method:
        methods = list_methods()
        if methods == []:
            raise Exception('Insufficient property data for any method.')
        Method = methods[0]

    if Method == 'Stephan-Abdelsalam':
        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,
                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,
                               correlation='general', **kwargs)
    elif Method == 'Stephan-Abdelsalam water':
        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,
                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,
                               correlation='water', **kwargs)
    elif Method == 'Stephan-Abdelsalam cryogenic':
        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,
                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,
                               correlation='cryogenic', **kwargs)
    elif Method == 'HEDH-Taborek':
        return HEDH_Taborek(Te=Te, q=q, P=P, Pc=Pc)
    elif Method == 'Forster-Zuber':
        return Forster_Zuber(Te=Te, q=q, dPsat=dPsat, Cpl=Cpl, kl=kl, mul=mul,
                          sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog, **kwargs)
    elif Method == 'Rohsenow':
        return Rohsenow(Te=Te, q=q, Cpl=Cpl, kl=kl, mul=mul, sigma=sigma, Hvap=Hvap,
                     rhol=rhol, rhog=rhog, **kwargs)
    elif Method == 'Cooper':
        return Cooper(Te=Te, q=q, P=P, Pc=Pc, MW=MW, **kwargs)
    elif Method == 'Bier':
        return Bier(Te=Te, q=q, P=P, Pc=Pc, **kwargs)
    elif Method == 'Montinsky':
        return Montinsky(Te=Te, q=q, P=P, Pc=Pc, **kwargs)
    elif Method == 'McNelly':
        return McNelly(Te=Te, q=q, P=P, Cpl=Cpl, kl=kl, sigma=sigma, Hvap=Hvap,
                    rhol=rhol, rhog=rhog, **kwargs)
    elif Method == 'Gorenflo (1993)':
        return Gorenflo(P=P, q=q, Pc=Pc, Te=Te, CASRN=CAS, **kwargs)
    else:
        raise Exception("Correlation name not recognized; see the "
                        "documentation for the available options.")