486 lines
19 KiB
ReStructuredText
486 lines
19 KiB
ReStructuredText
.. py:currentmodule:: ctml_writer
|
|
|
|
.. _sec-phases:
|
|
|
|
***************************
|
|
Phases and their Interfaces
|
|
***************************
|
|
|
|
Now that we have covered how to write syntactically-correct input files, we can
|
|
turn our attention to the content of the file. We'll start by describing the
|
|
entries for phases of various types, and the look at how to define interfaces
|
|
between phases.
|
|
|
|
Phases
|
|
======
|
|
|
|
For each phase that appears in a problem, a corresponding entry should be
|
|
present in the input file(s). For example, suppose we want to conduct a
|
|
simulation with detailed chemistry of an idealized solid-oxide fuel cell shown
|
|
below. The problem involves three solid phases (A nickel anode, a
|
|
platinum cathode, and an oxygen-conducting yttrium-stabilized zirconia
|
|
electrolyte), and two different gas phases (a fuel mixture on the anode side,
|
|
and air on the cathode side). The problem also involves a number of interfaces
|
|
at which heterogeneous chemistry may occur---two gas-metal interfaces, two
|
|
gas-electrolyte interfaces, and two metal-electrolyte interfaces.
|
|
|
|
.. figure:: /_static/images/sofc-phases.png
|
|
:align: center
|
|
|
|
**Phases entering into a hypothetical microkinetic simulation of an
|
|
idealized solid-oxide fuel cell.**
|
|
|
|
How to carry out this fuel cell simulation is beyond the scope of this document;
|
|
we introduce it here only to give an example of the types of phases and
|
|
interfaces that might need to be defined in order to carry out a simulation. (Of
|
|
course, many simulations with Cantera only require defining a single phase.)
|
|
|
|
There are several different types of entries, corresponding to different types
|
|
of phases. Phases are created using one of the directives corresponding to an
|
|
implemented phase type:
|
|
|
|
* :class:`ideal_gas`
|
|
* :class:`stoichiometric_solid`
|
|
* :class:`stoichiometric_liquid`
|
|
* :class:`metal`
|
|
* :class:`semiconductor`
|
|
* :class:`incompressible_solid`
|
|
* :class:`lattice`
|
|
* :class:`lattice_solid`
|
|
* :class:`liquid_vapor`
|
|
* :class:`redlich_kwong`
|
|
* :class:`ideal_interface`
|
|
* :class:`edge`
|
|
|
|
These phase typese share many common features, however, and so we will begin by
|
|
discussing those aspects common to all entries for phases. The :class:`phase`
|
|
class contains the features common to all phase types.
|
|
|
|
Phase Attributes
|
|
----------------
|
|
|
|
Phase Name
|
|
^^^^^^^^^^
|
|
|
|
The ``name`` field is a string that identifies the phase. It must not contain
|
|
any whitespace characters or reserved XML characters, and must be unique within
|
|
the file among all phase definitions of any type.
|
|
|
|
Phases are referenced by name when importing them into an application program,
|
|
or when defining an interface between phases.
|
|
|
|
Declaring the Elements
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The elements that may be present in the phase are declared in the elements
|
|
field. This must be a string of element symbols separated by spaces and/or
|
|
commas. Each symbol must either match one listed in the database file
|
|
``elements.xml``, or else match the symbol of an element entry defined elsewhere
|
|
in the input file (See :ref:`sec-elements`).
|
|
|
|
The ``elements.xml`` database contains most elements of the periodic table, with
|
|
their natural-abundance atomic masses. It also contains a few isotopes (D, Tr),
|
|
and an "element" for an electron (E). This pseudo-element can be used to specify
|
|
the composition of charged species. Note that two-character symbols should have
|
|
an uppercase first letter, and a lowercase second letter (e.g. ``Cu``, not ``CU``).
|
|
|
|
It should be noted that the order of the element symbols in the string
|
|
determines the order in which they are stored internally by Cantera. For
|
|
example, if a phase definition specifies the elements as::
|
|
|
|
ideal_gas(name = "gasmix",
|
|
elements = "H C O N Ar",
|
|
...)
|
|
|
|
then when this definition is imported by an application, element-specific
|
|
properties will be ordered in the same way::
|
|
|
|
>>> gas = importPhase('example.cti', 'gasmix')
|
|
>>> for n in range(gas.nElements()):
|
|
... print n, gas.elementSymbol(n)
|
|
0 H
|
|
1 C
|
|
2 O
|
|
3 N
|
|
4 Ar
|
|
|
|
For some calculations, such as multi-phase chemical equilibrium, it is important
|
|
to synchronize the elements among multiple phases, so that each phase contains
|
|
the same elements with the same ordering. In such cases, simply use the same
|
|
string in the elements field for all phases.
|
|
|
|
.. _sec-defining-species:
|
|
|
|
Defining the Species
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The species in the phase are declared in the species field. They are not defined
|
|
there, only declared. Species definitions may be imported from other files, or
|
|
species may be defined locally using species entries elsewhere in the file.
|
|
|
|
If a single string of species symbols is given, then it is assumed that these
|
|
are locally defined. For each one, a corresponding species entry must be present
|
|
somewhere in the file, either preceding or following the phase entry. Note that
|
|
the string may extend over multiple lines by delimiting it with triple quotes::
|
|
|
|
# commas are optional
|
|
species = 'AR SI Si2 SiH SiH2 SiH3 SiH4'
|
|
species = 'H, O, OH, H2O, HO2, H2O2, H2, O2'
|
|
|
|
# include all species defined in this file
|
|
species = 'all'
|
|
|
|
# a multi-line species declaration
|
|
species = """ H2 H O O2 OH H2O HO2 H2O2 C CH
|
|
CH2 CH2(S) CH3 CH4 CO CO2 HCO CH2O CH2OH CH3O
|
|
CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO CH2CO HCCOH
|
|
N NH NH2 NH3 NNH NO NO2 N2O HNO CN
|
|
HCN H2CN HCNN HCNO HOCN HNCO NCO N2 AR C3H7
|
|
C3H8 CH2CHO CH3CHO """
|
|
|
|
If the species are imported from another file, instead of being defined locally,
|
|
then the string should begin with the file name (without extension), followed by
|
|
a colon::
|
|
|
|
# import selected species from silicon.xml
|
|
species = "silicon: SI SI2 SIH SIH2 SIH3 SIH4 SI2H6"
|
|
|
|
# import all species from silicon.xml
|
|
species = "silicon: all"
|
|
|
|
In this case, the species definitions will be taken from file ``silicon.xml``,
|
|
which must exist either in the local directory or somewhere on the Cantera
|
|
search path.
|
|
|
|
It is also possible to import species from several sources, or mix local
|
|
definitions with imported ones, by specifying a sequence of strings::
|
|
|
|
species = ["CL2 CL F F2 HF HCL", # defined in this file
|
|
"air: O2 N2 NO", # imported from 'air.xml'
|
|
"ions: CL- F-"] # imported from 'ions.xml'
|
|
|
|
Note that the strings must be separated by commas, and enclosed in square
|
|
brackets or parentheses.
|
|
|
|
.. _sec-declaring-reactions:
|
|
|
|
Declaring the Reactions
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The reactions among the species are declared in the ``reactions`` field. Just as
|
|
with species, reactions may be defined locally in the file, or may be imported
|
|
from one or more other files. All reactions must only involve species that have
|
|
been declared for the phase.
|
|
|
|
Unlike species, reactions do not have a name, but do have an optional ``ID``
|
|
field. If the ``ID`` field is not assigned a value, then when the reaction entry
|
|
is read it will be assigned a four-digit string encoding the reaction number,
|
|
beginning with ``'0001'`` for the first reaction in the file, and incrementing
|
|
by one for each new reaction.
|
|
|
|
If all reactions defined locally in the input file are to be included in the
|
|
phase definition, then assign the ``reactions`` field the string ``'all'``::
|
|
|
|
reactions = 'all'
|
|
|
|
If, on the other hand, only some of the reactions defined in the file are to be
|
|
included, then a range can be specified using the reaction ``ID`` fields::
|
|
|
|
reactions = 'nox-12 to nox-24'
|
|
|
|
In determining which reactions to include, a lexical comparison of id strings is
|
|
performed. This means, for example, that ``'nox-8'`` is greater than
|
|
``'nox-24'``. (If it is rewritten ``'nox-08'``, however, then it would be lexically
|
|
less than ``'nox-24'``.)
|
|
|
|
Just as described above for species, reactions can be imported from another
|
|
file, and reactions may be imported from several sources. Examples::
|
|
|
|
# import all reactions defined in this file
|
|
reactions = "all"
|
|
|
|
# import all reactions defined in rxns.xml
|
|
reactions = "rxns: all"
|
|
|
|
# import reactions 1-14 in rxns.xml
|
|
reactions = "rxns: 0001 to 0014"
|
|
|
|
# import reactions from several sources
|
|
reactions = ["all", # all local reactions
|
|
"gas: all", # all reactions in gas.xml
|
|
"nox: n005 to n008"] # reactions 5 to 8 in nox.xml
|
|
|
|
The Kinetics Model
|
|
^^^^^^^^^^^^^^^^^^
|
|
|
|
A *kinetics model* is a set of equations to use to compute reaction rates. In
|
|
most cases, each type of phase has an associated kinetics model that is used by
|
|
default, and so the ``kinetics`` field does not need to be assigned a value. For
|
|
example, the :class:`ideal_gas` entry has an associated kinetics model called
|
|
``GasKinetics`` that implements mass-action kinetics, computes reverse rates
|
|
from thermochemistry for reversible reactions, and provides various
|
|
pressure-independent and pressure-dependent reaction types. Other models could
|
|
be implemented, and this field would then be used to select the desired
|
|
model. For now, the ``kinetics`` field can be safely ignored.
|
|
|
|
The Transport Model
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
A *transport model* is a set of equations used to compute transport
|
|
properties. For :class:`ideal_gas` phases, multiple transport models are
|
|
available; the one desired can be selected by assiging a string to this
|
|
field. See :ref:`sec-gas-transport-models` for more details.
|
|
|
|
The Initial State
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
The phase may be assigned an initial state to which it will be set when the
|
|
definition is imported into an application and an object created. This is done
|
|
by assigning field ``initial_state`` an embedded entry of type :class:`state`,
|
|
described in :ref:`sec-state-entry`.
|
|
|
|
Most of the attributes defined here are "immutable," meaning that once the
|
|
definition has been imported into an application, they cannot be changed by the
|
|
application. For example, it is not possible to change the elements or the
|
|
species. The temperature, pressure, and composition, however, are "mutable"---
|
|
they can be changed. This is why the field defining the state is called the
|
|
``initial_state``; the object in the application will be initially set to this
|
|
state, but it may be changed at any time.
|
|
|
|
.. _sec-phase-options:
|
|
|
|
Special Processing Options
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The options field is used to indicate how certain conditions should be handled
|
|
when importing the phase definition. The options field may be assigned a string
|
|
or a sequence of strings from the table below.
|
|
|
|
================================== ================
|
|
Option String Meaning
|
|
================================== ================
|
|
``'no_validation'`` Turn off all validation. Use when the definition
|
|
has been previously validated to speed up importing
|
|
the definition into an application. Use with caution!
|
|
``'skip_undeclared_elements'`` When importing species, skip any containing undeclared
|
|
elements, rather than flagging them as an error.
|
|
``'skip_undeclared_species'`` When importing reactions, skip any containing undeclared
|
|
species, rather than flagging them as an error.
|
|
``'skip_undeclared_third_bodies'`` When importing reactions with third body efficiencies,
|
|
ignore any efficiencies for undeclared species, rather
|
|
than flagging them as an error.
|
|
================================== ================
|
|
|
|
Using the ``options`` field, it is possible to extract a sub-mechanism from a large
|
|
reaction mechanism, as follows::
|
|
|
|
ideal_gas(name = 'hydrogen_mech',
|
|
species = 'gri30: all',
|
|
reactions = 'gri30:all',
|
|
options = ('skip_undeclared_elements',
|
|
'skip_undeclared_species'))
|
|
|
|
If we import this into Matlab, for example, we get a gas mixture containing the
|
|
8 species (out of 53 total) that contain only H and O:
|
|
|
|
.. code-block:: matlab
|
|
|
|
>> gas = importPhase('gas.cti', 'hydrogen_mech')
|
|
|
|
temperature 300 K
|
|
pressure 1237.28 Pa
|
|
density 0.001 kg/m^3
|
|
mean mol. weight 2.01588 amu
|
|
|
|
X Y
|
|
------------ ------------
|
|
H2 1.000000e+00 1.000000e+00
|
|
H 0.000000e+00 0.000000e+00
|
|
O 0.000000e+00 0.000000e+00
|
|
O2 0.000000e+00 0.000000e+00
|
|
OH 0.000000e+00 0.000000e+00
|
|
H2O 0.000000e+00 0.000000e+00
|
|
HO2 0.000000e+00 0.000000e+00
|
|
H2O2 0.000000e+00 0.000000e+00
|
|
|
|
>> eqs = reactionEqn(gas)
|
|
|
|
eqs =
|
|
|
|
'2 O + M <=> O2 + M'
|
|
'O + H + M <=> OH + M'
|
|
'O + H2 <=> H + OH'
|
|
'O + HO2 <=> OH + O2'
|
|
'O + H2O2 <=> OH + HO2'
|
|
'H + O2 + M <=> HO2 + M'
|
|
'H + 2 O2 <=> HO2 + O2'
|
|
'H + O2 + H2O <=> HO2 + H2O'
|
|
'H + O2 <=> O + OH'
|
|
'2 H + M <=> H2 + M'
|
|
'2 H + H2 <=> 2 H2'
|
|
'2 H + H2O <=> H2 + H2O'
|
|
'H + OH + M <=> H2O + M'
|
|
'H + HO2 <=> O + H2O'
|
|
'H + HO2 <=> O2 + H2'
|
|
'H + HO2 <=> 2 OH'
|
|
'H + H2O2 <=> HO2 + H2'
|
|
'H + H2O2 <=> OH + H2O'
|
|
'OH + H2 <=> H + H2O'
|
|
'2 OH (+ M) <=> H2O2 (+ M)'
|
|
'2 OH <=> O + H2O'
|
|
'OH + HO2 <=> O2 + H2O'
|
|
'OH + H2O2 <=> HO2 + H2O'
|
|
'OH + H2O2 <=> HO2 + H2O'
|
|
'2 HO2 <=> O2 + H2O2'
|
|
'2 HO2 <=> O2 + H2O2'
|
|
'OH + HO2 <=> O2 + H2O'
|
|
|
|
Ideal Gas Mixtures
|
|
------------------
|
|
|
|
Now we turn to the specific entry types for phases, beginning with
|
|
:class:`ideal_gas`.
|
|
|
|
Many combustion and CVD simulations make use of reacting ideal gas
|
|
mixtures. These can be defined using the :class:`ideal_gas` entry. The Cantera
|
|
ideal gas model allows any number of species, and any number of reactions among
|
|
them. It supports all of the options in the widely-used model described by Kee
|
|
et al. [#Kee1989]_, plus some additional options for species thermodynamic
|
|
properties and reaction rate expressions.
|
|
|
|
An example of an ideal_gas entry is shown below::
|
|
|
|
ideal_gas(name='air8',
|
|
elements='N O Ar',
|
|
species='gri30: N2 O2 N O NO NO2 N2O AR',
|
|
reactions='all',
|
|
transport='mix',
|
|
initial_state=state(temperature=500.0,
|
|
pressure=(1.0, 'atm'),
|
|
mole_fractions='N2:0.78, O2:0.21, AR:0.01'))
|
|
|
|
This entry defines an ideal gas mixture that contains 8 species, the definitions
|
|
of which are imported from dataset gri30 (file ``gri30.xml``). All reactions
|
|
defined in the file are to be included, transport properties are to be computed
|
|
using mixture rules, and the state of the gas is to be set initially to 500 K, 1
|
|
atm, and a composition that corresponds to air.
|
|
|
|
.. _sec-gas-transport-models:
|
|
|
|
Transport Models
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
Two transport models are available for use with ideal gas mixtures. The first is
|
|
a multicomponent transport model that is based on the model described by
|
|
Dixon-Lewis [#dl68]_ (see also Kee et al. [#Kee2003]_). The second is a model that uses
|
|
mixture rules. To select the multicomponent model, set the transport field to
|
|
the string ``'multi'``, and to select the mixture-averaged model, set it to the
|
|
string ``'mix'``::
|
|
|
|
ideal_gas(name="gas1",
|
|
...,
|
|
transport="multi", # use multicomponent formulation
|
|
...)
|
|
|
|
ideal_gas(name="gas2",
|
|
...,
|
|
transport="mix", # use mixture-averaged formulation
|
|
...)
|
|
|
|
Stoichiometric Solid
|
|
--------------------
|
|
|
|
A :class:`stoichiometric_solid` is one that is modeled as having a precise,
|
|
fixed composition, given by the composition of the one species present. A
|
|
stoichiometric solid can be used to define a condensed phase that can
|
|
participate in heterogeneous reactions. (Of course, there cannot be homogeneous
|
|
reactions, since the composition is fixed.) ::
|
|
|
|
stoichiometric_solid(name='graphite',
|
|
elements='C',
|
|
species='C(gr)',
|
|
density=(2.2, 'g/cm3'),
|
|
initial_state=state(temperature=300.0,
|
|
pressure=(1.0, 'atm'))
|
|
|
|
Stoichiometric Liquid
|
|
---------------------
|
|
|
|
A stoichiometric liquid differs from a stoichiometric solid in only one respect:
|
|
the transport manager computes the viscosity as well as the thermal
|
|
conductivity.
|
|
|
|
Interfaces
|
|
==========
|
|
|
|
Now that we have seen how to define bulk, three-dimensional phases, we can
|
|
describe the procedure to define an interface between phases.
|
|
|
|
Cantera presently implements a simple model for an interface that treats is as a
|
|
two-dimensional ideal solution of interfacial species. There is a fixed site
|
|
density :math:`n^0`, and each site may be occupied by one of several adsorbates,
|
|
or may be empty. The chemical potential of each species is computed using the
|
|
expression for an ideal solution:
|
|
|
|
.. math::
|
|
|
|
\mu_k = \mu^0_k + \hat{R}T \log \theta_k,
|
|
|
|
where :math:`\theta_k` is the coverage of species :math:`k` on the surface. The
|
|
coverage is related to the surface concentration :math:`C_k` by
|
|
|
|
.. math::
|
|
|
|
\theta_k = \frac{C_k n_k}{n^0} ,
|
|
|
|
where :math:`n_k` is the number of sites covered or blocked by species
|
|
:math:`k`.
|
|
|
|
The entry type for this interface model is
|
|
:class:`ideal_interface`. (Additional interface models may be added to allow
|
|
non-ideal, coverage-dependent properties.)
|
|
|
|
Defining an interface is much like defining a phase. There are two new fields:
|
|
``phases`` and ``site_density``. The phases field specifies the bulk phases that
|
|
participate in the heterogeneous reactions. Although in most cases this string
|
|
will list one or two phases, no limit is placed on the number. This is
|
|
particularly useful in some electrochemical problems, where reactions take place
|
|
near the triple-phase bounday where a gas, an electrolyte, and a metal all meet.
|
|
|
|
The ``site_density`` field is the number of adsorption sites per unit area.
|
|
|
|
Another new aspect is in the embedded :class:`state` entry in the
|
|
``initial_state`` field. When specifying the initial state of an interface, the
|
|
:class:`state` entry has a field *coverages*, which can be assigned a string
|
|
specifying the initial surface species coverages::
|
|
|
|
ideal_interface(name='silicon_surface',
|
|
elements='Si H',
|
|
species='s* s-SiH3 s-H',
|
|
reactions='all',
|
|
phases='gas bulk-Si',
|
|
site_density=(1.0e15, 'molec/cm2'),
|
|
initial_state=state(temperature=1200.0,
|
|
coverages='s-H:1'))
|
|
|
|
.. _sec-state-entry:
|
|
|
|
The :class:`state` entry
|
|
========================
|
|
|
|
The initial state of either a phase or an interface may be set using an embedded
|
|
:class:`state` entry. Note that only one of (``pressure``, ``density``) may be
|
|
specified, and only one (``mole_fractions``, ``mass_fractions``, ``coverages``).
|
|
|
|
.. rubric:: References
|
|
|
|
.. [#Kee1989] R. J. Kee, F. M. Rupley, and J. A. Miller. Chemkin-II: A Fortran
|
|
chemical kinetics package for the analysis of gasphase chemical
|
|
kinetics. Technical Report SAND89-8009, Sandia National Laboratories, 1989.
|
|
|
|
.. [#dl68] G. Dixon-Lewis. Flame structure and flame reaction kinetics,
|
|
II: Transport phenomena in multicomponent systems. *Proc. Roy. Soc. A*,
|
|
307:111--135, 1968.
|
|
|
|
.. [#Kee2003] R. J. Kee, M. E. Coltrin, and P. Glarborg. *Chemically Reacting
|
|
Flow: Theory and Practice*. John Wiley and Sons, 2003.
|