Hi Matthis,
That input file doesn’t seem to be complete - it’s just a REACTIONS
section, but for a surface reaction mechanism, you also need something to define the species in a SITE
section, usually in the same input file, and something to define the gas phase species, usually in a separate file. If you have input files that include these sections, then the usual way to convert this with ck2cti
(or better, ck2yaml
) would be
ck2yaml --thermo=thermdata.dat --input=gas-definition.inp --surface=surface-definition.inp
Regards,
Ray
Hi,
The example files we use for testing purposes are surface1.inp (which contains SITE, THERMO ALL, and REACTIONS sections) and surface1-gas.inp (which contains ELEMENTS, SPECIES, THERMO, and REACTIONS sections). This can be converted to the Cantera format by running:
ck2yaml --input=surfac1-gas.inp --surface=surface1.inp --output=surface1.yaml
If you have a separate file containing the thermo data, that can be specified with the --thermo
option.
I’m not familiar with how these inputs are currently handled by Chemkin. Does it allow the inputs to be spread across even more files?
Regards,
Ray
Hi Kurth,
Can you share the YAML file you generated and any of the code you’ve tried writing? I think some of the details there would be helpful in understanding what’s going on.
The function you mentioned, surf.get_net_production_rates, is specifically meant for calculating just the production rates in the specified phase (as written, self.gas
), based on reactions occurring on the surface. So that should only include absorption and desorption reactions. The production rates of gas phase species due to gas phase reactions would be returned by self.gas.net_production_rates
, and the production rates for surface species due to surface reactions would be returned by self.surf.get_net_production_rates(self.surf)
.
Regards,
Ray
Hi Ray,
thanks for your reply and your kind help!
attached you'll find the .yaml file I created. I moified the coverage of the catalyst and the coverage but everything else
When I run ` self.gas.net_productio_rates ` I get the error:
```
***********************************************************************
NotImplementedError thrown by Kinetics::updateROP:
Not implemented.
***********************************************************************
```
The function call is the same as in the example:
```
class ReactorOde(object):
def __init__(self, gas, surf, u_0, dx, d_react):
self.gas = gas
self.surf = surf
self.mem_porosity = 0.38
self.x_out = dict( zip( self.gas.species_names, np.zeros(len(self.gas.species_names)) ) ) # Konzentration der Komponenten ausserhalb der Membran
self.d_0 = 2e-9 # pore size of membrane in m
self.L_mem = 35e-6 # Thickness of membrane in m
self.p_out = 1 # Druck ausserhalb der Membran in bar
self.epsilon_bed = 0.39 # Porosität des Bettes des Reaktors/void fraction
# Parameters of the ODE system and auxiliary data are stored in the
# ReactorOde object.
self.P = gas.P
self.T = gas.T
self.u_0 = u_0/self.epsilon_bed # von leerrohrgeschwindigkeit auf effektive Geschwindigkeit
self.dx = dx
self.d_react = d_react
# Ein dict Objekt erzeugen mit den Namen der Komponenten und dann als zweiten Teil, das Objekt der properties Klasse als reine Komponente. Dies basiert auf dem
# Thermp package von pypi
# self.properties = dict(zip( self.gas.species_names ,[( Chemical(i) ) for i in self.gas.species_names ] ) )
def __call__(self, t, y):
"""the ODE function, y' = f(t,y) """
# Kühlung
T_w = 350 + 273.15 # Wandtemperatur in K
U = 2000 # W/(m² * K)
# State vector is [T, Y_1, Y_2, ... Y_K]
self.gas.set_unnormalized_mole_fractions(y[1:]/self.gas.P)
self.gas.TP = y[0], self.gas.P
rho = self.gas.density_mole # kmol/m³
# wdot = self.kinetik # wdot ist in kmol/(m³ * s) Kinetik ist in mol/(s* kg_cat), deswegen wird der Wirkungsgrad und Dichte des Kats verwendet
Vo_Ar_fact = 4/self.d_react # Faktor, um die Oberfläche auf das Volumen zu beziehen in m²/m³
alpha_mem = 0.2 # Theoretischer Enhancementfaktor
alpha_heat = 1 # Idee einer besseren Wärmeübertragung durch die Feststoffschüttung
wdot = self.gas.net_production_rates
m_mem = 0
# m_mem = self.dgm_cantera * Vo_Ar_fact * alpha_mem # membran permeabilität auch in kmol/(m²*s), Durch Membranfaktor umformen auf kmol/m³-s
## Energiebilanz
dTdx = ( -(np.dot(self.gas.partial_molar_enthalpies, (wdot)) + (U * Vo_Ar_fact * ( gas.T - T_w ) * alpha_heat ) )/ # J/(s*m³)
(rho * gas.cp_mole) * self.u_0) # J/(m³*K) ---> # Energiebilanz in K/m
### Massenbilanz
dpdx = ((wdot-m_mem) * const.R * gas.T * 1000)/ (self.u_0) - \
(y[1:]/ gas.T * dTdx ) # 1/m # Es muss an dieser Stelle in 1/m sein, weil in diesem Fall der Ort diskretisiert wird
return np.hstack((dTdx, dpdx))
```
I can clearly see that something in the .yaml file is not set up correctly, but just following the tutorials I can't get my head around it.
Thanks in advance and have a great day!
Kurth
Hi Kurth,
Your YAML file doesn’t specify any gas phase reactions. Is this correct? In that case, the gas
object won’t have kinetics model attached to it, so all of the kinetics-related properties will throw the NotImplementedError
exception that you see.
The plug flow reactor with surface chemistry is actually a bit of a thorny problem, and so far we haven’t been able to get a reliable solver built into Cantera. One of the complexities is that it’s no longer just an ODE system, but a system of differential-algebraic equations, since the equations for the surface species don’t contain spatial derivatives of the coverages, and these equations seem to be very prone to problems with stiffness.
You might be interested in looking at the 1D PFR with surface chemistry Jupyter Notebook, which implements the system in Python. The one complexity I know of in this case is that the scikits.odes.dae
solver that it uses can be a little difficult to install, depending on your environment. There was some work towards rewriting the existing FlowReactor
model to allow surface chemistry, using the Sundials IDA solver. That can be seen in this pull request, but that work has been stalled.
Regards,
Ray