cantera/samples/python/fuel_cells/sofc.cti
Ray Speth 2528df0f75 Reorganized source tree structure
These changes make it unnecessary to copy header files around during
the build process, which tends to confuse IDEs and debuggers. The
headers which comprise Cantera's external C++ interface are now in
the 'include' directory.

All of the samples and demos are now in the 'samples' subdirectory.
2012-02-12 02:27:14 +00:00

357 lines
13 KiB
Text

#########################################################################
#
# This is a an example input file that defines models for phases and
# interfaces that could be used, for example, to simulate a solid
# oxide fuel cell. Note, however, that reaction rate coefficients and
# species thermochemistry ARE NOT REAL VALUES - they are chosen only
# for the purposes of this example.
#
#########################################################################
# since Cantera input files are actually executable Python scripts,
# we can put any valid Python statements in the input file. Here we
# import the value of R from Cantera.
from Cantera import GasConstant
# These units will be used by default for any quantities entered
# without units. Quantities with compound units (e.g. concentration)
# will be constructed from these - the units of concentration will be
# mol/cm^3, etc.
units(length = "cm", time = "s", quantity = "mol", act_energy = "kJ/mol")
# Turn on mechanism validation to detect unbalanced reactions, if any
validate()
#------------------------------------------------------------------
#
# parameters
#
#------------------------------------------------------------------
# a few numeric parameters are collected here to allow easy modification.
# this temperature is used to initialize objects. But since
# scripts/programs usually set the temperature, it is not really
# necessary.
tc = 800.0 # temperature in C
tt = tc + 273.15 # temperature in K
# these values are defined here only so they may be easily changed to
# assess the effects of the oxide thermochemistry. For work at a
# single temperature, all that we really need is g = h -
# Ts. Therefore, it is somewhat arbitrary to assign separately
# enthalpies and entropies (but this is what the input format
# requires).
hox = (-170.0, 'kJ/mol') # enthalpy of an oxygen ion
sox = (50.0, 'J/K/mol') # entropy of an oxygen ion
hhydrox = (-220.0, 'kJ/mol') # enthalpy of a surface hydroxyl group
shydrox = (87.0, 'J/mol/K') # entropy of a surface hydroxyl group
####################### BULK PHASES ####################################
# First we'll define the bulk (i.e. 3D) phases - a gas, a metal, and
# an oxide.
#------------------------------------------------------------------
#
# Gas phase.
#
#------------------------------------------------------------------
# The gas contains only the minimum number of species needed to model
# operation on hydrogen. The species definitions are imported from
# gri30.cti. The initial composition is set to hydrogen + 5% water, but
# usually this is reset in the program importing this definition.
#
ideal_gas(name = "gas",
elements = " H O N",
species = "gri30: H2 H2O N2 O2",
transport = "Mix",
initial_state = state( temperature = tt,
pressure = OneAtm,
mole_fractions = 'H2:0.95, H2O:0.05'))
#------------------------------------------------------------------
#
# Bulk solid metal phase.
#
#------------------------------------------------------------------
#
# This phase will be used for the electrodes. All we need is
# a source/sink for electrons, so we define this phase as only
# containing electrons. Note that the 'metal' entry type requires
# specifying a density, but it is not used in this simulation and
# therefore is arbitrary.
#
metal(name = "metal",
elements = "E",
species = "electron",
density = (9.0, 'kg/m3'),
initial_state = state( temperature =tt,
mole_fractions = 'electron:1.0'))
# The electron is set to have zero enthalpy and entropy. Therefore,
# the chemical potential of the electron is zero, and the
# electrochemical potential is simply -F * phi, where phi is the
# electric potential of the metal. Note that this simple model is
# adequate only because all we require is a reservior for electrons;
# if we wanted to do anything more complex, like carry out energy or
# charge balances on the metal, then we would require a more complex
# model. Note that there is no work function for this metal.
species( name = "electron", atoms = "E:1",
thermo = const_cp(h0 = (0.0, 'kcal/mol')))
# Note: the "const_cp" species thermo model is used throughout this
# file (with the exception of the gaseous species, which use NASA
# polynomials imported from gri30.cti). The const_cp model assumes a
# constant specific heat, which by default is zero. Parameters that
# can be specified are cp0, t0, h0, and s0. If omitted, t0 = 300 K, h0
# = 0, and s0 = 0. The thermo properties are computed as follows: h =
# h0 + cp0*(t - t0), s = s0 + cp0*ln(t/t0). For work at a single
# temperature, it is sufficient to specify only h0.
#-------------------------------------------------------------------
#
# Bulk solid oxide electrolyte
#
#--------------------------------------------------------------------
# Here too, we create a very simple model for the bulk phase. We only
# consider the oxygen sublattice. The only species we define are a
# lattice oxygen, and an oxygen vacancy. Again, the density is a
# required input, but is not used here, so may be set arbitrarily.
incompressible_solid(name = "oxide_bulk",
elements = "O E",
species = "Ox VO**",
density = (0.7, 'g/cm3'),
initial_state = state( temperature = tt,
pressure = OneAtm,
mole_fractions = "Ox:0.95 VO**:0.05")
)
# The vacancy will be modeled as truly vacant - it contains no atoms,
# has no charge, and has zero enthalpy and entropy. This is different
# from the usual convention in which the vacancy properties are are
# expressed relative to the perfect crystal lattice. For example, in
# the usual convention, an oxygen vacancy has charge +2. But the
# convention we will use is that an oxygen ion has charge -2, and a
# vacancy has charge 0. It all works out the same, as long as we are
# consistent.
# A bulk lattice vacancy
species( name = "VO**", atoms = "",
thermo = const_cp(h0 = (0.0, 'kJ/mol')))
# A bulk lattice oxygen
species( name = "Ox", atoms = "O:1 E:2",
thermo = const_cp(h0 = hox, s0 = sox))
####################### SURFACE PHASES ####################################
#--------------------------------------------------
#
# Metal surface
#
#--------------------------------------------------
# The surface of a bulk phase must be treated like a separate phase, with its
# own set of species. Here we define the model for the metal surface.
# We allow the following species:
# (m) - an empty metal site
# H(m) - a chemisorbed H atom
# O(m) - a chemisorbed O atom
# OH(m) - a chemisorbed hydroxl
# H2O(m) - a physisorbed water molecule
# Notes:
# 1. The site density is in mol/cm2, since no units are specified and
# 'mol' and 'cm' were specified in the units directive above as the
# units for quantity and length, respectively.
# 2. The 'reactions' field specifies that all reaction entries in this file
# that have ID strings beginning with "metal-" are reactions belonging
# to this surface mechanism.
ideal_interface(name = "metal_surface",
elements = "H O",
species = " (m) H(m) O(m) OH(m) H2O(m) ",
site_density = 2.60e-9,
phases = 'gas',
reactions = ["metal-*"],
initial_state = state( temperature = 973.0,
coverages = '(m):0.5 H(m):0.5') )
species( name = "(m)", atoms = "",
thermo = const_cp(h0 = (0.0, 'kJ/mol'),
s0 = (0.0, 'J/mol/K')))
species( name = "H(m)", atoms = "H:1",
thermo = const_cp(h0 = (-35.0, 'kJ/mol'),
s0 = (37.0, 'J/mol/K')))
species( name = "O(m)", atoms = "O:1",
thermo = const_cp(h0 = (-220.0, 'kJ/mol'),
s0 = (37.0, 'J/mol/K')))
species( name = "OH(m)", atoms = "O:1, H:1",
thermo = const_cp(h0 = (-198.0, 'kJ/mol'),
s0 = (102.0, 'J/mol/K')))
species( name = "H2O(m)", atoms = "H:2, O:1",
thermo = const_cp(h0 = (-281.0, 'kJ/mol'),
s0 = (123.0, 'J/mol/K')))
# Surface reactions on the metal. We assume three dissociave
# adsorption reactions, and three reactions on the surface
# among adsorbates. All reactions are treated as reversible.
surface_reaction( "H2 + (m) + (m) <=> H(m) + H(m)",
stick(0.1, 0, 0), id = 'metal-rxn1')
surface_reaction( "O2 + (m) + (m) <=> O(m) + O(m)",
stick(0.1, 0, 0), id = 'metal-rxn2')
surface_reaction( "H2O + (m) <=> H2O(m)",
stick(1.0, 0, 0), id = 'metal-rxn3')
surface_reaction( "H(m) + O(m) <=> OH(m) + (m)",
[5.00000E+22, 0, 100.0], id = 'metal-rxn4')
surface_reaction( "H(m) + OH(m) <=> H2O(m) + (m)",
[5.00000E+20, 0, 40.0], id = 'metal-rxn5')
surface_reaction( "OH(m) + OH(m) <=> H2O(m) + O(m)",
[5.00000E+21, 0, 100.0], id = 'metal-rxn6')
#--------------------------------------------------------
#
# Oxide surface.
#
#--------------------------------------------------------
#H
# On the oxide surface, we consider four species:
# 1. (ox) - a surface vacancy
# 2. O''(ox) - a surface oxygen with charge -2
# 3. OH'(ox) - a surface hydroxyl with charge -1
# 4. H2O(ox) - physisorbed neutral water
ideal_interface(name = "oxide_surface",
elements = "O H E",
species = "(ox) O''(ox) OH'(ox) H2O(ox)",
site_density = 2.0e-9,
phases = 'gas oxide_bulk',
reactions = 'oxide-*',
initial_state = state( temperature = tt,
coverages = "O''(ox):2.0, (ox):0.0") )
# Note: hox, sox, hhydrox, andd shydrox are defined near the top of
# this file.
# An oxygen ion at the surface, with charge = -2
species( name = "O''(ox)", atoms = "O:1 E:2",
thermo = const_cp(h0 = hox,
s0 = sox))
# An OH at the surface, with charge = -1
species( name = "OH'(ox)", atoms = "O:1 H:1 E:1",
thermo = const_cp(h0 = hhydrox,
s0 = shydrox))
# A surface vacancy in the oxygen sublattice
species( name = "(ox)", atoms = "",
thermo = const_cp(h0 = (0.0, 'kJ/mol'),
s0 = (0.0,'J/mol/K')))
species( name = "H2O(ox)", atoms = "H:2, O:1",
thermo = const_cp(h0 = (-265.0, 'kJ/mol'),
s0 = (98.0,'J/mol/K')))
# This reaction represents the exhange of a surface oxygen vacancy and
# a subsurface vacancy. The concentration of subsurface vacancies is
# fixed by the doping level. If this reaction is given a large rate,
# then the surface vacancies will stay in equilibrium with the bulk
# vacancies.
surface_reaction("(ox) + Ox <=> VO** + O''(ox)",
[5.0e8, 0.0, 0.0], id = "oxide-vac")
# Desorption of physisorbed water. This is made fast.
surface_reaction("H2O(ox) <=> H2O + (ox)",
[1.0e14, 0.0, (0.0, 'kJ/mol')], id = "oxide-water")
# chemisorption of water as surface hydroxyls. In reality, this
# reaction would surely be activated and have a lower pre-exponential
surface_reaction("H2O(ox) + O''(ox) <=> OH'(ox) + OH'(ox)",
[1.0e14, 0.0, (0.0, 'kJ/mol')], id = "oxide-oh")
####################### TRIPLE PHASE BOUNDARY #########################
# The triple phase boundary between the metal, oxide, and gas. A
# single species is specified, but it is not used, since all reactions
# only involve species on either side of the tpb. Note that the site
# density is in mol/cm. But since no reactions involve TPB species,
# this parameter is unused.
edge(name = "tpb",
elements = "H O",
species = "(tpb)",
site_density = 5.0e-17,
reactions = "edge-*",
phases = 'metal metal_surface oxide_surface',
initial_state = state( temperature = tt,
coverages = '(tpb):1.0 ') )
# dummy species
species( name = "(tpb)", atoms = "")
# Here we define two charge transfer reactions. Both reactions are
# reversible, and can be used to model either anodes or cathodes
# (although real anodes and cathodes would usually have different
# reaction mechanisms, except in a symmetric cell).
# in this reaction, a proton from the metal crosses the TPB to the
# oxide surface to make a hydroxyl and deliver an electron to the
# metal.
edge_reaction("H(m) + O''(ox) <=> (m) + electron + OH'(ox)",
[5.0e13, 0.0, 120.0], beta = 0.5, id="edge-f2")
# in this reaction, an oxygen on the metal surface plus 2 electrons
# from the metal bulk fill a surface vacancy in the oxide lattice.
edge_reaction("O(m) + (ox) + 2 electron <=> (m) + O''(ox)",
[5.0e13, 0.0, 120.0], beta = 0.5, id="edge-f3")
# this reaction is commented out, but you can explore its effects by
# uncommenting it. Be careful, if you are not solving for the OH'
# concentration that the system does not become overdetermined
# (i.e. impossible for all reactions to be simultaneously in
# equilibrium). If this happens, the wrong OCVs will result.
#edge_reaction("H(m) + OH'(ox) <=> H2O(ox) + (m) + electron",
# [5.0e13, 0.0, 120.0], beta = 0.5, id="edge-f")