<commit_before>"""Contains the adsorbate class."""

import warnings

from ..data import ADSORBATE_LIST
from ..utilities.converter_unit import _PRESSURE_UNITS
from ..utilities.converter_unit import c_unit
from ..utilities.coolprop_utilities import CP
from ..utilities.coolprop_utilities import thermodynamic_backend
from ..utilities.exceptions import CalculationError
from ..utilities.exceptions import ParameterError


class Adsorbate():
    """
    An unified class descriptor for an adsorbate.

    Its purpose is to expose properties such as adsorbate name,
    and formula, as well as physical properties, such as molar mass
    vapour pressure, etc.

    The properties can be either calculated through a wrapper over
    CoolProp or supplied in the initial adsorbate creation.
    All parameters passed are saved in a self.parameters
    dictionary.

    Parameters
    ----------
    name : str
        The name which should be used for this adsorbate.

    Other Parameters
    ----------------
    alias : list
        Other names the same adsorbate might take.
        Example: name=propanol, alias=['1-propanol'].
        pyGAPS disregards capitalisation (Propanol = propanol = PROPANOL).
    formula : str
        A chemical formula for the adsorbate in LaTeX form: He/N_{2}/C_{2}H_{4} etc.
    backend_name : str
        Used for integration with CoolProp/REFPROP. For a list of names
        look at the CoolProp `list of fluids
        <http://www.coolprop.org/fluid_properties/PurePseudoPure.html#list-of-fluids>`_
    molar_mass : float
        Custom value for molar mass (otherwise obtained through CoolProp).
    saturation_pressure : float
        Custom value for saturation pressure (otherwise obtained through CoolProp).
    surface_tension : float
        Custom value for surface tension (otherwise obtained through CoolProp).
    liquid_density : float
        Custom value for liquid density (otherwise obtained through CoolProp).
    liquid_molar_density : float
        Custom value for liquid molar density (otherwise obtained through CoolProp).
    gas_density : float
        Custom value for gas density (otherwise obtained through CoolProp).
    gas_molar_density : float
        Custom value for gas molar density (otherwise obtained through CoolProp).
    enthalpy_liquefaction : float
        Custom value for enthalpy of liquefaction (otherwise obtained through CoolProp).

    Notes
    -----
    The members of the properties dictionary are left at the discretion of the
    user, to keep the class extensible. There are, however, some unique
    properties which are used by calculations in other modules listed in the
    other parameters section above.

    These properties can be either calculated by CoolProp (if the adsorbate
    exists in CoolProp/REFPROP) or taken from the parameters dictionary. They
    are best accessed using the associated function.

    Calculated::

        my_adsorbate.surface_tension(77)

    Value from dictionary::

        my_adsorbate.surface_tension(77, calculate=False)

    If available, the underlying CoolProp state object
    (http://www.coolprop.org/coolprop/LowLevelAPI.html) can be accessed directly
    through the backend variable. For example, to get the CoolProp-calculated
    critical pressure::

        adsorbate.backend.p_critical()

    """
    def __init__(self, name: str = None, **properties):
        """Instantiate by passing a dictionary with the parameters."""
        # Adsorbate name
        if name is None:
            raise ParameterError(
                "Must provide a name for the created adsorbate."
            )
        self.name = name

        # List of aliases
        alias = properties.pop('alias', None)

        # Generate list of aliases
        _name = name.lower()
        if alias is None:
            self.alias = [_name]
        else:
            if isinstance(alias, str):
                self.alias = [alias.lower()]
            else:
                self.alias = [a.lower() for a in alias]
            if _name not in self.alias:
                self.alias.append(_name)

        #: Adsorbate properties
        self.properties = properties

        # CoolProp interaction variables, only generate when called
        self._state = None
        self._backend_mode = None

        # TODO
        # auto-upload adsorbates to global list?

    def __repr__(self):
        """Print adsorbate id."""
        return f"<pygaps.Adsorbate '{self.name}'>"

    def __str__(self):
        """Print adsorbate standard name."""
        return self.name

    def __hash__(self):
        """Override hashing as a name hash."""
        return hash(self.name)

    def __eq__(self, other):
        """Overload equality operator to include aliases."""
        if isinstance(other, Adsorbate):
            return self.name == other.name
        return other.lower() in self.alias

    def __add__(self, other):
        """Overload addition operator to use name."""
        return self.name + other

    def __radd__(self, other):
        """Overload rev addition operator to use name."""
        return other + self.name

    def print_info(self):
        """Print a short summary of all the adsorbate parameters."""
        string = ""

        string += f"Adsorbate: {self.name}\n"
        string += f"Aliases: { *self.alias,}\n"

        for prop in self.properties:
            string += f"{prop}:{str(self.properties.get(prop))}\n"

        return string

    @classmethod
    def find(cls, name: str):
        """Get the specified adsorbate from the master list.

        Parameters
        ----------
        name : str
            The name of the adsorbate to search

        Returns
        -------
        Adsorbate
            Instance of class

        Raises
        ------
        ``ParameterError``
            If it does not exist in list.
        """
        # Skip search if already adsorbate
        if isinstance(name, Adsorbate):
            return name
        elif not isinstance(name, str):
            raise ParameterError("Pass a string as an adsorbate name.")

        # See if adsorbate exists in master list
        try:
            return next(ads for ads in ADSORBATE_LIST if ads == name)
        except StopIteration:
            raise ParameterError(
                f"Adsorbate '{name}' does not exist in list of adsorbates. "
                "First populate pygaps.ADSORBATE_LIST with required adsorbate class."
            ) from None

    @property
    def backend(self) -> str:
        """Return the CoolProp state associated with the fluid."""
        if (
            not self._backend_mode
            or self._backend_mode != thermodynamic_backend()
        ):
            self._backend_mode = thermodynamic_backend()
            self._state = CP.AbstractState(
                self._backend_mode, self.backend_name
            )

        return self._state

    @property
    def formula(self) -> str:
        """Return the adsorbate formula."""
        formula = self.properties.get('formula')<commit_msg>backend does not return string<commit_after>"""Contains the adsorbate class."""

import warnings

from ..data import ADSORBATE_LIST
from ..utilities.converter_unit import _PRESSURE_UNITS
from ..utilities.converter_unit import c_unit
from ..utilities.coolprop_utilities import CP
from ..utilities.coolprop_utilities import thermodynamic_backend
from ..utilities.exceptions import CalculationError
from ..utilities.exceptions import ParameterError


class Adsorbate():
    """
    An unified class descriptor for an adsorbate.

    Its purpose is to expose properties such as adsorbate name,
    and formula, as well as physical properties, such as molar mass
    vapour pressure, etc.

    The properties can be either calculated through a wrapper over
    CoolProp or supplied in the initial adsorbate creation.
    All parameters passed are saved in a self.parameters
    dictionary.

    Parameters
    ----------
    name : str
        The name which should be used for this adsorbate.

    Other Parameters
    ----------------
    alias : list
        Other names the same adsorbate might take.
        Example: name=propanol, alias=['1-propanol'].
        pyGAPS disregards capitalisation (Propanol = propanol = PROPANOL).
    formula : str
        A chemical formula for the adsorbate in LaTeX form: He/N_{2}/C_{2}H_{4} etc.
    backend_name : str
        Used for integration with CoolProp/REFPROP. For a list of names
        look at the CoolProp `list of fluids
        <http://www.coolprop.org/fluid_properties/PurePseudoPure.html#list-of-fluids>`_
    molar_mass : float
        Custom value for molar mass (otherwise obtained through CoolProp).
    saturation_pressure : float
        Custom value for saturation pressure (otherwise obtained through CoolProp).
    surface_tension : float
        Custom value for surface tension (otherwise obtained through CoolProp).
    liquid_density : float
        Custom value for liquid density (otherwise obtained through CoolProp).
    liquid_molar_density : float
        Custom value for liquid molar density (otherwise obtained through CoolProp).
    gas_density : float
        Custom value for gas density (otherwise obtained through CoolProp).
    gas_molar_density : float
        Custom value for gas molar density (otherwise obtained through CoolProp).
    enthalpy_liquefaction : float
        Custom value for enthalpy of liquefaction (otherwise obtained through CoolProp).

    Notes
    -----
    The members of the properties dictionary are left at the discretion of the
    user, to keep the class extensible. There are, however, some unique
    properties which are used by calculations in other modules listed in the
    other parameters section above.

    These properties can be either calculated by CoolProp (if the adsorbate
    exists in CoolProp/REFPROP) or taken from the parameters dictionary. They
    are best accessed using the associated function.

    Calculated::

        my_adsorbate.surface_tension(77)

    Value from dictionary::

        my_adsorbate.surface_tension(77, calculate=False)

    If available, the underlying CoolProp state object
    (http://www.coolprop.org/coolprop/LowLevelAPI.html) can be accessed directly
    through the backend variable. For example, to get the CoolProp-calculated
    critical pressure::

        adsorbate.backend.p_critical()

    """
    def __init__(self, name: str = None, **properties):
        """Instantiate by passing a dictionary with the parameters."""
        # Adsorbate name
        if name is None:
            raise ParameterError(
                "Must provide a name for the created adsorbate."
            )
        self.name = name

        # List of aliases
        alias = properties.pop('alias', None)

        # Generate list of aliases
        _name = name.lower()
        if alias is None:
            self.alias = [_name]
        else:
            if isinstance(alias, str):
                self.alias = [alias.lower()]
            else:
                self.alias = [a.lower() for a in alias]
            if _name not in self.alias:
                self.alias.append(_name)

        #: Adsorbate properties
        self.properties = properties

        # CoolProp interaction variables, only generate when called
        self._state = None
        self._backend_mode = None

        # TODO
        # auto-upload adsorbates to global list?

    def __repr__(self):
        """Print adsorbate id."""
        return f"<pygaps.Adsorbate '{self.name}'>"

    def __str__(self):
        """Print adsorbate standard name."""
        return self.name

    def __hash__(self):
        """Override hashing as a name hash."""
        return hash(self.name)

    def __eq__(self, other):
        """Overload equality operator to include aliases."""
        if isinstance(other, Adsorbate):
            return self.name == other.name
        return other.lower() in self.alias

    def __add__(self, other):
        """Overload addition operator to use name."""
        return self.name + other

    def __radd__(self, other):
        """Overload rev addition operator to use name."""
        return other + self.name

    def print_info(self):
        """Print a short summary of all the adsorbate parameters."""
        string = ""

        string += f"Adsorbate: {self.name}\n"
        string += f"Aliases: { *self.alias,}\n"

        for prop in self.properties:
            string += f"{prop}:{str(self.properties.get(prop))}\n"

        return string

    @classmethod
    def find(cls, name: str):
        """Get the specified adsorbate from the master list.

        Parameters
        ----------
        name : str
            The name of the adsorbate to search

        Returns
        -------
        Adsorbate
            Instance of class

        Raises
        ------
        ``ParameterError``
            If it does not exist in list.
        """
        # Skip search if already adsorbate
        if isinstance(name, Adsorbate):
            return name
        elif not isinstance(name, str):
            raise ParameterError("Pass a string as an adsorbate name.")

        # See if adsorbate exists in master list
        try:
            return next(ads for ads in ADSORBATE_LIST if ads == name)
        except StopIteration:
            raise ParameterError(
                f"Adsorbate '{name}' does not exist in list of adsorbates. "
                "First populate pygaps.ADSORBATE_LIST with required adsorbate class."
            ) from None

    @property
    def backend(self):
        """Return the CoolProp state associated with the fluid."""
        if (
            not self._backend_mode
            or self._backend_mode != thermodynamic_backend()
        ):
            self._backend_mode = thermodynamic_backend()
            self._state = CP.AbstractState(
                self._backend_mode, self.backend_name
            )

        return self._state

    @property
    def formula(self) -> str:
        """Return the adsorbate formula."""
        formula = self.properties.get('formula')
{'fraction_non_alphanumeric': 0.07892503536067892, 'fraction_numerical': 0.0011315417256011315, 'mean_word_length': 2.256794104099493, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6932705', 'n_tokens_mistral': 3762, 'n_tokens_neox': 3531, 'n_words': 1344}