Exemplo n.º 1
0
    def get_A(self,
              sden_operation='min',
              include_entropy=True,
              T=c.T0('K'),
              units='molec/cm2',
              **kwargs):
        """Calculates the preexponential factor in the Cantera format

        Parameters
        ----------
        sden_operation : str, optional
            Site density operation to use. Default is 'min'
        include_entropy : bool, optional
            If True, includes the entropy of activation. Default is True
        T : float, optional
            Temperature in K. Default is 298.15 K
        units : str or :class:`~pmutt.omkm.units.Units`, optional
            Units for A. If `Units` class specified, determines the units for A.
            Default is 'molec/cm2'
        kwargs : keyword arguments
            Parameters required to calculate pre-exponential factor
        """

        if self.transition_state is None or not include_entropy:
            A = c.kb('J/K') / c.h('J s')
        else:
            A = super().get_A(T=T, **kwargs) / T

        # Uses site with highest site density
        site_dens = []
        for reactant, stoich in zip(self.reactants, self.reactants_stoich):
            # Skip species without a catalyst site
            try:
                site_den = reactant.phase.site_density
            except AttributeError:
                continue
            site_dens.extend([site_den] * int(stoich))

        # Apply the operation to the site densities
        if len(site_dens) == 0:
            err_msg = ('At least one species requires a catalytic site with '
                       'site density to calculate A.')
            raise ValueError(err_msg)
        eff_site_den = _apply_numpy_operation(quantity=site_dens,
                                              operation=sden_operation,
                                              verbose=False)
        # Convert site density to appropriate unit
        if isinstance(units, Units):
            quantity_unit = units.quantity
            area_unit = '{}2'.format(units.length)
        else:
            quantity_unit, area_unit = units.split('/')
        eff_site_den = eff_site_den\
                       *c.convert_unit(initial='mol', final=quantity_unit)\
                       /c.convert_unit(initial='cm2', final=area_unit)

        n_surf = self._get_n_surf()
        A = A / eff_site_den**(n_surf - 1)
        return A
Exemplo n.º 2
0
def get_rot_temperatures_from_atoms(atoms, geometry=None, degree_tol=5.):
    """Calculate the rotational temperatures from ase.Atoms object

    Parameters
    ----------
        atoms : `ase.Atoms`_ object
            Atoms object
        geometry : str, optional
            Geometry of molecule. If not specified, it will be guessed from
            Atoms object.
        degree_tol : float, optional
            Degree tolerance in degrees. Default is 5 degrees
    Returns
    -------
        rot_temperatures : list of float
            Rotational temperatures

    .. _`ase.Atoms`: https://wiki.fysik.dtu.dk/ase/ase/atoms.html#ase.Atoms
    """
    if geometry is None:
        geometry = get_geometry_from_atoms(atoms=atoms, degree_tol=degree_tol)

    rot_temperatures = []
    for moment in atoms.get_moments_of_inertia():
        if np.isclose(0., moment):
            continue
        moment_SI = moment*c.convert_unit(initial='amu', final='kg') \
            * c.convert_unit(initial='A2', final='m2')
        rot_temperatures.append(c.inertia_to_temp(moment_SI))

    if geometry == 'monatomic':
        # Expecting all modes to be 0
        if not np.isclose(np.sum(rot_temperatures), 0.):
            err_msg = ('Geometry expected to be monatomic but contains '
                       'non-zero rotational temperatures.')
            raise ValueError(err_msg)
        return [0.]
    elif geometry == 'linear':
        # Expecting one mode to be 0 and the other modes to be identical
        if not np.isclose(rot_temperatures[0], rot_temperatures[1]):
            warn_msg = ('Expected rot_temperatures for linear specie, {}, to '
                        'be similar. Values found were: {}'
                        ''.format(atoms, rot_temperatures))
            warn(warn_msg)
        return [min(rot_temperatures)]
    elif geometry == 'nonlinear':
        # Expecting 3 modes. May or may not be equal
        return rot_temperatures
    else:
        err_msg = 'Geometry, {}, not supported.'.format(geometry)
        raise ValueError(err_msg)
Exemplo n.º 3
0
 def __init__(self,
              A_st=None,
              atoms=None,
              symmetrynumber=None,
              inertia=None,
              geometry=None,
              vib_wavenumbers=None,
              potentialenergy=None,
              **kwargs):
     super().__init__(atoms=atoms,
                      symmetrynumber=symmetrynumber,
                      geometry=geometry,
                      vib_wavenumbers=vib_wavenumbers,
                      potentialenergy=potentialenergy,
                      **kwargs)
     self.A_st = A_st
     self.atoms = atoms
     self.geometry = geometry
     self.symmetrynumber = symmetrynumber
     self.inertia = inertia
     self.etotal = potentialenergy
     self.vib_energies = c.wavenumber_to_energy(np.array(vib_wavenumbers))
     self.theta = np.array(self.vib_energies) / c.kb('eV/K')
     self.zpe = sum(np.array(self.vib_energies)/2.) *\
         c.convert_unit(initial='eV', final='kcal')*c.Na
     if np.sum(self.vib_energies) != 0:
         self.q_vib = np.product(
             np.divide(1, (1 - np.exp(-self.theta / c.T0('K')))))
     if self.phase == 'G':
         if self.inertia is not None:
             self.I3 = self.inertia
         else:
             self.I3 = atoms.get_moments_of_inertia() *\
                     c.convert_unit(initial='A2', final='m2') *\
                     c.convert_unit(initial='amu', final='kg')
         self.T_I = c.h('J s')**2 / (8 * np.pi**2 * c.kb('J/K'))
     if self.phase == 'G':
         Irot = np.max(self.I3)
         if self.geometry == 'nonlinear':
             self.q_rot = np.sqrt(np.pi*Irot)/self.symmetrynumber *\
                                 (c.T0('K')/self.T_I)**(3./2.)
         else:
             self.q_rot = (c.T0('K') * Irot /
                           self.symmetrynumber) / self.T_I
     else:
         self.q_rot = 0.
     if self.A_st is not None:
         self.MW = mw(self.elements) * c.convert_unit(initial='g',
                                                      final='kg') / c.Na
         self.q_trans2D = self.A_st * (2 * np.pi * self.MW * c.kb('J/K') *
                                       c.T0('K')) / c.h('J s')**2
Exemplo n.º 4
0
    def setUp(self):
        slope = 0.5
        intercept = 10.  # kcal/mol
        del_E = -1.  # kcal/mol
        del_E_eV = del_E * c.convert_unit(initial='kcal/mol',
                                          final='eV/molecule')
        E_surf = -2.  # kcal/mol
        E_surf_eV = E_surf * c.convert_unit(initial='kcal/mol',
                                            final='eV/molecule')
        E_gas = -3.  # kcal/mol
        E_gas_eV = E_gas * c.convert_unit(initial='kcal/mol',
                                          final='eV/molecule')

        species = {
            'A(g)_shomate':
            Shomate(name='A(g)_shomate',
                    T_low=100.,
                    T_high=500.,
                    a=np.zeros(8)),
            'A(g)_statmech':
            StatMech(),
            '*':
            StatMech(),
            'A*':
            StatMech(U=del_E_eV, H=del_E_eV, **presets['constant']),
            'surf':
            StatMech(U=E_surf_eV, H=E_surf_eV, **presets['constant']),
            'gas':
            StatMech(U=E_gas_eV, H=E_gas_eV, **presets['constant'])
        }
        reaction_shomate = Reaction.from_string('A(g)_shomate + * = A*',
                                                species)
        reaction_statmech = Reaction.from_string('A(g)_statmech + * = A*',
                                                 species)

        self.lsr_const = LSR(slope=slope,
                             intercept=intercept,
                             reaction=del_E,
                             surf_species=E_surf,
                             gas_species=E_gas)
        self.lsr_shomate = LSR(slope=slope,
                               intercept=intercept,
                               reaction=reaction_shomate,
                               surf_species=species['surf'],
                               gas_species=species['gas'])
        self.lsr_statmech = LSR(slope=slope,
                                intercept=intercept,
                                reaction=reaction_statmech,
                                surf_species=species['surf'],
                                gas_species=species['gas'])
Exemplo n.º 5
0
    def get_Vm(self, T=c.T0('K'), P=c.P0('bar'), gas_phase=True):
        """Calculates the molar volume of a van der Waals gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            P : float, optional
                Pressure in bar. Default is standard pressure
            gas_phase : bool, optional
                Relevant if system is in vapor-liquid equilibrium. If True,
                return the larger volume (gas phase). If False, returns the
                smaller volume (liquid phase).
        Returns
        -------
            Vm : float
                Volume in m3
        """
        P_SI = P * c.convert_unit(initial='bar', final='Pa')
        Vm = np.roots([
            P_SI, -(P_SI * self.b + c.R('J/mol/K') * T), self.a,
            -self.a * self.b
        ])
        real_Vm = np.real([Vm_i for Vm_i in Vm if np.isreal(Vm_i)])
        if gas_phase:
            return np.max(real_Vm)
        else:
            return np.min(real_Vm)
Exemplo n.º 6
0
    def to_CTI(self, act_energy_unit=None, units=None, delimiter='_'):
        """Writes the object in Cantera's CTI format.

        Parameters
        ----------
            act_energy_unit : str, optional
                Unit to use for energy. Default is 'cal/mol'
            units : :class:`~pmutt.omkm.units.Units` object
                If specified, `energy_unit` is overwritten. Default is None.
        Returns
        -------
            cti_str : str
                Surface reaction string in CTI format
        """
        if units is not None:
            act_energy_unit = units.act_energy
        # synthesis_reactions = self._get_reactions_CTI(direction='synthesis')
        # cleavage_reactions = self._get_reactions_CTI(direction='cleavage')
        synthesis_reactions = _get_range_CTI(objs=self.synthesis_reactions,
                                             parent_obj=self,
                                             delimiter=delimiter)
        cleavage_reactions = _get_range_CTI(objs=self.cleavage_reactions,
                                            parent_obj=self,
                                            delimiter=delimiter)
        intercept = c.convert_unit(self.intercept, 'kcal/mol', act_energy_unit)
        cti_str = ('bep(id="{}",\n'
                   '    slope={},\n'
                   '    intercept={},\n'
                   '    direction="{}",\n'
                   '    cleavage_reactions={},\n'
                   '    synthesis_reactions={})\n'
                   ''.format(self.name, self.slope, intercept, self.direction,
                             cleavage_reactions, synthesis_reactions))
        return cti_str
Exemplo n.º 7
0
    def get_SoR(self, T, P=c.P0('bar')):
        """Calculates the dimensionless entropy

        :math:`\\frac{S^{trans}}{R}=1+\\frac{n_{degrees}}{2}+\\log\\bigg(\\big(
        \\frac{2\\pi mk_bT}{h^2})^\\frac{n_{degrees}}{2}\\frac{RT}{PN_a}\\bigg)`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float, optional
                Pressure (bar) or pressure-like quantity.
                Default is atmospheric pressure

        Returns
        -------
            SoR_trans : float
                Translational dimensionless entropy
        """
        V = self.get_V(T=T, P=P)
        unit_mass = self.molecular_weight *\
            c.convert_unit(initial='g', final='kg')/c.Na
        return 1. + float(self.n_degrees)/2. \
            + np.log((2.*np.pi*unit_mass*c.kb('J/K')*T/c.h('J s')**2)
                     ** (float(self.n_degrees)/2.)*V/c.Na)
Exemplo n.º 8
0
    def get_E_act(self, units, rev=False, **kwargs):
        """Calculate Arrhenius activation energy using BEP relationship

        Parameters
        ----------
            units : str
                Units as string. See :func:`~pmutt.constants.R` for accepted
                units but omit the '/K' (e.g. J/mol).
            rev : bool, optional
                Reverse direction. If True, uses products as initial state
                instead of reactants. Default is False
            kwargs : keyword arguments
                Parameters required to calculate the descriptor
        Returns
        -------
            E_act : float
                Dimensionless activation energy
        """
        if 'rev_delta' in self.descriptor:
            # If the descriptor is for the reverse reaction, the slope has to
            # be modified
            if rev:
                E_act = self.slope * self._descriptor_fn(
                    **kwargs) + self.intercept
            else:
                E_act = (self.slope-1.)*self._descriptor_fn(**kwargs) \
                        + self.intercept
        else:
            if rev:
                E_act = (self.slope-1.)*self._descriptor_fn(**kwargs) \
                        + self.intercept
            else:
                E_act = self.slope * self._descriptor_fn(
                    **kwargs) + self.intercept
        return E_act * c.convert_unit(initial='kcal/mol', final=units)
Exemplo n.º 9
0
    def to_cti(self, energy_unit='kcal', quantity_unit='mol', units=None):
        """Writes the lateral interaction in CTI format

        Parameters
        ----------
            energy_unit : str, optional
                Energy unit for slopes. Default is 'kcal'
            quantity_unit : str, optional
                Quantity unit for slopes. Default is 'mol'
            units : :class:`~pmutt.cantera.units.Units` object
                If specified, ``energy_unit`` and ``quantity_unit`` are
                overwritten. Default is None.
        Returns
        -------
            lat_inter_str : str
                Lateral interaction in CTI format
        """
        if units is not None:
            energy_unit = units.energy
            quantity_unit = units.quantity
        final = '{}/{}'.format(energy_unit, quantity_unit)
        slopes = [c.convert_unit(slope, initial='kcal/mol', final=final) \
                  for slope in self.slopes]
        lat_inter_str = ('lateral_interaction("{} {}",\n'
                         '                    coverage_thresholds={},\n'
                         '                    strengths={},\n'
                         '                    id="{}")'
                         ''.format(self.name_i, self.name_j, self.intervals,
                                   slopes, self.name))
        return lat_inter_str
Exemplo n.º 10
0
    def setUp(self):
        unittest.TestCase.setUp(self)
        # Testing Ideal Gas Model
        CO2 = molecule('CO2')
        CO2_pmutt_parameters = {
            'name':
            'CO2',
            'elements': {
                'C': 1,
                'O': 2
            },
            'trans_model':
            trans.FreeTrans,
            'n_degrees':
            3,
            'molecular_weight':
            get_molecular_weight('CO2'),
            'rot_model':
            rot.RigidRotor,
            'rot_temperatures':
            rot.get_rot_temperatures_from_atoms(CO2, geometry='linear'),
            'geometry':
            'linear',
            'symmetrynumber':
            2,
            'elec_model':
            elec.GroundStateElec,
            'potentialenergy':
            -22.994202,
            'spin':
            0.,
            'vib_model':
            vib.HarmonicVib,
            'vib_wavenumbers': [3360., 954., 954., 1890.],
        }
        CO2_ase_parameters = {
            'atoms':
            CO2,
            'potentialenergy':
            -22.994202,
            'vib_energies': [
                c.wavenumber_to_energy(x) *
                c.convert_unit(initial='J', final='eV')
                for x in CO2_pmutt_parameters['vib_wavenumbers']
            ],
            'geometry':
            'linear',
            'symmetrynumber':
            2,
            'spin':
            0.
        }
        self.CO2_pmutt = StatMech(**CO2_pmutt_parameters)
        self.CO2_ASE = IdealGasThermo(**CO2_ase_parameters)

        self.T0 = c.T0('K')  # K
        self.P0 = c.P0('Pa')
        self.V0 = c.V0('m3')
        self.mw = get_molecular_weight({'C': 1, 'O': 2})
Exemplo n.º 11
0
    def get_Pc(self):
        """Calculates the critical pressure

        Returns
        -------
            Pc : float
                Critical pressure in bar
        """
        return self.a / 27. / self.b**2 * c.convert_unit(initial='Pa',
                                                         final='bar')
Exemplo n.º 12
0
def read_molecular_mass(filename, units='g/mol'):
    """Reads the molecular mass from the Gaussian log file.

    Parameters
    ----------
        filename : str
            Log file
        units : str, optional
            Units for molecular mass. Default is 'g/mol'
    Returns
    -------
        molecular_mass : float
            Molecular mass in ``units``. Default is 'g/mol'
    """
    if units == 'amu':
        units = 'amu/molecule'
    mass_unit, amount_unit = units.split('/')
    molecular_mass = float(read_pattern(filename=filename,
                                        pattern='Molecular mass:(.*)',
                                        group=0,
                                        return_immediately=True).split()[0]) \
                     *c.convert_unit(initial='amu', final=mass_unit) \
                     /c.convert_unit(initial='molecule', final=amount_unit)
    return molecular_mass
Exemplo n.º 13
0
    def _float_to_specie(self, val):
        """Converts a float to a :class:`~pmutt.statmech.StatMech` object

        Parameters
        ----------
            val : float
                Value (in kcal/mol)
        Returns
        -------
            obj : :class:`~pmutt.statmech.StatMech` object
                :class:`~pmutt.statmech.StatMech` object that gives the val
                when `get_E` is called
        """
        val = val*c.convert_unit(initial='kcal/mol', final='eV/molecule')
        return StatMech(U=val, H=val, F=val, G=val, **presets['constant'])
Exemplo n.º 14
0
    def get_V(self, T, P):
        """Calculates the molar volume of an ideal gas at T and P

        :math:`V_m=\\frac{RT}{P}`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float
                Pressure in bar
        Returns
        -------
            V : float
                Molar volume in m3
        """
        return T*c.R('J/mol/K')/(P*c.convert_unit(initial='bar', final='Pa'))
Exemplo n.º 15
0
    def from_critical(cls, Tc, Pc):
        """Creates the van der Waals object from critical temperature and
        pressure

        Parameters
        ----------
            Tc : float
                Critical temperature in K
            Pc : float
                Critical pressure in bar
        Returns
        -------
            vanDerWaalsEOS : vanDerWaalsEOS object
        """
        Pc_SI = Pc * c.convert_unit(initial='bar', final='Pa')
        a = 27. / 64. * (c.R('J/mol/K') * Tc)**2 / Pc_SI
        b = c.R('J/mol/K') * Tc / 8. / Pc_SI
        return cls(a=a, b=b)
Exemplo n.º 16
0
def read_zpe(filename, units='eV/molecule'):
    """Reads the zero-point energy from the Gaussian log file.

    Parameters
    ----------
        filename : str
            Log file
        units : str, optional
            Units to return energy. Default is 'eV/molecule'
    Returns
    -------
        zero_point_energy : float
            Zero point energy in ``units``. Default units are 'eV/molecule'
    """
    return float(read_pattern(filename=filename,
                              pattern='Zero-point correction=(.*?)\(',
                              group=0,
                              return_immediately=True)) \
           *c.convert_unit(initial='Ha/molecule', final=units)
Exemplo n.º 17
0
    def get_P(self, T=c.T0('K'), V=c.V0('m3'), n=1.):
        """Calculates the pressure of a van der Waals gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            V : float, optional
                Volume in m3. Default is standard volume
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            P : float
                Pressure in bar
        """
        Vm = V / n
        return (c.R('J/mol/K')*T/(Vm - self.b) - self.a*(1./Vm)**2) \
            * c.convert_unit(initial='Pa', final='bar')
Exemplo n.º 18
0
    def get_T(self, V=c.V0('m3'), P=c.P0('bar'), n=1.):
        """Calculates the temperature of a van der Waals gas

        Parameters
        ----------
            V : float, optional
                Volume in m3. Default is standard volume
            P : float, optional
                Pressure in bar. Default is standard pressure
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            T : float
                Temperature in K
        """
        Vm = V / n
        return (P*c.convert_unit(initial='bar', final='Pa') + self.a/Vm**2) \
            * (Vm - self.b)/c.R('J/mol/K')
Exemplo n.º 19
0
    def to_omkm_yaml(self, act_energy_unit=None, units=None):
        """Writes the object in Cantera's YAML format.

        Parameters
        ----------
            act_energy_unit : str, optional
                Unit to use for activation energy. Default is 'cal/mol'
            units : :class:`~pmutt.omkm.units.Units` object
                If specified, `act_energy_unit` is overwritten.
                Default is None.
        Returns
        -------
            yaml_dict : dict
                Dictionary compatible with Cantera's YAML format
        """
        if units is not None:
            act_energy_unit = units.act_energy

        yaml_dict = {}
        yaml_dict['id'] = self.name
        yaml_dict['slope'] = self.slope
        # Assign intercept
        intercept = c.convert_unit(self.intercept, 'kcal/mol', act_energy_unit)
        intercept_param = _Param('intercept', intercept, '_act_energy')
        _assign_yaml_val(intercept_param, yaml_dict, units)

        yaml_dict['direction'] = self.direction
        if self.synthesis_reactions is not None \
           and len(self.synthesis_reactions) > 0:
            synthesis_reactions = _get_omkm_range(objs=self.synthesis_reactions,
                                                  parent_obj=self,
                                                  format='list')
            yaml_dict['synthesis-reactions'] = synthesis_reactions

        if self.cleavage_reactions is not None \
           and len(self.cleavage_reactions) > 0:
            cleavage_reactions = _get_omkm_range(objs=self.cleavage_reactions,
                                                 parent_obj=self,
                                                 format='list')
            yaml_dict['cleavage-reactions'] = cleavage_reactions

        return yaml_dict
Exemplo n.º 20
0
def read_frequencies(filename, units='1/cm'):
    """Reads the frequencies from the Gaussian log file.

    Parameters
    ----------
        filename : str
            Log file
        units : str, optional
            Units to return frequencies. Default is '1/cm'
    Returns
    -------
        frequencies : list of float
            Frequencies in ``units``. Default is '1/cm'
    """
    final = units.split('/')[-1]
    freq_patterns = read_pattern(filename=filename,
                                 pattern='Frequencies -- (.*)',
                                 group=0,
                                 return_immediately=False)
    return [float(freq)/c.convert_unit(initial='cm', final=final) \
            for freq in freq_patterns]
Exemplo n.º 21
0
Arquivo: cov.py Projeto: alongd/pMuTT
    def to_CTI(self, energy_unit='kcal/mol', units=None):
        """Writes the lateral interaction in CTI format

        Parameters
        ----------
            energy_unit : str, optional
                Energy unit for slopes. Default is 'kcal/mol'
            units : :class:`~pmutt.cantera.units.Units` object
                If specified, energy_unit` are overwritten. Default is None.
        Returns
        -------
            lat_inter_str : str
                Lateral interaction in CTI format
        """
        if units is not None:
            energy_unit = units.energy
        lat_inter_str = 'lateral_interaction("{} {}", {}, {}, id="{}")'.format(
            self.name_i, self.name_j,
            c.convert_unit(num=np.array(self.slopes),
                           initial='kcal/mol',
                           final=energy_unit), self.intervals, self.name)
        return lat_inter_str
Exemplo n.º 22
0
def read_electronic_and_zpe(filename, units='eV/molecule'):
    """Reads the electronic energy and zero-point energy from the
    Gaussian log file.

    Parameters
    ----------
        filename : str
            Log file
        units : str, optional
            Units to return energy. Default is 'eV/molecule'
    Returns
    -------
        electronic_and_zero_point_energy : float
            Electronic and zero point energy in ``units``. Default is
            'eV/molecule'
    """
    return float(read_pattern(filename=filename,
                              pattern='Sum of electronic and zero-point '
                              'Energies=(.*)',
                              group=0,
                              return_immediately=True)) \
           *c.convert_unit(initial='Ha/molecule', final=units)
Exemplo n.º 23
0
    def get_q(self, T, P=c.P0('bar')):
        """Calculates the partition function

        :math:`q_{trans} = \\bigg(\\frac{2\\pi \\sum_{i}^{atoms}m_ikT}{h^2}
        \\bigg)^\\frac {n_{degrees}} {2}V`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float, optional
                Pressure (bar) or pressure-like quantity.
                Default is atmospheric pressure
        Returns
        -------
            q_trans : float
                Translational partition function
        """
        V = self.get_V(T=T, P=P)
        unit_mass = self.molecular_weight *\
            c.convert_unit(initial='g', final='kg')/c.Na
        return V*(2*np.pi*c.kb('J/K')*T*unit_mass/c.h('J s')**2) \
            ** (float(self.n_degrees)/2.)
Exemplo n.º 24
0
def _get_R_adj(units, elements=None):
    """Get adjustment to mass when converting from mol to g
    
    Parameters
    ----------
        units : str
            Units as string. Units are delimited by '/'
        elements : dict, optional
            Composition of the species. Default is None.
            Keys of dictionary are elements, values are stoichiometric values
            in a formula unit.
            e.g. CH3OH can be represented as:
            {'C': 1, 'H': 4, 'O': 1,}.
    Returns
    -------
        R_adj : float
            Adjustment to the mass. If no mass units are found, returns R in
            appropriate units.
    """
    mass_unit = _get_mass_unit(units)

    # If no mass unit is found, return R in appropriate units
    if mass_unit is None:
        return c.R(units)
    # If elements were not provided, throw error
    if elements is None:
        err_msg = ('To calculate thermodynamic quantities on per mass basis, '
                   'the species object must have a dictionary assigned to '
                   'elements.')
        raise AttributeError(err_msg)

    mol_weight = get_molecular_weight(elements)  # g/mol
    mol_units = units.replace('/{}'.format(mass_unit), '/mol')
    R_adj = c.R(mol_units) / c.convert_unit(
        num=mol_weight, initial='g', final=mass_unit)
    return R_adj
Exemplo n.º 25
0
    def get_E_act(self, units, reaction, rev=False, **kwargs):
        """Calculate Arrhenius activation energy using BEP relationship

        Parameters
        ----------
            units : str
                Units as string. See :func:`~pmutt.constants.R` for accepted
                units but omit the '/K' (e.g. J/mol).
            reaction : :class:`~pmutt.reaction.Reaction` object
                Reaction related to BEP.
            rev : bool, optional
                Reverse direction. If True, uses products as initial state
                instead of reactants. Default is False
            kwargs : keyword arguments
                Parameters required to calculate the descriptor
        Returns
        -------
            E_act : float
                Dimensionless activation energy
        """
        adj_slope = self._get_adjusted_slope(rev=rev)
        descriptor_val = self._get_descriptor_val(reaction=reaction, **kwargs)
        E_act = adj_slope * descriptor_val + self.intercept
        return E_act * c.convert_unit(initial='kcal/mol', final=units)
Exemplo n.º 26
0
 def test_energy_to_wavenumber(self):
     E_J = c.convert_unit(0.1, initial='eV', final='J')
     self.assertAlmostEqual(c.energy_to_wavenumber(E_J),
                            self.ans.at['test_energy_to_wavenumber', 0])
Exemplo n.º 27
0
    def test_convert_unit(self):
        # Test all combinations for temperature conversion
        self.assertAlmostEqual(
            c.convert_unit(c.T0('K'), initial='K', final='C'),
            self.ans.at['test_convert_unit', 1])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('K'), initial='K', final='F'),
            self.ans.at['test_convert_unit', 2])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('K'), initial='K', final='R'),
            self.ans.at['test_convert_unit', 3])

        self.assertAlmostEqual(
            c.convert_unit(c.T0('C'), initial='C', final='K'),
            self.ans.at['test_convert_unit', 0])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('C'), initial='C', final='F'),
            self.ans.at['test_convert_unit', 2])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('C'), initial='C', final='R'),
            self.ans.at['test_convert_unit', 3])

        self.assertAlmostEqual(
            c.convert_unit(c.T0('F'), initial='F', final='K'),
            self.ans.at['test_convert_unit', 0])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('F'), initial='F', final='C'),
            self.ans.at['test_convert_unit', 1])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('F'), initial='F', final='R'),
            self.ans.at['test_convert_unit', 3])

        self.assertAlmostEqual(
            c.convert_unit(c.T0('R'), initial='R', final='K'),
            self.ans.at['test_convert_unit', 0])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('R'), initial='R', final='C'),
            self.ans.at['test_convert_unit', 1])
        self.assertAlmostEqual(
            c.convert_unit(c.T0('R'), initial='R', final='F'),
            self.ans.at['test_convert_unit', 2])

        # Test a unit conversion with multiple-based units
        self.assertAlmostEqual(c.convert_unit(initial='m', final='cm'),
                               self.ans.at['test_convert_unit', 4])
        # Test if error raised when units in different set
        with self.assertRaises(ValueError):
            c.convert_unit(initial='cm', final='J')
        # Test if error raised when unaccepted unit inputted
        with self.assertRaises(ValueError):
            c.convert_unit(initial='arbitrary unit', final='J')
        with self.assertRaises(ValueError):
            c.convert_unit(initial='cm', final='arbitrary unit')
Exemplo n.º 28
0
# ## Constants
# pmutt has a wide variety of constants to increase readability of the code. See [Constants page][0] in the documentation for supported units.
# 
# [0]: https://vlachosgroup.github.io/pmutt/constants.html#constants

# In[1]:


from pmutt import constants as c

print('Some constants')
print('R (J/mol/K) = {}'.format(c.R('J/mol/K')))
print("Avogadro's number = {}\n".format(c.Na))

print('Unit conversions')
print('5 kJ/mol --> {} eV/molecule'.format(c.convert_unit(num=5., initial='kJ/mol', final='eV/molecule')))
print('Frequency of 1000 Hz --> Wavenumber of {} 1/cm\n'.format(c.freq_to_wavenumber(1000.)))

print('See expected inputs, supported units of different constants')
help(c.R)
help(c.convert_unit)


# ## StatMech Objects
# Molecules show translational, vibrational, rotational, electronic, and nuclear modes.
# 
# <img src="images/statmech_modes.jpg" width=800>
# 
# The [``StatMech``][0] object allows us to specify translational, vibrational, rotational, electronic and nuclear modes independently, which gives flexibility in what behavior you would like.
# 
# [0]: https://vlachosgroup.github.io/pmutt/statmech.html#pmutt.statmech.StatMech
Exemplo n.º 29
0
from pmutt import constants as c

h1 = c.h('eV s', bar=True)
print('h = {} eV s'.format(h1))

# <a id='section_3_2'></a>

# ## 3.2. Convert between units
# Below, we convert 12 atm of pressure to psi.

# In[2]:

from pmutt import constants as c

P_atm = 12.  # atm
P_psi = c.convert_unit(num=P_atm, initial='atm', final='psi')

print('{} atm = {} psi'.format(P_atm, P_psi))

# <a id='section_3_3'></a>

# ## 3.3. Convert between equivalent quantities
# Below, we convert 1000 wavenumbers (cm-1) to frequency.

# In[3]:

from pmutt import constants as c

wave_num = 1000.  # cm-1
freq = c.wavenumber_to_freq(wave_num)  # Hz
Exemplo n.º 30
0
    def to_CTI(self,
               max_line_len=80,
               mass_unit='g',
               length_unit='cm',
               units=None):
        """Writes the object in Cantera's CTI format.

        Parameters
        ----------
            max_line_len : int, optional
                Maximum number of characters in the line. Default is 80.
            mass_unit : str, optional
                Mass unit for `density`. Default is 'g'
            length_unit : str, optional
                Length unit for `density`. Default is 'cm'
            units : :class:`~pmutt.cantera.units.Units` object, optional
                If specified, `mass_unit` and `length_unit` are overwritten.
                Default is None.
        Returns
        -------
            CTI_str : str
                Object represented as a CTI string.
        """
        if units is not None:
            length_unit = units.length
            mass_unit = units.mass

        species_names = [species.name for species in self.species]
        volume_unit = '{}3'.format(length_unit)
        density = self.density*c.convert_unit(initial='g', final=mass_unit)\
                  /c.convert_unit(initial='cm3', final=volume_unit)
        # Add required fields
        cti_str = ('stoichiometric_solid(name={},\n'
                   '                     elements={},\n'
                   '                     species={},\n'
                   '                     density={},\n'.format(
                       obj_to_CTI(self.name,
                                  line_len=max_line_len - 26,
                                  max_line_len=max_line_len - 27),
                       obj_to_CTI(self.elements,
                                  line_len=max_line_len - 30,
                                  max_line_len=max_line_len),
                       obj_to_CTI(species_names,
                                  line_len=max_line_len - 29,
                                  max_line_len=max_line_len), density))
        # Add optional fields
        optional_fields = ('transport', 'options', 'note', 'initial_state')
        for field in optional_fields:
            val = getattr(self, field)
            # Skip empty fields
            if val is None:
                continue

            cti_str += '                     {}={},\n'.format(
                field,
                obj_to_CTI(val,
                           line_len=max_line_len - len(field) - 22,
                           max_line_len=max_line_len))

        # Terminate the string
        cti_str = '{})\n'.format(cti_str[:-2])
        return cti_str