[Python] Remove the legacy Python module

This commit is contained in:
Ray Speth 2013-12-09 01:35:08 +00:00
parent 07739c4b1f
commit b5e540c903
298 changed files with 162 additions and 44361 deletions

View file

@ -46,20 +46,15 @@ extraEnvArgs = {}
if 'clean' in COMMAND_LINE_TARGETS:
removeDirectory('build')
removeDirectory('stage')
removeDirectory('interfaces/python/build')
removeDirectory('.sconf_temp')
removeFile('.sconsign.dblite')
removeFile('include/cantera/base/config.h')
removeFile('interfaces/python/setup.py')
removeFile('ext/f2c_libs/arith.h')
removeFile('ext/f2c_libs/signal1.h')
removeFile('ext/f2c_libs/sysdep1.h')
for name in os.listdir('.'):
if name.endswith('.msi'):
removeFile(name)
for name in os.listdir('interfaces/python/Cantera'):
if name.startswith('_cantera') or name.startswith('cantera_shared'):
removeFile('interfaces/python/Cantera/' + name)
removeFile('interfaces/matlab/toolbox/cantera_shared.dll')
for name in os.listdir('interfaces/matlab/toolbox'):
if name.startswith('ctmethods.'):
@ -189,8 +184,7 @@ compiler_options = [
'The C++ compiler to use.',
env['CXX']),
('CC',
"""The C compiler to use. This is only used to compile CVODE and
the Python extension module.""",
"""The C compiler to use. This is only used to compile CVODE.""",
env['CC'])]
opts.AddVariables(*compiler_options)
opts.Update(env)
@ -278,15 +272,13 @@ config_options = [
EnumVariable(
'python_package',
"""If you plan to work in Python, or you want to use the graphical
MixMaster application, then you need either the 'new' or 'full'
Cantera Python Package. If, on the other hand, you will only use
Cantera from some other language (e.g. MATLAB or Fortran 90/95) and
only need Python to process .cti files, then you only need a
'minimal' subset of the package (actually, only one file). The
default behavior is to build the Python package if the required
prerequisites (numpy) are installed. NOTE: The legacy 'full' option
is deprecated in favor of the 'new' Python package. The legacy
Python package will be removed in Cantera 2.2 """,
MixMaster application, then you need the 'full' Cantera Python
Package. If, on the other hand, you will only use Cantera from
some other language (e.g. MATLAB or Fortran 90/95) and only need
Python to process .cti files, then you only need a 'minimal'
subset of the package (actually, only two files). The default
behavior is to build the Python package if the required
prerequisites (numpy) are installed.""",
'default', ('new', 'full', 'minimal', 'none', 'default')),
PathVariable(
'python_cmd',
@ -867,7 +859,11 @@ env = conf.Finish()
# Python 2 Package Settings
cython_min_version = LooseVersion('0.17')
env['install_python2_action'] = ''
if env['python_package'] in ('full','default','new'):
if env['python_package'] == 'new':
env['python_package'] = 'full' # Allow 'new' as a synonym for 'full'
warnNoPython = False
if env['python_package'] in ('full','default'):
# Check for Cython:
try:
import Cython
@ -876,20 +872,18 @@ if env['python_package'] in ('full','default','new'):
except ImportError:
cython_version = LooseVersion('0.0.0')
if cython_version >= cython_min_version:
have_cython2 = True
else:
if cython_version < cython_min_version:
message = ("Cython not found or incompatible version: "
"Found {0} but {1} or newer is required".format(cython_version, cython_min_version))
if env['python_package'] == 'new':
if env['python_package'] == 'full':
print("ERROR: " + message)
sys.exit(1)
else:
have_cython2 = False
warnNoPython = True
env['python_package'] = 'minimal'
print ("WARNING: " + message)
# Test to see if we can import the specified array module
warnNoPython = False
if env['python_array_home']:
sys.path.append(env['python_array_home'])
try:
@ -900,15 +894,8 @@ if env['python_package'] in ('full','default','new'):
print """WARNING: Couldn't find include directory for Python array package"""
env['python_array_include'] = ''
if env['python_package'] == 'default':
if have_cython2:
env['python_package'] = 'new'
else:
env['python_package'] = 'full'
package_desc = 'new' if env['python_package'] == 'new' else 'legacy'
print """INFO: Building the %s Python package using %s.""" % (package_desc, env['python_array'])
except ImportError:
if env['python_package'] in ('full', 'new'):
if env['python_package'] == 'full':
print ("""ERROR: Unable to find the array package """
"""'%s' required by the Python package.""" % env['python_array'])
sys.exit(1)
@ -918,15 +905,20 @@ if env['python_package'] in ('full','default','new'):
warnNoPython = True
env['python_package'] = 'minimal'
if warnNoPython:
env['python_package'] = 'minimal'
else:
env['python_package'] = 'full'
print """INFO: Building the Python package using %s.""" % env['python_array']
try:
import site
env['python_usersitepackages'] = site.getusersitepackages()
except AttributeError: # getusersitepackages is only in Python 2.7+
env['python_usersitepackages'] = '<user site-packages directory>'
# Check for 3to2 if we're building the "new" Python module
# See http://pypi.python.org/pypi/3to2
if env['python_package'] == 'new':
# Check for 3to2. See http://pypi.python.org/pypi/3to2
if env['python_package'] == 'full':
try:
ret = getCommandOutput('3to2','-l')
except OSError:
@ -937,13 +929,7 @@ if env['python_package'] in ('full','default','new'):
env['python_convert_examples'] = False
print """WARNING: Couldn't find '3to2'. Python examples will not work correctly."""
if env['python_package'] == 'full':
print ("WARNING: The 'python_package=full' option is deprecated. "
"This legacy Python package will be removed in Cantera 2.2. "
"The new Python package may be build using 'python_package=new'.")
else:
warnNoPython = False
env['python_array_include'] = ''
env['python_module_loc'] = ''
@ -982,7 +968,7 @@ if env['python3_package'] in ('y', 'default'):
elif cython_version < cython_min_version:
message = ("Cython package for Python 3 not found or incompatible version: "
"Found {0} but {1} or newer is required".format(cython_version, cython_min_version))
if env['python3_package'] == 'new':
if env['python3_package'] == 'y':
print("ERROR: " + message)
sys.exit(1)
else:
@ -1247,7 +1233,7 @@ for cti in mglob(env, 'data/inputs', 'cti'):
outName = os.path.splitext(cti.name)[0] + '.xml'
convertedInputFiles.add(outName)
build(env.Command('build/data/%s' % outName, cti.path,
'$python_cmd interfaces/python/ctml_writer.py $SOURCE $TARGET'))
'$python_cmd interfaces/cython/cantera/ctml_writer.py $SOURCE $TARGET'))
# Copy input files which are not present as cti:
@ -1303,10 +1289,10 @@ if addInstallActions:
pyExt = '.py' if env['OS'] == 'Windows' else ''
install(env.InstallAs,
pjoin('$inst_bindir','ck2cti%s' % pyExt),
'interfaces/python/ck2cti.py')
'interfaces/cython/cantera/ck2cti.py')
install(env.InstallAs,
pjoin('$inst_bindir','ctml_writer%s' % pyExt),
'interfaces/python/ctml_writer.py')
'interfaces/cython/cantera/ctml_writer.py')
# Copy external libaries for Windows installations
if env['CC'] == 'cl' and env['use_boost_libs']:
@ -1394,13 +1380,12 @@ if env['f90_interface'] == 'y':
VariantDir('build/src', 'src', duplicate=0)
SConscript('build/src/SConscript')
if env['python_package'] in ('full','minimal'):
VariantDir('build/src/python', 'src/python', duplicate=0)
SConscript('build/src/python/SConscript')
if env['python3_package'] == 'y' or env['python_package'] == 'new':
if env['python3_package'] == 'y' or env['python_package'] == 'full':
SConscript('interfaces/cython/SConscript')
if env['python_package'] == 'minimal':
SConscript('interfaces/python_minimal/SConscript')
SConscript('build/src/apps/SConscript')
if env['OS'] != 'Windows':
@ -1477,19 +1462,15 @@ File locations:
if env['python_package'] == 'full':
print """
Python 2 package (Cantera) %(python_module_loc)s""" % env,
Python 2 package (cantera) %(python_module_loc)s
Python 2 samples %(python_example_loc)s""" % env,
elif warnNoPython:
print """
#################################################################
WARNING: the Cantera Python package was not installed because a
suitable array package (e.g. numpy) could not be found.
WARNING: the Cantera Python package was not installed because
the prerequisites (Cython and NumPy) could not be found.
#################################################################"""
if env['python_package'] == 'new':
print """
Python 2 package (cantera) %(python_module_loc)s
Python 2 samples %(python_example_loc)s""" % env,
if env['python3_package'] == 'y':
print """
Python 3 package (cantera) %(python3_module_loc)s

View file

@ -183,10 +183,6 @@ redesigned API that simplifies many operations and aims to provide a more
Building the new Python module requires the Cython package for Python.
For compatibility, the legacy Python module is still available, though it will not
receive feature updates, and will be removed in a future Cantera release. Users
are encouraged to switch to the new Python module when possible.
The Cython module is compatible with the following Python versions: 2.6, 2.7,
3.1, 3.2, and 3.3. Support for Python 2.6 and Python 3.1 requires the ``scipy``
and ``unittest2`` packages to be installed as well (see :ref:`sec-dependencies`)
@ -196,8 +192,8 @@ library in more recent versions.
Building for Python 2
.....................
By default, SCons will attempt to build the new Python module. To build the
legacy Python module instead, use the SCons option ``python_package=full``.
By default, SCons will attempt to build the Cython-based Python module for
Python 2, if both Numpy and Cython are installed.
Building for Python 3
.....................
@ -424,7 +420,7 @@ Other Required Software
* http://python.org/download/
* Known to work with 2.6 and 2.7; Expected to work with versions >= 2.5
* The Cython module supports Python 2.x and 3.x. However, SCons requires
Python 2.x, so compilation of the Cython module requires two Python
Python 2.x, so compilation of the Python 3 module requires two Python
installations.
* Boost
@ -458,11 +454,11 @@ Optional Programs
* `Scipy <http://scipy.org/install.html>`_
* Required in order to use the new Python module with Python 2.6 or 3.1.
* Required in order to use the Python module with Python 2.6 or 3.1.
* Unittest2
* Required in order to run the test suite for the new Python module with
* Required in order to run the test suite for the Python module with
Python 2.6 or Python 3.1.
* https://pypi.python.org/pypi/unittest2 (Python 2.6)
* https://pypi.python.org/pypi/unittest2py3k (Python 3.1)

View file

@ -20,7 +20,6 @@ if sys.version_info[0] == 3:
sys.path.insert(0, os.path.abspath('../../build/python3'))
else:
sys.path.insert(0, os.path.abspath('../../build/python2'))
sys.path.insert(0, os.path.abspath('../../interfaces/python'))
sys.path.append(os.path.abspath('.'))
sys.path.append(os.path.abspath('./exts'))

View file

@ -3,132 +3,134 @@
CTI Class Reference
*******************
.. py:module:: ctml_writer
.. py:module:: cantera.ctml_writer
.. py:currentmodule:: cantera.ctml_writer
Basic Classes & Functions
=========================
.. autofunction:: ctml_writer.units
.. autofunction:: units
.. autoclass:: ctml_writer.state
.. autoclass:: state
:no-undoc-members:
Phases of Matter
================
.. autoclass:: ctml_writer.phase
.. autoclass:: phase
:no-members:
.. autoclass:: ctml_writer.ideal_gas
.. autoclass:: ideal_gas
:no-undoc-members:
.. autoclass:: ctml_writer.stoichiometric_solid
.. autoclass:: stoichiometric_solid
:no-members:
.. autoclass:: ctml_writer.stoichiometric_liquid
.. autoclass:: stoichiometric_liquid
:no-undoc-members:
.. autoclass:: ctml_writer.metal
.. autoclass:: metal
:no-undoc-members:
.. autoclass:: ctml_writer.semiconductor
.. autoclass:: semiconductor
:no-undoc-members:
.. autoclass:: ctml_writer.incompressible_solid
.. autoclass:: incompressible_solid
:no-undoc-members:
.. autoclass:: ctml_writer.lattice
.. autoclass:: lattice
:no-undoc-members:
.. autoclass:: ctml_writer.lattice_solid
.. autoclass:: lattice_solid
:no-undoc-members:
.. autoclass:: ctml_writer.liquid_vapor
.. autoclass:: liquid_vapor
:no-undoc-members:
.. autoclass:: ctml_writer.redlich_kwong
.. autoclass:: redlich_kwong
:no-undoc-members:
.. autoclass:: ctml_writer.ideal_interface
.. autoclass:: ideal_interface
:no-undoc-members:
.. autoclass:: ctml_writer.edge
.. autoclass:: edge
:no-undoc-members:
Elements and Species
====================
.. autoclass:: ctml_writer.element
.. autoclass:: element
:no-undoc-members:
.. autoclass:: ctml_writer.species
.. autoclass:: species
:no-undoc-members:
Thermodynamic Properties
========================
.. autoclass:: ctml_writer.Mu0_table
.. autoclass:: Mu0_table
:no-undoc-members:
.. autoclass:: ctml_writer.NASA
.. autoclass:: NASA
:no-undoc-members:
.. autoclass:: ctml_writer.NASA9
.. autoclass:: NASA9
:no-undoc-members:
.. autoclass:: ctml_writer.Shomate
.. autoclass:: Shomate
:no-undoc-members:
.. autoclass:: ctml_writer.Adsorbate
.. autoclass:: Adsorbate
:no-undoc-members:
.. autoclass:: ctml_writer.const_cp
.. autoclass:: const_cp
:no-undoc-members:
Transport Properties
====================
.. autoclass:: ctml_writer.gas_transport
.. autoclass:: gas_transport
:no-undoc-members:
Reactions
=========
.. autoclass:: ctml_writer.reaction
.. autoclass:: reaction
:no-undoc-members:
.. autoclass:: ctml_writer.Arrhenius
.. autoclass:: Arrhenius
:no-undoc-members:
.. autoclass:: ctml_writer.three_body_reaction
.. autoclass:: three_body_reaction
:no-undoc-members:
.. autoclass:: ctml_writer.falloff_reaction
.. autoclass:: falloff_reaction
:no-undoc-members:
.. autoclass:: ctml_writer.chemically_activated_reaction
.. autoclass:: chemically_activated_reaction
:no-undoc-members:
.. autoclass:: ctml_writer.pdep_arrhenius
.. autoclass:: pdep_arrhenius
:no-undoc-members:
.. autoclass:: ctml_writer.chebyshev_reaction
.. autoclass:: chebyshev_reaction
:no-undoc-members:
.. autoclass:: ctml_writer.surface_reaction
.. autoclass:: surface_reaction
:no-undoc-members:
.. autoclass:: ctml_writer.edge_reaction
.. autoclass:: edge_reaction
:no-undoc-members:
Falloff Parameterizations
-------------------------
.. autoclass:: ctml_writer.Troe
.. autoclass:: Troe
:no-undoc-members:
.. autoclass:: ctml_writer.SRI
.. autoclass:: SRI
:no-undoc-members:
.. autoclass:: ctml_writer.Lindemann
.. autoclass:: Lindemann
:no-undoc-members:

View file

@ -29,7 +29,6 @@ Documentation
cti/index
reactors
cython/index
python/index
matlab/index
cxx-guide/index

View file

@ -1,10 +0,0 @@
Composite Classes
=================
These classes are composite representations of a substance which has
thermodynamic, chemical kinetic, and transport properties.
.. autoclass:: Cantera.Solution
.. autoclass:: Cantera.Interface.Interface
.. autoclass:: Cantera.Edge.Edge
.. autoclass:: Cantera.Mixture

View file

@ -1,4 +0,0 @@
Physical Constants
==================
.. automodule:: Cantera.constants

View file

@ -1,6 +0,0 @@
Convenience Functions
=====================
.. autofunction:: Cantera.gases.Air
.. autofunction:: Cantera.gases.Argon
.. autofunction:: Cantera.gases.GRI30

View file

@ -1,7 +0,0 @@
Error Handling
==============
.. autofunction:: Cantera.getCanteraError
.. autoexception:: Cantera.exceptions.CanteraError
.. autoexception:: Cantera.exceptions.OptionError

View file

@ -1,14 +0,0 @@
Func Module
===========
.. py:currentmodule:: Func
Quick links:
* :class:`Polynomial`
* :class:`Gaussian`
* :class:`Fourier`
* :class:`Arrhenius`
.. automodule:: Cantera.Func
:member-order: bysource
:no-show-inheritance:

View file

@ -1,8 +0,0 @@
Importing Phase Objects
=======================
.. autofunction:: Cantera.importPhase
.. autofunction:: Cantera.importPhases
.. autofunction:: Cantera.importEdge
.. autofunction:: Cantera.importInterface
.. autofunction:: Cantera.IdealGasMix

View file

@ -1,32 +0,0 @@
.. Cantera documentation master file, created by
sphinx-quickstart on Mon Mar 12 11:43:09 2012.
Python Module Documentation (Legacy)
====================================
.. warning::
This version of the Cantera Python module is deprecated. The last version
of Cantera that this module will be included with is Cantera 2.1. Starting
with Cantera 2.1, a new Python module (based on the Cython package) is
available. When compiling Cantera, the new module can be build by using the
SCons option ``python_package=new``. Changes to the user interface are documented in :ref:`sec-cython-documentation`.
Contents:
.. toctree::
:maxdepth: 2
importing
thermo
kinetics
transport
composite
zerodim
onedim
func
error-handling
constants
utilities
convenience

View file

@ -1,4 +0,0 @@
Chemical Kinetics
=================
.. autoclass:: Cantera.Kinetics.Kinetics

View file

@ -1,31 +0,0 @@
One-Dimensional Reacting Flows
==============================
.. automodule:: Cantera.OneD
.. autoclass:: Cantera.OneD.onedim.Domain1D
.. autofunction:: Cantera.OneD.onedim.clearDomains
.. autofunction:: Cantera.OneD.onedim.clearSim1D
============
Flow Domains
============
.. autoclass:: Cantera.OneD.onedim.AxisymmetricFlow
.. autoclass:: Cantera.OneD.StagnationFlow.StagnationFlow
==========
Boundaries
==========
.. autoclass:: Cantera.OneD.onedim.Bdry1D
.. autoclass:: Cantera.OneD.onedim.Inlet
.. autoclass:: Cantera.OneD.onedim.Outlet
.. autoclass:: Cantera.OneD.onedim.OutletRes
.. autoclass:: Cantera.OneD.onedim.SymmPlane
=================
Composite Domains
=================
.. autoclass:: Cantera.OneD.onedim.Stack
.. autoclass:: Cantera.OneD.BurnerDiffFlame.BurnerDiffFlame
.. autoclass:: Cantera.OneD.BurnerFlame.BurnerFlame
.. autoclass:: Cantera.OneD.CounterFlame.CounterFlame

View file

@ -1,9 +0,0 @@
Thermodyamic Properties
=======================
These classes are used to describe the thermodynamic state of a system.
.. autoclass:: Cantera.Phase.Phase
.. autoclass:: Cantera.ThermoPhase.ThermoPhase
.. autoclass:: Cantera.SurfacePhase.EdgePhase
.. autoclass:: Cantera.SurfacePhase.SurfacePhase

View file

@ -1,4 +0,0 @@
Transport Properties
====================
.. automodule:: Cantera.Transport

View file

@ -1,7 +0,0 @@
Miscellaneous Utilities
=======================
.. autofunction:: Cantera.addDirectory
.. autofunction:: Cantera.reset
.. autofunction:: Cantera.writeCSV
.. autofunction:: Cantera.writeLogFile

View file

@ -1,32 +0,0 @@
Zero-Dimensional Reactors
=========================
.. automodule:: Cantera.Reactor
:no-members:
============
Base Classes
============
.. autoclass:: Cantera.Reactor.ReactorBase
.. autoclass:: Cantera.Reactor.Reactor
.. autoclass:: Cantera.Reactor.FlowDevice
================
Reactor Networks
================
.. autoclass:: Cantera.Reactor.ReactorNet
=============
Flow Reactors
=============
.. autoclass:: Cantera.Reactor.FlowReactor
.. autoclass:: Cantera.Reactor.ConstPressureReactor
.. autoclass:: Cantera.Reactor.Reservoir
================
Flow Controllers
================
.. autoclass:: Cantera.Reactor.MassFlowController
.. autoclass:: Cantera.Reactor.Valve
.. autoclass:: Cantera.Reactor.PressureController
.. autoclass:: Cantera.Reactor.Wall

View file

@ -9,10 +9,8 @@ cantera/test/data/*.dat
cantera/test/data/*.csv
setup2.py
setup3.py
cantera/ctml_writer.py
scripts/ctml_writer.py
scripts/ctml_writer
cantera/ck2cti.py
scripts/ck2cti.py
scripts/ck2cti
scripts/mixmaster

View file

@ -47,14 +47,6 @@ localenv['py_ctml_writer'] = repr('scripts/ctml_writer%s' % script_ext)
localenv['py_ck2cti'] = repr('scripts/ck2cti%s' % script_ext)
localenv['py_mixmaster'] = repr('scripts/mixmaster%s' % script_ext)
# The actual ctml_writer and ck2cti scripts
build(env.Command('cantera/ctml_writer.py',
'#interfaces/python/ctml_writer.py',
Copy('$TARGET', '$SOURCE')))
build(env.Command('cantera/ck2cti.py',
'#interfaces/python/ck2cti.py',
Copy('$TARGET', '$SOURCE')))
# thin wrappers
scripts = []
for script in mglob(env, 'scripts', 'py.in'):
@ -177,7 +169,7 @@ if localenv['python3_package'] == 'y':
# Cython module for Python 2.x
if localenv['python_package'] == 'new':
if localenv['python_package'] == 'full':
module_ext, py2_version = configure_numpy(localenv['python_cmd'])
make_setup = localenv.SubstFile('#interfaces/cython/setup2.py',
'#interfaces/cython/setup.py.in')

View file

View file

@ -1,3 +0,0 @@
setup.py
*.os
*.pyd

View file

@ -1,76 +0,0 @@
"""
Dusty Gas model for transport in porous media.
"""
from Cantera.Transport import Transport
class DustyGasTransport(Transport):
"""The Dusty Gas transport model. This class implements a
transport manager for the Dusty Gas model for the effective
transport properties of a gas in a stationary, solid, porous
medium. The only properties computed are the multicomponent
diffusion coefficients. The model does not compute viscosity or
thermal conductivity.
This class is a Python shadow class for Cantera C++ class
DustyGasTransport.
"""
def __init__(self, phase = None):
"""
phase - The object representing the gas phase within the
pores.
"""
Transport.__init__(self, model = "DustyGas", phase = phase)
def setPorosity(self, porosity):
"""Set the porosity. Internal. See: set"""
self.setParameters(0, 0, [porosity, 0.0])
def setTortuosity(self, tortuosity):
"""Set the tortuosity. Internal. See: set"""
self.setParameters(1, 0, [tortuosity, 0.0])
def setMeanPoreRadius(self, pore_radius):
"""Set the mean pore radius [m]. Internal. See: set"""
self.setParameters(2, 0, [pore_radius, 0.0])
def setMeanParticleDiameter(self, diameter):
"""Set the mean particle diameter [m]. Internal. See: set"""
self.setParameters(3, 0, [diameter, 0.0])
def setPermeability(self, permeability):
"""Set the permeability. If not called, the value for close-packed
spheres is used. Internal."""
self.setParameters(4, 0, [permeability, 0.0])
def set(self, **p):
"""Set model parameters. This is a convenience method that simply
calls other methods depending on the keyword.
porosity - Porosity. Volume fraction of pores.
tortuosity - Tortuosity. A measure of the extent to which the
pores are straight cylinders (tortuosity = 1), or are more
tortuous.
pore_radius - The pore radius [m].
All keywords are optional.
"""
for o in p.keys():
if o == "porosity":
self.setPorosity(p[o])
elif o == "tortuosity":
self.setTortuosity(p[o])
elif o == "pore_radius":
self.setMeanPoreRadius(p[o])
elif o == "diameter":
self.setMeanParticleDiameter(p[o])
elif o == "permeability":
self.setPermeability(p[o])
else:
raise 'unknown parameter'

View file

@ -1,75 +0,0 @@
import string
import os
from constants import *
from SurfacePhase import EdgePhase
from Kinetics import Kinetics
import XML
class Edge(EdgePhase, Kinetics):
"""
One-dimensional edge between two surfaces.
Instances of class Edge represent reacting 1D edges between
between 2D surfaces. Class Edge defines no methods of its
own. All of its methods derive from either :class:`.EdgePhase` or
:class:`.Kinetics`.
Function :func:`.importInterface` should usually be used to build an
Edge object from a CTI file definition, rather than calling
the :class:`.Edge` constructor directly.
"""
def __init__(self, src="", root=None, surfaces=[]):
"""
:param src:
CTML or CTI input file name. If more than one phase is
defined in the file, src should be specified as ``filename#id``
If the file is not CTML, it will be run through the CTI -> CTML
preprocessor first.
:param root:
If a CTML tree has already been read in that contains
the definition of this interface, the root of this tree can be
specified instead of specifying *src*.
:param phases:
A list of all objects representing the neighboring
surface phases which participate in the reaction mechanism.
"""
self.ckin = 0
self._owner = 0
self.verbose = 1
# src has the form '<filename>#<id>'
fn = src.split('#')
id = ""
if len(fn) > 1:
id = fn[1]
fn = fn[0]
# read in the root element of the tree if not building from
# an already-built XML tree. Enable preprocessing if the film
# is a .cti file instead of XML.
if src and not root:
root = XML.XML_Node(name = 'doc', src = fn, preprocess = 1)
# If an 'id' tag was specified, find the node in the tree with
# that tag
if id:
s = root.child(id = id)
# otherwise, find the first element with tag name 'phase'
# (1D, 2D and 3D phases use the CTML tag name 'phase'
else:
s = root.child(name = "phase")
# build the surface phase
EdgePhase.__init__(self, xml_phase=s)
# build the reaction mechanism. This object (representing the
# surface phase) is added to the end of the list of phases
Kinetics.__init__(self, xml_phase=s, phases=surfaces+[self])
def __del__(self):
"""Delete the Edge instance."""
Kinetics.__del__(self)
EdgePhase.__del__(self)

View file

@ -1,472 +0,0 @@
"""
The classes in this module are designed to allow constructing
user-defined functions of one variable in Python that can be used with the
Cantera C++ kernel. These classes are mostly shadow classes for
corresponding classes in the C++ kernel.
"""
from Cantera.num import array, asarray, ravel, shape, transpose
import _cantera
import types
class Func1:
"""
Functors of one variable.
A Functor is an object that behaves like a function. :class:`Func1`
is the base class from which several functor classes derive. These
classes are designed to allow specifying functions of time from Python
that can be used by the C++ kernel.
Functors can be added, multiplied, and divided to yield new functors.
>>> f1 = Polynomial([1.0, 0.0, 3.0]) # 3*t*t + 1
>>> f1(2.0)
13
>>> f2 = Polynomial([-1.0, 2.0]) # 2*t - 1
>>> f2(2.0)
5
>>> f3 = f1/f2 # (3*t*t + 1)/(2*t - 1)
>>> f3(2.0)
4.3333333
"""
def __init__(self, typ, n, coeffs=[]):
"""
The constructor is meant to be called from constructors of subclasses
of Func1: :class:`Polynomial`, :class:`Gaussian`, :class:`Arrhenius`,
:class:`Fourier`, :class:`Const`, :class:`PeriodicFunction`.
"""
self.n = n
self._own = 1
self._func_id = 0
self._typ = typ
if _cantera.nummod == 'numpy':
self.coeffs = array(coeffs, dtype=float, ndmin=1)
else:
self.coeffs = asarray(coeffs,'d')
self._func_id = _cantera.func_new(typ, n, self.coeffs)
def __del__(self):
if self._func_id and self._own:
_cantera.func_del(self._func_id)
def __repr__(self):
return self.write()
def __call__(self, t):
"""Implements function syntax, so that F(t) is equivalent to
F.value(t)."""
if type(t) == types.NoneType:
return self
if type(t) == types.InstanceType:
return CompositeFunction(self, t)
else:
return _cantera.func_value(self._func_id, t)
def __add__(self, other):
"""Overloads operator '+'
Returns a new function self(t) + other(t)"""
# if 'other' is a number, then create a 'Const' functor for
# it.
if type(other) == types.FloatType:
return SumFunction(self, Const(other))
return SumFunction(self, other)
def __radd__(self, other):
"""Overloads operator '+'
Returns a new function other(t) + self(t)"""
# if 'other' is a number, then create a 'Const' functor for
# it.
if type(other) == types.FloatType:
return SumFunction(Const(other),self)
return SumFunction(other, self)
def __sub__(self, other):
"""Overloads operator '-'
Returns a new function self(t) - other(t)"""
# if 'other' is a number, then create a 'Const' functor for
# it.
if type(other) != types.InstanceType:
return DiffFunction(self, Const(other))
return DiffFunction(self, other)
def __rsub__(self, other):
"""Overloads operator '-'
Returns a new function other(t) - self(t)"""
# if 'other' is a number, then create a 'Const' functor for
# it.
if type(other) != types.InstanceType:
return DiffFunction(Const(other), self)
return DiffFunction(other, self)
def __mul__(self, other):
"""Overloads operator '*'
Return a new function self(t)*other(t)"""
if type(other) != types.InstanceType:
return ProdFunction(self, Const(other))
return ProdFunction(self, other)
def __rmul__(self, other):
"""Overloads operator '*'
Returns a new function other(t)*self(t)"""
if type(other) != types.InstanceType:
return ProdFunction(Const(other), self)
return ProdFunction(other, self)
def __div__(self, other):
"""Overloads operator '/'
Returns a new function self(t)/other(t)"""
if type(other) != types.InstanceType:
return RatioFunction(self, Const(other))
return RatioFunction(self, other)
def __rdiv__(self, other):
"""Overloads operator '/'
Returns a new function other(t)/self(t)"""
if type(other) != types.InstanceType:
return RatioFunction(Const(other), self)
return RatioFunction(other, self)
def func_id(self):
"""Internal. Return the integer index used internally to access the
kernel-level object."""
return self._func_id
def write(self, arg = 'x', length = 1000):
return _cantera.func_write(self._func_id, length, arg)
class Sin(Func1):
def __init__(self,omega=1.0):
Func1.__init__(self,100,1,omega)
class Cos(Func1):
def __init__(self, omega=1.0):
Func1.__init__(self,102,1,omega)
class Exp(Func1):
def __init__(self,A=1.0):
Func1.__init__(self,104,1,A)
class Pow(Func1):
def __init__(self, n):
Func1.__init__(self,106,1,n)
class Polynomial(Func1):
r"""
A polynomial.
Instances of class 'Polynomial' evaluate
.. math:: f(t) = \sum_{n = 0}^N a_n t^n .
The coefficients are supplied as a list, beginning with :math:`a_N` and
ending with :math:`a_0`.
>>> p1 = Polynomial([1.0, -2.0, 3.0]) # 3t^2 - 2t + 1
>>> p2 = Polynomial([6.0, 8.0]) # 8t + 6
"""
def __init__(self, coeffs=[]):
"""
coeffs - polynomial coefficients
"""
Func1.__init__(self, 2, len(coeffs)-1, coeffs)
class Gaussian(Func1):
r"""A Gaussian pulse. Instances of class 'Gaussian' evaluate
.. math:: f(t) = A \exp[-(t - t_0) / \tau]
where
.. math:: \tau = \frac{\mbox{FWHM}}{2.0\sqrt{\ln(2.0)}}
'FWHM' denotes the full width at half maximum.
As an example, here is how to create a Gaussian pulse with peak amplitude
10.0, centered at time 2.0, with full-width at half max = 0.2:
>>> f = Gaussian(A = 10.0, t0 = 2.0, FWHM = 0.2)
>>> f(2.0)
10
>>> f(1.9)
5
>>> f(2.1)
5
"""
def __init__(self, A, t0, FWHM):
coeffs = array([A, t0, FWHM], 'd')
Func1.__init__(self, 4, 0, coeffs)
class Fourier(Func1):
r"""
Fourier series. Instances of class 'Fourier' evaluate the Fourier series
.. math::
f(t) = \frac{a_0}{2} +
\sum_{n=1}^N [a_n \cos(n\omega t) + b_n \sin(n \omega t)]
where
.. math::
a_n = \frac{\omega}{\pi}
\int_{-\pi/\omega}^{\pi/\omega} f(t) \cos(n \omega t) dt
b_n = \frac{\omega}{\pi}
\int_{-\pi/\omega}^{\pi/\omega} f(t) \sin(n \omega t) dt.
The function :math:`f(t)` is periodic, with period :math:`T = 2\pi/\omega`.
As an example, a function with Fourier components up to the second harmonic
is constructed as follows:
>>> coeffs = [(a0, b0), (a1, b1), (a2, b2)]
>>> f = Fourier(omega, coeffs)
Note that ``b0`` must be specified, but is not used. The value of ``b0``
is arbitrary.
"""
def __init__(self, omega, coefficients):
"""
:param omega:
fundamental frequency [radians/sec].
:param coefficients:
List of (a,b) pairs, beginning with n = 0.
"""
cc = asarray(coefficients,'d')
n, m = cc.shape
if m <> 2:
raise CanteraError('provide (a, b) for each term')
cc[0,1] = omega
Func1.__init__(self, 1, n-1, ravel(transpose(cc)))
class Arrhenius(Func1):
r"""Sum of modified Arrhenius terms. Instances of class 'Arrhenius' evaluate
.. math:: f(T) = \sum_{n=1}^N A_n T^{b_n}\exp(-E_n/T)
Example:
>>> f = Arrhenius([(a0, b0, e0), (a1, b1, e1)])
"""
def __init__(self, coefficients):
"""
:param coefficients:
sequence of (*A*, *b*, *E*) triplets.
"""
cc = asarray(coefficients,'d')
n, m = cc.shape
if m <> 3:
raise CanteraError('Three Arrhenius parameters (A, b, E) required.')
Func1.__init__(self, 3, n, ravel(cc))
class Const(Func1):
"""Constant function.
Objects created by function Const act as functions that have a constant
value. These are used internally whenever a statement like
>>> f = Gausian(2.0, 1.0, 0.1) + 4.0
is encountered. The addition operator of class Func1 is defined so that
this is equivalent to
>>> f = SumFunction(Gaussian(2.0, 1.0, 0.1), Const(4.0))
Function Const returns instances of class Polynomial that have
degree zero, with the constant term set to the desired value.
"""
def __init__(self, value):
Func1.__init__(self,110,1,value)
#return Polynomial([value])
class PeriodicFunction(Func1):
"""Converts a function into a periodic function with period T."""
def __init__(self, func, T):
"""
:param func:
initial non-periodic function
:param T:
period [s]
"""
Func1.__init__(self, 50, func.func_id(), array([T],'d'))
func._own = 0
# functions that combine two functions
class ComboFunc1(Func1):
"""
Combines two functions.
This class is the base class for functors that combine two
other functors in a binary operation.
"""
def __init__(self, typ, f1, f2):
self._own = 1
self._func_id = 0
self._typ = typ
if type(f1) == types.IntType:
f1 = Const(f1)
if type(f2) == types.IntType:
f2 = Const(f2)
self.f1 = f1
self.f2 = f2
self.f1._own = 0
self.f2._own = 0
self._func_id = _cantera.func_newcombo(typ, f1.func_id(), f2.func_id())
class SumFunction(ComboFunc1):
"""Sum of two functions.
Instances of class SumFunction evaluate the sum of two supplied functors.
It is not necessary to explicitly create an instance of SumFunction, since
the addition operator of the base class is overloaded to return a SumFunction
instance.
>>> f1 = Polynomial([2.0, 1.0])
>>> f2 = Polynomial([3.0, -5.0])
>>> f3 = f1 + f2 # functor to evaluate (2t + 1) + (3t - 5)
In this example, object 'f3' is a functor of class'SumFunction' that calls
f1 and f2 and returns their sum.
"""
def __init__(self, f1, f2):
"""
:param f1:
first functor.
:param f2:
second functor.
"""
ComboFunc1.__init__(self, 20, f1, f2)
class DiffFunction(ComboFunc1):
"""Difference of two functions.
Instances of class DiffFunction evaluate the difference of two supplied
functors. It is not necessary to explicitly create an instance of
DiffFunction, since the subtraction operator of the base class is
overloaded to return a DiffFunction instance.
>>> f1 = Polynomial([2.0, 1.0])
>>> f2 = Polynomial([3.0, -5.0])
>>> f3 = f1 - f2 # functor to evaluate (2t + 1) - (3t - 5)
In this example, object 'f3' is a functor of class'DiffFunction' that
calls f1 and f2 and returns their difference.
"""
def __init__(self, f1, f2):
"""
:param f1:
first functor.
:param f2:
second functor.
"""
ComboFunc1.__init__(self, 25, f1, f2)
class ProdFunction(ComboFunc1):
"""Product of two functions. Instances of class ProdFunction
evaluate the product of two supplied functors. It is not
necessary to explicitly create an instance of 'ProdFunction',
since the multiplication operator of the base class is overloaded
to return a 'ProdFunction' instance.
>>> f1 = Polynomial([2.0, 1.0])
>>> f2 = Polynomial([3.0, -5.0])
>>> f3 = f1 * f2 # functor to evaluate (2t + 1)*(3t - 5)
In this example, object 'f3' is a functor of class'ProdFunction'
that calls f1 and f2 and returns their product.
"""
def __init__(self, f1, f2):
"""
:param f1:
first functor.
:param f2:
second functor.
"""
ComboFunc1.__init__(self, 30, f1, f2)
class RatioFunction(ComboFunc1):
"""Ratio of two functions.
Instances of class RatioFunction evaluate the ratio of two supplied functors.
It is not necessary to explicitly create an instance of 'RatioFunction', since
the division operator of the base class is overloaded to return a RatioFunction
instance.
>>> f1 = Polynomial([2.0, 1.0])
>>> f2 = Polynomial([3.0, -5.0])
>>> f3 = f1 / f2 # functor to evaluate (2t + 1)/(3t - 5)
In this example, object 'f3' is a functor of class'RatioFunction' that
calls f1 and f2 and returns their ratio.
"""
def __init__(self, f1, f2):
"""
:param f1:
first functor.
:param f2:
second functor.
"""
ComboFunc1.__init__(self, 40, f1, f2)
class CompositeFunction(ComboFunc1):
"""
Function of a function.
Instances of class CompositeFunction evaluate f(g(t)) for two supplied
functors f and g. It is not necessary to explicitly create an instance
of 'CompositeFunction', since the () operator of the base class is
overloaded to return a CompositeFunction when called with a functor
argument.
>>> f1 = Polynomial([2.0, 1.0])
>>> f2 = Polynomial([3.0, -5.0])
>>> f3 = f1(f2) # functor to evaluate 2(3t - 5) + 1
In this example, object 'f3' is a functor of class'CompositeFunction'
that calls f1 and f2 and returns f1(f2(t)).
"""
def __init__(self, f1, f2):
"""
:param f1:
first functor.
:param f2:
second functor.
"""
ComboFunc1.__init__(self, 60, f1, f2)
class DerivativeFunction(Func1):
def __init__(self, f):
self.f = f
#f._own = 0
self._own = 1
self._func_id = _cantera.func_derivative(f.func_id())
def derivative(f):
"""
Take the derivative of a functor *f*
"""
return DerivativeFunction(f)

View file

@ -1,75 +0,0 @@
import string
import os
from constants import *
from SurfacePhase import SurfacePhase, EdgePhase
from Kinetics import Kinetics
import XML
class Interface(SurfacePhase, Kinetics):
"""
Two-dimensional interfaces.
Instances of class Interface represent reacting 2D interfaces
between bulk 3D phases. Class Interface defines no methods of its
own. All of its methods derive from either :class:`.SurfacePhase` or
:class:`.Kinetics`.
Function :func:`.importInterface` should usually be used to build an
Interface object from a CTI file definition, rather than calling
the Interface constructor directly.
"""
def __init__(self, src="", root=None, phases=[], debug = 0):
"""
:param src:
CTML or CTI input file name. If more than one phase is
defined in the file, src should be specified as ``filename#id``
If the file is not CTML, it will be run through the CTI -> CTML
preprocessor first.
:param root:
If a CTML tree has already been read in that contains the
definition of this interface, the root of this tree can be
specified instead of specifying *src*.
:param phases:
A list of all objects representing the neighboring phases which
participate in the reaction mechanism.
"""
self.ckin = 0
self._owner = 0
self.verbose = 1
# src has the form '<filename>#<id>'
fn = src.split('#')
id = ""
if len(fn) > 1:
id = fn[1]
fn = fn[0]
# read in the root element of the tree if not building from
# an already-built XML tree. Enable preprocessing if the film
# is a .cti file instead of XML.
if src and not root:
root = XML.XML_Node(name = 'doc', src = fn, preprocess = 1, debug = debug)
# If an 'id' tag was specified, find the node in the tree with
# that tag
if id:
s = root.child(id = id)
# otherwise, find the first element with tag name 'phase'
# (both 2D and 3D phases use the CTML tag name 'phase'
else:
s = root.child(name = "phase")
# build the surface phase
SurfacePhase.__init__(self, xml_phase=s)
# build the reaction mechanism. This object (representing the
# surface phase) is added to the end of the list of phases
Kinetics.__init__(self, xml_phase=s, phases=phases+[self])
def __del__(self):
"""Delete the Interface instance."""
Kinetics.__del__(self)
SurfacePhase.__del__(self)

View file

@ -1,308 +0,0 @@
"""
Kinetics managers.
"""
from Cantera.exceptions import CanteraError, getCanteraError
from Cantera.ThermoPhase import ThermoPhase
from Cantera.XML import XML_Node
from Cantera.num import zeros
import _cantera
class Kinetics:
"""
Kinetics managers. Instances of class Kinetics are responsible for
evaluating reaction rates of progress, species production rates,
and other quantities pertaining to a reaction mechanism.
"""
def __init__(self, kintype=-1, thrm=0, xml_phase=None, id=None, phases=[]):
"""
Build a kinetics manager from an XML specification.
:param kintype:
Integer specifying the type of kinetics manager to create.
:param root:
Root of a CTML tree
:param id:
id of the 'kinetics' node within the tree that contains the
specification of the parameters.
"""
np = len(phases)
self._sp = []
self._phnum = {}
# p0 through p4 are the integer indices of the phase objects
# corresponding to the input sequence of phases
self._end = [0]
p0 = phases[0].thermophase()
p1 = -1
p2 = -1
p3 = -1
p4 = -1
if np >= 2:
p1 = phases[1].thermophase()
if np >= 3:
p2 = phases[2].thermophase()
if np >= 4:
p3 = phases[3].thermophase()
if np >= 5:
p4 = phases[4].thermophase()
if np >= 6:
raise CanteraError("a maximum of 4 neighbor phases allowed")
self.ckin = _cantera.KineticsFromXML(xml_phase,
p0, p1, p2, p3, p4)
self._np = self.nPhases()
for nn in range(self._np):
p = self.phase(nn)
self._phnum[p.thermophase()] = nn
self._end.append(self._end[-1]+p.nSpecies())
for k in range(p.nSpecies()):
self._sp.append(p.speciesName(k))
def __del__(self):
self.clear()
def clear(self):
"""Delete the kinetics manager."""
if self.ckin > 0:
_cantera.kin_delete(self.ckin)
def kin_index(self):
print "kin_index is deprecated. Use kinetics_hndl."
return self.ckin
def kinetics_hndl(self):
return self.ckin
def kineticsType(self):
"""Kinetics manager type."""
return _cantera.kin_type(self.ckin)
def kineticsSpeciesIndex(self, name, phase):
"""The index of a species.
:param name:
species name
:param phase:
phase name
Kinetics managers for heterogeneous reaction mechanisms
maintain a list of all species in all phases. The order of the
species in this list determines the ordering of the arrays of
production rates. This method returns the index for the
specified species of the specified phase, and is used to
locate the entry for a particular species in the production
rate arrays.
"""
return _cantera.kin_speciesIndex(self.ckin, name, phase)
def kineticsStart(self, n):
"""The starting location of phase n in production rate arrays."""
return _cantera.kin_start(self.ckin, n)
def nPhases(self):
"""Number of phases."""
return _cantera.kin_nPhases(self.ckin)
def reactionPhaseIndex(self):
"""The phase in which the reactions take place."""
return _cantera.kin_reactionPhaseIndex(self)
def phase(self, n):
"""Return an object representing the nth phase."""
return ThermoPhase(index = _cantera.kin_phase(self.ckin, n))
def nReactions(self):
"""Number of reactions."""
return _cantera.kin_nreactions(self.ckin)
def isReversible(self,i):
"""
True (1) if reaction number *i* is reversible,
and false (0) otherwise.
"""
return _cantera.kin_isreversible(self.ckin,i)
def reactionType(self,i):
"""Type of reaction *i*"""
return _cantera.kin_rxntype(self.ckin,i)
def reactionEqn(self,i):
"""The equation for the specified reaction. If a list of equation numbers
is given, then a list of equation strings is returned."""
try:
eqs = []
for rxn in i:
eqs.append(self.reactionString(rxn))
return eqs
except:
return self.reactionString(i)
def reactionString(self, i):
"""Reaction string for reaction number *i*"""
s = ''
nsp = _cantera.kin_nspecies(self.ckin)
for k in range(nsp):
nur = _cantera.kin_rstoichcoeff(self.ckin,k,i)
if nur <> 0.0:
if nur <> 1.0:
if nur <> round(nur):
s += str(nur)+' '
else:
s += `int(nur)`+' '
s += self._sp[k]+' + '
s = s[:-2]
if self.isReversible(i):
s += ' <=> '
else:
s += ' => '
for k in range(nsp):
nup = _cantera.kin_pstoichcoeff(self.ckin,k,i)
if nup <> 0.0:
if nup <> 1.0:
if nup <> round(nup):
s += str(nup)+' '
else:
s += `int(nup)`+' '
s += self._sp[k]+' + '
s = s[:-2]
return s
def reactantStoichCoeff(self,k,i):
"""The stoichiometric coefficient of species *k* as a reactant in reaction *i*."""
return _cantera.kin_rstoichcoeff(self.ckin,k,i)
def reactantStoichCoeffs(self):
"""The array of reactant stoichiometric coefficients. Element
[k,i] of this array is the reactant stoichiometric
coefficient of species k in reaction i."""
nsp = _cantera.kin_nspecies(self.ckin)
nr = _cantera.kin_nreactions(self.ckin)
nu = zeros((nsp,nr),'d')
for i in range(nr):
for k in range(nsp):
nu[k,i] = _cantera.kin_rstoichcoeff(self.ckin,k,i)
return nu
def productStoichCoeff(self,k,i):
"""The stoichiometric coefficient of species *k* as a product in reaction *i*."""
return _cantera.kin_pstoichcoeff(self.ckin,k,i)
def productStoichCoeffs(self):
"""The array of product stoichiometric coefficients. Element
[k,i] of this array is the product stoichiometric
coefficient of species *k* in reaction *i*."""
nsp = _cantera.kin_nspecies(self.ckin)
nr = _cantera.kin_nreactions(self.ckin)
nu = zeros((nsp,nr),'d')
for i in range(nr):
for k in range(nsp):
nu[k,i] = _cantera.kin_pstoichcoeff(self.ckin,k,i)
return nu
def fwdRatesOfProgress(self):
"""Forward rates of progress of the reactions."""
return _cantera.kin_getarray(self.ckin,10)
def revRatesOfProgress(self):
"""Reverse rates of progress of the reactions."""
return _cantera.kin_getarray(self.ckin,20)
def netRatesOfProgress(self):
"""Net rates of progress of the reactions."""
return _cantera.kin_getarray(self.ckin,30)
def equilibriumConstants(self):
"""Equilibrium constants in concentration units for all reactions."""
return _cantera.kin_getarray(self.ckin,40)
def activationEnergies(self):
"""Activation energies in Kelvin for all reactions."""
return _cantera.kin_getarray(self.ckin,32)
def fwdRateConstants(self):
"""Forward rate constants for all reactions."""
return _cantera.kin_getarray(self.ckin,34)
def revRateConstants(self, doIrreversible = 0):
"""Reverse rate constants for all reactions."""
if doIrreversible:
return _cantera.kin_getarray(self.ckin,35)
else:
return _cantera.kin_getarray(self.ckin,36)
def creationRates(self, phase = None):
c = _cantera.kin_getarray(self.ckin,50)
if phase:
kp = phase.thermophase()
if self._phnum.has_key(kp):
n = self._phnum[kp]
return c[self._end[n]:self._end[n+1]]
else:
raise CanteraError('unknown phase')
else:
return c
def destructionRates(self, phase = None):
d = _cantera.kin_getarray(self.ckin,60)
if phase:
kp = phase.thermophase()
if self._phnum.has_key(kp):
n = self._phnum[kp]
return d[self._end[n]:self._end[n+1]]
else:
raise CanteraError('unknown phase')
else:
return d
def netProductionRates(self, phase = None):
w = _cantera.kin_getarray(self.ckin,70)
if phase:
kp = phase.thermophase()
if self._phnum.has_key(kp):
n = self._phnum[kp]
return w[self._end[n]:self._end[n+1]]
else:
raise CanteraError('unknown phase')
else:
return w
def sourceTerms(self):
return _cantera.kin_getarray(self.ckin,80)
def delta_H(self):
return _cantera.kin_getarray(self.ckin,90)
def delta_G(self):
return _cantera.kin_getarray(self.ckin,91)
def delta_S(self):
return _cantera.kin_getarray(self.ckin,92)
def delta_H0(self):
return _cantera.kin_getarray(self.ckin,93)
def delta_G0(self):
return _cantera.kin_getarray(self.ckin,94)
def delta_S0(self):
return _cantera.kin_getarray(self.ckin,95)
def multiplier(self,i):
return _cantera.kin_multiplier(self.ckin,i)
def setMultiplier(self, value = 0.0, reaction = -1):
if reaction < 0:
nr = self.nReactions()
for i in range(nr):
_cantera.kin_setMultiplier(self.ckin,i,value)
else:
_cantera.kin_setMultiplier(self.ckin,reaction,value)
def advanceCoverages(self,dt):
return _cantera.kin_advanceCoverages(self.ckin,dt)

View file

@ -1,138 +0,0 @@
from onedim import *
from Cantera.num import array, zeros
class BurnerDiffFlame(Stack):
"""A burner-stabilized flat flame."""
def __init__(self, gas = None, burner = None, outlet = None, grid = None):
"""
:param gas:
object to use to evaluate all gas properties and reaction
rates. Required
:param burner:
Inlet object representing the burner. Optional; if not supplied,
one will be created with name 'burner'
:param outlet:
Outlet object representing the outlet. Optional; if not supplied,
one will be created with name 'outlet'
:param grid:
array of initial grid points
A domain of type :class:`.AxisymmetricFlow` named 'flame' will be
created to represent the flame. The three domains comprising the stack
are stored as ``self.burner``, ``self.flame``, and ``self.outlet``.
"""
if burner:
self.burner = burner
else:
self.burner = Inlet('burner')
self.gas = gas
self.burner.set(temperature = gas.temperature())
if outlet:
self.outlet = outlet
else:
self.outlet = OutletRes('outletres')
self.flame = AxisymmetricFlow('flame',gas = gas)
self.flame.setupGrid(grid)
Stack.__init__(self, [self.burner, self.flame, self.outlet])
self.setRefineCriteria()
def init(self):
"""Set the initial guess for the solution. The adiabatic flame
temperature and equilibrium composition are computed for the
burner gas composition. The temperature profile rises linearly
in the first 20% of the flame to Tad, then is flat. The mass
fraction profiles are set similarly.
"""
self.getInitialSoln()
gas = self.gas
nsp = gas.nSpecies()
yin = zeros(nsp, 'd')
for k in range(nsp):
yin[k] = self.burner.massFraction(k)
gas.setState_TPY(self.burner.temperature(), self.flame.pressure(), yin)
u0 = self.burner.mdot()/gas.density()
t0 = self.burner.temperature()
# get adiabatic flame temperature and composition
gas.equilibrate('HP')
teq = gas.temperature()
yeq = gas.massFractions()
u1 = self.burner.mdot()/gas.density()
z1 = 0.2
locs = array([0.0, z1, 1.0],'d')
self.setProfile('u', locs, [u0, u1, u1])
self.setProfile('T', locs, [t0, teq, teq])
for n in range(nsp):
self.setProfile(gas.speciesName(n), locs, [yin[n], yeq[n], yeq[n]])
self._initialized = 1
def solve(self, loglevel = 1, refine_grid = 1):
if not self._initialized: self.init()
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
def setRefineCriteria(self, ratio = 10.0, slope = 0.8,
curve = 0.8, prune = 0.0):
Stack.setRefineCriteria(self, domain = self.flame,
ratio = ratio, slope = slope, curve = curve,
prune = prune)
def setGridMin(self, gridmin):
Stack.setGridMin(self, self.flame, gridmin)
def setProfile(self, component, locs, vals):
self._initialized = 1
Stack.setProfile(self, self.flame, component, locs, vals)
def set(self, tol = None, energy = '', tol_time = None):
"""Set parameters.
:param tol:
(rtol, atol) for steady-state
:param tol_time:
(rtol, atol) for time stepping
:param energy:
``'on'`` or ``'off'`` to enable or disable the energy equation
"""
if tol:
self.flame.setTolerances(default = tol)
if tol_time:
self.flame.setTolerances(default = tol_time, time = 1)
if energy:
self.flame.set(energy = energy)
def T(self, point = -1):
"""Temperature profile or value at one point."""
return self.solution('T', point)
def u(self, point = -1):
"""Axial velocity profile or value at one point."""
return self.solution('u', point)
def V(self, point = -1):
"""Radial velocity profile or value at one point."""
return self.solution('V', point)
def solution(self, component = '', point = -1):
"""Solution component at one point, or full profile if no
point specified."""
if point >= 0: return self.value(self.flame, component, point)
else: return self.profile(self.flame, component)
def setGasState(self, j):
"""Set the state of the object representing the gas to the
current solution at grid point *j*."""
nsp = self.gas.nSpecies()
y = zeros(nsp, 'd')
for n in range(nsp):
nm = self.gas.speciesName(n)
y[n] = self.solution(nm, j)
self.gas.setState_TPY(self.T(j), self.flame.pressure(), y)
fix_docs(BurnerDiffFlame)

View file

@ -1,137 +0,0 @@
from onedim import *
from Cantera.num import array, zeros
class BurnerFlame(Stack):
"""A burner-stabilized flat flame."""
def __init__(self, gas = None, burner = None, outlet = None, grid = None):
"""
:param gas:
object to use to evaluate all gas properties and reaction
rates. Required
:param burner:
Inlet object representing the burner. Optional;
if not supplied, one will be created with name ``burner``
:param outlet:
Outlet object representing the outlet. Optional;
if not supplied, one will be created with name ``outlet``
:param grid:
array of initial grid points
A domain of type :class:`.AxisymmetricFlow` named ``flame`` will be
created to represent the flame. The three domains comprising the stack
are stored as ``self.burner``, ``self.flame``, and ``self.outlet``.
"""
if burner:
self.burner = burner
else:
self.burner = Inlet('burner')
self.gas = gas
self.burner.set(temperature = gas.temperature())
if outlet:
self.outlet = outlet
else:
self.outlet = Outlet('outlet')
self.flame = AxisymmetricFlow('flame',gas = gas)
self.flame.setupGrid(grid)
Stack.__init__(self, [self.burner, self.flame, self.outlet])
self.setRefineCriteria()
def init(self):
"""Set the initial guess for the solution. The adiabatic flame
temperature and equilibrium composition are computed for the
burner gas composition. The temperature profile rises linearly
in the first 20% of the flame to Tad, then is flat. The mass
fraction profiles are set similarly.
"""
self.getInitialSoln()
gas = self.gas
nsp = gas.nSpecies()
yin = zeros(nsp, 'd')
for k in range(nsp):
yin[k] = self.burner.massFraction(k)
gas.setState_TPY(self.burner.temperature(), self.flame.pressure(), yin)
u0 = self.burner.mdot()/gas.density()
t0 = self.burner.temperature()
# get adiabatic flame temperature and composition
gas.equilibrate('HP',solver=1)
teq = gas.temperature()
yeq = gas.massFractions()
u1 = self.burner.mdot()/gas.density()
z1 = 0.2
locs = array([0.0, z1, 1.0],'d')
self.setProfile('u', locs, [u0, u1, u1])
self.setProfile('T', locs, [t0, teq, teq])
for n in range(nsp):
self.setProfile(gas.speciesName(n), locs, [yin[n], yeq[n], yeq[n]])
self._initialized = 1
def solve(self, loglevel = 1, refine_grid = 1):
if not self._initialized: self.init()
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
def setRefineCriteria(self, ratio = 10.0, slope = 0.8,
curve = 0.8, prune = 0.0):
Stack.setRefineCriteria(self, domain = self.flame,
ratio = ratio, slope = slope, curve = curve,
prune = prune)
def setGridMin(self, gridmin):
Stack.setGridMin(self, self.flame, gridmin)
def setProfile(self, component, locs, vals):
self._initialized = 1
Stack.setProfile(self, self.flame, component, locs, vals)
def set(self, tol = None, energy = '', tol_time = None):
"""Set parameters.
:param tol:
(rtol, atol) for steady-state
:param tol_time:
(rtol, atol) for time stepping
:param energy:
``'on'`` or ``'off'`` to enable or disable the energy equation
"""
if tol:
self.flame.setTolerances(default = tol)
if tol_time:
self.flame.setTolerances(default = tol_time, time = 1)
if energy:
self.flame.set(energy = energy)
def T(self, point = -1):
"""Temperature profile or value at one point."""
return self.solution('T', point)
def u(self, point = -1):
"""Axial velocity profile or value at one point."""
return self.solution('u', point)
def V(self, point = -1):
"""Radial velocity profile or value at one point."""
return self.solution('V', point)
def solution(self, component = '', point = -1):
"""Solution component at one point, or full profile if no
point specified."""
if point >= 0: return self.value(self.flame, component, point)
else: return self.profile(self.flame, component)
def setGasState(self, j):
"""Set the state of the object representing the gas to the
current solution at grid point *j*."""
nsp = self.gas.nSpecies()
y = zeros(nsp, 'd')
for n in range(nsp):
nm = self.gas.speciesName(n)
y[n] = self.solution(nm, j)
self.gas.setState_TPY(self.T(j), self.flame.pressure(), y)
fix_docs(BurnerFlame)

View file

@ -1,219 +0,0 @@
"""A counterflow flame."""
from onedim import *
from Cantera.num import zeros
import math
def erfc(x):
"""The complementary error function."""
exp = math.exp
p = 0.3275911
a1 = 0.254829592
a2 = -0.284496736
a3 = 1.421413741
a4 = -1.453152027
a5 = 1.061405429
t = 1.0 / (1.0 + p*x)
erfcx = ( (a1 + (a2 + (a3 +
(a4 + a5*t)*t)*t)*t)*t ) * exp(-x*x)
return erfcx
def erf(x):
"""The error function."""
if x < 0:
return -(1.0 - erfc(-x))
else:
return 1.0 - erfc(x)
class CounterFlame(Stack):
"""A non-premixed counterflow flame."""
def __init__(self, gas = None, grid = None):
"""
The domains are::
[self.fuel_inlet, # class Inlet,
self.flame, # class AxisymmetricFlow,
self.oxidizer_inlet] # class Inlet
"""
self.fuel_inlet = Inlet('fuel inlet')
self.oxidizer_inlet = Inlet('oxidizer inlet')
self.gas = gas
self.fuel_inlet.set(temperature = gas.temperature())
self.oxidizer_inlet.set(temperature = gas.temperature())
self.flame = AxisymmetricFlow('flame',gas = gas)
self.flame.setupGrid(grid)
Stack.__init__(self, [self.fuel_inlet, self.flame,
self.oxidizer_inlet])
self.setRefineCriteria()
def init(self, fuel = '', oxidizer = 'O2', stoich = -1.0):
"""Set the initial guess for the solution. The fuel species
must be specified, and the oxidizer may be
>>> f.init(fuel='CH4')
The initial guess is generated by assuming infinitely-fast
chemistry."""
self.getInitialSoln()
gas = self.gas
nsp = gas.nSpecies()
wt = gas.molecularWeights()
# find the fuel and oxidizer species
iox = gas.speciesIndex(oxidizer)
ifuel = gas.speciesIndex(fuel)
# if no stoichiometric ratio was input, compute it
if stoich < 0.0:
if oxidizer == 'O2':
nh = gas.nAtoms(fuel, 'H')
nc = gas.nAtoms(fuel, 'C')
stoich = 1.0*nc + 0.25*nh
else:
raise CanteraError('oxidizer/fuel stoichiometric ratio must'+
' be specified, since the oxidizer is not O2')
s = stoich*wt[iox]/wt[ifuel]
y0f = self.fuel_inlet.massFraction(ifuel)
y0ox = self.oxidizer_inlet.massFraction(iox)
phi = s*y0f/y0ox
zst = 1.0/(1.0 + phi)
pressure = self.flame.pressure()
yin_f = zeros(nsp, 'd')
yin_o = zeros(nsp, 'd')
yst = zeros(nsp, 'd')
for k in range(nsp):
yin_f[k] = self.fuel_inlet.massFraction(k)
yin_o[k] = self.oxidizer_inlet.massFraction(k)
yst[k] = zst*yin_f[k] + (1.0 - zst)*yin_o[k]
gas.setState_TPY(self.fuel_inlet.temperature(), pressure, yin_f)
mdotf = self.fuel_inlet.mdot()
u0f = mdotf/gas.density()
t0f = self.fuel_inlet.temperature()
gas.setState_TPY(self.oxidizer_inlet.temperature(),
pressure, yin_o)
mdoto = self.oxidizer_inlet.mdot()
u0o = mdoto/gas.density()
t0o = self.oxidizer_inlet.temperature()
# get adiabatic flame temperature and composition
tbar = 0.5*(t0o + t0f)
gas.setState_TPY(tbar, pressure, yst)
gas.equilibrate('HP')
teq = gas.temperature()
yeq = gas.massFractions()
# estimate strain rate
zz = self.flame.grid()
dz = zz[-1] - zz[0]
a = (u0o + u0f)/dz
diff = gas.mixDiffCoeffs()
f = math.sqrt(a/(2.0*diff[iox]))
x0 = mdotf*dz/(mdotf + mdoto)
nz = len(zz)
y = zeros([nz,nsp],'d')
t = zeros(nz,'d')
for j in range(nz):
x = zz[j]
zeta = f*(x - x0)
zmix = 0.5*(1.0 - erf(zeta))
if zmix > zst:
for k in range(nsp):
y[j,k] = yeq[k] + (zmix - zst)*(yin_f[k]
- yeq[k])/(1.0 - zst)
t[j] = teq + (t0f - teq)*(zmix - zst)/(1.0 - zst)
else:
for k in range(nsp):
y[j,k] = yin_o[k] + zmix*(yeq[k] - yin_o[k])/zst
t[j] = t0o + (teq - t0o)*zmix/zst
t[0] = t0f
t[-1] = t0o
zrel = zz/dz
self.setProfile('u', [0.0, 1.0], [u0f, -u0o])
self.setProfile('V', [0.0, x0/dz, 1.0], [0.0, a, 0.0])
self.setProfile('T', zrel, t)
for k in range(nsp):
self.setProfile(gas.speciesName(k), zrel, y[:,k])
self._initialized = 1
def solve(self, loglevel = 1, refine_grid = 1):
if not self._initialized: self.init()
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
def setRefineCriteria(self, ratio = 10.0, slope = 0.8, curve = 0.8,
prune = 0.0):
Stack.setRefineCriteria(self, domain = self.flame,
ratio = ratio, slope = slope, curve = curve,
prune = prune)
def setGridMin(self, gridmin):
Stack.setGridMin(self, self.flame, gridmin)
def setProfile(self, component, locs, vals):
self._initialized = 1
Stack.setProfile(self, self.flame, component, locs, vals)
def set(self, tol = None, energy = '', tol_time = None):
"""Set parameters.
:param tol:
(rtol, atol) for steady-state
:param tol_time:
(rtol, atol) for time stepping
:param energy:
'on' or 'off' to enable or disable the energy equation
"""
if tol:
self.flame.setTolerances(default = tol)
if tol_time:
self.flame.setTolerances(default = tol_time, time = 1)
if energy:
self.flame.set(energy = energy)
def T(self, point = -1):
"""The temperature [K]"""
return self.solution('T', point)
def u(self, point = -1):
"""The axial velocity [m/s]"""
return self.solution('u', point)
def V(self, point = -1):
"""The radial velocity divided by radius [s^-1]"""
return self.solution('V', point)
def solution(self, component = '', point = -1):
"""The solution for one specified component. If a point number
is given, return the value of component 'component' at this
point. Otherwise, return the entire profile for this
component."""
if point >= 0: return self.value(self.flame, component, point)
else: return self.profile(self.flame, component)
def setGasState(self, j):
"""Set the state of the object representing the gas to the
current solution at grid point j."""
nsp = self.gas.nSpecies()
y = zeros(nsp, 'd')
for n in range(nsp):
nm = self.gas.speciesName(n)
y[n] = self.solution(nm, j)
self.gas.setState_TPY(self.T(j), self.flame.pressure(), y)
fix_docs(CounterFlame)

View file

@ -1,135 +0,0 @@
from onedim import *
from Cantera import _cantera
from Cantera.num import array, zeros
class FreeFlame(Stack):
"""A freely-propagating flat flame."""
def __init__(self, gas = None, grid = None, tfix = 500.0):
"""
:param gas:
object to use to evaluate all gas properties and reaction
rates. Required
:param grid:
array of initial grid points
A domain of type FreeFlame named 'flame' will be created to
represent the flame. The three domains comprising the stack
are stored as ``self.inlet``, ``self.flame``, and ``self.outlet``.
"""
self.inlet = Inlet('burner')
self.gas = gas
self.inlet.set(temperature = gas.temperature())
self.outlet = Outlet('outlet')
# type 2 is Cantera C++ class FreeFlame
self.flame = AxisymmetricFlow('flame',gas = gas,type=2)
self.flame.setupGrid(grid)
Stack.__init__(self, [self.inlet, self.flame, self.outlet])
self.setRefineCriteria()
self.tfix = tfix
def init(self):
"""Set the initial guess for the solution. The adiabatic flame
temperature and equilibrium composition are computed for the
inlet gas composition. The temperature profile rises linearly
in the first 20% of the flame to Tad, then is flat. The mass
fraction profiles are set similarly.
"""
self.getInitialSoln()
gas = self.gas
nsp = gas.nSpecies()
yin = zeros(nsp, 'd')
for k in range(nsp):
yin[k] = self.inlet.massFraction(k)
gas.setState_TPY(self.inlet.temperature(), self.flame.pressure(), yin)
u0 = self.inlet.mdot()/gas.density()
t0 = self.inlet.temperature()
# get adiabatic flame temperature and composition
gas.equilibrate('HP',solver=1)
teq = gas.temperature()
yeq = gas.massFractions()
u1 = self.inlet.mdot()/gas.density()
z1 = 0.5
locs = array([0.0, 0.3, z1, 1.0],'d')
self.setProfile('u', locs, [u0, u0, u1, u1])
self.setProfile('T', locs, [t0, t0, teq, teq])
self.setFixedTemperature(self.tfix)
for n in range(nsp):
self.setProfile(gas.speciesName(n), locs, [yin[n], yin[n],
yeq[n], yeq[n]])
self._initialized = 1
def solve(self, loglevel = 1, refine_grid = 1):
if not self._initialized: self.init()
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
def setRefineCriteria(self, ratio = 10.0, slope = 0.8,
curve = 0.8, prune = 0.0):
Stack.setRefineCriteria(self, domain = self.flame,
ratio = ratio, slope = slope, curve = curve,
prune = prune)
def setGridMin(self, gridmin):
Stack.setGridMin(self, self.flame, gridmin)
def setFixedTemperature(self, temp):
_cantera.sim1D_setFixedTemperature(self._hndl, temp)
def setProfile(self, component, locs, vals):
self._initialized = 1
Stack.setProfile(self, self.flame, component, locs, vals)
def set(self, tol = None, energy = '', tol_time = None):
"""Set parameters.
:param tol:
(rtol, atol) for steady-state
:param tol_time:
(rtol, atol) for time stepping
:param energy:
'on' or 'off' to enable or disable the energy equation
"""
if tol:
self.flame.setTolerances(default = tol)
if tol_time:
self.flame.setTolerances(default = tol_time, time = 1)
if energy:
self.flame.set(energy = energy)
def T(self, point = -1):
"""Temperature profile or value at one point."""
return self.solution('T', point)
def u(self, point = -1):
"""Axial velocity profile or value at one point."""
return self.solution('u', point)
def V(self, point = -1):
"""Radial velocity profile or value at one point."""
return self.solution('V', point)
def solution(self, component = '', point = -1):
"""Solution component at one point, or full profile if no
point specified."""
if point >= 0: return self.value(self.flame, component, point)
else: return self.profile(self.flame, component)
def setGasState(self, j):
"""Set the state of the object representing the gas to the
current solution at grid point j."""
nsp = self.gas.nSpecies()
y = zeros(nsp, 'd')
for n in range(nsp):
nm = self.gas.speciesName(n)
y[n] = self.solution(nm, j)
self.gas.setState_TPY(self.T(j), self.flame.pressure(), y)
fix_docs(FreeFlame)

View file

@ -1,151 +0,0 @@
from onedim import *
from Cantera.num import array, zeros
class StagnationFlow(Stack):
"""An axisymmetric flow impinging on a surface at normal incidence."""
def __init__(self, gas = None, surfchem = None, grid = None):
"""
:param gas:
object to use to evaluate all gas properties and reaction
rates. Required.
:param surfchem:
object used to evaluate surface reaction rates. If omitted,
surface will be treated as inert.
:param grid:
array of initial grid points
A domain of type :class:`.AxisymmetricFlow` named ``flow`` will be
created to represent the flow, and one of type :class:`.Surface` named
``surface`` will be created to represent the surface. The three domains
comprising the stack are stored as ``self.inlet``, ``self.flow``,
and ``self.surface``.
"""
self.inlet = Inlet('inlet')
self.gas = gas
self.surfchem = surfchem
self.inlet.set(temperature = gas.temperature())
self.surface = Surface(id = 'surface', surface_mech = surfchem)
self.flow = AxisymmetricFlow('flow',gas = gas)
self.flow.setupGrid(grid)
Stack.__init__(self, [self.inlet, self.flow, self.surface])
self.setRefineCriteria()
def init(self, products = 'inlet'):
"""Set the initial guess for the solution. If products = 'equil',
then the equilibrium composition at the adiabatic flame temperature
will be used to form the initial guess. Otherwise the inlet composition
will be used."""
self.getInitialSoln()
gas = self.gas
nsp = gas.nSpecies()
yin = zeros(nsp, 'd')
for k in range(nsp):
yin[k] = self.inlet.massFraction(k)
gas.setState_TPY(self.inlet.temperature(), self.flow.pressure(), yin)
u0 = self.inlet.mdot()/gas.density()
t0 = self.inlet.temperature()
V0 = 0.0
tsurf = self.surface.temperature()
zz = self.flow.grid()
dz = zz[-1] - zz[0]
if products == 'equil':
gas.equilibrate('HP')
teq = gas.temperature()
yeq = gas.massFractions()
locs = array([0.0, 0.3, 0.7, 1.0],'d')
self.setProfile('T', locs, [t0, teq, teq, tsurf])
for n in range(nsp):
self.setProfile(gas.speciesName(n), locs, [yin[n], yeq[n], yeq[n], yeq[n]])
else:
locs = array([0.0, 1.0],'d')
self.setProfile('T', locs, [t0, tsurf])
for n in range(nsp):
self.setProfile(gas.speciesName(n), locs, [yin[n], yin[n]])
locs = array([0.0, 1.0],'d')
self.setProfile('u', locs, [u0, 0.0])
self.setProfile('V', locs, [V0, V0])
self._initialized = 1
def solve(self, loglevel = 1, refine_grid = 1):
if not self._initialized: self.init()
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
def setRefineCriteria(self, ratio = 10.0, slope = 0.8,
curve = 0.8, prune = 0.0):
Stack.setRefineCriteria(self, domain = self.flow,
ratio = ratio, slope = slope, curve = curve,
prune = prune)
def setGridMin(self, gridmin):
Stack.setGridMin(self, self.flow, gridmin)
def setProfile(self, component, locs, vals):
self._initialized = 1
Stack.setProfile(self, self.flow, component, locs, vals)
def set(self, tol = None, energy = '', tol_time = None):
"""Set parameters.
:param tol:
(rtol, atol) for steady-state
:param tol_time:
(rtol, atol) for time stepping
:param energy:
'on' or 'off' to enable or disable the energy equation
"""
if tol:
self.flow.setTolerances(default = tol)
if tol_time:
self.flow.setTolerances(default = tol_time, time = 1)
if energy:
self.flow.set(energy = energy)
def T(self, point = -1):
"""The temperature [K]"""
return self.solution('T', point)
def u(self, point = -1):
"""The axial velocity [m/s]"""
return self.solution('u', point)
def V(self, point = -1):
"""The radial velocity divided by radius [s^-1]"""
return self.solution('V', point)
def solution(self, component = '', point = -1):
"""The solution for one specified component. If a point number
is given, return the value of component *component* at this
point. Otherwise, return the entire profile for this
component."""
if point >= 0: return self.value(self.flow, component, point)
else: return self.profile(self.flow, component)
def coverages(self):
"""The coverages of the surface species."""
nsurf = self.surfchem.nSpecies()
cov = zeros(nsurf,'d')
for n in range(nsurf):
nm = self.surfchem.speciesName(n)
cov[n] = self.value(self.surface, nm, 0)
return cov
def setGasState(self, j):
"""Set the state of the object representing the gas to the
current solution at grid point *j*."""
nsp = self.gas.nSpecies()
y = zeros(nsp, 'd')
for n in range(nsp):
nm = self.gas.speciesName(n)
y[n] = self.solution(nm, j)
self.gas.setState_TPY(self.T(j), self.flow.pressure(), y)
fix_docs(StagnationFlow)

View file

@ -1,8 +0,0 @@
"""
The classes in this package implement one-dimensional reacting flow problems.
"""
from onedim import *
from BurnerFlame import BurnerFlame
from BurnerDiffFlame import BurnerDiffFlame
from CounterFlame import CounterFlame
from StagnationFlow import StagnationFlow

View file

@ -1,746 +0,0 @@
from Cantera import *
from Cantera import _cantera
from Cantera.num import asarray, zeros
_onoff = {'on':1, 'yes':1, 'off':0, 'no':0, 1:1, 0:0}
class Domain1D:
"""Base class for one-dimensional domains."""
def __init__(self):
self._hndl = 0
def __del__(self):
_cantera.domain_del(self._hndl)
def domain_hndl(self):
"""Integer used to reference the kernel object."""
return self._hndl
def type(self):
"""Domain type. Integer."""
return _cantera.domain_type(self._hndl)
def index(self):
"""Index of this domain in a stack. Returns -1 if this domain
is not part of a stack."""
return _cantera.domain_index(self._hndl)
def nComponents(self):
"""Number of solution components at each grid point."""
return _cantera.domain_nComponents(self._hndl)
def nPoints(self):
"""Number of grid points belonging to this domain."""
return _cantera.domain_nPoints(self._hndl)
def componentName(self, n):
"""Name of the nth component."""
return _cantera.domain_componentName(self._hndl, n)
def componentNames(self):
"""List of the names of all components of this domain."""
names = []
for n in range(self.nComponents()):
names.append(self.componentName(n))
return names
def componentIndex(self, name):
"""Index of the component with name 'name'"""
return _cantera.domain_componentIndex(self._hndl, name)
def setBounds(self, **bounds):
"""Set the lower and upper bounds on the solution.
The argument list should consist of keyword/value pairs, with
component names as keywords and (lower_bound, upper_bound)
tuples as the values. The keyword *default* may be used to
specify default bounds for all unspecified components. The
keyword *Y* can be used to stand for all species mass
fractions in flow domains.
>>> d.setBounds(default=(0, 1),
... Y=(-1.0e-5, 2.0))
"""
d = {}
if bounds.has_key('default'):
for n in range(self.nComponents()):
d[self.componentName(n)] = bounds['default']
del bounds['default']
for b in bounds.keys():
if b == 'Y':
if self.type >= 50:
nc = self.nComponents()
for n in range(4, nc):
d[self.componentName(n)] = bounds[b]
else:
raise CanteraError('Y can only be specified in flow domains.')
else:
d[b] = bounds[b]
for b in d.keys():
n = self.componentIndex(b)
_cantera.domain_setBounds(self._hndl, n, d[b][0], d[b][1])
def bounds(self, component):
"""Return the (lower, upper) bounds for a solution component.
>>> d.bounds('T')
(200.0, 5000.0)
"""
ic = self.componentIndex(component)
lower = _cantera.domain_lowerBound(self._hndl, ic)
upper = _cantera.domain_upperBound(self._hndl, ic)
return (lower, upper)
def tolerances(self, component):
"""Return the (relative, absolute) error tolerances for
a solution component.
>>> (r, a) = d.tolerances('u')
"""
ic = self.componentIndex(component)
r = _cantera.domain_rtol(self._hndl, ic)
a = _cantera.domain_atol(self._hndl, ic)
return (r, a)
def setTolerances(self, **tol):
"""Set the error tolerances. If *time* is present and
non-zero, then the values entered will apply to the transient
problem. Otherwise, they will apply to the steady-state
problem.
The argument list should consist of keyword/value pairs, with
component names as keywords and (rtol, atol) tuples as the
values. The keyword *default* may be used to specify default
bounds for all unspecified components. The keyword *Y* can be
used to stand for all species mass fractions in flow domains.
>>> d.setTolerances(Y=(1.0e-5, 1.0e-9),
... default=(1.0e-7, 1.0e-12),
... time=1)
"""
d = {}
if tol.has_key('default'):
for n in range(self.nComponents()):
d[self.componentName(n)] = tol['default']
del tol['default']
itime = 0
for b in tol.keys():
if b == 'time': itime = -1
elif b == 'steady': itime = 1
elif b == 'Y':
if self.type >= 50:
nc = self.nComponents()
for n in range(4, nc):
d[self.componentName(n)] = tol[b]
else:
raise CanteraError('Y can only be specified in flow domains.')
else:
d[b] = tol[b]
for b in d.keys():
n = self.componentIndex(b)
# print 'setting tol for ',b,' itime = ',itime
_cantera.domain_setTolerances(self._hndl, n, d[b][0], d[b][1], itime)
def setupGrid(self, grid):
"""Specify the grid.
>>> d.setupGrid([0.0, 0.1, 0.2])
"""
return _cantera.domain_setupGrid(self._hndl, asarray(grid))
def setID(self, id):
return _cantera.domain_setID(self._hndl, id)
def setDesc(self, desc):
"""Set the description of this domain."""
return _cantera.domain_setDesc(self._hndl, desc)
def grid(self, n = -1):
""" If *n* >= 0, return the value of the nth grid point
from the left in this domain. If n is not supplied, return
the entire grid.
>>> z4 = d.grid(4)
>>> z_array = d.grid()
"""
if n >= 0:
return _cantera.domain_grid(self._hndl, n)
else:
g = zeros(self.nPoints(),'d')
for j in range(len(g)):
g[j] = _cantera.domain_grid(self._hndl, j)
return g
def set(self, **options):
"""
convenient function to invoke other methods.
Parameters that can be set:
grid, name, desc
>>> d.set(name='flame', grid=z)
"""
self._set(options)
def _set(self, options):
for opt in options.keys():
v = options[opt]
if opt == 'grid':
self.setupGrid(v)
elif opt == 'name':
self.setID(v)
elif opt == 'desc':
self.setDesc(v)
#elif opt == 'bounds':
# lower, upper = self._dict2arrays(v)
# self.setBounds(lower,upper)
#elif opt == 'tol':
# self.setTolerances(v[0],v[1])
#else:
# raise CanteraError('unknown attribute: '+opt)
def _dict2arrays(self, d = None, array1 = None, array2 = None):
nc = self.nComponents()
if d.has_key('default'):
a1 = zeros(nc,'d') + d['default'][0]
a2 = zeros(nc,'d') + d['default'][1]
del d['default']
else:
if array1: a1 = array(array1)
else: a1 = zeros(nc,'d')
if array2: a2 = array(array2)
else: a2 = zeros(nc,'d')
for k in d.keys():
c = self.componentIndex(k)
if c >= 0:
a1[self.componentIndex(k)] = d[k][0]
a2[self.componentIndex(k)] = d[k][1]
else:
raise CanteraError('unknown component '+k)
return (a1, a2)
class Bdry1D(Domain1D):
"""Base class for boundary domains."""
def __init__(self):
Domain1D.__init__(self)
def setMdot(self, mdot):
"""Set the mass flow rate per unit area [kg/m2]."""
_cantera.bdry_setMdot(self._hndl, mdot)
def setTemperature(self, t):
"""Set the temperature [K]"""
_cantera.bdry_setTemperature(self._hndl, t)
def setMoleFractions(self, x):
"""set the mole fraction values. """
_cantera.bdry_setMoleFractions(self._hndl, x)
def temperature(self):
"""Set the temperature [K]."""
return _cantera.bdry_temperature(self._hndl)
def massFraction(self, k):
"""The mass fraction of species k."""
return _cantera.bdry_massFraction(self._hndl, k)
def mdot(self):
"""The mass flow rate per unit area [kg/m2/s"""
return _cantera.bdry_mdot(self._hndl)
def set(self, **options):
"""Set parameters:
mdot or massflux
temperature or T
mole_fractions or X
"""
for opt in options.keys():
v = options[opt]
if opt == 'mdot' or opt == 'massflux':
self.setMdot(v)
del options[opt]
elif opt == 'temperature' or opt == 'T':
self.setTemperature(v)
del options[opt]
elif opt == 'mole_fractions' or opt == 'X':
self.setMoleFractions(v)
del options[opt]
self._set(options)
class Inlet(Bdry1D):
"""A one-dimensional inlet.
Note that an inlet can only be a terminal domain - it must be
either the leftmost or rightmost domain in a stack.
"""
def __init__(self, id = 'inlet'):
Bdry1D.__init__(self)
self._hndl = _cantera.inlet_new()
if id: self.setID(id)
def setSpreadRate(self, V0 = 0.0):
"""Set the spead rate, defined as the value of V = v/r at the inlet."""
_cantera.inlet_setSpreadRate(self._hndl, V0)
class Outlet(Bdry1D):
"""A one-dimensional outlet. An outlet imposes a
zero-gradient boundary condition on the flow."""
def __init__(self, id = 'outlet'):
Bdry1D.__init__(self)
self._hndl = _cantera.outlet_new()
if id: self.setID(id)
class OutletRes(Bdry1D):
"""A one-dimensional outlet into a reservoir."""
def __init__(self, id = 'outletres'):
Bdry1D.__init__(self)
self._hndl = _cantera.outletres_new()
if id: self.setID(id)
class SymmPlane(Bdry1D):
"""A symmetry plane."""
def __init__(self, id = 'symmetry_plane'):
Bdry1D.__init__(self)
self._hndl = _cantera.symm_new()
if id: self.setID(id)
class Surface(Bdry1D):
"""A surface (possibly reacting)."""
def __init__(self, id = 'surface', surface_mech = None):
Bdry1D.__init__(self)
if surface_mech:
self._hndl = _cantera.reactingsurf_new()
self.setKineticsMgr(surface_mech)
else:
self._hndl = _cantera.surf_new()
if id: self.setID(id)
def setKineticsMgr(self, kin):
"""Set the kinetics manager (surface reaction mechanism object)."""
_cantera.reactingsurf_setkineticsmgr(self._hndl,
kin.kinetics_hndl())
def setCoverageEqs(self, onoff='on'):
"""Turn solving the surface coverage equations on or off."""
if onoff == 'on':
_cantera.reactingsurf_enableCoverageEqs(self._hndl, 1)
else:
_cantera.reactingsurf_enableCoverageEqs(self._hndl, 0)
class AxisymmetricFlow(Domain1D):
"""An axisymmetric flow domain.
In an axisymmetric flow domain, the equations solved are the
similarity equations for the flow in a finite-height gap of
infinite radial extent. The solution variables are
*u*
axial velocity
*V*
radial velocity divided by radius
*T*
temperature
*lambda*
(1/r)(dP/dr)
*Y_k*
species mass fractions
It may be shown that if the boundary conditions on these variables
are independent of radius, then a similarity solution to the exact
governing equations exists in which these variables are all
independent of radius. This solution holds only in in
low-Mach-number limit, in which case (dP/dz) = 0, and lambda is a
constant. (Lambda is treated as a spatially-varying solution
variable for numerical reasons, but in the final solution it is
always independent of z.) As implemented here, the governing
equations assume an ideal gas mixture. Arbitrary chemistry is
allowed, as well as arbitrary variation of the transport
properties.
"""
def __init__(self, id = 'axisymmetric_flow', gas = None, type = 1):
Domain1D.__init__(self)
iph = gas.thermo_hndl()
ikin = gas.kinetics_hndl()
itr = gas.transport_hndl()
self._hndl = _cantera.stflow_new(iph, ikin, itr, type)
if id: self.setID(id)
self.setPressure(gas.pressure())
self.solveEnergyEqn()
def setPressure(self, p):
"""Set the pressure [Pa]. The pressure is a constant, since
the governing equations are those for the low-Mach-number limit."""
_cantera.stflow_setPressure(self._hndl, p)
def setTransportModel(self, transp, withSoret = 0):
"""Set the transport model. The argument must be a transport
manager for the 'gas' object."""
itr = transp.transport_hndl()
_cantera.stflow_setTransport(self._hndl, itr, withSoret)
def enableSoret(self, withSoret = 1):
"""Include or exclude thermal diffusion (Soret effect) when computing
diffusion velocities. If withSoret is not supplied or is positive,
thermal diffusion is enabled; otherwise it is disabled."""
_cantera.stflow_enableSoret(self._hndl, withSoret)
def pressure(self):
"""Pressure [Pa]."""
return _cantera.stflow_pressure(self._hndl)
def setFixedTempProfile(self, pos, temp):
"""Set the fixed temperature profile. This profile is used
whenever the energy equation is disabled.
:param pos:
arrray of relative positions from 0 to 1
:param temp:
array of temperature values
>>> d.setFixedTempProfile(array([0.0, 0.5, 1.0]),
... array([500.0, 1500.0, 2000.0])
"""
return _cantera.stflow_setFixedTempProfile(self._hndl, pos, temp)
def solveSpeciesEqs(self, flag = 1):
"""Enable or disable solving the species equations. If invoked
with no arguments or with a non-zero argument, the species
equations will be solved. If invoked with a zero argument,
they will not be, and instead the species profiles will be
held at their initial values. Default: species equations
enabled."""
return _cantera.stflow_solveSpeciesEqs(self._hndl, _onoff[flag])
def solveEnergyEqn(self, flag = 1):
"""Enable or disable solving the energy equation. If invoked
with no arguments or with a non-zero argument, the energy
equations will be solved. If invoked with a zero argument,
it will not be, and instead the temperature profiles will be
held to the one specified by the call to :meth:`.setFixedTempProfile`.
Default: energy equation enabled."""
return _cantera.stflow_solveEnergyEqn(self._hndl, _onoff[flag])
def set(self, **opt):
"""Set parameters.
In addition to the parameters that may be set by Domain1D.set,
this method can be used to set the pressure and energy flag
>>> d.set(pressure=OneAtm, energy='on')
"""
for o in opt.keys():
v = opt[o]
if o == 'P' or o == 'pressure':
self.setPressure(v)
del opt[o]
elif o == 'energy':
self.solveEnergyEqn(flag = _onoff[v])
else:
self._set(opt)
class Stack:
""" Class Stack is a container for one-dimensional domains. It
also holds the multi-domain solution vector, and controls the
process of finding the solution.
Domains are ordered left-to-right, with domain number 0 at the left.
This class is largely a shadow class for C++ kernel class Sim1D.
"""
def __init__(self, domains = None):
self._hndl = 0
nd = len(domains)
hndls = zeros(nd,'i')
for n in range(nd):
hndls[n] = domains[n].domain_hndl()
self._hndl = _cantera.sim1D_new(hndls)
self._domains = domains
self._initialized = False
def __del__(self):
_cantera.sim1D_del(self._hndl)
def setValue(self, dom, comp, localPoint, value):
"""Set the value of one component in one domain at one point
to 'value'.
:param dom:
domain object
:param comp:
component number
:param localPoint:
grid point number within domain *dom* starting with zero on the left
:param value:
numerical value
>>> s.set(d, 3, 5, 6.7)
"""
idom = dom.domain_hndl()
_cantera.sim1D_setValue(self._hndl, idom,
comp, localPoint, value)
def setProfile(self, dom, comp, pos, v):
"""Set an initial estimate for a profile of one component in
one domain.
:param dom:
domain object
:param comp:
component name
:param pos:
sequence of relative positions, from 0 on the left to 1 on the right
:param v:
sequence of values at the relative positions specified in 'pos'
>>> s.setProfile(d, 'T', [0.0, 0.2, 1.0], [400.0, 800.0, 1500.0])
"""
idom = dom.index()
icomp = dom.componentIndex(comp)
_cantera.sim1D_setProfile(self._hndl, idom, icomp,
asarray(pos), asarray(v))
def setFlatProfile(self, dom, comp, v):
"""Set a flat profile for one component in one domain.
:param dom:
domain object
:param comp:
component name
:param v:
value
>>> s.setFlatProfile(d, 'u', -3.0)
"""
idom = dom.index()
icomp = dom.componentIndex(comp)
_cantera.sim1D_setFlatProfile(self._hndl, idom, icomp, v)
def showSolution(self, fname='-'):
"""Show the current solution. If called with no argument,
the solution is printed to the screen. If a filename is
supplied, it is written to the file.
>>> s.showSolution()
>>> s.showSolution('soln.txt')
"""
if not self._initialized:
self.init()
_cantera.sim1D_showSolution(self._hndl, fname)
def setTimeStep(self, stepsize, nsteps):
"""Set the sequence of time steps to try when Newton fails.
:param stepsize:
initial time step size [s]
:param nsteps:
sequence of integer step numbers
>>> s.setTimeStep(1.0e-5, [1, 2, 5, 10])
"""
# 3/20/09
# The use of asarray seems to set the nsteps array to be of
# type double. This needs to be checked out further.
# Probably a function of python version and Numerics version
_cantera.sim1D_setTimeStep(self._hndl, stepsize, asarray(nsteps))
def getInitialSoln(self):
"""Load the initial solution from each domain into the global
solution vector."""
_cantera.sim1D_getInitialSoln(self._hndl)
def solve(self, loglevel=1, refine_grid=1):
"""Solve the problem.
:param loglevel:
integer flag controlling the amount of diagnostic output. Zero
suppresses all output, and 5 produces very verbose output. Default: 1
:param refine_grid:
if non-zero, enable grid refinement."""
return _cantera.sim1D_solve(self._hndl, loglevel, refine_grid)
def refine(self, loglevel=1):
"""Refine the grid, adding points where solution is not
adequately resolved."""
return _cantera.sim1D_refine(self._hndl, loglevel)
def setRefineCriteria(self, domain = None, ratio = 10.0, slope = 0.8,
curve = 0.8, prune = 0.05):
"""Set the criteria used to refine one domain.
:param domain:
domain object
:param ratio:
additional points will be added if the ratio of the spacing
on either side of a grid point exceeds this value
:param slope:
maximum difference in value between two adjacent points, scaled by
the maximum difference in the profile (0.0 < slope < 1.0). Adds
points in regions of high slope.
:param curve:
maximum difference in slope between two adjacent intervals, scaled
by the maximum difference in the profile (0.0 < curve < 1.0). Adds
points in regions of high curvature.
:param prune:
if the slope or curve criteria are satisfied to the level of
'prune', the grid point is assumed not to be needed and is removed.
Set prune significantly smaller than 'slope' and 'curve'. Set to
zero to disable pruning the grid.
>>> s.setRefineCriteria(d, ratio=5.0, slope=0.2, curve=0.3,
... prune=0.03)
"""
idom = domain.index()
return _cantera.sim1D_setRefineCriteria(self._hndl,
idom, ratio, slope, curve, prune)
def setGridMin(self, domain, gridmin):
"""
Set the minimum allowable grid spacing in a domain.
:param domain:
domain object
:param gridmin:
The minimum allowable grid spacing [m] for this domain
"""
idom = domain.index()
return _cantera.sim1D_setGridMin(self._hndl, idom, gridmin)
def save(self, file = 'soln.xml', id = 'solution', desc = 'none'):
"""Save the solution in XML format.
>>> s.save(file='save.xml', id='energy_off',
... desc='solution with energy eqn. disabled')
"""
return _cantera.sim1D_save(self._hndl, file, id, desc)
def restore(self, file = 'soln.xml', id = 'solution'):
"""Set the solution vector to a previously-saved solution.
:param file:
solution file
:param id:
solution name within the file
>>> s.restore(file = 'save.xml', id = 'energy_off')
"""
self._initialized = True
return _cantera.sim1D_restore(self._hndl, file, id)
def showStats(self, printTime = 1):
"""Show the statistics for the last solution.
If invoked with no arguments or with a non-zero argument, the
timing statistics will be printed. If invoked with a zero argument,
the timing will not be printed.
Default: print timing enabled.
"""
return _cantera.sim1D_writeStats(self._hndl, _onoff[printTime])
def domainIndex(self, name):
"""Integer index of the domain with name 'name'"""
return _cantera.sim1D_domainIndex(self._hndl, name)
def value(self, domain, component, localPoint):
"""Solution value at one point.
:param domain:
domain object
:param component:
component name
:param localPoint:
grid point number in the domain, starting with zero at the left
>>> t = s.value(flow, 'T', 6)
"""
icomp = domain.componentIndex(component)
idom = domain.index()
return _cantera.sim1D_value(self._hndl, idom, icomp, localPoint)
def profile(self, domain, component):
"""Spatial profile of one component in one domain.
>>> print s.profile(flow, 'T')
"""
np = domain.nPoints()
x = zeros(np,'d')
for n in range(np):
x[n] = self.value(domain, component, n)
return x
def workValue(self, dom, icomp, localPoint):
"""Internal work array value at one point. After calling eval,
this array contains the values of the residual function.
:param domain:
domain object
:param component:
component name
:param localPoint:
grid point number in the domain, starting with zero at the left
>>> t = s.value(flow, 'T', 6)
"""
idom = dom.index()
return _cantera.sim1D_workValue(self._hndl, idom, icomp, localPoint)
def eval(self, rdt, count=1):
"""Evaluate the residual function. If count = 0, do is 'silently',
without adding to the function evaluation counter"""
return _cantera.sim1D_eval(self._hndl, rdt, count)
def setMaxJacAge(self, ss_age, ts_age):
"""Set the maximum number of times the Jacobian will be used
before it must be re-evaluated.
:param ss_age:
age criterion during steady-state mode
:param ts_age:
age criterion during time-stepping mode
"""
return _cantera.sim1D_setMaxJacAge(self._hndl, ss_age, ts_age)
def timeStepFactor(self, tfactor):
"""Set the factor by which the time step will be increased
after a successful step, or decreased after an unsuccessful one.
>>> s.timeStepFactor(3.0)
"""
return _cantera.sim1D_timeStepFactor(self._hndl, tfactor)
def setTimeStepLimits(self, tsmin, tsmax):
"""Set the maximum and minimum time steps."""
return _cantera.sim1D_setTimeStepLimits(self._hndl, tsmin, tsmax)
def setFixedTemperature(self, temp):
"""This is a temporary fix."""
_cantera.sim1D_setFixedTemperature(self._hndl, temp)
def clearDomains():
"""Clear all domains."""
_cantera.domain_clear()
def clearSim1D():
"""Clear all stacks."""
_cantera.sim1D_clear()

View file

@ -1,351 +0,0 @@
"""Cantera.Phase
This module provides class Phase.
"""
import _cantera
import types
from Cantera.num import asarray
from exceptions import CanteraError
# return true is x is a sequence
def _isseq(n, x):
try:
y = x[n-1]
return 1
except:
return 0
class Phase:
"""Phases of matter.
Class Phase manages basic state and constituent property
information for a homogeneous phase of matter. It handles only
those properties that do not require the equation of state, namely
the temperature, density, chemical composition, and attributes of
the elements and species.
It does not know about the pressure, or any other thermodynamic property
requiring the equation of state -- class ThermoPhase derives from Phase
and adds those properties.
Class Phase is not usually instantiated directly. It is used as a
base class for class ThermoPhase.
"""
#def __init__(self, index = -1):
# pass
def phase_id(self):
"""The integer index used to access the kernel-level object.
Internal."""
return self._phase_id
def nElements(self):
"""Number of elements."""
return _cantera.phase_nelements(self._phase_id)
def atomicWeights(self, elements = []):
"""Array of element molar masses [kg/kmol].
If a sequence of element symbols is supplied, only the values
for those elements are returned, ordered as in the
list. Otherwise, the values are for all elements in the phase,
ordered as in the input file. """
atw = _cantera.phase_getarray(self._phase_id,1)
if elements:
ae = []
m = 0
for e in elements:
m = self.elementIndex(e)
ae.append(atw[m])
return asarray(ae)
else:
return atw
def nSpecies(self):
"""Number of species."""
return _cantera.phase_nspecies(self._phase_id)
def nAtoms(self, species = None, element = None):
"""Number of atoms of element *element* in species *species*.
The element and species may be specified by name or by number.
>>> ph.nAtoms('CH4','H')
4
"""
try:
m = self.elementIndex(element)
k = self.speciesIndex(species)
na = _cantera.phase_natoms(self._phase_id, k, m)
#if na < 0: return 0
return na
except CanteraError:
return 0
def temperature(self):
"""Temperature [K]."""
return _cantera.phase_temperature(self._phase_id)
def density(self):
"""Mass density [kg/m^3]."""
return _cantera.phase_density(self._phase_id)
def volume_mass(self):
"""Specific volume [m^3/kg]."""
return 1.0/_cantera.phase_density(self._phase_id)
def molarDensity(self):
"""Molar density [kmol/m^3]."""
return _cantera.phase_molardensity(self._phase_id)
def meanMolecularWeight(self):
"""Mean molar mass [kg/kmol]."""
return _cantera.phase_meanmolwt(self._phase_id)
def meanMolarMass(self):
"""Mean molar mass [kg/kmol]."""
return _cantera.phase_meanmolwt(self._phase_id)
def molarMasses(self, species = None):
"""Array of species molar masses [kg/kmol]."""
mm = _cantera.phase_getarray(self._phase_id,22)
return self.selectSpecies(mm, species)
def molecularWeights(self, species = None):
"""Array of species molar masses [kg/kmol]."""
return self.molarMasses(species)
def moleFractions(self, species = None):
"""Species mole fraction array.
If optional argument *species* is supplied, then only the values
for the selected species are returned.
>>> x1 = ph.moleFractions() # all species
>>> x2 = ph.moleFractions(['OH', 'CH3'. 'O2'])
"""
x = _cantera.phase_getarray(self._phase_id,20)
return self.selectSpecies(x, species)
def moleFraction(self, species):
"""Mole fraction of a species, referenced by name or index number.
>>> ph.moleFraction(4)
>>> ph.moleFraction('CH4')
"""
k = self.speciesIndex(species)
return _cantera.phase_molefraction(self._phase_id,k)
def massFractions(self, species = None):
"""Species mass fraction array.
If optional argument *species* is supplied, then only the values for
the selected species are returned.
>>> y1 = ph.massFractions() # all species
>>> y2 = ph.massFractions(['OH', 'CH3'. 'O2'])
"""
y = _cantera.phase_getarray(self._phase_id,21)
return self.selectSpecies(y, species)
def massFraction(self, species):
"""Mass fraction of one species, referenced by name or
index number.
>>> ph.massFraction(4)
>>> ph.massFraction('CH4')
"""
k = self.speciesIndex(species)
return _cantera.phase_massfraction(self._phase_id,k)
def elementName(self,m):
"""Name of the element with index number *m*."""
return _cantera.phase_getstring(self._phase_id,1,m)
def elementNames(self):
"""Return a tuple of all element names."""
nel = self.nElements()
return map(self.elementName,range(nel))
def elementIndex(self, element):
"""The index of element *element*, which may be specified as
a string or an integer index. In the latter case, the index is
checked for validity and returned. If no such element is
present, an exception is thrown."""
nel = self.nElements()
if type(element) == types.IntType:
m = element
else:
m = _cantera.phase_elementindex(self._phase_id, element)
if m < 0 or m >= nel:
raise CanteraError("""Element """+element+""" not in set """
+`self.elementNames()`)
return m
def speciesName(self,k):
"""Name of the species with index *k*."""
return _cantera.phase_getstring(self._phase_id,2,k)
def speciesNames(self):
"""Return a tuple of all species names."""
nsp = self.nSpecies()
return map(self.speciesName,range(nsp))
def speciesIndex(self, species):
"""The index of species *species*, which may be specified as
a string or an integer index. In the latter case, the index is
checked for validity and returned. If no such species is
present, an exception is thrown."""
nsp = self.nSpecies()
if type(species) == types.ListType:
s = []
for sp in species:
s.append(self.speciesIndex(sp))
return s
if type(species) == types.IntType or type(species) == types.FloatType:
k = species
else:
k = _cantera.phase_speciesindex(self._phase_id,species)
if k < 0 or k >= nsp:
raise CanteraError("""Species """+`species`+""" not in set """
+`self.speciesNames()`)
return k
def setTemperature(self, t):
"""Set the temperature [K]."""
_cantera.phase_setfp(self._phase_id,1,t)
def setDensity(self, rho):
"""Set the density [kg/m3]."""
_cantera.phase_setfp(self._phase_id,2,rho)
def setMolarDensity(self, n):
"""Set the density [kmol/m3]."""
_cantera.phase_setfp(self._phase_id,3,n)
def setMoleFractions(self, x, norm = 1):
"""Set the mole fractions.
:param x:
string or array of mole fraction values
:param norm:
If non-zero (default), array values will be scaled to sum to 1.0.
>>> ph.setMoleFractions('CO:1, H2:7, H2O:7.8')
>>> x = [1.0]*ph.nSpecies()
>>> ph.setMoleFractions(x)
>>> ph.setMoleFractions(x, norm = 0) # don't normalize values
"""
if type(x) == types.StringType:
_cantera.phase_setstring(self._phase_id,1,x)
elif _isseq(self.nSpecies(), x):
_cantera.phase_setarray(self._phase_id,1,norm,asarray(x))
else:
raise CanteraError('mole fractions must be a string or array')
def setMassFractions(self, x, norm = 1):
"""Set the mass fractions.
See :meth:`~.Phase.setMoleFractions`
"""
if type(x) == types.StringType:
_cantera.phase_setstring(self._phase_id,2,x)
elif _isseq(self.nSpecies(), x):
_cantera.phase_setarray(self._phase_id,2,norm,asarray(x))
else:
raise CanteraError('mass fractions must be a string or array')
def setState_TRX(self, t, rho, x):
"""Set the temperature, density, and mole fractions. The mole
fractions may be entered as a string or array,
>>> ph.setState_TRX(600.0, 2.0e-3, 'CH4:0.4, O2:0.6')
"""
self.setTemperature(t)
self.setMoleFractions(x)
self.setDensity(rho)
def setState_TNX(self, t, n, x):
"""Set the temperature, molardensity, and mole fractions. The mole
fractions may be entered as a string or array,
>>> ph.setState_TNX(600.0, 2.0e-3, 'CH4:0.4, O2:0.6')
"""
self.setTemperature(t)
self.setMoleFractions(x)
self.setMolarDensity(n)
def setState_TRY(self, t, rho, y):
"""Set the temperature, density, and mass fractions."""
self.setTemperature(t)
self.setMassFractions(y)
self.setDensity(rho)
def setState_TR(self, t, rho):
"""Set the temperature and density, leaving the composition
unchanged."""
self.setTemperature(t)
self.setDensity(rho)
def selectSpecies(self, f, species):
"""Given an array *f* of floating-point species properties, return
those values corresponding to species listed in *species*. Returns an
array if *species* is a sequence, or a scalar if *species* is a
scalar. This method is used internally to implement species selection
in methods like moleFractions, massFractions, etc.
>>> f = ph.chemPotentials()
>>> muo2, muh2 = ph.selectSpecies(f, ['O2', 'H2'])
>>> muh2 = ph.selectSpecies(f, 'H2')
"""
if isinstance(species, types.StringTypes):
k = self.speciesIndex(species)
return f[k]
elif species:
fs = []
k = 0
for s in species:
k = self.speciesIndex(s)
fs.append(f[k])
return asarray(fs)
else:
return asarray(f)
def selectElements(self, f, elements):
"""Given an array *f* of floating-point element properties, return a
those values corresponding to elements listed in *elements*. Returns an
array if *elements* is a sequence, or a scalar if *elements* is a
scalar.
>>> f = ph.elementPotentials()
>>> lam_o, lam_h = ph.selectElements(f, ['O', 'H'])
>>> lam_h = ph.selectElements(f, 'H')
"""
if isinstance(elements, types.StringTypes):
m = self.elementIndex(elements)
return f[m]
if elements:
fs = []
k = 0
for s in elements:
k = self.elementIndex(s)
fs.append(f[k])
return asarray(fs)
else:
return asarray(f)

File diff suppressed because it is too large Load diff

View file

@ -1,32 +0,0 @@
"""
Transport properties for solids.
This class implements a simple model for the diffusion coefficients and
the thermal conductivity of a solid. The diffusion coefficients have
modified Arrhenius form, and the thermal conductivity is constant.
All parameters are user-specified, not computed from a physical model.
Examples:
>>> tr = SolidTransport(solid_phase)
>>> tr.setThermalConductivity(0.5) # W/m/K
>>> tr.setDiffCoeff(species = "OxygenIon", A = 2.0, n = 0.0, E = 700.0)
Note that the diffusion coefficient is computed from D = A * T^n *
exp(-E/t) in m^2/s. Diffusion coefficients for unspecified species are
set to zero.
"""
from Cantera.Transport import Transport
class SolidTransport(Transport):
def __init__(self, phase = None):
Transport.__init__(self, model = "Solid", phase = phase)
def setThermalConductivity(self, lamb):
self.setParameters(1, 0, [lamb, 0.0])
def setDiffCoeff(self, species = "", A = 0.0, n = 0.0, E = 0.0):
k = self._phase.speciesIndex(species)
self.setParameters(0, k, [A, n, E])

View file

@ -1,49 +0,0 @@
from ThermoPhase import ThermoPhase
from exceptions import CanteraError
from Cantera.num import asarray
import _cantera
class SurfacePhase(ThermoPhase):
"""A class for surface phases."""
def __init__(self, xml_phase=None, index=-1):
ThermoPhase.__init__(self, xml_phase=xml_phase, index=index)
def setSiteDensity(self, n0):
"""Set the site density."""
_cantera.surf_setsitedensity(self._phase_id, n0)
def siteDensity(self):
"""Site density [kmol/m2]"""
return _cantera.surf_sitedensity(self._phase_id)
def setCoverages(self, theta):
"""Set the surface coverages to the values in array *theta*."""
nt = len(theta)
if nt == self.nSpecies():
_cantera.surf_setcoverages(self._phase_id,
asarray(theta,'d'))
else:
raise CanteraError('expected '+`self.nSpecies()`+
' coverage values, but got '+`nt`)
def coverages(self):
"""Return the array of surface coverages."""
return _cantera.surf_getcoverages(self._phase_id)
def setConcentrations(self, conc):
"""Set the surface concentrations to the values in
array *conc*."""
_cantera.surf_setconcentrations(self._phase_id, conc)
def concentrations(self):
"""Return the array of surface concentrations [kmol/m2]."""
return _cantera.surf_getconcentrations(self._phase_id)
class EdgePhase(SurfacePhase):
"""A one-dimensonal edge."""
def __init__(self, xml_phase=None, index=-1):
SurfacePhase.__init__(self, xml_phase=xml_phase, index=index)

View file

@ -1,340 +0,0 @@
"""
This module implements class ThermoPhase, a class representing
thermodynamic phases.
"""
from Cantera.num import zeros
from Cantera.Phase import Phase
import _cantera
import types
class ThermoPhase(Phase):
"""
A phase with an equation of state.
Class ThermoPhase may be used to represent the intensive
thermodynamic state of a phase of matter, which might be a gas,
liquid, or solid. Class ThermoPhase extends class Phase by
providing methods that require knowledge of the equation of state.
Class ThermoPhase is not usually instantiated directly. It is used
as base class for classes :class:`~Cantera.Solution` and
:class:`~Cantera.Interface.Interface`.
"""
# used in the 'equilibrate' method
_equilmap = {'TP':104,'TV':100,'HP':101,'SP':102,'SV':107,'UV':105,
'PT':104,'VT':100,'PH':101,'PS':102,'VS':107,'VU':105}
def __init__(self, xml_phase=None, index=-1):
"""
:param xml_phase:
CTML node specifying the attributes of this phase
:param index:
optional. If positive, create only a Python wrapper for an existing
kernel object, instead of creating a new kernel object. The value
of *index* is the integer index number to reference the existing
kernel object.
"""
self._phase_id = 0
self._owner = 0
self.idtag = ""
if index >= 0:
# create a Python wrapper for an existing kernel
# ThermoPhase instance
self._phase_id = index
elif xml_phase:
# create a new kernel instance from an XML specification
self._phase_id = _cantera.ThermoFromXML(xml_phase._xml_id)
self.idtag = xml_phase["id"]
self._owner = 1
else:
raise CanteraError('either xml_phase or index must be specified')
def __del__(self):
"""Delete the object. If it is the owner of the kernel object,
this is also deleted."""
if self._owner:
_cantera.thermo_delete(self._phase_id)
def name(self):
"""The name assigned to the phase. The default value is the name
attribute from the CTI file. But method setName can be used to
set the name to anything desired, e.g. 'gas at inlet' or 'exhaust'
"""
return self.idtag
def setName(self, name):
""" Set the name attribute. This can be any string"""
self.idtag = name
def refPressure(self):
"""Reference pressure [Pa].
All standard-state thermodynamic properties are for this pressure.
"""
return _cantera.thermo_refpressure(self._phase_id)
def minTemp(self, sp=None):
""" Minimum temperature for which thermodynamic property fits
are valid. If a species is specified (by name or number),
then the minimum temperature is for only this
species. Otherwise it is the lowest temperature for which the
properties are valid for all species. """
if not sp:
return _cantera.thermo_mintemp(self._phase_id, -1)
else:
return _cantera.thermo_mintemp(self._phase_id,
self.speciesIndex(sp))
def maxTemp(self, sp=None):
""" Maximum temperature for which thermodynamic property fits
are valid. If a species is specified (by name or number),
then the maximum temperature is for only this
species. Otherwise it is the highest temperature for which the
properties are valid for all species. """
if not sp:
return _cantera.thermo_maxtemp(self._phase_id, -1)
else:
return _cantera.thermo_maxtemp(self._phase_id,
self.speciesIndex(sp))
def enthalpy_mole(self):
""" The molar enthalpy [J/kmol]."""
return _cantera.thermo_getfp(self._phase_id,1)
def intEnergy_mole(self):
""" The molar internal energy [J/kmol]."""
return _cantera.thermo_getfp(self._phase_id,2)
def entropy_mole(self):
""" The molar entropy [J/kmol/K]."""
return _cantera.thermo_getfp(self._phase_id,3)
def gibbs_mole(self):
""" The molar Gibbs function [J/kmol]."""
return _cantera.thermo_getfp(self._phase_id,4)
def cp_mole(self):
""" The molar heat capacity at constant pressure [J/kmol/K]."""
return _cantera.thermo_getfp(self._phase_id,5)
def cv_mole(self):
""" The molar heat capacity at constant volume [J/kmol/K]."""
return _cantera.thermo_getfp(self._phase_id,6)
def pressure(self):
""" The pressure [Pa]."""
return _cantera.thermo_getfp(self._phase_id,7)
def electricPotential(self):
"""Electric potential [V]."""
return _cantera.thermo_getfp(self._phase_id,25)
def chemPotentials(self, species = []):
"""Species chemical potentials.
This method returns an array containing the species
chemical potentials [J/kmol]. The expressions used to
compute these depend on the model implemented by the
underlying kernel thermo manager."""
mu = _cantera.thermo_getarray(self._phase_id,20)
return self.selectSpecies(mu, species)
def elementPotentials(self, elements = []):
"""Element potentials of the elements.
This method returns an array containing the element potentials
[J/kmol]. The element potentials are only defined for
equilibrium states. This method first sets the composition to
a state of equilibrium holding T and P constant, then computes
the element potentials for this equilibrium state. """
lamb = _cantera.thermo_getarray(self._phase_id,21)
return self.selectElements(lamb, elements)
def enthalpies_RT(self, species = []):
"""Pure species non-dimensional reference state enthalpies.
This method returns an array containing the pure-species
standard-state enthalpies divided by RT. For gaseous species,
these values are ideal gas enthalpies."""
hrt = _cantera.thermo_getarray(self._phase_id,23)
return self.selectSpecies(hrt, species)
def entropies_R(self, species = []):
"""Pure species non-dimensional entropies.
This method returns an array containing the pure-species
standard-state entropies divided by R. For gaseous species,
these values are ideal gas entropies."""
sr = _cantera.thermo_getarray(self._phase_id,24)
return self.selectSpecies(sr, species)
def gibbs_RT(self, species = []):
"""Pure species non-dimensional Gibbs free energies.
This method returns an array containing the pure-species
standard-state Gibbs free energies divided by R.
For gaseous species, these are ideal gas values."""
grt = (_cantera.thermo_getarray(self._phase_id,23)
- _cantera.thermo_getarray(self._phase_id,24))
return self.selectSpecies(grt, species)
def cp_R(self, species = []):
"""Pure species non-dimensional heat capacities
at constant pressure.
This method returns an array containing the pure-species
standard-state heat capacities divided by R. For gaseous
species, these values are ideal gas heat capacities."""
cpr = _cantera.thermo_getarray(self._phase_id,25)
return self.selectSpecies(cpr, species)
def setPressure(self, p):
"""Set the pressure [Pa]."""
_cantera.thermo_setfp(self._phase_id,1,p,0.0)
def enthalpy_mass(self):
"""Specific enthalpy [J/kg]."""
return _cantera.thermo_getfp(self._phase_id,8)
def intEnergy_mass(self):
"""Specific internal energy [J/kg]."""
return _cantera.thermo_getfp(self._phase_id,9)
def entropy_mass(self):
"""Specific entropy [J/kg/K]."""
return _cantera.thermo_getfp(self._phase_id,10)
def gibbs_mass(self):
"""Specific Gibbs free energy [J/kg]."""
return _cantera.thermo_getfp(self._phase_id,11)
def cp_mass(self):
"""Specific heat at constant pressure [J/kg/K]."""
return _cantera.thermo_getfp(self._phase_id,12)
def cv_mass(self):
"""Specific heat at constant volume [J/kg/K]."""
return _cantera.thermo_getfp(self._phase_id,13)
def setState_TPX(self, t, p, x):
"""Set the temperature [K], pressure [Pa], and
mole fractions."""
self.setTemperature(t)
self.setMoleFractions(x)
self.setPressure(p)
def setState_TPY(self, t, p, y):
"""Set the temperature [K], pressure [Pa], and
mass fractions."""
self.setTemperature(t)
self.setMassFractions(y)
self.setPressure(p)
def setState_TP(self, t, p):
"""Set the temperature [K] and pressure [Pa]."""
self.setTemperature(t)
self.setPressure(p)
def setState_PX(self, p, x):
"""Set the pressure [Pa], and mole fractions."""
self.setMoleFractions(x)
self.setPressure(p)
def setState_PY(self, p, y):
"""Set the pressure [Pa], and mass fractions."""
self.setMassFractions(y)
self.setPressure(p)
def setState_HP(self, h, p):
"""Set the state by specifying the specific enthalpy and
the pressure."""
_cantera.thermo_setfp(self._phase_id, 2, h, p)
def setState_UV(self, u, v):
"""Set the state by specifying the specific internal
energy and the specific volume."""
_cantera.thermo_setfp(self._phase_id, 3, u, v)
def setState_SV(self, s, v):
"""Set the state by specifying the specific entropy
and the specific volume."""
_cantera.thermo_setfp(self._phase_id, 4, s, v)
def setState_SP(self, s, p):
"""Set the state by specifying the specific entropy
energy and the pressure."""
_cantera.thermo_setfp(self._phase_id, 5, s, p)
def setElectricPotential(self, v):
"""Set the electric potential."""
_cantera.thermo_setfp(self._phase_id, 6, v, 0);
def equilibrate(self, XY, solver = -1, rtol = 1.0e-9,
maxsteps = 1000, maxiter = 100, loglevel = 0):
"""
Set to a state of chemical equilibrium holding property pair
*XY* constant.
:param XY:
A two-letter string, which must be one of the set::
['TP','TV','HP','SP','SV','UV','PT','VT','PH','PS','VS','VU']
If H, U, S, or V is specified, the value must be the specific
value (per unit mass)
:param solver:
Specifies the equilibrium solver to use. If solver = 0, a fast
solver using the element potential method will be used. If
solver > 0, a slower but more robust Gibbs minimization solver
will be used. If solver < 0 or unspecified, the fast solver will
be tried first, then if it fails the other will be tried.
:param rtol:
the relative error tolerance.
:param maxsteps:
maximum number of steps in composition to take to find a converged
solution.
:param maxiter:
For the Gibbs minimization solver only, this specifies the number
of 'outer' iterations on T or P when some property pair other than
TP is specified.
:param loglevel:
Set to a value > 0 to write diagnostic output to a file in HTML
format. Larger values generate more detailed information. The file
will be named ``equilibrate_log.html.`` Subsequent files will be
named ``equilibrate_log1.html``, etc., so that log files are
not overwritten.
"""
_cantera.thermo_equil(self._phase_id, XY, solver,
rtol, maxsteps, maxiter, loglevel)
def saveState(self):
"""Return an array with state information that can later be
used to restore the state."""
state = zeros(self.nSpecies()+2,'d')
state[0] = self.temperature()
state[1] = self.density()
state[2:] = self.massFractions()
return state
def restoreState(self, s):
"""Restore the state to that stored in array s."""
self.setState_TRY(s[0], s[1], s[2:])
def thermophase(self):
"""Return the integer index that is used to
reference the kernel object. For internal use."""
return self._phase_id
def thermo_hndl(self):
"""Return the integer index that is used to
reference the kernel object. For internal use."""
return self._phase_id

View file

@ -1,178 +0,0 @@
""" Cantera provides a set of 'transport manager' classes that manage
the computation of transport properties. Every object representing a
phase of matter for which transport properties are needed has a
transport manager assigned to it. The transport manager has only one
job: to compute the values of the transport properties of its assigned
phase.
A transport manager may do things not apparent to the user in order to
improve the speed of transport property evaluation. For example, it
may cache intermediate results that depend only on temperature, so
that if it happens to be called again at the same temperature (a
common occurrence) it can skip over computing the stored
temperature-dependent intermediate properties. This is why we use the
term 'manager' rather than 'calculator.'
In the Cantera kernel, each different transport model is implemented
by a different class derived from the base class Transport. A
highly simplified class structure is used in the Python interface --
there is only one class. """
import _cantera
from Cantera.num import asarray
import exceptions
class Transport:
"""Transport properties.
This class provides the Python interface to the family of
transport manager classes in the Cantera C++ kernel. A transport
manager has one job: to compute transport properties of a phase of
matter assigned to it. The phase is represented by an object
belonging to a class derived from ThermoPhase.
In the C++ kernel, a transport manager implements a single
transport model, and is an instance of a subclass of the base
class ``Transport``. The structure in Python is a little
different. A single class ``Transport`` represents any kernel-level
transport manager. In addition, multiple kernel-kevel transport
managers may be installed in one Python transport manager,
although only one is active at any one time. This feature allows
switching between transport models."""
def __init__(self, xml_phase=None,
phase=None, model = "", loglevel=0):
"""Create a transport property manager.
:param xml_phase:
XML phase element
:param phase:
:class:`.ThermoPhase` instance representing the phase that the
transport properties are for
:param model:
String specifying transport model. If omitted or set to ``Default``,
the model will be read from the input file.
:param loglevel:
controls the amount of diagnostic output
"""
# if the transport model is not specified, look for attribute
# 'model' of the XML 'transport' element
if model == "" or model == "Default" or model == "default":
try:
self.model = xml_phase.child('transport')['model']
except:
self.model = ""
else:
self.model = model
self.__tr_id = 0
self.__tr_id = _cantera.Transport(self.model,
phase._phase_id, loglevel)
self.trnsp = phase.nSpecies()
self._phase_id = phase._phase_id
# dictionary holding all installed transport managers
self._models = {}
self._models[self.model] = self.__tr_id
def __del__(self):
"""Delete all installed transport models."""
if hasattr(self,'_models'):
for m in self._models.keys():
try:
_cantera.tran_delete(self._models[m])
except:
pass
def addTransportModel(self, model, loglevel=1):
"""Add a new transport model. Note that if *model* is the
name of an already-installed transport model, the new
transport manager will take the place of the old one, which
will no longer be accessible. This method does not change the
active model."""
new_id = _cantera.Transport(model,
self._phase_id, loglevel)
self._models[model] = new_id
def switchTransportModel(self, model):
"""Switch to a different transport model."""
if self._models.has_key(model):
self.__tr_id = self._models[model]
self.model = model
else:
raise CanteraError("Transport model "+model+" not defined. Use "
+"method addTransportModel first.")
def desc(self):
"""A short description of the active model."""
if self.model == 'Multi':
return 'Multicomponent'
elif self.model == 'Mix':
return 'Mixture-averaged'
else:
return self.model
def transport_id(self):
"""For internal use."""
return self.__tr_id
def transport_hndl(self):
"""For internal use."""
return self.__tr_id
def viscosity(self):
"Viscosity [Pa-s]."""
return _cantera.tran_viscosity(self.__tr_id)
def electricalConductivity(self):
"""electrical conductivity. [S/m]."""
return _cantera.tran_electricalConductivity(self.__tr_id)
def thermalConductivity(self):
"""Thermal conductivity. [W/m/K]."""
return _cantera.tran_thermalConductivity(self.__tr_id)
def thermalDiffCoeffs(self):
"""Return a one-dimensional array of the species thermal diffusion
coefficients. Not implemented in all transport models."""
return _cantera.tran_thermalDiffCoeffs(self.__tr_id,
self.trnsp)
def binaryDiffCoeffs(self):
"""Two-dimensional array of species binary diffusion coefficients."""
return _cantera.tran_binaryDiffCoeffs(self.__tr_id,
self.trnsp)
def diffusionCoeffs(self):
"""Species diffusion coefficients. (m^2/s)."""
return self.mixDiffCoeffs()
def mixDiffCoeffs(self):
"""Mixture-averaged diffusion coefficients."""
return _cantera.tran_mixDiffCoeffs(self.__tr_id,
self.trnsp)
def multiDiffCoeffs(self):
"""Two-dimensional array of species multicomponent diffusion
coefficients. Not implemented in all transport managers."""
return _cantera.tran_multiDiffCoeffs(self.__tr_id,
self.trnsp)
def setParameters(self, type, k, params):
"""Set model-specific parameters."""
return _cantera.tran_setParameters(self.__tr_id,
type, k, asarray(params))
def molarFluxes(self, state1, state2, delta):
return _cantera.tran_getMolarFluxes(self.__tr_id, self.trnsp,
asarray(state1), asarray(state2),
delta)
def massFluxes(self, state1, state2, delta):
return _cantera.tran_getMassFluxes(self.__tr_id, self.trnsp,
asarray(state1), asarray(state2),
delta)

View file

@ -1,166 +0,0 @@
"""
This module provides the Python interface to C++ class XML_Node.
"""
import _cantera
import types
import tempfile
import string
import exceptions
class XML_Node:
"""A node in an XML tree."""
def __init__(self, name="--", src="", wrap=0, root=None, preprocess=0, debug=0):
"""
Return an instance representing a node in an XML tree.
If 'src' is specified, then the XML tree found in file 'src' is
constructed, and this node forms the root of the tree. The XML tree
is saved, and a second call with the same value for 'src' will use
the XML tree already read in, instead of reading it in again.
If 'wrap' is greater than zero, then only a Python wrapper is
created - no new kernel object results.
"""
self._xml_id = 0
self.wrap = wrap
# create a wrapper for an existing kernel object
if wrap > 0:
self._xml_id = wrap
# create an XML tree by parsing a file, and possibly
# preprocessing it first
elif src:
self._xml_id = _cantera.xml_get_XML_File(src, debug)
self.wrap = 1 # disable deleting
# create a new empty node
else:
self._xml_id = _cantera.xml_new(name)
def __del__(self):
"""Delete the node. Does nothing if this node is only a wrapper."""
if not self.wrap:
_cantera.xml_del(self._xml_id)
def tag(self):
return _cantera.xml_tag(self._xml_id)
def id(self):
"""Return the id attribute if one exists, or else the empty string."""
try:
return self['id']
except:
return ''
def nChildren(self):
"""Number of child elements."""
return _cantera.xml_nChildren(self._xml_id)
def children(self,tag=""):
"""Return a list of all child elements, or just those with a specified
tag name.
"""
nch = self.nChildren()
children = []
for n in range(nch):
m = _cantera.xml_childbynumber(self._xml_id, n)
ch = XML_Node(wrap = m)
if (tag == "" or ch.tag() == tag):
children.append(ch)
return children
def removeChild(self, child):
"""Remove a child and all its descendants."""
_cantera.xml_removeChild(self._xml_id, child._xml_id)
def addChild(self, name, value=""):
"""Add a child with tag 'name', and set its value if the value
parameter is supplied."""
if type(value) <> types.StringType:
v = `value`
else:
v = value
m = _cantera.xml_addChild(self._xml_id, name, v)
return XML_Node(wrap = m)
def hasAttrib(self, key):
x = self.attrib(key)
if x: return 1
else: return 0
def attrib(self, key):
"""Return attribute 'key', or the empty string if this attribute
does not exist."""
try:
return _cantera.xml_attrib(self._xml_id, key)
except:
return ''
def addAttrib(self, key, value):
"""Add attribute 'key' with value 'value'."""
_cantera.xml_addAttrib(self._xml_id, key, value)
def addComment(self, comment):
"""Add a comment."""
_cantera.xml_addComment(self._xml_id, comment)
def value(self, loc=""):
"""Return the value of this node, or, if
the loc argument is supplied, of the node with relative
address 'loc'."""
if loc:
node = self.child(loc)
return node.value()
else:
return _cantera.xml_value(self._xml_id)
def child(self, loc="", id="", name=""):
if loc:
m = _cantera.xml_child(self._xml_id, loc)
elif id:
m = _cantera.xml_findID(self._xml_id, id)
elif name:
m = _cantera.xml_findByName(self._xml_id, name)
ch = XML_Node(wrap=m)
return ch
def __getitem__(self, key):
"""Get an attribute using the syntax node[key]"""
return self.attrib(key)
def __setitem__(self, key, value):
"""Set a new attribute using the syntax node[key] = value."""
return self.addAttrib(key, value)
def __int__(self):
"""Conversion to integer."""
return self._xml_id
def __call__(self, loc=''):
"""Get the value using the syntax node(loc)."""
return self.value(loc)
def write(self, file):
_cantera.xml_write(self._xml_id, file)
def __repr__(self):
tmp = tempfile.mktemp('.xml')
self.write(tmp)
f = open(tmp)
lines = f.readlines()
f.close()
s = ''
for line in lines:
s += line
return s
def clear_XML():
_cantera.xml_clear()
def getFloatArray(node, convert_units=0):
sz = int(node['size'])
return _cantera.ctml_getFloatArray(node._xml_id, convert_units, sz)

View file

@ -1,102 +0,0 @@
"""
Cantera provides capabilities for simulating problems involving
chemical kinetics and transport processes.
"""
import types
import _cantera
from num import *
from constants import *
from exceptions import *
from gases import *
from set import set
from importFromFile import *
import os as _os
import sys as _sys
__version__ = _cantera.ct_get_version()
import warnings
warnings.warn(
"\nThis version of the Cantera Python module is deprecated and will not be\n"
"available in Cantera 2.2 or later. For details on the new module, see\n"
"http://cantera.github.io/dev-docs/sphinx/html/cython/index.html\n",
stacklevel=2)
if not os.getenv('PYTHON_CMD'):
# Setting PYTHON_CMD here avoids issues with .cti -> .xml conversions
# in cases where the python interpreter isn't in the system path.
os.environ['PYTHON_CMD'] = _sys.executable
def writeCSV(f, lst):
"""
Write list items to file *f* in
comma-separated-value format. Strings will be written as-is, and
other types of objects will be converted to strings and then
written. Each call to writeCSV writes one line of the file.
"""
for i,item in enumerate(lst):
if type(item) == types.StringType:
f.write(item)
else:
f.write(repr(item))
if i != len(lst)-1:
f.write(',')
f.write('\n')
def table(keys, values):
"""Create a map with the keys and values specified."""
x = {}
pairs = map(None, keys, values)
for p in pairs:
k, v = p
x[k] = v
return x
def getCanteraError():
"""Return the Cantera error message, if any."""
return _cantera.get_Cantera_Error()
def refCount(a):
"""Return the reference count for an object."""
return _cantera.ct_refcnt(a)
def addDirectory(dir):
"""Add a directory to search for Cantera data files."""
return _cantera.ct_addDirectory(dir)
def writeLogFile(file):
return _cantera.ct_writelogfile(file)
def reset():
"""Release all cached Cantera data. Equivalent to
starting a fresh session."""
_cantera.ct_appdelete()
def fix_docs(cls):
"""
Inherit method docstrings from parent class if none is specified on the
child. Usable as a decorator in Python >= 2.6.
"""
for name, func in vars(cls).items():
if not func.__doc__:
for parent in cls.__bases__:
parfunc = getattr(parent, name)
if parfunc and getattr(parfunc, '__doc__', None):
func.__doc__ = parfunc.__doc__
break
return cls
# workaround for case problems in CVS repository file Mixture.py. On some
# systems it appears as mixture.py, and on others as Mixture.py
try:
from Mixture import Mixture
except:
from mixture import Mixture
from num import *

View file

@ -1,33 +0,0 @@
import _cantera
"""
Convert a Chemkin-format input file to CTI format.
Parameters:
infile - name of the Chemkin-format input file.
thermodb - Thermodynamic database. This may be a standard
Chemkin-format thermo database, or may be any
Chemkin-format input file containing a THERMO section.
trandb - Transport database. File containing species transport
parameters in Chemkin format. If this argument is omitted,
the CTI file will not contain transport property information.
idtag - ID tag. Used to identify the ideal_gas entry in the CTI file. Optional.
debug - If set to 1, extra debugging output will be written. This
should only be used if ck2cti fails, in order to view
intermediate output of the parser. Default: off (0).
validate - If set to 1, the mechanism will be checked for errors. This
is recommended, but for very large mechanisms may slow down
the conversion process. Default: on (1).
The translated file is written to the standard output.
"""
def ck2cti(infile = "chem.inp", thermodb = "", trandb
= "", idtag = "", debug = 0, validate = 1):
_cantera.ct_ck2cti(infile,
thermodb, trandb, idtag, debug, validate)

View file

@ -1,49 +0,0 @@
"""
Physical Constants
These values are the same as those in the C++ header file ct_defs.h in
the Cantera kernel.
"""
import math
#: One atmosphere in Pascals
OneAtm = 101325.0
#: The ideal gas constant in J/kmo-K
GasConstant = 8314.4621
#: Avogadro's Number, /kmol
Avogadro = 6.02214129e26
#: The ideal gas constant in cal/mol-K
GasConst_cal_mol_K = GasConstant / 4184.0
#: Boltzmann-s constant
Boltzmann = GasConstant / Avogadro
#: The Stefan-Boltzmann constant, W/m^2K^4
StefanBoltz = 5.670373e-8
#: The charge on an electron (C)
ElectronCharge = 1.602176565e-19
#: The mass of an electron (kg)
ElectronMass = 9.10938291e-31
Pi = math.pi
#: Faraday's constant, C/kmol
Faraday = ElectronCharge * Avogadro
#: Planck's constant (J/s)
Planck = 6.62607009e-34
#: Speed of Light (m/s).
lightSpeed = 299792458.0
#: Permeability of free space :math:`\mu_0` in N/A^2.
permeability_0 = 4.0e-7*Pi ## N/A^2
#: Permittivity of free space
epsilon_0 = 1.0 / (lightSpeed*lightSpeed*permeability_0) ## Farads/m = C^2/N/m^2

View file

@ -1,24 +0,0 @@
"""
Atomic elements.
"""
def elementMoles(s, element):
"""Number of moles of an element in one mole of a solution.
s -- an object representing a solution.
element -- the symbol for an element in 's'.
"""
# see if 'element' corresponds to a symbol for one of the elements
# in s. If it does not, return zero moles.
try:
m = s.elementIndex(element)
if m < 0.0: return 0.0
except:
return 0.0
x = s.moleFractions()
moles = 0.0
for k in range(s.nSpecies()):
moles += x[k]*s.nAtoms(k,m)
return moles

View file

@ -1,28 +0,0 @@
"""EXCEL CSV file utilities."""
def write_CSV_data(fname, names, npts, nvar, append, data):
"""
Write CSV data that can be imported into Excel
fname -- file name
names -- sequence of variable names
npts -- number of data points
nvar -- number of variables
append -- if > 0, append to plot file, otherwise overwrite
data -- object to generate plot data. This object must have a
method 'value', defined so that data.value(j,n) returns
the value of variable n at point j.
"""
if append > 0:
f = open(fname,'a')
else:
f = open(fname,'w')
for nm in names:
f.write(nm+',')
f.write('\n')
for j in range(npts):
for n in range(nvar):
f.write('%10.4e, ' % data.value(j,n))
f.write('\n')
f.close()

View file

@ -1,26 +0,0 @@
"""
Cantera exceptions
"""
import _cantera
def getCanteraError():
"""
Get an error message generated when Cantera throws an exception.
"""
return _cantera.get_Cantera_Error()
class CanteraError(Exception):
def __init__(self, msg = ""):
if msg == "":
msg = _cantera.get_Cantera_Error()
self.msg = msg
def __str__(self):
print '\n\n\n####################### CANTERA ERROR ######################\n'
print ' ',self.msg
print '\n##############################################################\n'
class OptionError(CanteraError):
def __init__(self, msg):
self.msg = 'Unknown option: '+msg

View file

@ -1,47 +0,0 @@
"""Gas mixtures.
These functions all return instances of class Solution that represent
gas mixtures.
"""
# for pydoc
import solution, constants
from constants import *
from Cantera.solution import Solution
#import _cantera
import os
def IdealGasMix(src="", id = "", loglevel = 0):
"""Return a :class:`.Solution` object representing an ideal gas mixture.
:param src:
input file
:param id:
XML id tag for phase
"""
return Solution(src=src,id=id,loglevel=loglevel)
def GRI30(transport = ""):
"""Return a :class:`.Solution` instance implementing reaction mechanism
GRI-Mech 3.0."""
if transport == "":
return Solution(src="gri30.cti", id="gri30")
elif transport == "Mix":
return Solution(src="gri30.cti", id="gri30_mix")
elif transport == "Multi":
return Solution(src="gri30.cti", id="gri30_multi")
def Air():
"""Return a :class:`.Solution` instance implementing the O/N/Ar portion of
reaction mechanism GRI-Mech 3.0. The initial composition is set to
that of air"""
return Solution(src="air.cti", id="air")
def Argon():
"""Return a :class:`.Solution` instance representing pure argon."""
return Solution(src="argon.cti", id="argon")

View file

@ -1,62 +0,0 @@
"""Functions to import phase and interface definitions from CTI or
CTML files. This module is imported when the Cantera package is
imported, and therfore does not need to be explicitly imported in
application programs."""
import solution
import Interface
import Edge
import XML
def importPhase(file, name = '', loglevel = 0, debug = 0):
"""Import one phase from an input file. If 'name' is specified, the
phase definition with this name will be imported, otherwise the first
phase definition in the file will be imported. If 'loglevel' is set to
a positive integer, additional information will be printed or written
to log files about the details of the object constructed.
"""
return importPhases(file, [name], loglevel, debug)[0]
def importPhases(file, names = [], loglevel = 0, debug = 0):
"""Import multiple phases from one file. The phase names should be
entered as a list of strings. See: importPhase """
s = []
for nm in names:
s.append(solution.Solution(src=file,id=nm,loglevel=loglevel,debug=debug))
return s
def importInterface(file, name = '', phases = []):
"""Import an interface definition from input file 'file', and return
an instance of class Interface implementing this definition. If 'name'
is specified, the definition by this name will be imported; otherwise, the
first interface definition in the file will be imported.
The 'phases' argument is a list of objects representing the other phases
that participate in the interfacial reactions, for example an object
representing a gas phase or a solid.
>>> gas1, cryst1 = importPhases('diamond.cti', ['gas', 'solid'])
>>> diamond_surf = importInterface('diamond.cti', [gas1, cryst1])
Note the difference between the lists in the argument lists of these
two functions. In importPhases, a list of name strings is entered,
which are used to identify the appropriate definitions in the input
file to build the objects. In importInterface, the list is of the
objects that were built by importPhases. The reason these objects must be
given as inputs is that these objects will be queried when phase
properties (temperature, pressure, composition,
electric potential) are needed to compute the reaction rates of progress.
"""
if name:
src = file+'#'+name
else:
src = file
return Interface.Interface(src = src, phases = phases)
def importEdge(file, name = '', surfaces = []):
if name:
src = file+'#'+name
else:
src = file
return Edge.Edge(src = src, surfaces = surfaces)

View file

@ -1,64 +0,0 @@
def interp(z0, z, f):
"""
Linear interpolation.
Sequences z and f must be of the same length,
and the entries in z must be monotonically increasing.
Example:
>>> z = [0.0, 0.2, 0.5, 1.2, 2.1]
>>> f = [3.0, 2.0, 1.0, 0.0, -1.0]
>>>print interp(-2, z, f), interp(0.5, z, f), interp(6, z, f)
3.0 7.0 -9.0
"""
n = len(z)
# if z0 is outside the range of z, then return the endpoint value,
# instead of extrapolating.
if z0 <= z[0]:
return f[0]
elif z0 > z[-1]:
return f[-1]
for i in range(1,n):
if z0 <= z[i]:
return f[i-1] + (f[i] - f[i-1])*(z0 - z[i-1])/(z[i] - z[i-1])
# if this statement is reached, then there is an error.
raise 'interpolation error!'
def quadInterp(z0, z, f):
n = len(z)
# if z0 is outside the range of z, then return the endpoint value,
# instead of extrapolating.
if z0 <= z[0]:
return f[0]
elif z0 > z[-1]:
return f[-1]
for i in range(1,n):
if z0 <= z[i]:
j = max(2,i)
dx21 = z[j-1] - z[j-2]
dx32 = z[j] - z[j-1]
dx31 = dx21 + dx32
dy32 = f[j] - f[j-1]
dy21 = f[j-1] - f[j-2]
a = (dx21*dy32 - dy21*dx32)/(dx21*dx31*dx32)
return a*(z0 - z[j-2])*(z0 - z[j-1]) + (
(dy21/dx21)*(z0 - z[j-1]) + f[j-1])
# if this statement is reached, then there is an error.
raise 'interpolation error!'
## if __name__ == '__main__':
## z = [0.0, 0.2, 0.5, 1.2, 2.1]
## f = [3.0, 5.0, 11.0, 0.0, -9.0]
## print interp(-2, z, f), interp(0.3, z, f), interp(6, z, f)
## print quadInterp(-2, z, f), quadInterp(0.3, z, f), quadInterp(6, z, f)

View file

@ -1,126 +0,0 @@
"""Fluids with complete liquid/vapor equations of state..
These functions are defined for convenience only. They simply call
function 'importPhase' to import the phase definition from file
'liquidvapor.cti' """
from importFromFile import importPhase
import os
from constants import *
from ThermoPhase import ThermoPhase
from set import setByName
import XML
import _cantera
class PureFluid(ThermoPhase):
"""
A class for chemically-reacting solutions.
Instances can be created to represent any type of solution -- a
mixture of gases, a liquid solution, or a solid solution, for
example.
"""
def __init__(self, src="", id=""):
self.ckin = 0
self._owner = 0
self.verbose = 1
fname = os.path.basename(src)
ff = os.path.splitext(fname)
if src:
root = XML.XML_Node(name = 'doc', src = src, preprocess = 1)
if id:
s = root.child(id = id)
else:
s = root.child(name = "phase")
self._name = s['id']
# initialize the equation of state
ThermoPhase.__init__(self, xml_phase=s)
def __del__(self):
ThermoPhase.__del__(self)
def __repr__(self):
return _cantera.phase_report(self._phase_id, self.verbose)
def name(self):
return self._name
def set(self, **options):
"""Set various properties.
T --- temperature [K]
P --- pressure [Pa]
Rho --- density [kg/m3]
V --- specific volume [m3/kg]
H --- specific enthalpy [J/kg]
U --- specific internal energy [J/kg]
S --- specific entropy [J/kg/K]
X --- mole fractions (string or array)
Y --- mass fractions (string or array)
Vapor --- saturated vapor fraction
Liquid --- saturated liquid fraction
"""
setByName(self, options)
def critTemperature(self):
"""Critical temperature [K]."""
return _cantera.thermo_getfp(self._phase_id,50)
def critPressure(self):
"""Critical pressure [Pa]."""
return _cantera.thermo_getfp(self._phase_id,51)
def critDensity(self):
"""Critical density [kg/m3]."""
return _cantera.thermo_getfp(self._phase_id,52)
def vaporFraction(self):
"""Vapor fraction."""
return _cantera.thermo_getfp(self._phase_id,53)
def setState_Psat(self, p, vaporFraction):
"""Set the state of a saturated liquid/vapor mixture by
specifying the pressure and vapor fraction."""
_cantera.thermo_setfp(self._phase_id,8, p, vaporFraction)
def setState_Tsat(self, t, vaporFraction):
"""Set the state of a saturated liquid/vapor mixture by
specifying the temperature and vapor fraction."""
_cantera.thermo_setfp(self._phase_id,7, t, vaporFraction)
def Water():
return PureFluid('liquidvapor.cti','water')
def Nitrogen():
return PureFluid('liquidvapor.cti','nitrogen')
def Methane():
return PureFluid('liquidvapor.cti','methane')
def Hydrogen():
return PureFluid('liquidvapor.cti','hydrogen')
def Oxygen():
return PureFluid('liquidvapor.cti','oxygen')
def HFC134a():
return PureFluid('liquidvapor.cti','hfc134a')
def CarbonDioxide():
return PureFluid('liquidvapor.cti','carbondioxide')
def Heptane():
return PureFluid('liquidvapor.cti','heptane')

View file

@ -1,406 +0,0 @@
"""
Multiphase mixtures.
"""
import _cantera
import types
from Cantera.num import zeros, array, asarray
from exceptions import CanteraError
from Cantera import writeLogFile
class Mixture:
"""
Multiphase mixtures. Class Mixture represents
mixtures of one or more phases of matter. To construct a mixture,
supply a list of phases to the constructor, each paired with the
number of moles for that phase:
>>> gas = importPhase('gas.cti')
>>> gas.speciesNames()
['H2', 'H', 'O2', 'O', 'OH']
>>> graphite = importPhase('graphite.cti')
>>> graphite.speciesNames()
['C(g)']
>>> mix = Mixture([(gas, 1.0), (graphite, 0.1)])
>>> mix.speciesNames()
['H2', 'H', 'O2', 'O', 'OH', 'C(g)']
Note that the objects representing each phase compute only the
intensive state of the phase -- they do not store any information
on the amount of this phase. Mixture objects, on the other hand, represent
the full extensive state.
Mixture objects are 'lightweight' in the sense that they do not
store parameters needed to compute thermodynamic or kinetic
properties of the phases. These are contained in the
('heavyweight') phase objects. Multiple mixture objects may be
constructed using the same set of phase objects. Each one stores
its own state information locally, and synchronizes the phases
objects whenever it requires phase properties.
"""
def __init__(self, phases=[]):
self.__mixid = _cantera.mix_new()
self._spnames = []
self._phases = []
if phases:
for p in phases:
try:
ph = p[0]
moles = p[1]
except:
ph = p
if p == phases[0]:
moles = 1
else:
moles = 0
self._addPhase(ph, moles)
self._phases.append(ph)
_cantera.mix_init(self.__mixid)
self.setTemperature(self._phases[0].temperature())
self.setPressure(self._phases[0].pressure())
def __del__(self):
"""Delete the Mixture instance. The phase objects are not deleted."""
_cantera.mix_del(self.__mixid)
def __str__(self):
s = ''
for p in range(len(self._phases)):
s += '\n******************* Phase '+self._phases[p].name()+' ******************************\n'
s += '\n Moles: '+`self.phaseMoles(p)`+'\n'
s += self._phases[p].__repr__()+'\n\n'
return s
def _addPhase(self, phase = None, moles = 0.0):
"""Add a phase to the mixture."""
for k in range(phase.nSpecies()):
self._spnames.append(phase.speciesName(k))
_cantera.mix_addPhase(self.__mixid, phase.thermo_hndl(), moles)
def nPhases(self):
"""Total number of phases defined for the mixture."""
return len(self._phases)
def phase(self, n):
"""Return the object representing the nth phase in the mixture."""
return self._phases[n]
def phaseName(self, n):
"""Name of phase *n*."""
return self._phases[n].name()
def phaseNames(self):
"""Names of all phases in the order added."""
np = self.nPhases()
nm = []
for n in range(np):
nm.append(self.phaseName(n))
return nm
def phaseIndex(self, phase):
"""Index of phase with name *phase*"""
np = self.nPhases()
if type(phase) <> types.StringType:
return phase
for n in range(np):
if self.phaseName(n) == phase:
return n
return -1
def nElements(self):
"""Total number of elements present in the mixture."""
return _cantera.mix_nElements(self.__mixid)
def elementIndex(self, element):
"""Index of element with name 'element'.
>>> mix.elementIndex('H')
2
"""
if type(element) == types.StringType:
return _cantera.mix_elementIndex(self.__mixid, element)
else:
return element
def nSpecies(self):
"""Total number of species present in the mixture. This is the
sum of the numbers of species in each phase."""
return _cantera.mix_nSpecies(self.__mixid)
def speciesName(self, k):
"""Name of the species with index *k*. Note that index numbers
are assigned in order as phases are added."""
return self._spnames[k]
def speciesNames(self):
n = self.nSpecies()
s = []
for k in range(n):
s.append(self.speciesName(k))
return s
def speciesIndex(self, species):
"""Index of species with name *species*. If *species* is not a string,
then it is simply returned."""
if type(species) == types.StringType:
return self._spnames.index(species)
else:
return species
def nAtoms(self, k, m):
"""Number of atoms of element *m* in species *k*. Both the species and
the element may be referenced either by name or by index number.
>>> n = mix.nAtoms('CH4','H')
4.0
"""
kk = self.speciesIndex(k)
mm = self.elementIndex(m)
return _cantera.mix_nAtoms(self.__mixid, kk, mm)
def setTemperature(self, t):
"""Set the temperature [K]. The temperatures of all phases are
set to this value, holding the pressure fixed."""
return _cantera.mix_setTemperature(self.__mixid, t)
def temperature(self):
"""The temperature [K]."""
return _cantera.mix_temperature(self.__mixid)
def minTemp(self):
"""The minimum temperature for which all species in
multi-species solutions have valid thermo data. Stoichiometric
phases are not considered in determining minTemp. """
return _cantera.mix_minTemp(self.__mixid)
def maxTemp(self):
"""The maximum temperature for which all species in
multi-species solutions have valid thermo data. Stoichiometric
phases are not considered in determining maxTemp. """
return _cantera.mix_maxTemp(self.__mixid)
def charge(self):
"""The total charge in Coulombs, summed over all phases."""
return _cantera.mix_charge(self.__mixid)
def phaseCharge(self, p):
"""The charge of phase *p* (Coulombs)."""
return _cantera.mix_phaseCharge(self.__mixid, p)
def setPressure(self, p):
"""Set the pressure [Pa]. The pressures of all phases are set
to the specified value, holding the temperature fixed."""
return _cantera.mix_setPressure(self.__mixid, p)
def pressure(self):
"""The pressure [Pa]."""
return _cantera.mix_pressure(self.__mixid)
def phaseMoles(self, n = -1):
"""Moles of phase *n*."""
if n == -1:
np = self.nPhases()
moles = zeros(np,'d')
for m in range(np):
moles[m] = _cantera.mix_phaseMoles(self.__mixid, m)
return moles
else:
return _cantera.mix_phaseMoles(self.__mixid, n)
def setPhaseMoles(self, n, moles):
"""Set the number of moles of phase *n*."""
_cantera.mix_setPhaseMoles(self.__mixid, n, moles)
def setSpeciesMoles(self, moles):
"""Set the moles of the species [kmol]. The moles may be
specified either as a string, or as an array. If an array is
used, it must be dimensioned at least as large as the total
number of species in the mixture. Note that the species may
belong to any phase, and unspecified species are set to zero.
>>> mix.setSpeciesMoles('C(s):1.0, CH4:2.0, O2:0.2')
"""
if type(moles) == types.StringType:
_cantera.mix_setMolesByName(self.__mixid, moles)
else:
_cantera.mix_setMoles(self.__mixid, asarray(moles))
def speciesMoles(self, species = ""):
"""Moles of species k."""
moles = zeros(self.nSpecies(),'d')
for k in range(self.nSpecies()):
moles[k] = _cantera.mix_speciesMoles(self.__mixid, k)
return self.selectSpecies(moles, species)
def elementMoles(self, m):
"""Total number of moles of element *m*, summed over all species.
The element may be referenced either by index number or by name.
"""
mm = self.elementIndex(m)
return _cantera.mix_elementMoles(self.__mixid, mm)
def chemPotentials(self, species=[]):
"""The chemical potentials of all species [J/kmol]."""
mu = zeros(self.nSpecies(),'d')
_cantera.mix_getChemPotentials(self.__mixid, mu)
return self.selectSpecies(mu, species)
def set(self, **p):
for o in p.keys():
v = p[o]
if o == 'T' or o == 'Temperature':
self.setTemperature(v)
elif o == 'P' or o == 'Pressure':
self.setPressure(v)
elif o == 'Moles' or o == 'N':
self.setSpeciesMoles(v)
else:
raise CanteraError("unknown property: "+o)
def equilibrate(self, XY = "TP", err = 1.0e-9,
maxsteps = 1000, maxiter = 200, loglevel = 0):
"""Set the mixture to a state of chemical equilibrium.
This method uses a version of the VCS algorithm to find the
composition that minimizes the total Gibbs free energy of the
mixture, subject to element conservation constraints. For a
description of the theory, see Smith and Missen, "Chemical
Reaction Equilibrium." The VCS algorithm is implemented in
Cantera kernel class ``MultiPhaseEquil``.
The VCS algorithm solves for the equilibrium composition for
specified temperature and pressure. If any other property pair
other than ``TP`` is specified, then an outer iteration loop is
used to adjust T and/or P so that the specified property
values are obtained.
:param XY:
Two-letter string specifying the two properties to hold fixed.
Currently, ``'TP'``, ``'HP'``, and ``'SP'`` are implemented.
Default: ``'TP'``.
:param err:
Error tolerance. Iteration will continue until (Delta mu)/RT is
less than this value for each reaction. Default: 1.0e-9. Note that
this default is very conservative, and good equilibrium solutions
may be obtained with larger error tolerances.
:param maxsteps:
Maximum number of steps to take while solving the equilibrium
problem for specified *T* and *P*. Default: 1000.
:param maxiter:
Maximum number of temperature and/or pressure iterations.
This is only relevant if a property pair other than (T,P) is
specified. Default: 200.
:param loglevel:
Controls the amount of diagnostic output. If loglevel = 0, no
diagnostic output is written. For values > 0, more detailed
information is written to the log file as loglevel increases.
The default is loglevel = 0.
The logfile is written in HTML format, and may be viewed with
any web browser. The default log file name is
``equilibrium_log.html``, but if this file exists, the log
information will be written to "equilibrium_log{n}.html", where
{n} is an integer chosen so that the log file does not already
exist. Therefore, if 'equilibrate' is called multiple times,
multiple log files will be written, with names
``equilibrate_log.html``, ``equilibrate_log1.html``,
``equilibrate_log2.html``, and so on. Existing log files will
not be overwritten.
>>> mix.equilibrate('TP')
>>> mix.equilibrate('TP', err = 1.0e-6, maxiter = 500)
"""
i = _cantera.mix_equilibrate(self.__mixid, XY, err, maxsteps,
maxiter, loglevel)
def vcs_equilibrate(self, XY = "TP", estimateEquil = 0, printLvl = 0,
solver = 2, rtol = 1.0e-9,
maxsteps = 1000, maxiter = 1000, loglevel = 0):
"""Set the mixture to a state of chemical equilibrium.
This method uses a version of the VCS algorithm to find the
composition that minimizes the total Gibbs free energy of the
mixture, subject to element conservation constraints. For a
description of the theory, see Smith and Missen, "Chemical
Reaction Equilibrium." The VCS algorithm is implemented in
Cantera kernel class MultiPhaseEquil.
The VCS algorithm solves for the equilibrium composition for
specified temperature and pressure. If any other property pair
other than ``'TP'`` is specified, then an outer iteration loop is
used to adjust T and/or P so that the specified property
values are obtained.
:param XY:
Two-letter string specifying the two properties to hold fixed.
Currently, ``'TP'``, ``'HP'``, and ``'SP'`` are implemented.
Default: ``'TP'``.
:param printLvl:
Controls the amount of diagnostic output written to cout. If
printLvl = 0, no diagnostic output is written. For values > 0,
more detailed information is written to cout.
The default is printLvl = 0.
:param solver:
Determines which solver is used.
- 1 MultiPhaseEquil solver
- 2 VCSnonideal Solver (default)
:param err:
Error tolerance. Iteration will continue until (Delta mu)/RT is
less than this value for each reaction. Default: 1.0e-9. Note that
this default is very conservative, and good equilibrium solutions
May be obtained with larger error tolerances.
:param maxsteps:
Maximum number of steps to take while solving the equilibrium
problem for specified T and P. Default: 1000.
:param maxiter:
Maximum number of temperature and/or pressure iterations. This is
only relevant if a property pair other than (T,P) is specified.
Default: 200.
:param loglevel:
Controls the amount of diagnostic output written to html. If
loglevel = 0, no diagnostic output is written. For values > 0,
more detailed information is written to the log file as
loglevel increases. The default is loglevel = 0.
The logfile is written in HTML format, and may be viewed with
any web browser. The default log file name is
"equilibrium_log.html", but if this file exists, the log
information will be written to "equilibrium_log{n}.html",
where {n} is an integer chosen so that the log file does not
already exist. Therefore, if 'equilibrate' is called multiple
times, multiple log files will be written, with names
"equilibrate_log.html", "equilibrate_log1.html",
"equilibrate_log2.html", and so on. Existing log files will
not be overwritten.
"""
i = _cantera.mix_vcs_equilibrate(self.__mixid, XY, estimateEquil,
printLvl, solver, rtol, maxsteps,
maxiter, loglevel)
def selectSpecies(self, f, species):
"""Given an array *f* of floating-point species properties,
return an array of those values corresponding to species
listed in *species*. This method is used internally to implement
species selection in methods like :meth:`~.Phase.moleFractions`,
:meth:`~.Phase.massFractions`, etc.
>>> f = mix.chemPotentials()
>>> muo2, muh2 = mix.selectSpecies(f, ['O2', 'H2'])
"""
sp = []
if species:
if type(species) == types.StringType:
sp = [species]
else:
sp = species
fs = []
k = 0
for s in sp:
k = self.speciesIndex(s)
fs.append(f[k])
return asarray(fs)
else:
return f

View file

@ -1,36 +0,0 @@
import _cantera
nummodule = None
try:
if _cantera.nummod == 'numpy':
import numpy
nummodule = numpy
elif _cantera.nummod == 'numarray':
import numarray
nummodule = numarray
else:
import Numeric
nummodule = Numeric
except:
print """
ERROR: """+_cantera.nummod+""" not found!
Cantera uses a set of numerical extensions to Python, but these do
not appear to be present on your system. To install the required
package, go to http://sourceforge.net/projects/numpy, and install
either the """+_cantera.nummod+""" package for your system. If you are
using a Windows system, use the binary installer to install the
selected package for you automatically.
"""
raise "could not import "+_cantera.nummod
zeros = nummodule.zeros
array = nummodule.array
asarray = nummodule.asarray
transpose = nummodule.transpose
ravel = nummodule.ravel
shape = nummodule.shape
ones = nummodule.ones
log10 = nummodule.log10

View file

@ -1,163 +0,0 @@
"""
Reaction path diagrams.
To create a simple reaction path diagram:
>>> import rxnpath
>>> element = 'C'
>>> rxnpath.write(gas, element, file)
Object 'gas' must an instance of a class derived from class 'Kinetics'
(for example class IdealGasMix). The diagram layout is written to
'file'. The output must be postprocessed with program 'dot', which is
part of the GraphViz package. To create a Postscript plot:
dot -Tps rp.dot > rp.ps
Other output formats are also supported by dot, including gif, pcl,
jpg, png, and svg
For more control over the graph properties, create a PathDiagam object
and pass it to the 'write' procedure.
PathDiagram keyword options:
diagram type:
-- detailed 'true' or 'false'
-- type 'both' or 'net' (forward and reverse arrows,
or net arrow)
-- dot_options options passed through to 'dot'
colors:
-- normal_color color for normal-weight lines
-- bold_color color for bold-weight lines
-- dashed_color color for dashed lines
thresholds:
-- threshold min relative strength for a path to be shown
-- normal_threshold min relative strength for normal-weight path
Below this value, paths are dashed.
-- bold_threshold min relative strength for bold-weight path
"""
import _cantera
class PathDiagram:
def __init__(self, **options):
self.__rdiag_id = _cantera.rdiag_new()
self.setOptions({"detailed":"true",
"dashed_color":"gray",
"bold_color":"red",
"normal_color":"steelblue",
"scale":-1,
"dot_options":'center=1;margin=0;size="5,6";page="5,6";ratio=compress;fontname=Arial;',
"title":"-",
"arrow_width":-5,
"threshold":0.001,
"bold_threshold":0.2,
"normal_threshold":0.01,
"label_threshold":0.001,
"flow_type":"net"}
)
self.setOptions(options)
def __del__(self):
_cantera.rdiag_del(self.__rdiag_id)
def id(self):
return self.__rdiag_id
def write(self, fmt, file):
_cantera.rdiag_write(self.__rdiag_id, fmt, file)
def add(self, other):
_cantera.rdiag_add(self.__rdiag_id, other.id())
def findMajorPaths(self, a, threshold = 0.0):
_cantera.rdiag_findMajor(self.__rdiag_id, threshold, a)
def displayOnly(self, node=-1):
_cantera.rdiag_displayOnly(self.__rdiag_id, node)
def setOptions(self, options):
for o in options.keys():
v = options[o]
if o == "detailed":
if v == "true":
_cantera.rdiag_detailed(self.__rdiag_id)
elif v == "false":
_cantera.rdiag_brief(self.__rdiag_id)
elif o == "dashed_color":
_cantera.rdiag_setDashedColor(self.__rdiag_id, v)
elif o == "bold_color":
_cantera.rdiag_setBoldColor(self.__rdiag_id, v)
elif o == "normal_color":
_cantera.rdiag_setNormalColor(self.__rdiag_id, v)
elif o == "scale":
_cantera.rdiag_setScale(self.__rdiag_id, v)
elif o == "dot_options":
_cantera.rdiag_setDotOptions(self.__rdiag_id, v)
elif o == "title":
_cantera.rdiag_setTitle(self.__rdiag_id, v)
elif o == "arrow_width":
_cantera.rdiag_setArrowWidth(self.__rdiag_id, v)
elif o == "threshold":
_cantera.rdiag_setThreshold(self.__rdiag_id, v)
elif o == "bold_threshold":
_cantera.rdiag_setBoldThreshold(self.__rdiag_id, v)
elif o == "normal_threshold":
_cantera.rdiag_setNormalThreshold(self.__rdiag_id, v)
elif o == "label_threshold":
_cantera.rdiag_setLabelThreshold(self.__rdiag_id, v)
elif o == "font":
_cantera.rdiag_setFont(self.__rdiag_id, v)
elif o == "flow_type":
if v == "one_way":
_cantera.rdiag_setFlowType(self.__rdiag_id, 0)
else:
_cantera.rdiag_setFlowType(self.__rdiag_id, 1)
else:
raise("unknown attribute "+o)
class PathBuilder:
def __init__(self, kin, logfile=""):
if logfile == "":
logfile = "rxnpath.log"
self.__rbuild_id = _cantera.rbuild_new()
self.kin = kin
_cantera.rbuild_init(self.__rbuild_id, logfile, kin.ckin)
def __del__(self):
_cantera.rbuild_del(self.__rbuild_id)
def build(self, diagram = None, element = "C",
dotfile = "rxnpaths.dot", format="dot"):
if diagram == None:
diagram = PathDiagram()
_cantera.rbuild_build(self.__rbuild_id, self.kin.ckin, element,
"buildlog", diagram.id(), 1)
if format == "dot":
diagram.write(0, dotfile)
diagram.write(1, "rp.txt")
elif format == "plain":
diagram.write(1, dotfile)
def write(g, el, file, d=None, format="dot"):
b = PathBuilder(g)
b.build(element = el, diagram = d, dotfile = file, format = format)
def view(url):
import webbrowser
webbrowser.open(url)
if __name__ == "__main__":
from Cantera.gases import GRI30
gas = GRI30()
x = [1.0] * gas.nSpecies()
gas.setState_TPX(1800.0, 1.01325e5, x)
write(gas, 'C', 'c:/users/dgg/test.dot')

View file

@ -1,132 +0,0 @@
from exceptions import CanteraError
def setByName(a, options):
"""Set properties of phase 'a' by specifying keywords. Either the full
property name or the short form may be given. The capitalization must
be exactly as shown here.
Note: all extensive property values are specified for a unit mass
- i.e., the *specific* (not molar) property value should be
specified.
keyword short form property
--------------------------------------------
Pressure P pressure
Density Rho density
Temperature T temperature
Volume V specific volume
MoleFractions X mole fractions
MassFracttions Y mass fractions
Enthalpy H specific enthalpy
IntEnergy U specific internal energy
Entropy S specific entropy
Vapor Vap vapor fraction in a two-phase mixture
Liquid Liq liquid fraction in a two-phase mixture
"""
tval = None
pval = None
hval = None
uval = None
sval = None
vval = None
qval = None
np = 0
nt = 0
nv = 0
nx = 0
ny = 0
ns = 0
nh = 0
nu = 0
nq = 0
for o in options.keys():
val = options[o]
if o == 'Temperature' or o == 'T':
nt += 1
tval = val
elif o == 'Density' or o == 'Rho':
nv += 1
vval = 1.0/val
elif o == 'Volume' or o == 'V':
nv += 1
vval = val
elif o == 'MoleFractions' or o == 'X':
nx += 1
a.setMoleFractions(val)
elif o == 'MassFractions' or o == 'Y':
ny += 1
a.setMassFractions(val)
elif o == 'Pressure' or o == 'P':
pval = val
np += 1
elif o == 'Enthalpy' or o == 'H':
hval = val
nh += 1
elif o == 'IntEnergy' or o == 'U':
uval = val
nu += 1
elif o == 'Entropy' or o == 'S':
sval = val
ns += 1
elif o == 'Vapor' or o == 'Vap':
nq += 1
qval = val
elif o == 'Liquid' or o == 'Liq':
nq += 1
qval = 1.0 - val
else:
raise CanteraError('unknown property: '+o)
if nx + ny > 1:
raise CanteraError('composition specified multiple times')
nn = [nt, np, nv, ns, nh, nu, nq]
for n in nn:
if n > 1:
raise CanteraError('property specified multiple times')
ntot = nt + np + nv + ns + nh + nu + nq
# set individual properties
if ntot == 1:
if nt == 1:
a.setTemperature(tval)
elif nv == 1:
a.setDensity(1.0/vval)
elif np == 1:
a.setPressure(pval)
else:
props = options.keys()
raise CanteraError('property '+props[0]+
' can only be set in combination with '
+'another property')
# set property pairs
elif ntot == 2:
if np == 1 and nh == 1:
a.setState_HP(hval, pval)
elif nu == 1 and nv == 1:
a.setState_UV(uval, vval)
elif ns == 1 and np == 1:
a.setState_SP(sval, pval)
elif ns == 1 and nv == 1:
a.setState_SV(sval, vval)
elif nt == 1 and np == 1:
a.setState_TP(tval, pval)
elif nt == 1 and nv == 1:
a.setState_TR(tval, 1.0/vval)
elif nt == 1 and nq == 1:
a.setState_Tsat(tval, qval)
elif np == 1 and nq == 1:
a.setState_Psat(pval, qval)
else:
raise CanteraError('unimplemented property pair')
def set(a, **options):
setByName(a, options)

View file

@ -1,45 +0,0 @@
"""
"""
import string
import os
from constants import *
from ThermoPhase import ThermoPhase
from Kinetics import Kinetics
from SolidTransport import SolidTransport
import XML
import _cantera
class Solid(ThermoPhase, Kinetics, SolidTransport):
"""
"""
def __init__(self, src="", root=None):
self.ckin = 0
self._owner = 0
self.verbose = 1
# get the 'phase' element
s = XML.find_XML(src=src, root=root, name="phase")
# get the equation of state model
ThermoPhase.__init__(self, xml_phase=s)
# get the kinetics model
Kinetics.__init__(self, xml_phase=s, phases=[self])
SolidTransport.__init__(self, phase=self)
#self.setState_TP(300.0, OneAtm)
def __repr__(self):
return _cantera.phase_report(self._phase_id, self.verbose)
def __del__(self):
SolidTransport.__del__(self)
Kinetics.__del__(self)
ThermoPhase.__del__(self)

View file

@ -1,13 +0,0 @@
"""This module defines classes and functions used to model gas mixtures."""
from solution import Solution
def Solid(src="",
kmodel=1, transport=None):
return Solution(import_file=import_file,
thermo_db="",
eos=0,
id=id,
kmodel=kmodel,
trmodel=transport,
validate=0)

View file

@ -1,97 +0,0 @@
import os
from constants import *
from ThermoPhase import ThermoPhase
from Kinetics import Kinetics
from Transport import Transport
from set import setByName
import XML
import _cantera
class Solution(ThermoPhase, Kinetics, Transport):
"""
A class for chemically-reacting solutions.
Instances can be created to represent any type of solution -- a
mixture of gases, a liquid solution, or a solid solution, for
example.
Class Solution derives from classes :class:`.ThermoPhase`, :class:`.Kinetics`,
and :class:`.Transport`. It defines very few methods of its own, and is
provided largely for convenience, so that a single object can be
used to compute thermodynamic, kinetic, and transport properties
of a solution. Functions like :func:`.IdealGasMix` and others defined in
module gases return objects of class :class:`.Solution`.
"""
def __init__(self, src="", id="", loglevel = 0, debug = 0):
self.ckin = 0
self._owner = 0
self.verbose = 1
fname = os.path.basename(src)
ff = os.path.splitext(fname)
if src:
root = XML.XML_Node(name = 'doc', src = src,
preprocess = 1, debug = debug)
if id:
s = root.child(id = id)
else:
s = root.child(name = "phase")
self._name = s['id']
# initialize the equation of state
ThermoPhase.__init__(self, xml_phase=s)
# initialize the kinetics model
ph = [self]
Kinetics.__init__(self, xml_phase=s, phases=ph)
# initialize the transport model
Transport.__init__(self, xml_phase=s, phase=self,
model = '', loglevel=loglevel)
def __del__(self):
Transport.__del__(self)
Kinetics.__del__(self)
ThermoPhase.__del__(self)
def __repr__(self):
return _cantera.phase_report(self._phase_id, self.verbose)
def name(self):
return self._name
def set(self, **options):
"""Set various properties.
:param T:
temperature [K]
:param P:
pressure [Pa]
:param Rho:
density [kg/m3]
:param V:
specific volume [m3/kg]
:param H:
specific enthalpy [J/kg]
:param U:
specific internal energy [J/kg]
:param S:
specific entropy [J/kg/K]
:param X:
mole fractions (string or array)
:param Y:
mass fractions (string or array)
:param Vapor:
saturated vapor fraction
:param Liquid:
saturated liquid fraction
"""
setByName(self, options)

View file

@ -1,112 +0,0 @@
""" Solve a steady-state problem by combined damped Newton iteration
and time integration. Function solve is no longer used, now that the
functional equivalent has been added to the Cantera C++ kernel. """
from Cantera import CanteraError
from Cantera.num import array
import math, types
print
"""
module solve is deprecated, and may be removed in a future release. If you
use it and do not want it removed, send an e-mail to cantera-help@caltech.edu.
"""
def solve(sim, loglevel = 0, refine_grid = 1, plotfile = '', savefile = ''):
"""
Solve a steady-state problem by combined damped Newton iteration
and time integration.
"""
new_points = 1
# get options
dt = sim.option('timestep')
ft = sim.option('ftime')
# sequence of timesteps
_steps = sim.option('nsteps')
if type(_steps) == types.IntType: _steps = [_steps]
len_nsteps = len(_steps)
dt = sim.option('timestep')
ll = loglevel
soln_number = -1
max_timestep = sim.option('max_timestep')
sim.collect()
# loop until refine adds no more points
while new_points > 0:
istep = 0
nsteps = _steps[istep]
# loop until Newton iteration succeeds
ok = 0
while ok == 0:
# Try to solve the steady-state problem by damped
# Newton iteration.
try:
if loglevel > 0:
print 'Attempt Newton solution of ',\
'steady-state problem...',
sim.newton_solve(loglevel-1)
if loglevel > 0:
print 'success.\n\n'
print '%'*79+'\n'
print 'Problem solved on ',sim.npts,' point grid(s).\n'
print '%'*79+'\n'
ok = 1
soln_number += 1
sim.finish()
except CanteraError:
# Newton iteration failed.
if loglevel > 0: print '\n'
# Take nsteps time steps, starting with step size
# dt. The final dt may be smaller than the initial
# value if one or more steps fail.
if loglevel == 1:
print 'Take',nsteps,' timesteps',
dt = sim.py_timeStep(nsteps,dt,loglevel=ll-1)
if loglevel == 1: print dt, math.log10(sim.ssnorm())
istep += 1
if istep >= len_nsteps:
nsteps = _steps[-1]
dt *= 2.0
else:
nsteps = _steps[istep]
if dt > max_timestep: dt = max_timestep
# A converged solution was found. Save and/or plot it, then
# check whether the grid should be refined.
# Add the solution to the plot file
if plotfile:
sim.outputTEC(plotfile,"flame","p"+`sim.npts`,append=soln_number)
# If a filename has been specified for a save file, add
# the solution to this file
if savefile:
sim.save(savefile, soln_name+'_'+`sim.npts`+'_points')
if loglevel > 2: sim.show()
if refine_grid:
# Call refine to add new points, if needed
new_points = sim.refine(loglevel = loglevel - 1)
else:
new_points = 0

View file

@ -1,45 +0,0 @@
from Cantera import exceptions
from Cantera.num import array
from Cantera.elements import elementMoles
def det3(A):
"""Determinant of a 3x3 matrix."""
return (A[0,0]*(A[1,1]*A[2,2] - A[1,2]*A[2,1])
- A[0,1]*(A[1,0]*A[2,2] - A[1,2]*A[2,0])
+ A[0,2]*(A[1,0]*A[2,1] - A[2,0]*A[1,1]))
def stoich_fuel_to_oxidizer(mix, fuel, oxidizer):
"""Fuel to oxidizer ratio for stoichiometric combustion.
This function only works for fuels composed of carbon, hydrogen,
and/or oxygen. The fuel to oxidizer ratio is returned that results in
"""
# fuel
mix.setMoleFractions(fuel)
f_carbon = elementMoles(mix, 'C')
f_oxygen = elementMoles(mix, 'O')
f_hydrogen = elementMoles(mix, 'H')
#oxidizer
mix.setMoleFractions(oxidizer)
o_carbon = elementMoles(mix, 'C')
o_oxygen = elementMoles(mix, 'O')
o_hydrogen = elementMoles(mix, 'H')
B = array([f_carbon, f_hydrogen, f_oxygen],'d')
A = array([[1.0, 0.0, -o_carbon],
[0.0, 2.0, -o_hydrogen],
[2.0, 1.0, -o_oxygen]], 'd')
num = array(A,'d')
num[:,2] = B
r = det3(num)/det3(A)
if r <= 0.0:
raise CanteraError('negative or zero computed stoichiometric fuel/oxidizer ratio!')
return 1.0/r
if __name__ == "__main__":
g = GRI30()
print stoich_fuel_to_oxidizer(g, 'CH4:1', 'O2:1')

View file

@ -1,37 +0,0 @@
"""TECPLOT utilities."""
def write_TECPLOT_zone(fname, title, zone, names, npts, nvar, append, data):
"""
Write a TECPLOT zone specification to generate line plots of multiple
variables.
fname -- file name
title -- plot title
zone -- zone name
names -- sequence of variable names
npts -- number of data points
nvar -- number of variables
append -- if > 0, append to plot file, otherwise overwrite
data -- object to generate plot data. This object must have a
method 'value', defined so that data.value(j,n) returns
the value of variable n at point j.
"""
if append > 0:
f = open(fname,'a')
else:
f = open(fname,'w')
f.write('TITLE = "' + title + '"\n')
f.write('VARIABLES = \n')
for nm in names:
f.write('"'+nm+'"\n')
f.write('ZONE T="'+zone+'"\n')
f.write(' I='+`npts`+',J=1,K=1,F=POINT\n')
f.write('DT=(')
for n in range(nvar):
f.write('SINGLE ')
f.write(')\n')
for j in range(npts):
for n in range(nvar):
f.write('%10.4e ' % data[j,n])
f.write('\n')
f.close()

View file

@ -1,65 +0,0 @@
"""Conversion factors to SI (m, kg, kmol, s)"""
from constants import Avogadro, GasConstant
kmol = 1.0
mol = 1.e-3
molecule = kmol/Avogadro
m = 1.0
cm = 0.01
mm = 0.001
m2 = 1.0
cm2 = 1.e-4
mm2 = 1.e-6
A2 = 1.e-20
m3 = 1.0
cm3 = 1.e-6
mm3 = 1.e-9
J = 1.0
kJ = 1000.0
cal = 4.184
kcal = 4184.0
K = 1.0
kJ_per_mol = kJ/mol
cal_per_mol = cal/mol
kcal_per_mol = kcal/mol
mol_per_cm2 = mol/cm/cm
molecule_per_cm2 = molecule/cm/cm
# pressure
Pa = 1.0
kPa = 1000.0
atm = 1.01325e5
bar = 1.0e5
torr = atm/760.0
# mass
kg = 1.0
gm = 1000.0
# mass flux
kg_per_m2_per_s = 1.0
g_per_cm2_per_s = gm/(cm*cm)
_lengthdict = {'m':m, 'cm':cm, 'mm':mm}
def length(u):
return _lengthdict[u]
_moldict = {'kmol':kmol, 'mol':mol, 'molecule':molecule}
def mole(u):
return _moldict[u]
_eadict = {'kJ_per_mol':kJ_per_mol,
'kcal_per_mol':kcal_per_mol,
'cal_per_mol':cal_per_mol,
'K':GasConstant}
def actEnergy(u):
return _eadict[u]/GasConstant

View file

@ -1,244 +0,0 @@
from Tkinter import *
from Cantera import *
from SpeciesInfo import SpeciesInfo
#from KineticsFrame import KineticsFrame
_CUTOFF = 1.e-15
_ATOL = 1.e-15
_RTOL = 1.e-7
class CompFrame(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.config(relief=FLAT, bd=4)
self.top = self.master.top
self.controls=Frame(self)
self.hide = IntVar()
self.hide.set(0)
self.comp = IntVar()
self.comp.set(0)
self.controls.grid(column=1,row=0,sticky=W+E+N)
self.makeControls()
mf = self.master
def makeControls(self):
Radiobutton(self.controls,text='Moles',
variable=self.comp,value=0,
command=self.show).grid(column=0,row=0,sticky=W)
Radiobutton(self.controls,text='Mass',
variable=self.comp,value=1,
command=self.show).grid(column=0,row=1,sticky=W)
Radiobutton(self.controls,text='Concentration',
variable=self.comp,value=2,
command=self.show).grid(column=0,row=2,sticky=W)
Button(self.controls,text='Clear',
command=self.zero).grid(column=0,row=4,sticky=W+E)
Button(self.controls,text='Normalize',
command=self.norm).grid(column=0,row=5,sticky=W+E)
Checkbutton(self.controls,text='Hide Missing\nSpecies',
variable=self.hide,onvalue=1,
offvalue=0,command=self.master.redo).grid(column=0,
row=3,
sticky=W)
def norm(self):
mf = self.master
mf.update()
data = mf.comp
sum = 0.0
for sp in data:
sum += sp
for i in range(len(mf.comp)):
mf.comp[i] /= sum
self.show()
def set(self):
c = self.comp.get()
mix = self.top.mix
mf = self.master
g = mix.g
if c == 0:
mix.setMoles(mf.comp)
elif c == 1:
mix.setMass(mf.comp)
elif c == 2:
pass
self.top.thermo.setState()
self.top.kinetics.show()
def show(self):
mf = self.master
mf.active = self
c = self.comp.get()
mix = self.top.mix
g = mix.g
if c == 0:
mf.var.set("Moles")
#mf.data = spdict(mix.g, mix.moles())
mf.comp = mix.moles()
elif c == 1:
mf.var.set("Mass")
#mf.data = spdict(mix.g,mix.mass())
mf.comp = mix.mass()
elif c == 2:
mf.var.set("Concentration")
mf.comp = mix.concentrations()
#mf.data = spdict(mix,mix,mf.comp)
for s in mf.variable.keys():
try:
k = g.speciesIndex(s)
if mf.comp[k] > _CUTOFF:
mf.variable[s].set(mf.comp[k])
else:
mf.variable[s].set(0.0)
except:
pass
def zero(self):
mf = self.master
mf.comp *= 0.0
self.show()
class MixtureFrame(Frame):
def __init__(self,master,top):
Frame.__init__(self,master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.top.mixframe = self
self.g = self.top.mix.g
#self.scroll = Scrollbar(self)
self.entries=Frame(self)
#self.scroll.config(command=self.entries.xview)
#self.scroll.grid(column=0,row=1)
self.var = StringVar()
self.var.set("Moles")
self.comp = array(self.top.mix.moles())
self.names = self.top.mix.speciesNames()
self.nsp = len(self.names)
#self.data = self.top.mix.moleDict()
self.makeControls()
self.makeEntries()
self.entries.bind('<Double-l>',self.minimize)
self.ctype = 0
self.newcomp = 0
def makeControls(self):
self.c = CompFrame(self)
#self.k = KineticsFrame(self)
self.active = self.c
self.c.grid(column=1,row=0,sticky=E+W+N+S)
#self.k.grid(column=2,row=0,sticky=E+W+N+S)
def update(self):
self.newcomp = 0
for s in self.variable.keys():
k = self.g.speciesIndex(s)
current = self.comp[k]
val = self.variable[s].get()
dv = abs(val - current)
if dv > _RTOL*abs(current) + _ATOL:
self.comp[k] = val
self.newcomp = 1
def show(self):
self.active.show()
## for k in range(self.nsp):
## sp = self.names[k]
## if self.comp[k] > _CUTOFF:
## self.variable[sp].set(self.comp[k])
## else:
## self.variable[sp].set(0.0)
def redo(self):
self.update()
self.entries.destroy()
self.entries=Frame(self)
self.makeEntries()
def minimize(self,Event=None):
self.c.hide.set(1)
self.redo()
self.c.grid_forget()
self.entries.bind("<Double-1>",self.maximize)
def maximize(self,Event=None):
self.c.hide.set(0)
self.redo()
self.c.grid(column=1,row=0,sticky=E+W+N+S)
self.entries.bind("<Double-1>",self.minimize)
def up(self, x):
self.update()
if self.newcomp:
self.c.set()
self.c.show()
self.top.update()
#thermo.showState()
#self.top.kinetics.show()
def makeEntries(self):
self.entries.grid(row=0,column=0,sticky=W+N+S+E)
self.entries.config(relief=FLAT,bd=4)
DATAKEYS = self.top.species
self.variable = {}
n=0
ncol = 3
col = 0
row = 60
equil = 0
if self.top.thermo:
equil = self.top.thermo.equil.get()
for sp in DATAKEYS:
s = sp # self.top.species[sp]
k = s.index
if row > 25:
row = 0
col = col + 2
l = Label(self.entries,text='Species')
l.grid(column=col,row=row,sticky=E+W)
e1 = Entry(self.entries)
e1.grid(column=col+1,row=row,sticky=E+W)
e1['textvariable'] = self.var
e1.config(state=DISABLED)
e1.config(bg='lightyellow',relief=RIDGE)
row = row + 1
spname = s.name
val = self.comp[k]
if not self.c.hide.get() or val: showit = 1
else: showit = 0
l=SpeciesInfo(self.entries,species=s,
text=spname,relief=FLAT,justify=RIGHT,
fg='darkblue')
entry1 = Entry(self.entries)
self.variable[spname] = DoubleVar()
self.variable[spname].set(self.comp[k])
entry1['textvariable']=self.variable[spname]
entry1.bind('<Any-Leave>',self.up)
if showit:
l.grid(column= col ,row=row,sticky=E)
entry1.grid(column=col+1,row=row)
n=n+1
row = row + 1
if equil == 1:
entry1.config(state=DISABLED,bg='lightgray')
## if self.c.hide.get():
## b=Button(self.entries,height=1,command=self.maximize)
## else:
## b=Button(self.entries,command=self.minimize)
## b.grid(column=col,columnspan=2, row=row+1)

View file

@ -1,213 +0,0 @@
from types import *
from Tkinter import *
from ScrolledText import ScrolledText
#import datawindow
#import filewindow
def ff():
print ' hi '
class ControlWindow(Frame):
fncs = [ff]*10
def __init__(self, title, master=None):
self.app = master
Frame.__init__(self,master)
self.grid(row=0,column=0,sticky=E+W+N+S)
self.master.title(title)
def addButtons(self, label, funcs):
self.buttonholder = Frame(self, relief=FLAT, bd=2)
self.buttonholder.pack(side=TOP,anchor=W)
b = Label(self.buttonholder,text=label)
b.pack(side=LEFT,fill=X)
for f in funcs:
b=Button(self.buttonholder,
text=f[0],command=f[1], padx=1,pady=1)
b.pack(side=LEFT,fill=X)
def disableButtons(self, *buttons):
for button in self.buttonholder.slaves():
if (button.cget('text') in buttons):
try:
button.config(state=DISABLED)
except:
pass
def enableButtons(self, *buttons):
for button in self.buttonholder.slaves():
if (button.cget('text') in buttons):
try:
button.config(state=NORMAL)
except:
pass
def newFrame(self, label, var):
fr = Frame(self, relief = RIDGE, bd = 2)
fr.pack(side=TOP,fill=X)
c = Checkbutton(fr, variable=var)
c.pack(side = LEFT, fill = X)
b = Label(fr,text=label,foreground="NavyBlue")
b.pack(side=LEFT,fill=X)
return fr
##creates a new Toplevel object
##options: transient=<callback for window close>,
## placement=(<screen x-coord>, <screen y-coord>)
def newWindow(self, master, title, **options):
new = Toplevel(master)
new.title(title)
#new.config(takefocus=0)
if 'transient' in options.keys():
new.transient(master)
if options['transient']:
new.protocol('WM_DELETE_WINDOW', options['transient'])
if 'placement' in options.keys():
new.geometry("+%d+%d" % tuple(options['placement']))
return new
##routes mouse and keyboard events to the window and
##waits for it to close before returning
def makemodal(self, window):
window.focus_set()
window.grab_set()
window.wait_window()
return
def PlotMenu(self, fr, label, funcs):
filebutton = Menubutton(fr,text=label, padx=3,pady=1)
filebutton.pack(side=LEFT)
filemenu = Menu(filebutton,tearoff=TRUE)
i = 0
for f in funcs:
filemenu.add_command(label=f[0], command=f[1])
i = i + 1
filebutton['menu']=filemenu
return filemenu
def testevent(event):
print 'event ',event.value
def make_menu(name, menubar, list):
nc = len(name)
button=Menubutton(menubar, text=name, width=nc+4, padx=3,pady=1)
button.pack(side=LEFT)
menu = Menu(button,tearoff=FALSE)
m = menu
i = 0
for entry in list:
i += 1
if entry == 'separator':
menu.add_separator({})
elif type(entry)==ListType:
for num in entry:
menu.entryconfig(num,state=DISABLED)
elif type(entry[1]) != ListType:
if i == 20:
i = 0
submenu = Menu(button,tearoff=FALSE)
m.add_cascade(label='More...',
menu=submenu)
m = submenu
if len(entry) == 2 or entry[2] == 'command':
m.add_command(label=entry[0],
command=entry[1])
elif entry[2] == 'check':
entry[3].set(0)
if len(entry) >= 5: val = entry[4]
else: val = 1
m.add_checkbutton(label=entry[0],
command=entry[1],
variable = entry[3],
onvalue=val)
else:
submenu=make_menu(entry[0], menu, entry[1])
m.add_cascade(label=entry[0],
menu=submenu)
button['menu']=menu
return button
def menuitem_state(button, *statelist):
for menu in button.children.keys():
if isinstance(button.children[menu], Menu):
for (commandnum, onoff) in statelist:
if onoff==0:
button.children[menu].entryconfig(commandnum,state=DISABLED)
if onoff==1:
button.children[menu].entryconfig(commandnum,state=NORMAL)
else:
pass
class ArgumentWindow(Toplevel):
import tkMessageBox
def __init__(self, sim, **options):
Toplevel.__init__(self, sim.cwin)
self.resizable(FALSE,FALSE)
self.protocol("WM_DELETE_WINDOW", lambda:0) #self.cancelled)
self.transient(sim.cwin)
if 'placement' in options.keys():
self.geometry("+%d+%d" % tuple(options['placement']))
self.title('Thermal Model Initialization')
self.sim = sim
self.make_options()
buttonframe = Frame(self)
buttonframe.pack(side=BOTTOM)
b1=Button(buttonframe, text='OK', command=self.callback)
b1.pack(side=LEFT)
#b2=Button(buttonframe, text='Cancel', command=self.cancelled)
#b2.pack(side=LEFT)
self.bind("<Return>", self.callback)
#self.bind("<Escape>", self.cancelled)
self.initial_focus = self
self.initial_focus.focus_set()
#self.wait_window(self)
def make_options(self):
pass
### must override this function ###
### with the entry forms ###
### be sure to use pack or a ###
### frame that is packed into self ###
def getArguments(self):
pass
### must override this function ###
### with the validation checking ###
### must return None if error, ###
### and non_null if ok ###
def callback(self, event=None):
g=self.getArguments()
if not g:
self.initial_focus.focus_set()
return
self.withdraw()
self.update_idletasks()
self.assign(g)
self.cancelled()
def assign(self, obj):
pass
### must override this function ###
### to do the assignment in sim ###
def cancelled(self,event=None):
self.sim.cwin.focus_set()
self.destroy()
if __name__=='__main__':
t = Tk()
ControlWindow(t).mainloop()

View file

@ -1,359 +0,0 @@
import os, math, string
from Tkinter import *
from Cantera import *
from Cantera.num import *
from Cantera import num
from tkFileDialog import askopenfilename
from GraphFrame import Graph
from DataGraph import DataGraph, plotLimits
from ControlPanel import make_menu
U_LOC = 1
V_LOC = 2
T_LOC = 3
P_LOC = 4
Y_LOC = 5
def testit(e = None):
pass
class DataFrame(Frame):
def __init__(self,master,top):
# if master==None:
self.master = Toplevel()
self.master.protocol("WM_DELETE_WINDOW",self.hide)
#else:
# self.master = master
#self.vis = vis
Frame.__init__(self,self.master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.mix = self.top.mix
self.g = self.top.mix.g
self.data = None
self.zdata = None
self.ydata = None
self.plt = None
#self.pltwhat = None
self.datasets = []
self.vars = []
self.whichsoln = IntVar()
self.loc = IntVar()
# self.loc.set(1)
self.lastloc = T_LOC # self.loc.get()
self.datafile = StringVar()
self.solnid = StringVar()
self.gr = Frame(self)
self.n = IntVar()
self.scframe = Frame(self)
self.sc = Scale(self.scframe, variable = self.n,
orient='horizontal',digits=0,
length=300,resolution=1,command=self.updateplot)
self.sc.config(cnf={'from':0,'to':1})
Label(self.scframe,text='Grid Point').grid(column=0,row=0)
self.sc.grid(row=0,column=1)
self.sc.bind('<ButtonRelease-1>',self.updateState)
self.gr.grid(row=4,column=0,columnspan=10)
self.grid(column=0,row=10)
self.makeMenu()
self.hide()
def makeMenu(self):
self.menubar = Frame(self, relief=GROOVE,bd=2)
self.menubar.grid(row=0,column=0,sticky=N+W+E,columnspan=10)
f = [('Open...',self.browseForDatafile)]
#make_menu('File',self.menubar,items)
make_menu('File',self.menubar,f)
make_menu('Dataset',self.menubar,self.datasets)
make_menu('Plot',self.menubar,self.vars)
def browseForDatafile(self, e=None):
pathname = askopenfilename(
filetypes=[("Data Files", ("*.xml","*.csv","*.dat")),
("All Files", "*.*")])
if pathname:
self.datafile.set(pathname)
self.show()
self.getSoln()
def getSoln(self):
fname = os.path.basename(self.datafile.get())
ff = os.path.splitext(fname)
self.datasets = []
if len(ff) == 2 and (ff[1] == '.xml' or ff[1] == '.ctml'):
x = XML.XML_Node('root',src=self.datafile.get())
c = x.child('ctml')
self.solns = c.children('simulation')
if len(self.solns) > 1:
i = 0
for soln in self.solns:
self.datasets.append((soln['id'],self.pickSoln,
'check',self.whichsoln,i))
i += 1
self.solnid.set(self.solns[-1]['id'])
self.soln = self.solns[-1]
self.importData()
elif len(ff) == 2 and (ff[1] == '.csv' or ff[1] == '.CSV'):
self.importCSV()
self.makeMenu()
if self.loc.get() <= 0:
self.loc.set(self.lastloc)
def importCSV(self):
self.lastloc = self.loc.get()
if self.lastloc <= 0: self.lastloc = T_LOC
self.vars = []
self.zdata = None
self.ydata = None
if self.plt:
self.plt.destroy()
f = open(self.datafile.get(),'r')
lines = f.readlines()
vars = string.split(lines[0],',')
nlines = len(lines)
self.np = nlines - 1
nv = len(vars)
vv = []
for n in range(nv):
nm = vars[n].split()
if n < nv - 1 or (len(nm) > 0 and nm[0].isalnum()):
vv.append(nm[0])
else:
break
nv = len(vv)
vars = vv
fdata = zeros((nv, self.np),'d')
for n in range(self.np):
v = string.split(lines[n+1],',')
for j in range(nv):
try:
fdata[j,n] = float(v[j])
except:
fdata[j,n] = 0.0
self.nsp = self.g.nSpecies()
self.y = zeros(self.nsp,'d')
self.data = zeros((self.nsp+6,self.np),'d')
self.data[0,:] = fdata[0,:]
self.label = ['-']*(self.nsp+6)
self.label[0] = vars[0]
w = []
for n in range(1,nv-1):
try:
k = self.g.speciesIndex(vars[n])
except:
k = -1
v2 = vars[n]
if v2 == 'T':
self.data[T_LOC,:] = fdata[n,:]
self.label[T_LOC] = vars[n]
w.append(('T', self.newplot, 'check', self.loc, T_LOC))
elif v2 == 'P':
self.data[P_LOC,:] = fdata[n,:]
self.label[P_LOC] = vars[n]
w.append((vars[n], self.newplot, 'check', self.loc, P_LOC))
elif v2 == 'u':
self.data[U_LOC,:] = fdata[n,:]
self.label[U_LOC] = vars[n]
w.append((vars[n], self.newplot, 'check', self.loc, U_LOC))
elif v2 == 'V':
self.data[V_LOC,:] = fdata[n,:]
self.label[V_LOC] = vars[n]
w.append((vars[n], self.newplot, 'check', self.loc, V_LOC))
elif k >= 0:
self.data[k+Y_LOC,:] = fdata[n,:]
self.label[k+Y_LOC] = vars[n]
w.append((vars[n], self.newplot, 'check', self.loc, k + Y_LOC))
if self.data[P_LOC,0] == 0.0:
self.data[P_LOC,:] = ones(self.np,'d')*OneAtm
print 'Warning: no pressure data. P set to 1 atm.'
self.sc.config(cnf={'from':0,'to':self.np-1})
if self.loc.get() <= 0:
self.loc.set(self.lastloc)
self.updateplot()
self.vars = w
#self.makeMenu()
self.scframe.grid(row=5,column=0,columnspan=10)
def pickSoln(self):
self.solnid.set(self.solns[self.whichsoln.get()]['id'])
self.soln = self.solns[self.whichsoln.get()]
# self.t.destroy()
self.importData()
def importData(self):
self.lastloc = self.loc.get()
if self.lastloc <= 0: self.lastloc = T_LOC
self.vars = []
self.zdata = None
self.ydata = None
if self.plt:
self.plt.destroy()
self.nsp = self.g.nSpecies()
self.label = ['-']*(self.nsp + 6)
self.y = zeros(self.nsp,'d')
gdata = self.soln.child('flowfield/grid_data')
xp = self.soln.child('flowfield').children('float')
p = 0.0
for x in xp:
if x['title'] == 'pressure':
p = float(x.value())
fa = gdata.children('floatArray')
self.np = int(fa[0]['size'])
self.data = zeros((self.nsp+6,self.np),'d')
w = []
for f in fa:
t = f['title']
try:
k = self.g.speciesIndex(t)
except:
k = -1
v = XML.getFloatArray(f)
if t == 'z' or t == 't':
self.data[0,:] = v
self.label[0] = t
elif k >= 0:
self.data[k + Y_LOC] = v
self.label[k + Y_LOC] = t
w.append((t, self.newplot, 'check', self.loc, k + Y_LOC))
elif t == 'T':
self.data[T_LOC,:] = v
self.label[T_LOC] = t
w.append((t, self.newplot, 'check', self.loc, T_LOC))
elif t == 'u':
self.data[U_LOC,:] = v
self.label[U_LOC] = t
w.append((t, self.newplot, 'check', self.loc, U_LOC))
elif t == 'V':
self.data[V_LOC,:] = v
self.label[V_LOC] = t
w.append((t, self.newplot, 'check', self.loc, V_LOC))
self.data[P_LOC,:] = ones(self.np,'d')*p
self.label[P_LOC] = 'P (Pa)'
self.sc.config(cnf={'from':0,'to':self.np-1})
if self.loc.get() <= 0:
self.loc.set(self.lastloc)
self.updateplot()
self.vars = w
self.scframe.grid(row=5,column=0,columnspan=10)
def hide(self):
#self.vis.set(0)
self.master.withdraw()
#if self.pltwhat: self.pltwhat.withdraw()
def show(self, e=None):
self.master.deiconify()
def updateState(self, e=None):
n = self.n.get()
if self.plt: self.plt.update()
for k in range(self.nsp):
self.y[k] = self.data[k+Y_LOC,n]
self.top.thermo.checkTPBoxes()
self.mix.setMass(self.y)
self.mix.set(temperature = self.data[T_LOC,n],
pressure = self.data[P_LOC,n])
self.top.update()
def newplot(self,e=0):
loc = self.loc.get()
self.zdata = self.data[0,:]
self.ydata = self.data[loc,:]
npts = len(self.zdata)
ylog = 0
if loc >= Y_LOC:
for n in range(npts):
if self.ydata[n] <= 0.0:
#print n, self.ydata[n]
self.ydata[n] = 1.0e-20
self.ydata = num.log10(self.ydata)
ylog = 1
self.gdata = []
zmin = self.zdata[0]
zmax = self.zdata[-1]
for n in range(npts):
self.gdata.append((self.zdata[n],self.ydata[n]))
ymin, ymax, dtick = plotLimits(self.ydata)
if loc > 0:
self.plt = DataGraph(self.gr,self.data, 0, loc,
title='',
label=(self.label[0],self.label[loc]),
logscale=(0,ylog),
pixelX=500,pixelY=400)
self.plt.canvas.config(bg='white')
self.plt.grid(row=1,column=0,columnspan=2,sticky=W+E)
n = self.n.get()
self.gdot = self.plt.plot(n,'red')
def updateplot(self,event=None):
if self.data == None: return
if self.zdata == None:
self.newplot()
n = self.n.get()
self.pnt = self.zdata[n], self.ydata[n]
if hasattr(self, 'gdot'):
self.plt.delete(self.gdot)
self.gdot = self.plt.plot(n,'red')
def plotLimits(self, xy):
ymax = -1.e10
ymin = 1.e10
for x, y in xy:
if y > ymax: ymax = y
if y < ymin: ymin = y
dy = abs(ymax - ymin)
if dy < 0.2*ymin:
ymin = ymin*.9
ymax = ymax*1.1
dy = abs(ymax - ymin)
else:
ymin = ymin - 0.1*dy
ymax = ymax + 0.1*dy
dy = abs(ymax - ymin)
p10 = math.floor(math.log10(0.1*dy))
fctr = math.pow(10.0, p10)
mm = [2.0, 2.5, 2.0]
i = 0
while dy/fctr > 5:
fctr = mm[i % 3]*fctr
i = i + 1
ymin = fctr*math.floor(ymin/fctr)
ymax = fctr*(math.floor(ymax/fctr + 1))
return (ymin, ymax, fctr)

View file

@ -1,229 +0,0 @@
from Tkinter import *
import math
from Cantera.num import *
def plotLimits(ypts, f=0.0, ndiv=5, logscale=0):
"""Return plot limits that"""
if logscale:
threshold = 1.0e-19
else:
threshold = -1.0e20
ymax = -1.e20
ymin = 1.e20
for y in ypts:
if y > ymax: ymax = y
if y < ymin and y > threshold: ymin = y
dy = abs(ymax - ymin)
if logscale:
ymin = math.floor(math.log10(ymin))
ymax = math.floor(math.log10(ymax))+1
fctr = 1.0
## if dy < 0.2*ymin:
## ymin = ymin*.9
## ymax = ymax*1.1
## dy = abs(ymax - ymin)
## else:
else:
ymin = ymin - f*dy
ymax = ymax + f*dy
dy = abs(ymax - ymin)
try:
p10 = math.floor(math.log10(0.1*dy))
fctr = math.pow(10.0, p10)
except:
return (ymin -1.0, ymax + 1.0, 1.0)
mm = [2.0, 2.5, 2.0]
i = 0
while dy/fctr > ndiv:
fctr = mm[i % 3]*fctr
i = i + 1
ymin = fctr*math.floor(ymin/fctr)
ymax = fctr*(math.floor(ymax/fctr+0.999))
return (ymin, ymax, fctr)
class DataGraph(Frame):
def __init__(self,master,
data, ix=0, iy=0,
title='',
label = ('x-axis','y-axis'),
logscale = (0,0),
pixelX=500,
pixelY=500):
self.logscale = logscale
self.data = data
self.ix = ix
self.iy = iy
self.minX, self.maxX, self.dx = plotLimits(data[ix,:],
logscale=self.logscale[0])
self.minY, self.maxY, self.dy = plotLimits(data[iy,:],
logscale=self.logscale[1])
Frame.__init__(self,master, relief=RIDGE, bd=2)
self.title = Label(self,text=' ')
self.title.grid(row=0,column=1,sticky=W+E)
self.graph_w, self.graph_h = pixelX - 120, pixelY - 70
self.origin = (100, 20)
self.canvas = Canvas(self,
width=pixelX,
height=pixelY,
relief=SUNKEN,bd=1)
id = self.canvas.create_rectangle(self.origin[0],self.origin[1],
pixelX-20,pixelY-50)
self.canvas.grid(row=1,column=1,rowspan=2,sticky=N+S+E+W)
self.last_points=[]
self.ticks(self.minX, self.maxX, self.dx,
self.minY, self.maxY, self.dy, 10)
self.screendata()
self.draw()
self.canvas.create_text(self.origin[0] + self.graph_w/2,
self.origin[1] + self.graph_h + 30,
text=label[0],anchor=N)
self.canvas.create_text(self.origin[0] - 50,
self.origin[1] + self.graph_h/2,
text=label[1],anchor=E)
def writeValue(self, y):
yval = '%15.4f' % (y)
self.title.config(text = yval)
def delete(self, ids):
for id in ids:
self.canvas.delete(id)
def screendata(self):
self.xdata = array(self.data[self.ix,:])
self.ydata = array(self.data[self.iy,:])
npts = len(self.ydata)
if self.logscale[0] > 0:
self.xdata = log10(self.xdata)
if self.logscale[1] > 0:
self.ydata = log10(self.ydata)
f = float(self.graph_w)/(self.maxX-self.minX)
self.xdata = (self.xdata - self.minX)*f + self.origin[0]
f = float(self.graph_h)/(self.maxY-self.minY)
self.ydata = (self.maxY - self.ydata)*f + self.origin[1]
def toscreen(self,x,y):
if self.logscale[0] > 0:
x = log10(x)
if self.logscale[1] > 0:
y = log10(y)
f = float(self.graph_w)/(self.maxX-self.minX)
xx = (x - self.minX)*f + self.origin[0]
f = float(self.graph_h)/(self.maxY-self.minY)
yy = (self.maxY - y)*f + self.origin[1]
return (xx, yy)
def move(self, id, newpos, oldpos):
dxpt = (newpos[0] - oldpos[0])/(self.maxX-self.minX)*self.graph_w
dypt = -(newpos[1] - oldpos[1])/(self.maxY-self.minY)*self.graph_h
self.canvas.move(id, dxpt, dypt)
self.writeValue(newpos[1])
def plot(self,n,color='black'):
xpt, ypt = self.toscreen(self.data[self.ix,n],
self.data[self.iy,n])
#xpt = (x-self.minX)/(self.maxX-self.minX)*float(self.graph_w) + self.origin[0]
#ypt = (self.maxY-y)/(self.maxY-self.minY)*float(self.graph_h) + self.origin[1]
id_ycross = self.canvas.create_line(xpt,self.graph_h+self.origin[1],xpt,self.origin[1],fill = 'gray')
id_xcross = self.canvas.create_line(self.origin[0],ypt,self.graph_w+self.origin[0],ypt,fill = 'gray')
id = self.canvas.create_oval(xpt-2,ypt-2,xpt+2,ypt+2,fill=color)
#self.writeValue(y)
s = '(%g, %g)' % (self.data[self.ix,n],self.data[self.iy,n])
if n > 0 and self.data[self.iy,n] > self.data[self.iy,n-1]:
idt = self.canvas.create_text(xpt+5,ypt+5,text=s,anchor=NW)
else:
idt = self.canvas.create_text(xpt+5,ypt-5,text=s,anchor=SW)
return [id,id_xcross,id_ycross, idt]
def draw(self,color='red'):
npts = len(self.xdata)
for n in range(1,npts):
self.canvas.create_line(self.xdata[n-1],self.ydata[n-1],
self.xdata[n],self.ydata[n],fill=color)
def addLabel(self, y, orient=0):
if orient==0:
xpt, ypt = self.toscreen(y, 1.0)
ypt = self.origin[1] + self.graph_h + 5
self.canvas.create_text(xpt,ypt,text=y,anchor=N)
else:
xpt, ypt = self.toscreen(self.minX, y)
xpt = self.origin[0] - 5
self.canvas.create_text(xpt,ypt,text=y,anchor=E)
def addLegend(self,text,color=None):
m=Message(self,text=text,width=self.graph_w-10)
m.pack(side=BOTTOM)
if color:
m.config(fg=color)
def pauseWhenFinished(self):
self.wait_window()
def minorTicks(self, x0, x1, y, n, size, orient=0):
xtick = x0
dx = (x1 - x0)/float(n)
if orient == 0:
while xtick <= x1:
xx, yy = self.toscreen(xtick, y)
self.canvas.create_line(xx,yy,
xx,yy-size)
xtick += dx
else:
while xtick <= x1:
xx, yy = self.toscreen(y, xtick)
self.canvas.create_line(xx,yy,
xx+size,yy)
xtick += dx
def ticks(self, xmin, xmax, dx, ymin, ymax, dy, size):
if self.logscale[0]:
xmin = math.pow(10.0,xmin)
xmax = math.pow(10.0,xmax)
if self.logscale[1]:
ymin = math.pow(10.0,ymin)
ymax = math.pow(10.0,ymax)
n = 5
ytick = ymin
while ytick <= ymax:
xx, yy = self.toscreen(xmin, ytick)
self.canvas.create_line(xx, yy, xx + size,yy)
self.addLabel(ytick,1)
xx, yy = self.toscreen(xmax, ytick)
self.canvas.create_line(xx, yy, xx - size,yy)
ytick0 = ytick
if self.logscale[1]:
ytick *= 10.0
n = 10
else: ytick = ytick + dy
if ytick <= ymax:
self.minorTicks(ytick0, ytick, xmin, n, 5, 1)
self.minorTicks(ytick0, ytick, xmax, n, -5, 1)
n = 5
xtick = xmin
while xtick <= xmax:
xx, yy = self.toscreen(xtick, ymin)
self.canvas.create_line(xx, yy, xx, yy - size)
self.addLabel(xtick,0)
xx, yy = self.toscreen(xtick, ymax)
self.canvas.create_line(xx, yy, xx, yy + size)
if self.logscale[0]:
xtick *= 10.0
n = 10
else: xtick = xtick + dx
if xtick <= xmax:
self.minorTicks(xtick - dx, xtick, ymin, n, 5, 0)
self.minorTicks(xtick - dx, xtick, ymax, n, -5, 0)

View file

@ -1,193 +0,0 @@
from Tkinter import *
from ElementFrame import getElements
from utilities import handleError
from Cantera import *
from config import *
from SpeciesFrame import getSpecies
def testit():
pass
class EditFrame(Frame):
def redraw(self):
try:
self.eframe.destroy()
self.sframe.destroy()
self.rframe.destroy()
except:
pass
self.addElementFrame()
self.addSpeciesFrame()
self.addReactionFrame()
def __init__(self, master, app):
Frame.__init__(self, master)
self.mix = app.mix
print self.mix, dir(self.mix)
self.app = app
self.master = master
self.master.title("Cantera Mechanism Editor")
self.redraw()
def addReactionFrame(self):
self.rframe = Frame(self)
self.rframe.config(relief=GROOVE,bd=4)
self.rframe.grid(row=2,column=0,columnspan=10,sticky=E+W)
b=Button(self.rframe,text='Reactions',command=testit)
b.grid(column=5, row=0)
def addElementFrame(self):
self.eframe = Frame(self)
self.eframe.config(relief=GROOVE,bd=4)
self.eframe.grid(row=0,column=0,columnspan=10,sticky=E+W)
self.element_labels = []
n = 0
for el in self.mix._mech.elementNames():
x = Label(self.eframe,text=el,fg='darkblue')
x.grid(column = n, row=0)
self.element_labels.append(x)
n = n + 1
b=Button(self.eframe,text='Element',command=self.chooseElements, default=ACTIVE)
b.grid(column=0, row=1, columnspan=10)
def addSpeciesFrame(self):
self.sframe = Frame(self)
self.sframe.config(relief=GROOVE,bd=4)
self.sframe.grid(row=1,column=0,columnspan=10,sticky=E+W)
r = 0
c = 0
splist = self.app.species
self.spcheck = []
self.spec = []
for i in range(self.app.mech.nSpecies()):
self.spec.append(IntVar())
self.spec[i].set(1)
self.spcheck.append( Checkbutton(self.sframe,
text=splist[i].name,
variable=self.spec[i],
onvalue = 1, offvalue = 0) )
self.spcheck[i].grid(row = r, column = c, sticky = N+W)
self.spcheck[i].bind("<Button-3>", self.editSpecies)
c = c + 1
if c > 4:
c, r = 0, r + 1
def getspecies(self):
print getSpecies(self.mix.speciesNames(),
self.mix.speciesNames())
def editSpecies(self, event=None):
e = Toplevel(event.widget.master)
w = event.widget
txt = w.cget('text')
sp = self.app.mix.species[txt]
# name, etc.
e1 = Frame(e, relief=FLAT)
self.addEntry(e1,'Name',0,0,sp.name)
self.addEntry(e1,'ID Tag',1,0,sp.id)
self.addEntry(e1,'Phase',2,0,sp.phase)
e1.grid(row=0,column=0)
# elements
elframe = Frame(e)
elframe.grid(row=1,column=0)
Label(elframe,text='Elemental Composition').grid(row=0,column=0,columnspan=2,sticky=E+W)
i = 0
for el in self.app.mech.elementNames():
self.addEntry(elframe,el,i,0,self.mech.nAtoms(sp, el))
i = i + 1
# thermo
thframe = Frame(e)
thframe.grid(row=0,rowspan=2,column=1)
thframe.config(relief=GROOVE,bd=4)
i = 0
Label(thframe,text='Thermodynamic Properties').grid(row=0,
column=0, columnspan=4, sticky=E+W)
if isinstance(sp.thermoParam(),NasaPolynomial):
Label(thframe,text='Parametrization:').grid(row=1,column=1)
self.addEntry(thframe,'',2,0,'NasaPolynomial')
Label(thframe,text='Temperatures (min, mid, max):').grid(row=3,column=1)
self.addEntry(thframe,'',4,0,`sp.minTemp`)
self.addEntry(thframe,'',5,0,`sp.midTemp`)
self.addEntry(thframe,'',6,0,`sp.maxTemp`)
low = Frame(thframe)
low.config(relief=GROOVE,bd=4)
low.grid(row=1,rowspan=6,column=3,columnspan=2)
Label(low,text='Coefficients for the Low\n Temperature Range').grid(row=0,column=0,columnspan=2,sticky=E+W)
c = sp.thermoParam().coefficients(sp.minTemp)
for j in range(7):
self.addEntry(low,'a'+`j`,j+3,0,`c[j]`)
high = Frame(thframe)
high.config(relief=GROOVE,bd=4)
high.grid(row=1,rowspan=6,column=5,columnspan=2)
Label(high,text='Coefficients for the High\n Temperature Range').grid(row=0,column=0,columnspan=2,sticky=E+W)
c = sp.thermoParam().coefficients(sp.maxTemp)
for j in range(7):
self.addEntry(high,'a'+`j`,j+3,0,`c[j]`)
com = Frame(e)
com.grid(row=10,column=0,columnspan=5)
ok = Button(com,text='OK',default=ACTIVE)
ok.grid(row=0,column=0)
ok.bind('<1>',self.modifySpecies)
Button(com,text='Cancel',command=e.destroy).grid(row=0,column=1)
self.especies = e
def modifySpecies(self,event=None):
button = event.widget
e = self.especies
for fr in e.children.values():
for item in fr.children.values():
try:
print item.cget('selection')
except:
pass
e.destroy()
def addEntry(self,master,name,row,column,text):
if name:
Label(master, text=name).grid(row=row, column=column)
nm = Entry(master)
nm.grid(row=row, column=column+1)
nm.insert(END,text)
def chooseElements(self):
oldel = self.mix.g.elementNames()
newel = getElements(self.mix.g.elementNames())
removeList = []
for el in oldel:
if not el in newel:
removeList.append(el)
#self.app.mech.removeElements(removeList)
addList = []
for el in newel:
if not el in oldel:
addList.append(el)
#self.app.mech.addElements(addList)
try:
self.redraw()
self.app.makeWindows()
except:
handleError('Edit err')
self.app.mix = IdealGasMixture(self.app.mech)
self.mix = self.app.mix
nn = self.mix.speciesList[0].name
self.mix.set(temperature = 300.0, pressure = 101325.0, moles = {nn:1.0})
for label in self.element_labels:
label.destroy()
self.element_labels = []
n = 0
for el in self.mix._mech.elementList():
x = Label(self.eframe,text=el.symbol(),fg='darkblue')
x.grid(column = n, row=0)
self.element_labels.append(x)
n = n + 1
self.app.makeWindows()

View file

@ -1,182 +0,0 @@
#
# function getElements displays a periodic table, and returns a list of
# the selected elements
#
from Tkinter import *
from types import *
import tkMessageBox
import string
from Cantera import *
# (row,column) positions in the periodic table
_pos = {'H':(1,1), 'He':(1,18),
'Li':(2,1), 'Be':(2,2),
'B':(2,13), 'C':(2,14), 'N':(2,15), 'O':(2,16), 'F':(2,17), 'Ne':(2,18),
'Na':(3,1), 'Mg':(3,2),
'Al':(3,13), 'Si':(3,14), 'P':(3,15), 'S':(3,16), 'Cl':(3,17), 'Ar':(3,18),
'K':(4,1), 'Ca':(4,2),
'Sc':(4,3), 'Ti':(4,4), 'V':(4,5), 'Cr':(4,6), 'Mn':(4,7), 'Fe':(4,8),
'Co':(4,9), 'Ni':(4,10), 'Cu':(4,11), 'Zn':(4,12),
'Ga':(4,13), 'Ge':(4,14), 'As':(4,15), 'Se':(4,16), 'Br':(4,17), 'Kr':(4,18),
'Rb':(5,1), 'Sr':(5,2),
'Y':(5,3), 'Zr':(5,4), 'Nb':(5,5), 'Mo':(5,6), 'Tc':(5,7), 'Ru':(5,8),
'Rh':(5,9), 'Pd':(5,10), 'Ag':(5,11), 'Cd':(5,12),
'In':(5,13), 'Sn':(5,14), 'Sb':(5,15), 'Te':(5,16), 'I':(5,17), 'Xe':(5,18)
}
class PeriodicTable(Frame):
def __init__(self, master, selected=[]):
Frame.__init__(self,master)
self.master = master
self.control = Frame(self)
self.control.config(relief=GROOVE,bd=4)
Button(self.control, text = 'Display',command=self.show).pack(fill=X,pady=3, padx=10)
Button(self.control, text = 'Clear',command=self.clear).pack(fill=X,pady=3, padx=10)
Button(self.control, text = ' OK ',command=self.get).pack(side=BOTTOM,
fill=X,pady=3, padx=10)
Button(self.control, text = 'Cancel',command=self.master.quit).pack(side=BOTTOM,
fill=X,pady=3, padx=10)
self.entries = Frame(self)
self.entries.pack(side=LEFT)
self.control.pack(side=RIGHT,fill=Y)
self.c = {}
self.element = {}
self.selected = selected
n=0
ncol = 8
for el in _pos.keys():
self.element[el] = Frame(self.entries)
self.element[el].config(relief=GROOVE, bd=4, bg=self.color(el))
self.c[el] = Button(self.element[el],text=el,bg=self.color(el),width=3,relief=FLAT)
self.c[el].pack()
self.c[el].bind("<Button-1>",self.setColors)
self.element[el].grid(row=_pos[el][0]-1, column = _pos[el][1]-1,sticky=W+N+E+S)
n = n + 1
Label(self.entries,text='select the elements to be included, and then press OK.\nTo view the properties of the selected elements, press Display ').grid(row=0, column=2, columnspan=10, sticky=W)
def select(self, el):
e = string.capitalize(el)
self.c[e]['relief'] = RAISED
self.c[e]['bg'] = self.color(e, sel=1)
def deselect(self, el):
e = string.capitalize(el)
self.c[e]['relief'] = FLAT
self.c[e]['bg'] = self.color(e, sel=0)
def selectElements(self,ellist):
for el in ellist:
ename = el
self.select(ename)
def setColors(self,event):
el = event.widget['text']
if event.widget['relief'] == RAISED:
event.widget['relief'] = FLAT
back = self.color(el, sel=0)
elif event.widget['relief'] == FLAT:
event.widget['relief'] = RAISED
back = self.color(el, sel=1)
event.widget['bg'] = back
def color(self, el, sel=0):
_normal = ['#88dddd','#dddd88','#dd8888']
_selected = ['#aaffff','#ffffaa','#ffaaaa']
row, column = _pos[el]
if sel: list = _selected
else: list = _normal
if column < 3:
return list[0]
elif column > 12:
return list[1]
else:
return list[2]
def show(self):
elnames = _pos.keys()
elnames.sort()
selected = []
for el in elnames:
if self.c[el]['relief'] == RAISED:
selected.append(periodicTable[el])
showElementProperties(selected)
def get(self):
self.selected = []
names = _pos.keys()
names.sort()
for el in names:
if self.c[el]['relief'] == RAISED:
self.selected.append(periodicTable[el])
#self.master.quit()'
self.master.destroy()
def clear(self):
for el in _pos.keys():
self.c[el]['bg'] = self.color(el, sel=0)
self.c[el]['relief'] = FLAT
class ElementPropertyFrame(Frame):
def __init__(self,master,ellist):
Frame.__init__(self,master)
n = 1
ellist.sort()
Label(self,text='Name').grid(column=0,row=0,sticky=W+S,padx=10,pady=10)
Label(self,text='Atomic \nNumber').grid(column=1,row=0,sticky=W+S,padx=10,pady=10)
Label(self,
text='Atomic \nWeight').grid(column=2,
row=0,
sticky=W+S,
padx=10,
pady=10)
for el in ellist:
Label(self,
text=el.name).grid(column=0,
row=n,
sticky=W,
padx=10)
Label(self,
text=`el.atomicNumber`).grid(column=1,
row=n,
sticky=W,
padx=10)
Label(self,
text=`el.atomicWeight`).grid(column=2,
row=n,
sticky=W,
padx=10)
n = n + 1
# utility functions
def getElements(ellist=None):
master = Toplevel()
master.title('Periodic Table of the Elements')
t = PeriodicTable(master)
if ellist: t.selectElements(ellist)
t.pack()
t.focus_set()
t.grab_set()
t.wait_window()
try:
master.destroy()
except TclError:
pass
return t.selected
# display table of selected element properties in a window
def showElementProperties(ellist):
m = Tk()
m.title('Element Properties')
elem = []
ElementPropertyFrame(m, ellist).pack()
if __name__ == "__main__":
print getElements()

View file

@ -1,128 +0,0 @@
from Tkinter import *
import math
class Graph(Frame):
def __init__(self,master,title,minX,maxX,minY,maxY,pixelX=250,pixelY=250):
Frame.__init__(self,master, relief=RIDGE, bd=2)
# self.pack()
self.title = Label(self,text=' ')
self.title.grid(row=0,column=1,sticky=W+E)
self.graph_w, self.graph_h = pixelX, pixelY
self.maxX, self.maxY = maxX, maxY #float(math.floor(maxX + 1)), \
#float(math.floor(maxY + 1))
self.minX, self.minY = minX, minY # float(math.floor(minX)), float(math.floor(minY))
self.canvas = Canvas(self,
width=self.graph_w,
height=self.graph_h,
relief=SUNKEN,bd=1)
ymintext = "%8.1f" % (self.minY)
ymaxtext = "%8.1f" % (self.maxY)
self.ml=Label(self, text=ymintext)
self.mr=Label(self, text=ymaxtext)
self.ml.grid(row=2,column=0,sticky=S+E)
self.mr.grid(row=1,column=0,sticky=N+E)
self.canvas.grid(row=1,column=1,rowspan=2,sticky=N+S+E+W)
self.last_points=[]
def writeValue(self, y):
yval = '%15.4f' % (y)
self.title.config(text = yval)
def delete(self, ids):
for id in ids:
self.canvas.delete(id)
def move(self, id, newpos, oldpos):
dxpt = (newpos[0] - oldpos[0])/(self.maxX-self.minX)*self.graph_w
dypt = -(newpos[1] - oldpos[1])/(self.maxY-self.minY)*self.graph_h
self.canvas.move(id, dxpt, dypt)
self.writeValue(newpos[1])
def plot(self,x,y,color='black'):
xpt = (x-self.minX)/(self.maxX-self.minX)*float(self.graph_w) + 1.5
ypt = (self.maxY-y)/(self.maxY-self.minY)*float(self.graph_h) - 1.5
id_ycross = self.canvas.create_line(xpt,self.graph_h,xpt,0,fill = 'gray')
id_xcross = self.canvas.create_line(0,ypt,self.graph_w,ypt,fill = 'gray')
id = self.canvas.create_oval(xpt-2,ypt-2,xpt+2,ypt+2,fill=color)
self.writeValue(y)
return [id,id_xcross,id_ycross]
def reset(self,minX,maxX,minY,maxY):
self.maxX, self.maxY = maxX, maxY
self.minX, self.minY = minX, minY
self.canvas.destroy()
self.canvas = Canvas(self,
width=self.graph_w,
height=self.graph_h,
relief=SUNKEN,bd=1)
self.canvas.create_text(4,2,text=self.maxY,anchor=NW)
self.canvas.create_text(4,self.graph_h,text=self.minY,anchor=SW)
self.ml["text"] = `minX`
self.mr["text"] = `maxX`
self.canvas.pack()
self.last_points = []
def join(self,point_list):
i = 0
for pt in point_list:
x, y, color = pt
if self.last_points == []:
last_x, last_y, last_color = pt
else:
last_x, last_y, last_color = self.last_points[i]
i = i + 1
xpt = (x - self.minX)/(float(self.maxX - self.minX)/self.graph_w) + 1.5
ypt = (self.maxY-y)/(float(self.maxY - self.minY)/self.graph_h) - 1.5
last_xpt = (last_x - self.minX)/(float(self.maxX - self.minX)/self.graph_w) + 1.5
last_ypt = (self.maxY-last_y)/(float(self.maxY - self.minY)/self.graph_h) - 1.5
self.canvas.create_line(last_xpt,last_ypt,
xpt,ypt,fill=color)
self.last_points = point_list
self.canvas.update()
return
def addLegend(self,text,color=None):
m=Message(self,text=text,width=self.graph_w-10)
m.pack(side=BOTTOM)
if color:
m.config(fg=color)
def pauseWhenFinished(self):
self.wait_window()
if __name__=='__main__':
root= Tk()
g = Graph(root,'graph1',0,10,0.01,120)
h = Graph(root,'graph2',0,15,0,20000)
g.pack(side=LEFT)
h.pack(side=RIGHT)
#root.protocol("WM_DELETE_WINDOW", root.destroy())
j = Graph(root,'Graph',0,1000,0,2000)
j.pack()
j.plot(0, 0, color='red')
j.last_points = [ (0, 0, 'red') ]
for i in range(100):
j.join( [ ( (i*10),(i*10+500), 'red' ) ] )
g.addLegend('An example of the GraphFrame')
h.addLegend('This is where the legend goes')
for i in range(100):
if root:
x,y = float(i)/10, i
g.plot(x,y,color='red')
h.plot(i,i**2)#(0,0)
#h.join([(i,i**2,'black')])
else:
break
#print("finished")
g.pauseWhenFinished()
h.pauseWhenFinished()
print g

View file

@ -1,123 +0,0 @@
import os, math
from Tkinter import *
from Cantera import *
#from Cantera.ck2ctml import ck2ctml
from tkFileDialog import askopenfilename
class ImportFrame(Frame):
def __init__(self,top):
self.master = Toplevel()
self.master.title('Convert and Import CK File')
self.master.protocol("WM_DELETE_WINDOW",self.hide)
Frame.__init__(self,self.master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.infile = StringVar()
Label(self,text="Input File").grid(row=0,column=0)
Entry(self, width=40,
textvariable=self.infile).grid(column=1,row=0)
Button(self, text='Browse',
command=self.browseForInput).grid(row=0,column=2)
self.thermo = StringVar()
Label(self,text="Thermodynamic Database").grid(row=1,column=0)
Entry(self, width=40,
textvariable=self.thermo).grid(column=1,row=1)
Button(self, text='Browse',
command=self.browseForThermo).grid(row=1,column=2)
self.transport = StringVar()
Label(self,text="Transport Database").grid(row=2,column=0)
Entry(self, width=40,
textvariable=self.transport).grid(column=1,row=2)
Button(self, text='Browse',
command=self.browseForTransport).grid(row=2,column=2)
bframe = Frame(self)
bframe.config(relief=GROOVE, bd=1)
bframe.grid(row=100,column=0)
Button(bframe, text='OK', width=8, command=self.importfile).grid(row=0,column=0)
self.grid(column=0,row=0)
Button(bframe, text='Cancel', width=8, command=self.hide).grid(row=0,column=1)
self.grid(column=0,row=0)
self.hide()
def browseForInput(self, e=None):
pathname = askopenfilename(
filetypes=[("Reaction Mechanism Files",
("*.inp","*.mech","*.ck2")),
("All Files", "*.*")])
if pathname:
self.infile.set(pathname)
self.show()
def browseForThermo(self, e=None):
pathname = askopenfilename(
filetypes=[("Thermodynamic Databases",
("*.dat","*.inp","*.therm")),
("All Files", "*.*")])
if pathname:
self.thermo.set(pathname)
self.show()
def browseForTransport(self, e=None):
pathname = askopenfilename(
filetypes=[("Transport Databases", "*.dat"),
("All Files", "*.*")])
if pathname:
self.transport.set(pathname)
self.show()
def importfile(self):
ckfile = self.infile.get()
thermdb = self.thermo.get()
trandb = self.transport.get()
p = os.path.normpath(os.path.dirname(ckfile))
fname = os.path.basename(ckfile)
ff = os.path.splitext(fname)
nm = ""
if len(ff) > 1: nm = ff[0]
else: nm = ff
outfile = p+os.sep+nm+'.xml'
try:
print 'not supported.'
#ck2ctml(infile = ckfile, thermo = thermdb,
# transport = trandb, outfile = outfile,
# id = nm)
self.hide()
return
except:
print 'Errors were encountered. See log file ck2ctml.log'
self.hide()
return
self.top.loadmech(nm,outfile,1)
self.hide()
## cmd = 'ck2ctml -i '+ckfile+' -o '+outfile
## if thermdb <> "":
## cmd += ' -t '+thermdb
## if trandb <> "":
## cmd += ' -tr '+trandb
## cmd += ' -id '+nm
## ok = os.system(cmd)
## if ok == 0:
## self.top.loadmech(nm,outfile,1)
def hide(self):
#self.vis.set(0)
self.master.withdraw()
def show(self):
#v = self.vis.get()
#if v == 0:
# self.hide()
# return
self.master.deiconify()

View file

@ -1,417 +0,0 @@
import os, math
from Tkinter import *
from Cantera import *
from SpeciesInfo import SpeciesInfo
from Cantera import rxnpath
import webbrowser
_CUTOFF = 1.e-15
_ATOL = 1.e-15
_RTOL = 1.e-7
def showsvg():
f = open('_rp_svg.html','w')
f.write('<embed src="rxnpath.svg" name="rxnpath" height=500\n')
f.write('type="image/svg-xml" pluginspage="http://www.adobe.com/svg/viewer/install/">\n')
f.close()
webbrowser.open('file:///'+os.getcwd()+'/_rp_svg.html')
def showpng():
f = open('_rp_png.html','w')
f.write('<img src="rxnpath.png" height=500/>\n')
f.close()
webbrowser.open('file:///'+os.getcwd()+'/_rp_png.html')
class KineticsFrame(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.config(relief=FLAT, bd=4)
self.top = self.master.top
self.controls=Frame(self)
self.hide = IntVar()
self.hide.set(0)
self.comp = IntVar()
self.comp.set(2)
self.controls.grid(column=1,row=0,sticky=W+E+N)
self.makeControls()
mf = self.master
def makeControls(self):
Radiobutton(self.controls,text='Creation Rates',
variable=self.comp,value=0,
command=self.show).grid(column=0,row=0,sticky=W)
Radiobutton(self.controls,text='Destruction Rates',
variable=self.comp,value=1,
command=self.show).grid(column=0,row=1,sticky=W)
Radiobutton(self.controls,text='Net Production Rates',
variable=self.comp,value=2,
command=self.show).grid(column=0,row=2,sticky=W)
def show(self):
mf = self.master
mf.active = self
c = self.comp.get()
mix = self.top.mix
g = mix.g
if c == 0:
mf.var.set("Creation Rates")
#mf.data = spdict(mix.g, mix.moles())
mf.comp = g.creationRates()
elif c == 1:
mf.var.set("Destruction Rates")
#mf.data = spdict(mix.g,mix.mass())
mf.comp = g.destructionRates()
elif c == 2:
mf.var.set("Net Production Rates")
mf.comp = g.netProductionRates()
#mf.data = spdict(mix,mix,mf.comp)
for s in mf.variable.keys():
try:
k = g.speciesIndex(s)
if mf.comp[k] > _CUTOFF or -mf.comp[k] > _CUTOFF:
mf.variable[s].set(mf.comp[k])
else:
mf.variable[s].set(0.0)
except:
pass
class SpeciesKineticsFrame(Frame):
def __init__(self,master,top):
Frame.__init__(self,master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.top.kinetics = self
self.g = self.top.mix.g
self.entries=Frame(self)
self.var = StringVar()
self.var.set("Net Production Rates")
self.names = self.top.mix.speciesNames()
self.nsp = len(self.names)
self.comp = [0.0]*self.nsp
self.makeControls()
self.makeEntries()
self.entries.bind('<Double-l>',self.minimize)
self.ctype = 0
def makeControls(self):
self.c = KineticsFrame(self)
#self.rr = ReactionKineticsFrame(self, self.top)
self.c.grid(column=1,row=0,sticky=E+W+N+S)
#self.rr.grid(column=0,row=1,sticky=E+W+N+S)
def show(self):
self.c.show()
def redo(self):
self.update()
self.entries.destroy()
self.entries=Frame(self)
self.makeEntries()
def minimize(self,Event=None):
self.c.hide.set(1)
self.redo()
self.c.grid_forget()
self.entries.bind("<Double-1>",self.maximize)
def maximize(self,Event=None):
self.c.hide.set(0)
self.redo()
self.c.grid(column=1,row=0,sticky=E+W+N+S)
self.entries.bind("<Double-1>",self.minimize)
def up(self, x):
self.update()
def makeEntries(self):
self.entries.grid(row=0,column=0,sticky=W+N+S+E)
self.entries.config(relief=FLAT,bd=4)
DATAKEYS = self.top.species
self.variable = {}
n=0
ncol = 3
col = 0
row = 60
for sp in DATAKEYS:
s = sp
k = s.index
if row > 15:
row = 0
col = col + 2
l = Label(self.entries,text='Species')
l.grid(column=col,row=row,sticky=E+W)
e1 = Entry(self.entries)
e1.grid(column=col+1,row=row,sticky=E+W)
e1['textvariable'] = self.var
e1.config(state=DISABLED)
e1.config(bg='lightyellow',relief=RIDGE)
row = row + 1
spname = s.name
val = self.comp[k]
if not self.c.hide.get() or val: showit = 1
else: showit = 0
l=SpeciesInfo(self.entries,species=s,
text=spname,relief=FLAT,justify=RIGHT,
fg='darkblue')
entry1 = Entry(self.entries)
self.variable[spname] = DoubleVar()
self.variable[spname].set(self.comp[k])
entry1['textvariable']=self.variable[spname]
entry1.bind('<Any-Leave>',self.up)
if showit:
l.grid(column= col ,row=row,sticky=E)
entry1.grid(column=col+1,row=row)
n=n+1
row = row + 1
entry1.config(state=DISABLED,bg='lightgray')
class ReactionKineticsFrame(Frame):
def __init__(self,vis,top):
self.master = Toplevel()
self.master.protocol("WM_DELETE_WINDOW",self.hide)
self.vis = vis
Frame.__init__(self,self.master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.g = self.top.mix.g
nr = self.g.nReactions()
self.eqs=Text(self,width=40,height=30)
self.data = []
self.start = DoubleVar()
if nr > 30:
self.end = self.start.get()+30
else:
self.end = self.start.get()+nr
for i in range(4):
self.data.append(Text(self,width=15,height=30))
for n in range(nr):
s = self.g.reactionEqn(n)
self.eqs.insert(END,s+'\n')
self.eqs.grid(column=0,row=1,sticky=W+E+N)
for i in range(4):
self.data[i].grid(column=i+1,row=1,sticky=W+E+N)
Label(self, text='Reaction').grid(column=0,row=0,sticky=W+E+N)
Label(self, text='Fwd ROP').grid(column=1,row=0,sticky=W+E+N)
Label(self, text='Rev ROP').grid(column=2,row=0,sticky=W+E+N)
Label(self, text='Net ROP').grid(column=3,row=0,sticky=W+E+N)
Label(self, text='Kp').grid(column=4,row=0,sticky=W+E+N)
self.scfr = Frame(self)
self.scfr.config(relief=GROOVE,bd=4)
## self.sc = Scrollbar(self.scfr,command=self.show,
## variable = self.start,
## orient='horizontal',length=400)
self.sc = Scale(self.scfr,command=self.show,
variable=self.start,
orient='vertical',length=400)
# self.sc.config(cnf={'from':0,'to':nr},variable = self.start)
#self.sc.bind('<Any-Enter>',self.couple)
#self.scfr.bind('<Any-Leave>',self.decouple)
self.sc.pack(side=RIGHT,fill=Y)
self.scfr.grid(row=0,column=6,rowspan=10,sticky=N+E+W)
self.grid(column=0,row=0)
self.hide()
## def decouple(self,event=None):
## d = DoubleVar()
## xx = self.start.get()
## d.set(xx)
## self.sc.config(variable = d)
## def couple(self,event=None):
## self.sc.config(variable = self.start)
def hide(self):
# self.vis.set(0)
self.master.withdraw()
def show(self,e=None,b=None,c=None):
v = self.vis.get()
print e,b,c
#if v == 0:
# self.hide()
# return
self.master.deiconify()
nr = self.g.nReactions()
frop = self.g.fwdRatesOfProgress()
rrop = self.g.revRatesOfProgress()
kp = self.g.equilibriumConstants()
self.data[0].delete(1.0,END)
self.data[1].delete(1.0,END)
self.data[2].delete(1.0,END)
self.data[3].delete(1.0,END)
self.eqs.delete(1.0,END)
n0 = int(self.start.get())
nn = nr - n0
if nn > 30: nn = 30
for n in range(n0, nn+n0):
s = '%12.5e \n' % (frop[n],)
self.data[0].insert(END,s)
s = '%12.5e \n' % (rrop[n],)
self.data[1].insert(END,s)
s = '%12.5e \n' % (frop[n] - rrop[n],)
self.data[2].insert(END,s)
s = '%12.5e \n' % (kp[n],)
self.data[3].insert(END,s)
self.eqs.insert(END, self.g.reactionEqn(n)+'\n')
class ReactionPathFrame(Frame):
def __init__(self,top):
self.master = Toplevel()
self.master.protocol("WM_DELETE_WINDOW",self.hide)
#self.vis = vis
Frame.__init__(self,self.master)
self.config(relief=GROOVE, bd=4)
self.grid(column=0,row=0)
self.top = top
self.g = self.top.mix.g
self.el = IntVar()
self.el.set(0)
self.thresh = DoubleVar()
scframe = Frame(self)
self.sc = Scale(scframe,variable = self.thresh,
orient='horizontal',digits=3,length=300,resolution=0.01)
self.sc.config(cnf={'from':-6,'to':0})
Label(scframe,text='log10 Threshold').grid(column=0,row=0)
self.sc.grid(row=0,column=1,columnspan=10)
self.sc.bind('<ButtonRelease-1>',self.show)
scframe.grid(row=3,column=0,columnspan=10)
enames = self.g.elementNames()
self.nel = len(enames)
i = 1
eframe = Frame(self)
Label(eframe,text='Element').grid(column=0,row=0,sticky=W)
for e in enames:
Radiobutton(eframe,text=e,
variable=self.el,value=i-1,
command=self.show).grid(column=i,row=0,sticky=W)
i += 1
eframe.grid(row=0,column=0)
self.detailed = IntVar()
Checkbutton(self, text = 'Show details', variable=self.detailed,
command=self.show).grid(column=1,row=0)
self.net = IntVar()
Checkbutton(self, text = 'Show net flux',
variable=self.net,
command=self.show).grid(column=2,row=0)
self.local = StringVar()
Label(self,text='Species').grid(column=1,row=1,sticky=E)
sp = Entry(self, textvariable=self.local,
width=15)
sp.grid(column=2,row=1)
sp.bind('<Any-Leave>',self.show)
self.b = rxnpath.PathBuilder(self.g)
self.fmt = StringVar()
self.fmt.set('svg')
i = 1
fmtframe = Frame(self)
fmtframe.config(relief=GROOVE, bd=4)
self.browser = IntVar()
self.browser.set(0)
Checkbutton(fmtframe, text = 'Display in Web Browser',
variable=self.browser,
command=self.show).grid(column=0,columnspan=6,row=0)
Label(fmtframe,text='Format').grid(column=0,row=1,sticky=W)
for e in ['svg', 'png', 'gif', 'jpg']:
Radiobutton(fmtframe,text=e,
variable=self.fmt,value=e,
command=self.show).grid(column=i,row=1,sticky=W)
i += 1
fmtframe.grid(row=5,column=0,columnspan=10,sticky=E+W)
self.cv = Canvas(self,relief=SUNKEN,bd=1)
self.cv.grid(column=0,row=4,sticky=W+E+N,columnspan=10)
pframe = Frame(self)
pframe.config(relief=GROOVE, bd=4)
self.dot = StringVar()
self.dot.set('dot -Tgif rxnpath.dot > rxnpath.gif')
Label(pframe,text='DOT command:').grid(column=0,row=0,sticky=W)
Entry(pframe,width=60,textvariable=self.dot).grid(column=0,
row=1,sticky=W)
pframe.grid(row=6,column=0,columnspan=10,sticky=E+W)
self.thresh.set(-2.0)
self.hide()
def hide(self):
#self.vis.set(0)
self.master.withdraw()
def show(self,e=None):
self.master.deiconify()
el = self.g.elementName(self.el.get())
det = 'false'
if self.detailed.get() == 1: det = 'true'
flow = 'one_way'
if self.net.get() == 1: flow = 'net'
self.d = rxnpath.PathDiagram(arrow_width=-2,
flow_type=flow,
detailed = det,
threshold=math.pow(10.0,
self.thresh.get()))
node = self.local.get()
try:
k = self.g.speciesIndex(node)
self.d.displayOnly(k)
except:
self.d.displayOnly()
self.b.build(element = el, diagram = self.d,
dotfile = 'rxnpath.dot', format = 'dot')
#self.b.build(element = el, diagram = self.d,
# dotfile = 'rxnpath.txt', format = 'plain')
if self.browser.get() == 1:
fmt = self.fmt.get()
os.system('dot -T'+fmt+' rxnpath.dot > rxnpath.'+fmt)
if fmt == 'svg': showsvg()
elif fmt == 'png': showpng()
else:
path = 'file:///'+os.getcwd()+'/rxnpath.'+fmt
webbrowser.open(path)
try:
self.cv.delete(self.image)
except:
pass
self.cv.configure(width=0, height=0)
else:
os.system(self.dot.get())
self.rp = None
try:
self.cv.delete(self.image)
except:
pass
try:
self.rp = PhotoImage(file='rxnpath.gif')
self.cv.configure(width=self.rp.width(),
height=self.rp.height())
self.image = self.cv.create_image(0,0,anchor=NW,
image=self.rp)
except:
pass

View file

@ -1,81 +0,0 @@
from Cantera import *
from Tkinter import *
from ControlPanel import ControlWindow
from ControlPanel import make_menu, menuitem_state
#from Cantera.Examples.Tk import _mechdir
import os
# automatically-loaded mechanisms
_autoload = [
(' GRI-Mech 3.0', 'gri30.cti'),
(' Air', 'air.cti'),
(' H/O/Ar', 'h2o2.cti')
]
def testit():
pass
class MechManager(Frame):
def __init__(self,master,app):
Frame.__init__(self,master)
#self.config(relief=GROOVE, bd=4)
self.app = app
self.master = master
self.mechindx = IntVar()
self.mechindx.set(1)
#m = Label(self, text = 'Loaded Mechanisms')
#m.grid(column=0,row=0)
# m.bind('<Double-1>',self.show)
# self.mechindx.set(0)
self.mechanisms = []
self.mlist = [ [] ]
i = 1
#for m in self.mechanisms:
# self.mlist.append((m[0], self.setMechanism, 'check', self.mechindx, i))
# i = i + 1
#self.mlist.append([])
self.mechmenu = make_menu('Mixtures', self, self.mlist)
self.mechmenu.grid(row=0,column=0,sticky=W)
self.mfr = None
def addMechanism(self, name, mech):
self.mechanisms.append((name, mech))
il = len(self.mechanisms)
self.mlist[-1] = (name, self.setMechanism, 'check', self.mechindx, il)
self.mlist.append([])
self.mechmenu = make_menu('Mixtures', self, self.mlist)
self.mechindx.set(il)
self.mechmenu.grid(row=0,column=0,sticky=W)
def delMechanism(self, mech):
self.mechanisms.remove(mech)
self.show()
## def show(self,event=None):
## print 'show'
## if self.mfr:
## self.mfr.destroy()
## self.mfr = Frame(self)
## self.mfr.grid(row=1,column=0)
## self.mfr.config(relief=GROOVE, bd=4)
## Label(self.mfr,text='jkl').grid(row=0,column=0)
## i = 0
## for name, mech in self.mechanisms:
## Radiobutton(self.mfr, text=name, variable=self.mechindx,
## value = i,
## command=self.setMechanism).grid(row=i,column=0)
## i = i + 1
## print 'end'
def setMechanism(self, event=None):
i = self.mechindx.get()
self.app.mech = self.mechanisms[i-1][1]
self.app.makeMix()
self.app.makeWindows()

View file

@ -1,138 +0,0 @@
from Cantera import GasConstant, OneAtm
from Cantera.num import zeros, ones
from utilities import handleError
def spdict(phase, x):
nm = phase.speciesNames()
data = {}
for k in range(len(nm)):
data[nm[k]] = x[k]
return data
class Species:
def __init__(self,g,name):
self.g = g
t = g.temperature()
p = g.pressure()
x = g.moleFractions()
self.name = name
self.symbol = name
self.index = g.speciesIndex(name)
self.minTemp = g.minTemp(self.index)
self.maxTemp = g.maxTemp(self.index)
self.molecularWeight = g.molecularWeights()[self.index]
self.c = []
self.e = g.elementNames()
self.hf0 = self.enthalpy_RT(298.15)*GasConstant*298.15
g.setState_TPX(t,p,x)
for n in range(len(self.e)):
na = g.nAtoms(self.index, n)
if na > 0:
self.c.append((self.e[n],na))
def composition(self):
return self.c
def enthalpy_RT(self,t):
self.g.setTemperature(t)
return self.g.enthalpies_RT()[self.index]
def cp_R(self,t):
self.g.setTemperature(t)
return self.g.cp_R()[self.index]
def entropy_R(self,t):
self.g.setTemperature(t)
return self.g.entropies_R()[self.index]
class Mix:
def __init__(self,g):
self.g = g
self._mech = g
self.nsp = g.nSpecies()
self._moles = zeros(self.nsp,'d')
self.wt = g.molecularWeights()
def setMoles(self, m):
self._moles = m
self.g.setMoleFractions(self._moles)
def moles(self):
return self._moles
def totalMoles(self):
sum = 0.0
for k in range(self.nsp):
sum += self._moles[k]
return sum
def totalMass(self):
sum = 0.0
for k in range(self.nsp):
sum += self._moles[k]*self.wt[k]
return sum
def moleDict(self):
d = {}
nm = self.g.speciesNames()
for e in range(self.nsp):
d[nm[e]] = self._moles[e]
return d
def setMass(self, m):
self.setMoles( m/self.wt)
def mass(self):
return self.wt*self._moles
def speciesNames(self):
return self.g.speciesNames()
def massDict(self):
d = {}
nm = self.g.speciesNames()
for e in range(self.nsp):
d[nm[e]] = self._moles[e]*self.wt[e]
return d
def set(self, temperature = None, pressure = None,
density = None, enthalpy = None,
entropy = None, intEnergy = None, equil = 0):
total_mass = self.totalMass()
if temperature and pressure:
self.g.setState_TP(temperature, pressure)
if equil:
self.g.equilibrate('TP',solver=0)
elif temperature and density:
self.g.setState_TR(temperature, density)
if equil:
self.g.equilibrate('TV',solver=0)
elif pressure and enthalpy:
self.g.setState_HP(enthalpy, pressure)
if equil:
self.g.equilibrate('HP',solver=0)
elif pressure and entropy:
self.g.setState_SP(entropy, pressure)
if equil:
self.g.equilibrate('SP',solver=0)
elif density and entropy:
self.g.setState_SV(entropy, 1.0/density)
if equil:
self.g.equilibrate('SV',solver=0)
elif density and intEnergy:
self.g.setState_UV(intEnergy, 1.0/density)
if equil:
self.g.equilibrate('UV',solver=0)
# else:
# handleError('unsupported property pair', warning=1)
total_moles = total_mass/self.g.meanMolecularWeight()
self._moles = self.g.moleFractions()*total_moles

View file

@ -1,114 +0,0 @@
from Tkinter import *
from Cantera import *
from SpeciesInfo import SpeciesInfo
_CUTOFF = 1.e-15
_ATOL = 1.e-15
_RTOL = 1.e-7
class NewFlowFrame(Frame):
def __init__(self,master):
Frame.__init__(self,master)
self.config(relief=GROOVE, bd=4)
self.app = self.master.app
self.controls=Frame(self)
self.hide = IntVar()
self.hide.set(0)
self.p = DoubleVar()
#self.comp.set(1.0)
self.controls.grid(column=1,row=0,sticky=W+E+N)
#self.makeControls()
mf = self.master
e1 = Entry(self)
e1.grid(column=0,row=0,sticky=E+W)
e1['textvariable'] = self.p
#e1.config(state=ENABLED)
e1.config(relief=RIDGE)
## def makeControls(self):
## Radiobutton(self.controls,text='Moles',
## variable=self.comp,value=0,command=self.show).grid(column=0,row=0,sticky=W)
## Radiobutton(self.controls,text='Mass',variable=self.comp,value=1,command=self.show).grid(column=0,row=1,sticky=W)
## Radiobutton(self.controls,text='Concentration',variable=self.comp,value=2,command=self.show).grid(column=0,row=2,sticky=W)
## Button(self.controls,text='Clear',command=self.zero).grid(column=0,row=4,sticky=W+E)
## Button(self.controls,text='Normalize',command=self.norm).grid(column=0,row=5,sticky=W+E)
## Checkbutton(self.controls,text='Hide Missing\nSpecies',
## variable=self.hide,onvalue=1,offvalue=0,command=self.master.redo).grid(column=0,row=3,sticky=W)
## def makeControls(self):
## self.c = CompFrame(self)
## self.c.grid(column=1,row=0,sticky=E+W+N+S)
## def redo(self):
## self.update()
## self.entries.destroy()
## self.entries=Frame(self)
## self.makeEntries()
## def minimize(self,Event=None):
## self.c.hide.set(1)
## self.redo()
## self.c.grid_forget()
## self.entries.bind("<Double-1>",self.maximize)
## def maximize(self,Event=None):
## self.c.hide.set(0)
## self.redo()
## self.c.grid(column=1,row=0,sticky=E+W+N+S)
## self.entries.bind("<Double-1>",self.minimize)
## def makeEntries(self):
## self.entries.grid(row=0,column=0,sticky=W+N+S+E)
## self.entries.config(relief=GROOVE,bd=4)
## DATAKEYS = self.top.species
## self.variable = {}
## n=0
## ncol = 3
## col = 0
## row = 60
## presbox =
## for sp in DATAKEYS:
## s = sp # self.top.species[sp]
## k = s.index
## if row > 15:
## row = 0
## col = col + 2
## l = Label(self.entries,text='Species')
## l.grid(column=col,row=row,sticky=E+W)
## e1 = Entry(self.entries)
## e1.grid(column=col+1,row=row,sticky=E+W)
## e1['textvariable'] = self.var
## e1.config(state=DISABLED)
## e1.config(bg='lightyellow',relief=RIDGE)
## row = row + 1
## spname = s.name
## val = self.comp[k]
## if not self.c.hide.get() or val: showit = 1
## else: showit = 0
## l=SpeciesInfo(self.entries,species=s,
## text=spname,relief=FLAT,justify=RIGHT,
## fg='darkblue')
## entry1 = Entry(self.entries)
## self.variable[spname] = DoubleVar()
## self.variable[spname].set(self.comp[k])
## entry1['textvariable']=self.variable[spname]
## entry1.bind('<Any-Leave>',self.up)
## if showit:
## l.grid(column= col ,row=row,sticky=E)
## entry1.grid(column=col+1,row=row)
## n=n+1
## row = row + 1
## if self.c.hide.get():
## b=Button(self.entries,height=1,command=self.maximize)
## else:
## b=Button(self.entries,command=self.minimize)
## b.grid(column=col,columnspan=2, row=row+1)

View file

@ -1,174 +0,0 @@
#
# function getElements displays a periodic table, and returns a list of
# the selected elements
#
from Tkinter import *
from types import *
import tkMessageBox
from Cantera import *
class SpeciesFrame(Frame):
def __init__(self, master, speciesList = [], selected=[]):
Frame.__init__(self,master)
self.master = master
self.control = Frame(self)
self.species = {}
for sp in speciesList:
self.species[sp.name] = sp
self.control.config(relief=GROOVE,bd=4)
Button(self.control, text = 'Display',command=self.show).pack(fill=X,pady=3, padx=10)
Button(self.control, text = 'Clear',command=self.clear).pack(fill=X,pady=3, padx=10)
Button(self.control, text = ' OK ',command=self.get).pack(side=BOTTOM,
fill=X,pady=3, padx=10)
Button(self.control, text = 'Cancel',command=self.master.quit).pack(side=BOTTOM,
fill=X,pady=3, padx=10)
self.entries = Frame(self)
self.entries.pack(side=LEFT)
self.control.pack(side=RIGHT,fill=Y)
self.c = {}
self.selected = selected
n=0
ncol = 8
rw = 1
col = 0
list = self.species.values()
list.sort()
for sp in list:
el = sp.name
self.species[el] = Frame(self.entries)
self.species[el].config(relief=GROOVE, bd=4, bg=self.color(el))
self.c[el] = Button(self.species[el],text=el,bg=self.color(el),width=6,relief=FLAT)
self.c[el].pack()
self.c[el].bind("<Button-1>",self.setColors)
self.species[el].grid(row= rw, column = col,sticky=W+N+E+S)
col = col + 1
if col > ncol:
rw = rw + 1
col = 0
Label(self.entries,text='select the species to be included, and then press OK.\nTo view the properties of the selected species, press Display ').grid(row=0, column=2, columnspan=10, sticky=W)
def select(self, el):
self.c[el]['relief'] = RAISED
self.c[el]['bg'] = self.color(el, sel=1)
def deselect(self, el):
self.c[el]['relief'] = FLAT
self.c[el]['bg'] = self.color(el, sel=0)
def selectSpecies(self,splist):
for sp in splist:
spname = sp.name
self.select(spname)
def setColors(self,event):
el = event.widget['text']
if event.widget['relief'] == RAISED:
event.widget['relief'] = FLAT
back = self.color(el, sel=0)
fore = '#ffffff'
elif event.widget['relief'] == FLAT:
event.widget['relief'] = RAISED
fore = '#000000'
back = self.color(el, sel=1)
event.widget['bg'] = back
event.widget['fg'] = fore
def color(self, el, sel=0):
_normal = ['#88dddd','#005500','#dd8888']
_selected = ['#aaffff','#88dd88','#ffaaaa']
#row, column = _pos[el]
if sel: list = _selected
else: list = _normal
return list[1]
#if column < 3:
# return list[0]
#elif column > 12:
# return list[1]
#else:
# return list[2]
def show(self):
selected = []
for sp in self.species.values():
if self.c[sp.name]['relief'] == RAISED:
selected.append(sp)
#showElementProperties(selected)
def get(self):
self.selected = []
for sp in self.species.values():
if self.c[sp.name]['relief'] == RAISED:
self.selected.append(sp)
#self.master.quit()'
self.master.destroy()
def clear(self):
for sp in self.species.values():
self.c[sp]['bg'] = self.color(sp, sel=0)
self.c[sp]['relief'] = FLAT
## class ElementPropertyFrame(Frame):
## def __init__(self,master,ellist):
## Frame.__init__(self,master)
## n = 1
## ellist.sort()
## Label(self,text='Name').grid(column=0,row=0,sticky=W+S,padx=10,pady=10)
## Label(self,text='Atomic \nNumber').grid(column=1,row=0,sticky=W+S,padx=10,pady=10)
## Label(self,
## text='Atomic \nWeight').grid(column=2,
## row=0,
## sticky=W+S,
## padx=10,
## pady=10)
## for el in ellist:
## Label(self,
## text=el.name).grid(column=0,
## row=n,
## sticky=W,
## padx=10)
## Label(self,
## text=`el.atomicNumber`).grid(column=1,
## row=n,
## sticky=W,
## padx=10)
## Label(self,
## text=`el.atomicWeight`).grid(column=2,
## row=n,
## sticky=W,
## padx=10)
## n = n + 1
# utility functions
def getSpecies(splist=[],selected=[]):
master = Toplevel()
master.title('Species')
t = SpeciesFrame(master,splist,selected)
if splist: t.selectSpecies(splist)
t.pack()
t.focus_set()
t.grab_set()
t.wait_window()
try:
master.destroy()
except TclError:
pass
return t.selected
# display table of selected element properties in a window
def showElementProperties(ellist):
m = Tk()
m.title('Element Properties')
elem = []
ElementPropertyFrame(m, ellist).pack()
if __name__ == "__main__":
print getSpecies()

View file

@ -1,242 +0,0 @@
from Tkinter import *
import re, math
from Cantera import *
from Units import temperature, specificEnergy, specificEntropy
from UnitChooser import UnitVar
from GraphFrame import Graph
def testit():
pass
class SpeciesInfo(Label):
def __init__(self,master,phase=None,species=None,**opt):
Label.__init__(self,master,opt)
self.sp = species
self.phase = phase
self.bind('<Double-1>', self.show)
self.bind('<Button-3>', self.show)
self.bind('<Any-Enter>', self.highlight)
self.bind('<Any-Leave>', self.nohighlight)
def highlight(self, event=None):
self.config(fg='yellow')
def nohighlight(self, event=None):
self.config(fg='darkblue')
def show(self, event):
self.new=Toplevel()
self.new.title(self.sp.symbol)
#self.new.transient(self.master)
self.new.bind("<Return>", self.update,"+")
self.cpr = 0.0
self.t = 0.0
self.cpl = 0.0
self.tl = 0.0
self.cpp = [[(0.0, 0.0, 'red')]]
# elemental composition
self.eframe = Frame(self.new)
self.eframe.config(relief=GROOVE,bd=4)
self.eframe.grid(row=0,column=0,columnspan=10,sticky=E+W)
r = 1
Label(self.eframe,text='Atoms:')\
.grid(row=0,column=0,sticky=N+W)
for el, c in self.sp.composition():
Label(self.eframe,text=`int(c)`+' '+el).grid(row=0,column=r)
r = r + 1
# thermodynamic properties
self.thermo = Frame(self.new)
self.thermo.config(relief=GROOVE,bd=4)
self.thermo.grid(row=1,column=0,columnspan=10,sticky=N+E+W)
Label(self.thermo,text = 'Standard Heat of Formation at 298 K: ').grid(row=0, column=0, sticky=W)
Label(self.thermo,text = '%8.2f kJ/mol' % (self.sp.hf0*1.0e-6)).grid(row=0, column=1, sticky=W)
Label(self.thermo,text = 'Molar Mass: ').grid(row=1, column=0, sticky=W)
Label(self.thermo,text = self.sp.molecularWeight).grid(row=1, column=1, sticky=W)
labels = ['Temperature', 'c_p', 'Enthalpy', 'Entropy']
units = [temperature, specificEntropy, specificEnergy, specificEntropy]
whichone = [0, 1, 1, 1]
r = 2
self.prop = []
for prop in labels:
Label(self.thermo,text=prop).grid(row=r,column=0,sticky=W)
p = UnitVar(self.thermo,units[r-2],whichone[r-2])
p.grid(row=r,column=1,sticky=W)
p.v.config(state=DISABLED,bg='lightgray')
self.prop.append(p)
r = r + 1
tmin = self.sp.minTemp
tmax = self.sp.maxTemp
cp = self.sp.cp_R(tmin)
hh = self.sp.enthalpy_RT(tmin)
ss = self.sp.entropy_R(tmin)
self.prop[0].bind("<Any-Enter>", self.decouple)
self.prop[0].bind("<Any-Leave>", self.update)
self.prop[0].bind("<Key>", self.update)
self.prop[0].v.config(state=NORMAL,bg='white')
self.prop[0].set(300.0)
self.graphs = Frame(self.new)
self.graphs.config(relief=GROOVE,bd=4)
self.graphs.grid(row=2,column=0,columnspan=10,sticky=E+W)
self.cpdata = []
self.hdata = []
self.sdata = []
t = tmin
n = int((tmax - tmin)/100.0)
while t <= tmax:
self.cpdata.append((t,self.sp.cp_R(t)))
self.hdata.append((t,self.sp.enthalpy_RT(t)))
self.sdata.append((t,self.sp.entropy_R(t)))
t = t + n
# specific heat
Label(self.graphs,text='c_p/R').grid(row=0,column=0,sticky=W+E)
ymin, ymax, dtick = self.plotLimits(self.cpdata)
self.cpg = Graph(self.graphs,'',tmin,tmax,ymin,ymax,
pixelX=150,pixelY=150)
self.cpg.canvas.config(bg='white')
self.cpg.grid(row=1,column=0,columnspan=2,sticky=W+E)
self.ticks(ymin, ymax, dtick, tmin, tmax, self.cpg)
# enthalpy
Label(self.graphs,text='enthalpy/RT').grid(row=0,column=3,sticky=W+E)
ymin, ymax, dtick = self.plotLimits(self.hdata)
self.hg = Graph(self.graphs,'',tmin,tmax,ymin,ymax,
pixelX=150,pixelY=150)
self.hg.canvas.config(bg='white')
self.hg.grid(row=1,column=3,columnspan=2,sticky=W+E)
self.ticks(ymin, ymax, dtick, tmin, tmax, self.hg)
# entropy
Label(self.graphs,text='entropy/R').grid(row=0,column=5,sticky=W+E)
ymin, ymax, dtick = self.plotLimits(self.sdata)
self.sg = Graph(self.graphs,'',tmin,tmax,ymin,ymax,
pixelX=150,pixelY=150)
self.sg.canvas.config(bg='white')
self.sg.grid(row=1,column=5,columnspan=2,sticky=W+E)
self.ticks(ymin, ymax, dtick, tmin, tmax, self.sg)
n = int((tmax - tmin)/100.0)
t = tmin
self.cpp = []
for t, cp in self.cpdata:
self.cpg.join([(t,cp,'red')])
for t, h in self.hdata:
self.hg.join([(t,h,'green')])
for t, s in self.sdata:
self.sg.join([(t,s,'blue')])
self.cpdot = self.cpg.plot(tmin,cp,'red')
self.hdot = self.hg.plot(tmin,hh,'green')
self.sdot = self.sg.plot(tmin,ss,'blue')
b=Button(self.new,text=' OK ',command=self.finished, default=ACTIVE)
#ed=Button(self.new,text='Edit',command=testit)
b.grid(column=0, row=4,sticky=W)
#ed.grid(column=1,row=4,sticky=W)
self.scfr = Frame(self.new)
self.scfr.config(relief=GROOVE,bd=4)
self.scfr.grid(row=3,column=0,columnspan=10,sticky=N+E+W)
self.sc = Scale(self.scfr,command=self.update,variable = self.prop[0].x,
orient='horizontal',digits=7,length=400)
self.sc.config(cnf={'from':tmin,'to':tmax})
self.sc.bind('<Any-Enter>',self.couple)
self.scfr.bind('<Any-Leave>',self.decouple)
self.sc.grid(row=0,column=0,columnspan=10)
def decouple(self,event=None):
d = DoubleVar()
xx = self.prop[0].get()
d.set(xx)
self.sc.config(variable = d)
def couple(self,event=None):
self.sc.config(variable = self.prop[0].x)
#self.update()
def update(self,event=None):
try:
tmp = self.prop[0].get()
cnd = self.sp.cp_R(tmp)
cc = cnd*GasConstant
self.prop[1].set(cc)
hnd = self.sp.enthalpy_RT(tmp)
hh = hnd*tmp*GasConstant
self.prop[2].set(hh)
snd = self.sp.entropy_R(tmp)
ss = snd*tmp*GasConstant
self.prop[3].set(ss)
self.cppoint = tmp, cnd
self.hpoint = tmp, hnd
self.spoint = tmp, snd
if hasattr(self, 'cpdot'):
self.cpg.delete(self.cpdot)
self.cpdot = self.cpg.plot(self.cppoint[0], self.cppoint[1],'red')
self.hg.delete(self.hdot)
self.hdot = self.hg.plot(self.hpoint[0], self.hpoint[1],'green')
self.sg.delete(self.sdot)
self.sdot = self.sg.plot(self.spoint[0], self.spoint[1],'blue')
except:
pass
def plotLimits(self, xy):
ymax = -1.e10
ymin = 1.e10
for x, y in xy:
if y > ymax: ymax = y
if y < ymin: ymin = y
dy = abs(ymax - ymin)
if dy < 0.2*ymin:
ymin = ymin*.9
ymax = ymax*1.1
dy = abs(ymax - ymin)
else:
ymin = ymin - 0.1*dy
ymax = ymax + 0.1*dy
dy = abs(ymax - ymin)
p10 = math.floor(math.log10(0.1*dy))
fctr = math.pow(10.0, p10)
mm = [2.0, 2.5, 2.0]
i = 0
while dy/fctr > 5:
fctr = mm[i % 3]*fctr
i = i + 1
ymin = fctr*math.floor(ymin/fctr)
ymax = fctr*(math.floor(ymax/fctr + 1))
return (ymin, ymax, fctr)
def ticks(self, ymin, ymax, dtick, tmin, tmax, plot):
ytick = ymin
eps = 1.e-3
while ytick <= ymax:
if abs(ytick) < eps:
plot.join([(tmin, ytick, 'gray')])
plot.join([(tmax, ytick, 'gray')])
plot.last_points = []
else:
plot.join([(tmin, ytick, 'gray')])
plot.join([(tmin + 0.05*(tmax - tmin), ytick, 'gray')])
plot.last_points = []
plot.join([(2.0*tmax, ytick, 'gray')])
plot.join([(tmax - 0.05*(tmax - tmin), ytick, 'gray')])
plot.last_points = []
ytick = ytick + dtick
def finished(self,event=None):
self.new.destroy()

View file

@ -1,143 +0,0 @@
from Cantera import *
from Tkinter import *
from Units import temperature, pressure, density, specificEnergy, specificEntropy
from UnitChooser import UnitVar
from ThermoProp import ThermoProp
from utilities import handleError
_PRESSURE = 1
_TEMPERATURE = 0
_DENSITY = 2
_INTENERGY = 3
_ENTHALPY = 4
_ENTROPY = 5
class ThermoFrame(Frame):
def __init__(self,master,top):
Frame.__init__(self,master)
self.config(relief=GROOVE, bd=4)
self.top = top
self.mix = self.top.mix
self.warn = 0
self.internal = Frame(self)
self.internal.pack(side=LEFT,anchor=N+W,padx=2,pady=2)
self.controls=Frame(self.internal)
self.controls.pack(side=LEFT,anchor=N+W,padx=4,pady=5)
self.entries=Frame(self.internal)
self.entries.pack(side=LEFT,anchor=N,padx=4,pady=2)
self.makeEntries()
self.makeControls()
self.showState()
def makeControls(self):
Button(self.controls,text='Set State', width=15,
command=self.setState).grid(column=0,row=0)
self.equil = IntVar()
self.equil.set(0)
Button(self.controls,text='Equilibrate', width=15,
command=self.eqset).grid(column=0,row=1)
## Radiobutton(self.controls,text='Frozen',variable = self.equil,
## command=self.freeze,value=0).grid(column=0,row=2,sticky='W')
## Radiobutton(self.controls,text='Equilibrium',
## variable=self.equil,
## command=self.eqset,value=1).grid(column=0,row=3,sticky='W')
def eqset(self):
self.equil.set(1)
self.setState()
self.equil.set(0)
#if self.top.mixframe:
# self.top.mixframe.redo()
def freeze(self):
self.equil.set(0)
if self.top.mixframe:
self.top.mixframe.redo()
def makeEntries(self):
self.entries.pack()
self.variable = {}
self.prop = []
props = ['Temperature', 'Pressure', 'Density',
'Internal Energy', 'Enthalpy', 'Entropy']
units = [temperature, pressure, density, specificEnergy,
specificEnergy, specificEntropy]
defaultunit = [0, 2, 0, 1, 1, 1]
for i in range(len(props)):
self.prop.append(ThermoProp(self.entries, self, i, props[i],
0.0, units[i], defaultunit[i]))
#self.prop[-1].entry.bind("<Any-Leave>",self.setState)
self.last2 = self.prop[3]
self.last1 = self.prop[2]
self.prop[0].checked.set(1)
self.prop[0].check()
self.prop[1].checked.set(1)
self.prop[1].check()
self.showState()
def checkTPBoxes(self):
if not self.prop[0].isChecked():
self.prop[0].checked.set(1)
self.prop[0].check()
if not self.prop[1].isChecked():
self.prop[1].checked.set(1)
self.prop[1].check()
def showState(self):
self.prop[_TEMPERATURE].set(self.mix.g.temperature())
self.prop[_PRESSURE].set(self.mix.g.pressure())
self.prop[_DENSITY].set(self.mix.g.density())
self.prop[_INTENERGY].set(self.mix.g.intEnergy_mass())
self.prop[_ENTHALPY].set(self.mix.g.enthalpy_mass())
self.prop[_ENTROPY].set(self.mix.g.entropy_mass())
def setState(self,event=None):
if event:
self.warn = 0
else:
self.warn = 1
self.top.mixfr.update()
i = self.equil.get()
optlist = ['frozen','equilibrium']
opt = [optlist[i]]
if self.prop[_PRESSURE].isChecked() \
and self.prop[_TEMPERATURE].isChecked():
self.mix.set(
temperature = self.prop[_TEMPERATURE].get(),
pressure = self.prop[_PRESSURE].get(),
equil=i)
elif self.prop[_DENSITY].isChecked() \
and self.prop[_TEMPERATURE].isChecked():
self.mix.set(
temperature = self.prop[_TEMPERATURE].get(),
density = self.prop[_DENSITY].get(),
equil=i)
elif self.prop[_ENTROPY].isChecked() \
and self.prop[_PRESSURE].isChecked():
self.mix.set(pressure = self.prop[_PRESSURE].get(),
entropy = self.prop[_ENTROPY].get(),
equil=i)
elif self.prop[_ENTHALPY].isChecked() \
and self.prop[_PRESSURE].isChecked():
self.mix.set(pressure = self.prop[_PRESSURE].get(),
enthalpy = self.prop[_ENTHALPY].get(),
equil=i)
elif self.prop[_INTENERGY].isChecked() \
and self.prop[_DENSITY].isChecked():
self.mix.set(density = self.prop[_DENSITY].get(),
intEnergy = self.prop[_INTENERGY].get(),
equil=i)
else:
if self.warn > 0:
handleError("unsupported property pair")
self.top.update()

View file

@ -1,66 +0,0 @@
from Tkinter import *
from UnitChooser import UnitVar
_tv = ['Temperature','Internal Energy','Enthalpy']
_pv = ['Pressure', 'Density']
def badpair(a,b):
if a.name in _tv:
if not b.name in _pv:
return 1
else:
if not b.name in _tv:
return 1
class ThermoProp:
def __init__(self, master, thermoframe, row, name, value, units, defaultunit=0):
self.value = DoubleVar()
self.thermoframe = thermoframe
self.entry = UnitVar(master,units,defaultunit)
self.entry.grid(column=1,row=row,sticky=W)
self.entry.v.config(state=DISABLED,bg='lightgray')
self.checked=IntVar()
self.checked.set(0)
self.name = name
self.c=Checkbutton(master,
text=name,
variable=self.checked,
onvalue=1,
offvalue=0,
command=self.check
)
self.c.grid(column=0,row=row, sticky=W+N)
def check(self):
if self == self.thermoframe.last1:
self.checked.set(1)
return
elif self == self.thermoframe.last2:
self.checked.set(1)
self.thermoframe.last2 = self.thermoframe.last1
self.thermoframe.last1 = self
return
# elif badpair(self, self.thermoframe.last1):
# self.checked.set(0)
# return
self._check()
self.thermoframe.last2.checked.set(0)
self.thermoframe.last2._check()
self.thermoframe.last2 = self.thermoframe.last1
self.thermoframe.last1 = self
def _check(self):
if self.isChecked():
self.entry.v.config(state=NORMAL,bg='white')
else:
self.entry.v.config(state=DISABLED,bg='lightgray')
def isChecked(self):
return self.checked.get()
def set(self, value):
self.entry.set(value)
def get(self):
return self.entry.get()

View file

@ -1,34 +0,0 @@
from Tkinter import *
class TransportFrame(Frame):
def show(self, i, frame, row, col):
if self.checked[i].get():
frame.grid(row=row,column=col,sticky=N+E+S+W)
else:
frame.grid_forget()
def showcomp(self):
self.show(0, self.top.mixfr, 8, 0)
def showthermo(self):
self.show(1, self.top.thermo, 7, 0)
def __init__(self,master,top):
self.top = top
self.c = []
self.checked = []
Frame.__init__(self,master)
self.config(relief=GROOVE, bd=4)
lbl = ['multicomponent', 'mixture-averaged']
cmds = [self.showcomp, self.showthermo]
for i in range(2):
self.checked.append(IntVar())
self.checked[i].set(0)
self.c.append(Checkbutton(self,
text=lbl[i],
variable=self.checked[i],
onvalue=1,
offvalue=0,
command=cmds[i]
))
self.c[i].grid(column=i,row=0, sticky=W+N)

View file

@ -1,82 +0,0 @@
from Tkinter import *
import re
class UnitVar(Frame):
def __init__(self,master,unitmod,defaultunit=0):
Frame.__init__(self,master)
self.x = DoubleVar()
self.xsi = 0.0
self.x.set(0.0)
self.unitmod = unitmod
try:
self.unitlist = self.unitmod.units
except:
self.unitlist = []
unitlist=dir(self.unitmod)
for it in unitlist:
if it[0] != '_':
self.unitlist.append(it)
self.v = Entry(self,textvariable=self.x)
self.s = StringVar()
tmp = re.sub('__',' / ',self.unitlist[defaultunit])
self.s.set(tmp)
self.conv = eval('self.unitmod.'+re.sub(' / ','__',self.s.get())).value
self.u = Label(self)
self.u.config(textvariable=self.s,fg='darkblue')
self.u.bind('<Double-1>', self.select)
self.u.bind('<Any-Enter>',self.highlight)
self.u.bind('<Any-Leave>',self.nohighlight)
self.v.grid(row=0,column=0)
self.u.grid(row=0,column=1)
def highlight(self, event=None):
self.u.config(fg='yellow')
def nohighlight(self, event=None):
self.u.config(fg='darkblue')
def select(self, event):
self.new=Toplevel()
self.new.title("Units")
self.new.transient(self.master)
self.new.bind("<Return>", self.finished,"+")
r=0
c=0
for each in self.unitlist:
if each[0] != '_' and each[:1] != '__' and each != 'SI':
each = re.sub('__',' / ',each)
Radiobutton(self.new,
text=each,
variable=self.u['textvariable'],
value=each,
command=self.update,
).grid(column=c, row=r, sticky=W)
r=r+1
if (r>10):
r=0
c=c+1
r=r+1
b=Button(self.new,text='OK',command=self.finished, default=ACTIVE)
b.grid(column=c, row=r)
self.new.grab_set()
self.new.focus_set()
self.new.wait_window()
def finished(self,event=None):
self.new.destroy()
def update(self):
self.xsi = self.x.get() * self.conv
self.conv = eval('self.unitmod.'+re.sub(' / ','__',self.s.get())).value
self.x.set(self.xsi/self.conv)
def get(self):
self.xsi = self.x.get() * self.conv
return self.xsi
def set(self,value):
self.xsi = value
self.x.set(value/self.conv)

View file

@ -1,113 +0,0 @@
#!/usr/bin/env python
from unit import unit, dimensionless
#
# The basic SI units
#
meter = unit(1.0, (1, 0, 0, 0, 0, 0, 0))
kilogram = unit(1.0, (0, 1, 0, 0, 0, 0, 0))
second = unit(1.0, (0, 0, 1, 0, 0, 0, 0))
ampere = unit(1.0, (0, 0, 0, 1, 0, 0, 0))
kelvin = unit(1.0, (0, 0, 0, 0, 1, 0, 0))
mole = unit(1.0, (0, 0, 0, 0, 0, 1, 0))
candela = unit(1.0, (0, 0, 0, 0, 0, 0, 1))
#
# The 21 derived SI units with special names
#
radian = dimensionless # plane angle
steradian = dimensionless # solid angle
hertz = 1/second # frequency
newton = meter*kilogram/second**2 # force
pascal = newton/meter**2 # pressure
joule = newton*meter # work, heat
watt = joule/second # power, radiant flux
coulomb = ampere*second # electric charge
volt = watt/ampere # electric potential difference
farad = coulomb/volt # capacitance
ohm = volt/ampere # electric resistance
siemens = ampere/volt # electric conductance
weber = volt*second # magnetic flux
tesla = weber/meter**2 # magnetic flux density
henry = weber/ampere # inductance
celsius = kelvin # Celsius temperature
lumen = candela*steradian # luminous flux
lux = lumen/meter**2 # illuminance
becquerel = 1/second # radioactivity
gray = joule/kilogram # absorbed dose
sievert = joule/kilogram # dose equivalent
#
# The prefixes
#
yotta = 1e24
zetta = 1e21
exa = 1e18
peta = 1e15
tera = 1e12
giga = 1e9
mega = 1e6
kilo = 1000
hecto = 100
deka = 10
deci = .1
centi = .01
milli = .001
micro = 1e-6
nano = 1e-9
pico = 1e-12
femto = 1e-15
atto = 1e-18
zepto = 1e-21
yocto = 1e-24
#
# Test
#
if __name__ == "__main__":
print "The 7 base SI units:"
print " meter: %s" % meter
print " kilogram: %s" % kilogram
print " second: %s" % second
print " ampere: %s" % ampere
print " kelvin: %s" % kelvin
print " mole: %s" % mole
print " candela: %s" % candela
print
print "The 21 SI derived units with special names:"
print " radian: %s" % radian
print " steradian: %s" % steradian
print " hertz: %s" % hertz
print " newton: %s" % newton
print " pascal: %s" % pascal
print " joule: %s" % joule
print " watt: %s" % watt
print " coulomb: %s" % coulomb
print " volt: %s" % volt
print " farad: %s" % farad
print " ohm: %s" % ohm
print " siemens: %s" % siemens
print " weber: %s" % weber
print " tesla: %s" % tesla
print " henry: %s" % henry
print " degree Celsius: %s" % celsius
print " lumen: %s" % lumen
print " lux: %s" % lux
print " becquerel: %s" % becquerel
print " gray: %s" % gray
print " sievert: %s" % sievert

View file

@ -1,18 +0,0 @@
from length import meter, centimeter, inch, foot, mile
#
# Definitions of common area units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
square_meter = meter**2
square_centimeter = centimeter**2
square_foot = foot**2
square_inch = inch**2
square_mile = mile**2
acre = 43560 * square_foot
hectare = 1000 * square_meter
barn = 1e-28 * square_meter

View file

@ -1,11 +0,0 @@
import SI, math
#
# Definitions of common density units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
units = ['kg__m3', 'g__m3', 'g__cm3']
kg__m3 = SI.kilogram/(SI.meter * SI.meter * SI.meter)
g__m3 = 1.e-3*kg__m3
g__cm3 = 1.e3*kg__m3

View file

@ -1,18 +0,0 @@
from SI import joule
#
# Definitions of common energy units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
Btu = 1055 * joule
erg = 1e-7 * joule
foot_pound = 1.356 * joule
horse_power_hour = 2.685e6 * joule
calorie = 4.186 * joule
Calorie = 1000 * calorie
kilowatt_hour = 3.6e6 * joule
electron_volt = 1.602e-19 * joule

View file

@ -1,6 +0,0 @@
from SI import meter
#
# Definitions of common force units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993

View file

@ -1,26 +0,0 @@
from SI import meter
from SI import nano, milli, centi, kilo
#
# Definitions of common length units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
nanometer = nano * meter
millimeter = milli * meter
centimeter = centi * meter
kilometer = kilo * meter
inch = 2.540 * centimeter
foot = 12 * inch
yard = 3 * foot
mile = 5280 * foot
fathom = 6 * foot
nautical_mile = 6076 * foot
angstrom = 1e-10 * meter
fermi = 1e-15 * meter
light_year = 9.460e12 * kilometer
parsec = 3.084e13 * kilometer

View file

@ -1,14 +0,0 @@
from SI import kilogram
#
# Definitions of common mass units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
gram = 1e-3 * kilogram
metric_ton = 1000 * kilogram
ounce = 28.35 * gram
pound = 16 * ounce
ton = 2000 * pound

View file

@ -1,9 +0,0 @@
from SI import watt, kilo
#
# Definitions of common power units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
kilowatt = kilo * watt
horsepower = 745.7 * watt

View file

@ -1,13 +0,0 @@
import SI
#
# Definitions of common pressure units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
bar = 1e5 * SI.pascal
mbar = 100 * SI.pascal
Pa = SI.pascal
torr = 133.3 * SI.pascal
atm = 1.01325e5 * SI.pascal

View file

@ -1,14 +0,0 @@
import SI, energy, mass
#
# Definitions of common energy units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
units = ['J__kg', 'kJ__kg', 'Btu__lbm', 'cal__g', 'kcal__g', 'kcal__kg']
J__kg = SI.joule/SI.kilogram
kJ__kg = 1000.0*J__kg
Btu__lbm = energy.Btu/mass.pound
cal__g = energy.calorie/mass.gram
kcal__g = 1000.0*cal__g
kcal__kg = cal__g

View file

@ -1,7 +0,0 @@
import SI, energy, mass
units = ['J__kg_K', 'kJ__kg_K', 'cal__g_K']
J__kg_K = SI.joule/(SI.kilogram * SI.kelvin)
kJ__kg_K = 1000.0*J__kg_K
cal__g_K = energy.calorie/(mass.gram * SI.kelvin)

View file

@ -1,10 +0,0 @@
from time import hour
from length import nautical_mile
#
# Definitions of common speed units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
knot = nautical_mile/hour

View file

@ -1,4 +0,0 @@
import SI
K = SI.kelvin
R = (9.0/5.0)*K

View file

@ -1,11 +0,0 @@
from SI import second
#
# Definitions of common time units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
minute = 60 * second
hour = 60 * minute
day = 24 * hour
year = 365.25 * day

View file

@ -1,107 +0,0 @@
import operator
class unit:
_zero = (0,) * 7
_negativeOne = (-1, ) * 7
_labels = ('m', 'kg', 's', 'A', 'K', 'mol', 'cd')
def __init__(self, value, derivation):
self.value = value
self.derivation = derivation
return
def __add__(self, other):
if not self.derivation == other.derivation:
raise ImcompatibleUnits(self, other)
return unit(self.value + other.value, self.derivation)
def __sub__(self, other):
if not self.derivation == other.derivation:
raise ImcompatibleUnits(self, other)
return unit(self.value - other.value, self.derivation)
def __mul__(self, other):
if type(other) == type(0) or type(other) == type(0.0):
return unit(other*self.value, self.derivation)
value = self.value * other.value
derivation = tuple(map(operator.add, self.derivation, other.derivation))
return unit(value, derivation)
def __div__(self, other):
if type(other) == type(0) or type(other) == type(0.0):
return unit(self.value/other, self.derivation)
value = self.value / other.value
derivation = tuple(map(operator.sub, self.derivation, other.derivation))
return unit(value, derivation)
def __pow__(self, other):
if type(other) != type(0) and type(other) != type(0.0):
raise BadOperation
value = self.value ** other
derivation = tuple(map(operator.mul, [other]*7, self.derivation))
return unit(value, derivation)
def __pos__(self): return self
def __neg__(self): return unit(-self.value, self.derivation)
def __abs__(self): return unit(abs(self.value), self.derivation)
def __invert__(self):
value = 1./self.value
derivation = tuple(map(operator.mul, self._negativeOne, self.derivation))
return unit(value, derivation)
def __rmul__(self, other):
return unit.__mul__(self, other)
def __rdiv__(self, other):
if type(other) != type(0) and type(other) != type(0.0):
raise BadOperation(self, other)
value = other/self.value
derivation = tuple(map(operator.mul, self._negativeOne, self.derivation))
return unit(value, derivation)
def __float__(self):
return self.value
#if self.derivation == self._zero: return self.value
#raise BadConversion(self)
def __str__(self):
str = "%g" % self.value
for i in range(0, 7):
exponent = self.derivation[i]
if exponent == 0: continue
if exponent == 1:
str = str + " %s" % (self._labels[i])
else:
str = str + " %s^%d" % (self._labels[i], exponent)
return str
dimensionless = unit(1, unit._zero)

View file

@ -1,18 +0,0 @@
from length import meter, centimeter, foot, inch
#
# Definitions of common volume units
# Data taken from Appendix F of Halliday, Resnick, Walker, "Fundamentals of Physics",
# fourth edition, John Willey and Sons, 1993
cubic_meter = meter**3
cubic_centimeter = centimeter**3
cubic_foot = foot**3
cubic_inch = inch**3
liter = 1000 * cubic_centimeter
us_fluid_ounce = 231./128 * cubic_inch
us_pint = 16 * us_fluid_ounce
us_fluid_quart = 2 * us_pint
us_fluid_gallon = 4 * us_fluid_quart

View file

@ -1,4 +0,0 @@
# from Cantera import *
from main import MixMaster

View file

@ -1,5 +0,0 @@
from Cantera import *
# thermo parametrizations
#from Cantera.Species.Thermo.NasaPolynomial import NasaPolynomial

Some files were not shown because too many files have changed in this diff Show more