483 lines
20 KiB
ReStructuredText
483 lines
20 KiB
ReStructuredText
.. py:currentmodule:: ctml_writer
|
|
|
|
.. _sec-input-files:
|
|
|
|
************************
|
|
Working with Input Files
|
|
************************
|
|
|
|
Before we can describe how to define phases, interfaces, and their components
|
|
(elements, species, and reactions), we need to go over a few points about the
|
|
mechanics of writing and processing input files.
|
|
|
|
Input File Syntax
|
|
=================
|
|
|
|
An input file consists of *entries* and *directives*, both of which have a
|
|
syntax much like functions. An entry defines an object---for example, a
|
|
reaction, or a species, or a phase. A directive sets options that affect how the
|
|
entry parameters are interpreted, such as the default unit system, or how
|
|
certain errors should be handled.
|
|
|
|
Cantera's input files follow the syntax rules for Python, so if you're familiar
|
|
with Python syntax you already understand many of the details and can probably
|
|
skip ahead to :ref:`sec-dimensions`.
|
|
|
|
Entries have fields that can be assigned values. A species entry is shown below
|
|
that has fields name and atoms (plus several others)::
|
|
|
|
species(name='C60', atoms='C:60')
|
|
|
|
Most entries have some fields that are required; these must be assigned values,
|
|
or else processing of the file will abort and an error message will be
|
|
printed. Other fields may be optional, and take default values if not assigned.
|
|
|
|
An entry may be either a *top-level entry* or an *embedded entry*. Top-level
|
|
entries specify a phase, an interface, an element, a species, or a reaction, and
|
|
begin in the first (leftmost) column. Embedded entries specify a model, or a
|
|
group of parameters for a top-level entry, and are usually embedded in a field
|
|
of another entry.
|
|
|
|
The fields of an entry are specified in the form ``<field_name> = <value>``, and may
|
|
be listed on one line, or extend across several. For example, two entries for
|
|
graphite are shown below. The first is compact::
|
|
|
|
stoichiometric_solid(name='graphite', species='C(gr)', elements='C', density=(2.2, 'g/cm3')))
|
|
|
|
and the second is formatted to be easier to read::
|
|
|
|
stoichiometric_solid(
|
|
name = 'graphite',
|
|
elements = 'C',
|
|
species = 'C(gr)',
|
|
density = (2.2, 'g/cm3')
|
|
)
|
|
|
|
Both are completely equivalent.
|
|
|
|
The species ``C(gr)`` that appears in the definition of the graphite phase is
|
|
also defined by a top-level entry. If the heat capacity of graphite is
|
|
approximated as constant, then the following definition could be used::
|
|
|
|
species(name='C(gr)',
|
|
atoms='C:1',
|
|
thermo=const_cp(t0=298.15,
|
|
h0=0.0,
|
|
s0=(5.6, 'J/mol/K'), # NIST
|
|
cp0=(8.43, 'J/mol/K'))) # Taylor and Groot (1980)
|
|
|
|
Note that the thermo field is assigned an embedded entry of type
|
|
:class:`const_cp`. Entries are stored as they are encountered when the file is
|
|
read, and only processed once the end of the file has been reached. Therefore,
|
|
the order in which they appear is unimportant.
|
|
|
|
Comments
|
|
--------
|
|
|
|
The character ``#`` is the comment character. Everything to the right of this
|
|
character on a line is ignored::
|
|
|
|
# set the default units
|
|
units(length = 'cm', # use centimeters for length
|
|
quantity = 'mol') # use moles for quantity
|
|
|
|
Strings
|
|
-------
|
|
|
|
Strings may be enclosed in single quotes or double quotes, but they must
|
|
match. To create a string containing single quotes, enclose it in double quotes,
|
|
and vice versa. If you want to create a string to extend over multiple lines,
|
|
enclose it in triple double quotes.
|
|
|
|
Strings may be enclosed in single quotes or double quotes, but they must
|
|
match. To create a string containing single quotes, enclose it in double quotes,
|
|
and vice versa. If you want to create a string to extend over multiple lines,
|
|
enclose it in triple quotes::
|
|
|
|
string1 = 'A string.'
|
|
string2 = "Also a 'string'"
|
|
string3 = """This is
|
|
a
|
|
string too."""
|
|
|
|
The multi-line form is useful when specifying a phase containing a large number
|
|
of species::
|
|
|
|
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 """
|
|
|
|
Sequences
|
|
---------
|
|
|
|
A sequence of multiple items is specified by separating the items by commas and
|
|
enclosing them in square brackets or parentheses. The individual items can have
|
|
any type---strings, integers, floating-point numbers (or even entries or other
|
|
lists). Square brackets are often preferred, since parentheses are also used for
|
|
other purposes in the input file, but either can be used::
|
|
|
|
s0 = (3.5, 'J/mol/K') # these are
|
|
s0 = [3.5, 'J/mol/K'] # equivalent
|
|
|
|
Variables
|
|
---------
|
|
|
|
Another way to specify the species C(gr) is shown here::
|
|
|
|
graphite_thermo = const_cp(t0=298.15,
|
|
h0=0.0,
|
|
s0=(5.6, 'J/mol/K'), # NIST
|
|
cp0=(8.43, 'J/mol/K')) # Taylor and Groot (1980)
|
|
|
|
species(name='C(gr)', atoms='C:1', thermo=graphite_thermo)
|
|
|
|
In this form, the ``const_cp`` entry is stored in a variable, instead of being
|
|
directly embedded within the species entry. The *thermo* field is assigned this
|
|
variable.
|
|
|
|
Variables can also be used for any other parameter type. For example, if you are
|
|
defining several phases in the file, and you want to set them all to the same
|
|
initial pressure, you could define a pressure variable::
|
|
|
|
P_initial = (2.0, 'atm')
|
|
|
|
and then set the pressure field in each embedded state entry to this variable.
|
|
|
|
Omitting Field Names
|
|
--------------------
|
|
|
|
Field names may be omitted if the values are entered in the order specified in
|
|
the entry declaration. (Entry declarations are the text printed on a colored
|
|
background in the following chapters.) It is also possible to omit only some of
|
|
the field names, as long as these fields are listed first, in order, before any
|
|
named fields.
|
|
|
|
For example, The first four entries below are equivalent, while the last two are
|
|
incorrect and would generate an error when processed::
|
|
|
|
element(symbol="Ar", atomic_mass=39.948) # OK
|
|
element(atomic_mass=39.948, symbol='Ar') # OK
|
|
element('Ar', atomic_mass=39.948) # OK
|
|
element("Ar", 39.948) # OK
|
|
|
|
element(39.948, "Ar") # error
|
|
element(symbol="Ar", 39.948) # error
|
|
|
|
.. _sec-dimensions:
|
|
|
|
Dimensional Values
|
|
==================
|
|
|
|
Many fields have numerical values that represent dimensional quantities---a
|
|
pressure, or a density, for example. If these are entered without specifying the
|
|
units, the default units (set by the :class:`units` directive described in
|
|
:ref:`sec-default-units`) will be used. However, it is also possible to specify
|
|
the units for each individual dimensional quantity (unless stated
|
|
otherwise). All that is required is to group the value in parentheses or square
|
|
brackets with a string specifying the units::
|
|
|
|
pressure = 1.0e5 # default is Pascals
|
|
pressure = (1.0, 'bar') # this is equivalent
|
|
density = (4.0, 'g/cm3')
|
|
density = 4000.0 # kg/m3
|
|
|
|
Compound unit strings may be used, as long as a few rules are followed:
|
|
|
|
1. Units in the denominator follow ``/``.
|
|
2. Units in the numerator follow ``-``, except for the first one.
|
|
3. Numerical exponents follow the unit string without a ``^`` character, and must
|
|
be in the range 2--6. Negative values are not allowed.
|
|
|
|
Examples of compound units::
|
|
|
|
A = (1.0e20, 'cm6/mol2/s') # OK
|
|
h = (6.626e-34, 'J-s') # OK
|
|
density = (3.0, 'g/cm3') # OK
|
|
A = (1.0e20, 'cm^6/mol/s') # error (^)
|
|
A = (1.0e20, 'cm6/mol2-s') # error ('s' should be in denominator)
|
|
density = (3.0, 'g-cm-3') # error (negative exponent)
|
|
|
|
.. _sec-default-units:
|
|
|
|
Setting the Default Units
|
|
-------------------------
|
|
|
|
The default unit system may be set with the :func:`units` directive. Note
|
|
that unit conversions are not done until the entire file has been read. Only one
|
|
units directive should be present in a file, and the defaults it specifies apply
|
|
to the entire file. If the file does not contain a units directive, the default
|
|
units are meters, kilograms, kilomoles, and seconds.
|
|
|
|
Shown below are two equivalent ways of specifying the site density for an
|
|
interface. In the first version, the site density is specified without a units
|
|
string, and so its units are constructed from the default units for quantity and
|
|
length, which are set with a units directive::
|
|
|
|
units(length = 'cm', quantity = 'molec')
|
|
interface(name = 'Si-100',
|
|
site_density = 1.0e15, # molecules/cm2 (default units)
|
|
...)
|
|
|
|
The second version uses a different default unit system, but overrides the
|
|
default units by specifying an explicit units string for the site density::
|
|
|
|
units(length = 'cm', quantity = 'mol')
|
|
interface(name = 'Si-100',
|
|
site_density = (1.0e15, 'molec/cm2') # override default units
|
|
...)
|
|
|
|
The second version is equivalent to the first, but would be very different if
|
|
the units of the site density were not specified!
|
|
|
|
The *length*, *quantity* and *time* units are used to construct the units for
|
|
reaction pre-exponential factors. The *energy* units are used for molar
|
|
thermodynamic properties, in combination with the units for *quantity*.
|
|
|
|
Since activation energies are often specified in units other than those used for
|
|
thermodynamic properties, a separate field is devoted to the default units for
|
|
activation energies::
|
|
|
|
units(length = 'cm', quantity = 'mol', act_energy = 'kcal/mol')
|
|
kf = Arrhenius(A = 1.0e14, b = 0.0, E = 54.0) # E is 54 kcal/mol
|
|
|
|
See :func:`units` for the declaration of the units directive.
|
|
|
|
Recognized Units
|
|
----------------
|
|
|
|
Cantera recognizes the following units in various contexts:
|
|
|
|
=========== ==============
|
|
field allowed values
|
|
=========== ==============
|
|
length ``'cm', 'm', 'mm'``
|
|
quantity ``'mol', 'kmol', 'molec'``
|
|
time ``'s', 'min', 'hr', 'ms'``
|
|
energy ``'J', 'kJ', 'cal', 'kcal'``
|
|
act_energy ``'kJ/mol', 'J/mol', 'J/kmol', 'kcal/mol', 'cal/mol', 'eV', 'K'``
|
|
pressure ``'Pa', 'atm', 'bar'``
|
|
=========== ==============
|
|
|
|
Processing Input Files
|
|
======================
|
|
|
|
A Two-step Process
|
|
------------------
|
|
|
|
From the point of view of the user, it appears that a Cantera application that
|
|
imports a phase definition reads the input file, and uses the information there
|
|
to construct the object representing the phase or interface in the
|
|
application. While this is the net effect, it is actually a two-step
|
|
process. When a function like importPhase is called to import a phase definition
|
|
from a file, a preprocessor runs automatically to read the input file and create
|
|
a data file that contains the same information but in an XML-based format called
|
|
CTML. After the preprocessor finishes, Cantera imports the phase definition from
|
|
the CTML data file.
|
|
|
|
The CTML file is saved in the same directory as the input file, and has the same
|
|
name but with the extension changed to ``.xml``. If the input file has the name
|
|
``propane.cti``, for example, then the CTML file will be placed in the same
|
|
directory with name ``propane.xml``. If you like, once the CTML file has been
|
|
created, you can specify it rather than the ``.cti`` input file in calls to
|
|
importPhase (or similar functions). This is slightly faster, since the
|
|
preprocessing step can be skipped. It also allows Cantera simulations to be run
|
|
on systems that do not have Python, which Cantera uses in the preprocessing step
|
|
but does not require to read CTML files.
|
|
|
|
Two File Formats
|
|
----------------
|
|
|
|
Why two file formats? There are several reasons. XML is a widely-used standard
|
|
for data files, and it is designed to be relatively easy to parse. This makes it
|
|
possible for other applications to use Cantera CTML data files, without
|
|
requiring the substantial chemical knowledge that would be required to use .cti
|
|
files. For example, "web services" (small applications that run remotely over a
|
|
network) are often designed to accept XML input data over the network, perform a
|
|
calculation, and send the output in XML back across the network. Supporting an
|
|
XML-based data file format facilitates using Cantera in web services or other
|
|
network computing applications.
|
|
|
|
The difference between the high-level description in a .cti input file and the
|
|
lower-level description in the CTML file may be illustrated by how reactions are
|
|
handled. In the input file, the reaction stoichiometry and its reversibility or
|
|
irreversibility are determined from the reaction equation. For example::
|
|
|
|
O + HCCO <=> H + 2 CO
|
|
|
|
specifies a reversible reaction between an oxygen atom and the ketenyl radical
|
|
HCCO to produce one hydrogen atom and two carbon monoxide molecules. If ``<=>``
|
|
were replaced with ``=>``, then it would specify that the reaction should be
|
|
treated as irreversible.
|
|
|
|
Of course, this convention is not spelled out in the input file---the parser
|
|
simply has to know it, and has to also know that a "reactant" appears on the
|
|
left side of the equation, a "product" on the right, that the optional number in
|
|
front of a species name is its stoichiometric coefficient (but if missing the
|
|
value is one), etc. The preprocessor does know all this, but we cannot expect
|
|
the same level of knowledge of chemical conventions by a generic XML parser.
|
|
|
|
Therefore, in the CTML file, reactions are explicitly specified to be reversible
|
|
or irreversible, and the reactants and products are explicitly listed with their
|
|
stoichiometric coefficients. The XML file is, in a sense, a "dumbed-down"
|
|
version of the input file, spelling out explicitly things that are only implied
|
|
in the input file syntax, so that "dumb" (i.e., easy to write) parsers can be
|
|
used to read the data with minimal risk of misinterpretation.
|
|
|
|
The reaction definition::
|
|
|
|
reaction( "O + HCCO <=> H + 2 CO", [1.00000E+14, 0, 0])
|
|
|
|
in the input file is translated by the preprocessor to the following CTML text:
|
|
|
|
.. code-block:: xml
|
|
|
|
<reaction id="0028" reversible="yes">
|
|
<equation>O + HCCO [=] H + 2 CO</equation>
|
|
<rateCoeff>
|
|
<Arrhenius>
|
|
<A units="cm3/mol/s"> 1.000000E+14</A>
|
|
<b>0</b>
|
|
<E units="cal/mol">0.000000</E>
|
|
</Arrhenius>
|
|
</rateCoeff>
|
|
<reactants>HCCO:1 O:1</reactants>
|
|
<products>H:1 CO:2</products>
|
|
</reaction>
|
|
|
|
The CTML version is much more verbose, and would be much more tedious to write
|
|
by hand, but is much easier to parse, particularly since it is not necessary to
|
|
write a custom parser---virtually any standard XML parser, of which there are
|
|
many, can be used to read the CTML data.
|
|
|
|
So in general files that are easy for knowledgable users (you) to write are more
|
|
difficult for machines to parse, because they make use of high-level
|
|
application-specific knowledge and conventions to simplify the
|
|
notation. Conversely, files that are designed to be easily parsed are tedious to
|
|
write because so much has to be spelled out explicitly. A natural solution is to
|
|
use two formats, one designed for writing by humans, the other for reading by
|
|
machines, and provide a preprocessor to convert the human-friendly format to the
|
|
machine-friendly one.
|
|
|
|
Preprocessor Intenals: the ``ctml_writer`` Module
|
|
-------------------------------------------------
|
|
|
|
If you are interested in seeing the internals of how the preprocessing works,
|
|
take a look at file ``ctml_writer.py`` in the Cantera Python package. Or simply
|
|
start Python, and type::
|
|
|
|
>>> import ctml_writer
|
|
>>> help(ctml_writer)
|
|
|
|
The ``ctml_writer.py`` module can also be run as a script to convert input .cti
|
|
files to CTML. For example, if you have an input file ``phasedefs.cti``, then
|
|
simply type at the command line::
|
|
|
|
python ctml_writer.py phasedefs.cti
|
|
|
|
to create CTML file ``phasedefs.xml``.
|
|
|
|
Of course, most of the time creation of the CTML file will happen behind the
|
|
scenes, and you will not need to be concerned with CTML files at all.
|
|
|
|
Error Handling
|
|
==============
|
|
|
|
During processing of an input file, errors may be encountered. These could be
|
|
syntax errors, or could be ones that are flagged as errors by Cantera due to
|
|
some apparent inconsistency in the data---an unphysical value, a species that
|
|
contains an undeclared element, a reaction that contains an undeclared species,
|
|
missing species or element definitions, multiple definitions of elements,
|
|
species, or reactions, and so on.
|
|
|
|
Syntax Errors
|
|
-------------
|
|
|
|
Syntax errors are caught by the Python preprocessor, not by Cantera, and must be
|
|
corrected before proceeding further. Python prints a "traceback" that allows
|
|
you to find the line that contains the error. For example, consider the
|
|
following input file, which is intended to create a gas with the species and
|
|
reactions of GRI-Mech 3.0, but has a misspelled the field name ``reactions``::
|
|
|
|
ideal_gas(name = 'gas',
|
|
elements = 'H O',
|
|
species = 'gri30: all',
|
|
reactionss = 'gri30: all')
|
|
|
|
When this definition is imported into an application, an error message like the
|
|
following would be printed to the screen, and execution of the program or script
|
|
would terminate. ::
|
|
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
File "/some/path/Cantera/importFromFile.py", line 18, in importPhase
|
|
return importPhases(file, [name], loglevel, debug)[0]
|
|
File "/some/path/Cantera/importFromFile.py", line 25, in importPhases
|
|
s.append(solution.Solution(src=file,id=nm,loglevel=loglevel,debug=debug))
|
|
File "/some/path/solution.py", line 39, in __init__
|
|
preprocess = 1, debug = debug)
|
|
File "/some/path/Cantera/XML.py", line 35, in __init__
|
|
self._xml_id = _cantera.xml_get_XML_File(src, debug)
|
|
cantera.error:
|
|
|
|
************************************************
|
|
Cantera Error!
|
|
************************************************
|
|
|
|
Procedure: ct2ctml
|
|
Error: Error converting input file "./gas.cti" to CTML.
|
|
Python command was: '/usr/bin/python'
|
|
The exit code was: 4
|
|
-------------- start of converter log --------------
|
|
TypeError on line 4 of './gas.cti':
|
|
__init__() got an unexpected keyword argument 'reactionss'
|
|
|
|
| Line |
|
|
| 1 | ideal_gas(name = 'gas',
|
|
| 2 | elements = 'H O',
|
|
| 3 | species = 'gri30: all',
|
|
> 4 > reactionss = 'gri30: all')
|
|
| 5 |
|
|
--------------- end of converter log ---------------
|
|
|
|
The top part of the error message shows the chain of functions that were called
|
|
before the error was encountered. For the most part, these are internal Cantera
|
|
functions not of direct concern here. The relevant part of this error message is
|
|
the part starting with the "Cantera Error" heading, and specifically the
|
|
contents of the *converter log* section. This message says that that on line 4
|
|
of ``gas.cti``, the the keyword argument ``reactionss`` was not
|
|
recognized. Seeing this message, it is clear that the problem is that
|
|
*reactions* is misspelled.
|
|
|
|
Cantera Errors
|
|
--------------
|
|
|
|
Now let's consider the other class of errors---ones that Cantera, not Python,
|
|
detects. Continuing the example above, suppose that the misspelling is
|
|
corrected, and the input file processed again. Again an error message results,
|
|
but this time it is from Cantera::
|
|
|
|
cantera.error:
|
|
Procedure: installSpecies
|
|
Error: species C contains undeclared element C
|
|
|
|
The problem is that the phase definition specifies that all species are to be
|
|
imported from dataset gri30, but only the elements H and O are declared. The
|
|
gri30 datset contains species composed of the elements H, O, C, N, and Ar. If
|
|
the definition is modified to declare these additional elements::
|
|
|
|
ideal_gas(name = 'gas',
|
|
elements = 'H O C N Ar',
|
|
species = 'gri30: all',
|
|
reactions = 'gri30: all')
|
|
|
|
it may be imported successfully.
|
|
|
|
Errors of this type do not have to be fatal, as long as you tell Cantera how you
|
|
want to handle them. You can, for example, instruct Cantera to quitely skip
|
|
importing any species that contain undeclared elements, instead of flagging them
|
|
as errors. You can also specify that reactions containing undeclared species
|
|
(also usually an error) should be skipped. This allows you to very easily
|
|
extract a portion of a large reaction mechanism, as described in :ref:`sec-phase-options`.
|