Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and improve to_cantera methods for conversion to in-memory Cantera objects #2700

Merged
merged 14 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions rmgpy/chemkin.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1209,18 +1209,16 @@ def read_species_block(f, species_dict, species_aliases, species_list):
if token_upper == 'END':
break

site_token = token.split('/')[0]
if site_token.upper() == 'SDEN':
species_name = token.split('/')[0] # CHO*/2/ indicates an adsorbate CHO* taking 2 surface sites
if species_name.upper() == 'SDEN': # SDEN/4.1e-9/ indicates surface site density
continue # TODO actually read in the site density

processed_tokens.append(token)
if token in species_dict:
species = species_dict[token]
elif site_token in species_dict:
species = species_dict[site_token]
if species_name in species_dict:
species = species_dict[species_name]
else:
species = Species(label=token)
species_dict[token] = species
species = Species(label=species_name)
species_dict[species_name] = species
species_list.append(species)


Expand Down
43 changes: 40 additions & 3 deletions rmgpy/kinetics/arrhenius.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -722,12 +722,49 @@ cdef class ArrheniusBM(KineticsModel):
"""
self._A.value_si *= factor

def to_cantera_kinetics(self):
"""
Converts the RMG ArrheniusBM object to a cantera BlowersMaselRate.

BlowersMaselRate(A, b, Ea, W) where A is in units of m^3/kmol/s,
b is dimensionless, and Ea and W are in J/kmol
"""
import cantera as ct

rate_units_conversion = {'1/s': 1,
's^-1': 1,
'm^3/(mol*s)': 1000,
'm^6/(mol^2*s)': 1000000,
'cm^3/(mol*s)': 1000,
'cm^6/(mol^2*s)': 1000000,
'm^3/(molecule*s)': 1000,
'm^6/(molecule^2*s)': 1000000,
'cm^3/(molecule*s)': 1000,
'cm^6/(molecule^2*s)': 1000000,
}

A = self._A.value_si

try:
A *= rate_units_conversion[self._A.units] # convert from /mol to /kmol
except KeyError:
raise ValueError(f'ArrheniusBM A-factor units {self._A.units} not found among accepted '
'units for converting to Cantera BlowersMaselRate object.')

b = self._n.value_si
Ea = self._E0.value_si * 1000 # convert from J/mol to J/kmol
w = self._w0.value_si * 1000 # convert from J/mol to J/kmol

return ct.BlowersMaselRate(A, b, Ea, w)

def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Sets a cantera Reaction() object with the modified Arrhenius object
converted to an Arrhenius form.
Accepts a cantera Reaction object and sets its rate to a Cantera BlowersMaselRate object.
"""
raise NotImplementedError('set_cantera_kinetics() is not implemented for ArrheniusBM class kinetics.')
import cantera as ct
if not isinstance(ct_reaction.rate, ct.BlowersMaselRate):
raise TypeError("ct_reaction must have a cantera BlowersMaselRate as the rate attribute")
ct_reaction.rate = self.to_cantera_kinetics()

################################################################################

Expand Down
10 changes: 0 additions & 10 deletions rmgpy/kinetics/falloff.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,12 @@ cdef class Lindemann(PDepKineticsModel):
self.arrheniusLow.change_rate(factor)
self.arrheniusHigh.change_rate(factor)



def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Sets the efficiencies and kinetics for a cantera reaction.
"""
import cantera as ct
assert isinstance(ct_reaction.rate, ct.LindemannRate), "Must have a Cantera LindemannRate attribute"

ct_reaction.efficiencies = PDepKineticsModel.get_cantera_efficiencies(self, species_list)
ct_reaction.rate = self.to_cantera_kinetics()

Expand Down Expand Up @@ -400,11 +397,8 @@ cdef class Troe(PDepKineticsModel):
for a cantera FalloffReaction.
"""
import cantera as ct

assert isinstance(ct_reaction.rate, ct.TroeRate), "Must have a Cantera TroeRate attribute"

ct_reaction.efficiencies = PDepKineticsModel.get_cantera_efficiencies(self, species_list)

ct_reaction.rate = self.to_cantera_kinetics()

def to_cantera_kinetics(self):
Expand All @@ -424,7 +418,3 @@ cdef class Troe(PDepKineticsModel):
high = self.arrheniusHigh.to_cantera_kinetics(arrhenius_class=True)
low = self.arrheniusLow.to_cantera_kinetics(arrhenius_class=True)
return ct.TroeRate(high=high, low=low, falloff_coeffs=falloff)




87 changes: 83 additions & 4 deletions rmgpy/kinetics/surface.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ cdef class StickingCoefficient(KineticsModel):
======================= =============================================================
Attribute Description
======================= =============================================================
`A` The preexponential factor
`A` The preexponential factor. Unitless (sticking probability)
`T0` The reference temperature
`n` The temperature exponent
`Ea` The activation energy
Expand Down Expand Up @@ -285,6 +285,34 @@ cdef class StickingCoefficient(KineticsModel):

return string

def to_cantera_kinetics(self):
"""
Converts the RMG StickingCoefficient object to a cantera StickingArrheniusRate

StickingArrheniusRate(A,b,E) where A is dimensionless, b is dimensionless, and E is in J/kmol
"""
import cantera as ct
import rmgpy.quantity
if type(self._A) != rmgpy.quantity.ScalarQuantity:
raise TypeError("A factor must be a dimensionless ScalarQuantity")
A = self._A.value_si
b = self._n.value_si
E = self._Ea.value_si * 1000 # convert from J/mol to J/kmol

return ct.StickingArrheniusRate(A, b, E)


def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Passes in a cantera Reaction() object and sets its
rate to a Cantera ArrheniusRate object.
"""
import cantera as ct
assert isinstance(ct_reaction.rate, ct.StickingArrheniusRate), "Must have a Cantera StickingArrheniusRate attribute"

# Set the rate parameter to a cantera Arrhenius object
ct_reaction.rate = self.to_cantera_kinetics()

################################################################################
cdef class StickingCoefficientBEP(KineticsModel):
"""
Expand Down Expand Up @@ -352,7 +380,7 @@ cdef class StickingCoefficientBEP(KineticsModel):
self.Pmin, self.Pmax, self.coverage_dependence, self.comment))

property A:
"""The preexponential factor."""
"""The preexponential factor. Dimensionless (sticking probability)"""
def __get__(self):
return self._A
def __set__(self, value):
Expand Down Expand Up @@ -395,7 +423,8 @@ cdef class StickingCoefficientBEP(KineticsModel):
cpdef double get_sticking_coefficient(self, double T, double dHrxn=0.0) except -1:
"""
Return the sticking coefficient (dimensionless) at
temperature `T` in K and enthalpy of reaction `dHrxn` in J/mol.
temperature `T` in K and enthalpy of reaction `dHrxn` in J/mol.
Never exceeds 1.0.
"""
cdef double A, n, Ea, stickingCoefficient
Ea = self.get_activation_energy(dHrxn)
Expand Down Expand Up @@ -524,7 +553,7 @@ cdef class SurfaceArrhenius(Arrhenius):
property A:
"""The preexponential factor.

This is the only thing different from a normal Arrhenius class."""
This (and the coverage dependence) is the only thing different from a normal Arrhenius class."""
def __get__(self):
return self._A
def __set__(self, value):
Expand Down Expand Up @@ -589,6 +618,56 @@ cdef class SurfaceArrhenius(Arrhenius):
)


def to_cantera_kinetics(self):
"""
Converts the RMG SurfaceArrhenius object to a cantera InterfaceArrheniusRate

InterfaceArrheniusRate(A,b,E) where A is in units like m^2/kmol/s (depending on dimensionality)
b is dimensionless, and E is in J/kmol
"""
import cantera as ct

rate_units_conversion = {'1/s': 1,
's^-1': 1,
'm^2/(mol*s)': 1000,
'm^4/(mol^2*s)': 1000000,
'cm^2/(mol*s)': 1000,
'cm^4/(mol^2*s)': 1000000,
'm^2/(molecule*s)': 1000,
'm^4/(molecule^2*s)': 1000000,
'cm^2/(molecule*s)': 1000,
'cm^4/(molecule^2*s)': 1000000,
'cm^5/(mol^2*s)': 1000000,
'm^5/(mol^2*s)': 1000000,
}

if self._T0.value_si != 1:
A = self._A.value_si / (self._T0.value_si) ** self._n.value_si
else:
A = self._A.value_si

try:
A *= rate_units_conversion[self._A.units] # convert from /mol to /kmol
except KeyError:
raise ValueError('Arrhenius A-factor units {0} not found among accepted units for converting to '
'Cantera Arrhenius object.'.format(self._A.units))

b = self._n.value_si
E = self._Ea.value_si * 1000 # convert from J/mol to J/kmol
return ct.InterfaceArrheniusRate(A, b, E)

def set_cantera_kinetics(self, ct_reaction, species_list):
"""
Takes in a cantera Reaction object and sets its
rate to a cantera InterfaceArrheniusRate object.
"""
import cantera as ct
if not isinstance(ct_reaction.rate, ct.InterfaceArrheniusRate):
raise TypeError("ct_reaction.rate must be an InterfaceArrheniusRate")

# Set the rate parameter to a cantera Arrhenius object
ct_reaction.rate = self.to_cantera_kinetics()

################################################################################

cdef class SurfaceArrheniusBEP(ArrheniusEP):
Expand Down
Loading
Loading