mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
Prerelease_1_6_0_branch merged into trunk
This commit is contained in:
@@ -52,17 +52,16 @@ class Kinetics:
|
||||
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)
|
||||
|
||||
for nn in range(self._np):
|
||||
p = self.phase(nn)
|
||||
p = phases[nn] # 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()
|
||||
@@ -141,7 +140,10 @@ class Kinetics:
|
||||
nur = _cantera.kin_rstoichcoeff(self.ckin,k,i)
|
||||
if nur <> 0.0:
|
||||
if nur <> 1.0:
|
||||
s += `int(nur)`+' '
|
||||
if nur <> round(nur):
|
||||
s += `nur`+' '
|
||||
else:
|
||||
s += `int(nur)`+' '
|
||||
s += self._sp[k]+' + '
|
||||
s = s[:-2]
|
||||
if self.isReversible(i):
|
||||
@@ -152,7 +154,10 @@ class Kinetics:
|
||||
nup = _cantera.kin_pstoichcoeff(self.ckin,k,i)
|
||||
if nup <> 0.0:
|
||||
if nup <> 1.0:
|
||||
s += `int(nup)`+' '
|
||||
if nup <> round(nup):
|
||||
s += `nup`+' '
|
||||
else:
|
||||
s += `int(nup)`+' '
|
||||
s += self._sp[k]+' + '
|
||||
s = s[:-2]
|
||||
return s
|
||||
|
||||
@@ -55,7 +55,7 @@ class BurnerFlame(Stack):
|
||||
t0 = self.burner.temperature()
|
||||
|
||||
# get adiabatic flame temperature and composition
|
||||
gas.equilibrate('HP')
|
||||
gas.equilibrate('HP',solver=1)
|
||||
teq = gas.temperature()
|
||||
yeq = gas.massFractions()
|
||||
u1 = self.burner.mdot()/gas.density()
|
||||
|
||||
135
Cantera/python/Cantera/OneD/FreeFlame.py
Normal file
135
Cantera/python/Cantera/OneD/FreeFlame.py
Normal file
@@ -0,0 +1,135 @@
|
||||
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):
|
||||
"""
|
||||
gas -- object to use to evaluate all gas properties and reaction
|
||||
rates. Required
|
||||
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')
|
||||
self.pressure = gas.pressure()
|
||||
|
||||
# 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._initialized = 0
|
||||
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.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):
|
||||
"""Solve the flame. See Stack.solve"""
|
||||
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):
|
||||
"""See Stack.setRefineCriteria"""
|
||||
Stack.setRefineCriteria(self, domain = self.flame,
|
||||
ratio = ratio, slope = slope, curve = curve,
|
||||
prune = prune)
|
||||
|
||||
def setFixedTemperature(self, temp):
|
||||
_cantera.sim1D_setFixedTemperature(self._hndl, temp)
|
||||
|
||||
def setProfile(self, component, locs, vals):
|
||||
"""Set a profile in the flame"""
|
||||
self._initialized = 1
|
||||
Stack.setProfile(self, self.flame, component, locs, vals)
|
||||
|
||||
def set(self, tol = None, energy = '', tol_time = None):
|
||||
"""Set parameters.
|
||||
tol -- (rtol, atol) for steady-state
|
||||
tol_time -- (rtol, atol) for time stepping
|
||||
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.pressure, y)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -371,12 +371,12 @@ class AxisymmetricFlow(Domain1D):
|
||||
allowed, as well as arbitrary variation of the transport
|
||||
properties.
|
||||
"""
|
||||
def __init__(self, id = 'axisymmetric_flow', gas = None):
|
||||
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)
|
||||
self._hndl = _cantera.stflow_new(iph, ikin, itr, type)
|
||||
if id: self.setID(id)
|
||||
self._p = -1.0
|
||||
self.setPressure(gas.pressure())
|
||||
@@ -676,6 +676,10 @@ class Stack:
|
||||
"""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()
|
||||
|
||||
@@ -12,6 +12,14 @@ from exceptions import CanteraError
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
# 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.
|
||||
@@ -224,6 +232,10 @@ class Phase:
|
||||
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.
|
||||
@@ -241,9 +253,11 @@ class Phase:
|
||||
"""
|
||||
if type(x) == types.StringType:
|
||||
_cantera.phase_setstring(self._phase_id,1,x)
|
||||
else:
|
||||
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.
|
||||
@@ -251,8 +265,11 @@ class Phase:
|
||||
"""
|
||||
if type(x) == types.StringType:
|
||||
_cantera.phase_setstring(self._phase_id,2,x)
|
||||
else:
|
||||
_cantera.phase_setarray(self._phase_id,2,norm,asarray(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
|
||||
@@ -264,6 +281,16 @@ class Phase:
|
||||
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)
|
||||
@@ -293,7 +320,7 @@ class Phase:
|
||||
fs.append(f[k])
|
||||
return asarray(fs)
|
||||
else:
|
||||
return f
|
||||
return asarray(f)
|
||||
|
||||
def selectElements(self, f, elements):
|
||||
"""Given an array 'f' of floating-point element properties,
|
||||
@@ -310,5 +337,5 @@ class Phase:
|
||||
fs.append(f[k])
|
||||
return asarray(fs)
|
||||
else:
|
||||
return f
|
||||
return asarray(f)
|
||||
|
||||
|
||||
@@ -269,7 +269,8 @@ class ThermoPhase(Phase):
|
||||
"""Set the electric potential."""
|
||||
_cantera.thermo_setfp(self._phase_id, 6, v, 0);
|
||||
|
||||
def equilibrate(self, XY):
|
||||
def equilibrate(self, XY, solver = 0, rtol = 1.0e-9,
|
||||
maxsteps = 1000, loglevel = 0):
|
||||
"""Set to a state of chemical equilibrium holding property pair
|
||||
'XY' constant. The pair is specified by a two-letter string,
|
||||
which must be one of the set
|
||||
@@ -279,7 +280,7 @@ class ThermoPhase(Phase):
|
||||
"""
|
||||
ixy = ThermoPhase._equilmap[XY]
|
||||
if ixy > 0:
|
||||
_cantera.thermo_equil(self._phase_id, ixy)
|
||||
_cantera.thermo_equil(self._phase_id, ixy, solver, rtol, maxsteps, loglevel)
|
||||
else:
|
||||
raise 'invalid equilibrium option: '+XY
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
"""
|
||||
|
||||
import types
|
||||
import _cantera
|
||||
from constants import *
|
||||
from exceptions import *
|
||||
from gases import *
|
||||
from set import set
|
||||
from importFromFile import *
|
||||
|
||||
from mixture import Mixture
|
||||
from num import *
|
||||
|
||||
def writeCSV(f, list):
|
||||
"""
|
||||
Write list items to file 'f' in
|
||||
@@ -40,17 +38,25 @@ def table(keys, values):
|
||||
|
||||
def getCanteraError():
|
||||
"""Return the Cantera error message, if any."""
|
||||
import _cantera
|
||||
return _cantera.get_Cantera_Error()
|
||||
|
||||
def refCount(a):
|
||||
"""Return the reference count for an object."""
|
||||
import _cantera
|
||||
return _cantera.ct_refcnt(a)
|
||||
|
||||
def addDirectory(dir):
|
||||
"""Add a directory to search for Cantera data files."""
|
||||
import _cantera
|
||||
return _cantera.ct_addDirectory(dir)
|
||||
|
||||
def writeLogFile(file):
|
||||
return _cantera.ct_writelogfile(file)
|
||||
|
||||
# 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 *
|
||||
|
||||
|
||||
34
Cantera/python/Cantera/ck2cti.py
Normal file
34
Cantera/python/Cantera/ck2cti.py
Normal file
@@ -0,0 +1,34 @@
|
||||
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)
|
||||
|
||||
@@ -6,7 +6,7 @@ Physical Constants
|
||||
OneAtm = 101325.0
|
||||
|
||||
# The ideal gas constant in J/kmo-K
|
||||
GasConstant = 8314.0
|
||||
GasConstant = 8314.47215
|
||||
|
||||
# Avogadro's Number, /kmol
|
||||
Avogadro = 6.022136736e26
|
||||
|
||||
@@ -6,10 +6,11 @@ import _cantera
|
||||
import types
|
||||
from Cantera.num import zeros, array, asarray
|
||||
from exceptions import CanteraError
|
||||
from Cantera import writeLogFile
|
||||
|
||||
class Mixture:
|
||||
"""
|
||||
xxx Multiphase mixtures. Class Mixture represents
|
||||
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:
|
||||
@@ -180,14 +181,14 @@ class Mixture:
|
||||
def setPhaseMoles(self, n, moles):
|
||||
"""Set the number of moles of phase n."""
|
||||
_cantera.mix_setPhaseMoles(self.__mixid, n, moles)
|
||||
def setMoles(self, 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.setMoles('C(s):1.0, CH4:2.0, O2:0.2')
|
||||
>>> mix.setSpeciesMoles('C(s):1.0, CH4:2.0, O2:0.2')
|
||||
|
||||
"""
|
||||
if type(moles) == types.StringType:
|
||||
@@ -197,7 +198,7 @@ class Mixture:
|
||||
|
||||
def speciesMoles(self, species = ""):
|
||||
"""Moles of species k."""
|
||||
moles = array(self.nSpecies(),'d')
|
||||
moles = zeros(self.nSpecies(),'d')
|
||||
for k in range(self.nSpecies()):
|
||||
moles[k] = _cantera.mix_speciesMoles(self.__mixid, k)
|
||||
return self.selectSpecies(moles, species)
|
||||
@@ -227,30 +228,64 @@ class Mixture:
|
||||
else:
|
||||
raise CanteraError("unknown property: "+o)
|
||||
|
||||
def equilibrate(self, XY = "TP", err = 1.0e-9, maxiter = 1000):
|
||||
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 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.
|
||||
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.
|
||||
|
||||
XY - Two-letter string specifying the two properties to hold fixed.
|
||||
Currently, only TP (constant T and P) is implemented. Default: "TP".
|
||||
Currently, 'TP', 'HP', and 'SP' are implemented. Default: 'TP'.
|
||||
|
||||
err - Error tolerance. Iteration will continue until (Delta
|
||||
mu)/RT is less than this value for each reaction. Default:
|
||||
1.0e-9.
|
||||
1.0e-9. Note that this default is very conservative, and good
|
||||
equilibrium solutions may be obtained with larger error
|
||||
tolerances.
|
||||
|
||||
maxiter - Maximum number of iterations to attempt. Default: 1000.
|
||||
maxsteps - Maximum number of steps to take while solving the
|
||||
equilibrium problem for specified T and P. Default: 1000.
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
"""
|
||||
return _cantera.mix_equilibrate(self.__mixid, XY, err, maxiter)
|
||||
i = _cantera.mix_equilibrate(self.__mixid, XY, err, maxsteps,
|
||||
maxiter, loglevel)
|
||||
if loglevel > 0:
|
||||
writeLogFile("equilibrate_log");
|
||||
|
||||
def selectSpecies(self, f, species):
|
||||
"""Given an array 'f' of floating-point species properties,
|
||||
@@ -263,12 +298,12 @@ class Mixture:
|
||||
sp = []
|
||||
if species:
|
||||
if type(species) == types.StringType:
|
||||
sp = [sp]
|
||||
sp = [species]
|
||||
else:
|
||||
sp = species
|
||||
fs = []
|
||||
k = 0
|
||||
for s in s:
|
||||
for s in sp:
|
||||
k = self.speciesIndex(s)
|
||||
fs.append(f[k])
|
||||
return asarray(fs)
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
|
||||
import _cantera
|
||||
nummodule = None
|
||||
|
||||
try:
|
||||
import numarray
|
||||
nummodule = numarray
|
||||
except:
|
||||
try:
|
||||
if _cantera.nummod == 'numarray':
|
||||
import numarray
|
||||
nummodule = numarray
|
||||
else:
|
||||
import Numeric
|
||||
nummodule = Numeric
|
||||
except:
|
||||
print """
|
||||
except:
|
||||
print """
|
||||
|
||||
ERROR: numarray / numeric not found!
|
||||
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 numarray or Numeric package for your system. If you are
|
||||
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 numarray or Numeric"
|
||||
raise "could not import "+_cantera.nummod
|
||||
|
||||
zeros = nummodule.zeros
|
||||
array = nummodule.array
|
||||
|
||||
@@ -15,7 +15,10 @@ python_site_package_topdir=@python_prefix@
|
||||
CANTERA_LIBDIR= @buildlib@
|
||||
LIB_DEPS = $(CANTERA_LIBDIR)/libcantera.a $(CANTERA_LIBDIR)/libzeroD.a \
|
||||
$(CANTERA_LIBDIR)/liboneD.a \
|
||||
$(CANTERA_LIBDIR)/libtransport.a
|
||||
$(CANTERA_LIBDIR)/libtransport.a \
|
||||
$(CANTERA_LIBDIR)/libclib.a \
|
||||
$(CANTERA_LIBDIR)/libconverters.a
|
||||
|
||||
WIN_LIB_DEPS = $(CANTERA_LIBDIR)/cantera.lib $(CANTERA_LIBDIR)/zeroD.lib \
|
||||
$(CANTERA_LIBDIR)/oneD.lib \
|
||||
$(CANTERA_LIBDIR)/transport.lib
|
||||
@@ -40,7 +43,7 @@ all: _build
|
||||
|
||||
win: _winbuild
|
||||
|
||||
_build: $(SRCS) $(LIB_DEPS)
|
||||
_build: $(SRCS) $(LIB_DEPS) Makefile
|
||||
touch src/pycantera.cpp
|
||||
(CXX=@CXX@; export CXX; CC=@CC@; export CC; @PYTHON_CMD@ setup.py build)
|
||||
echo 'ok' > _build
|
||||
|
||||
@@ -199,17 +199,25 @@ _pref = 1.0e5 # 1 bar
|
||||
_name = 'noname'
|
||||
|
||||
# these lists store top-level entries
|
||||
_elements = []
|
||||
_species = []
|
||||
_speciesnames = []
|
||||
_phases = []
|
||||
_reactions = []
|
||||
_atw = {}
|
||||
|
||||
_enames = {}
|
||||
|
||||
_valsp = ''
|
||||
_valrxn = ''
|
||||
_valexport = ''
|
||||
_valfmt = ''
|
||||
|
||||
|
||||
def export_species(file, fmt = 'CSV'):
|
||||
global _valexport
|
||||
global _valfmt
|
||||
_valexport = file
|
||||
_valfmt = fmt
|
||||
|
||||
def validate(species = 'yes', reactions = 'yes'):
|
||||
global _valsp
|
||||
global _valrxn
|
||||
@@ -265,7 +273,12 @@ def write():
|
||||
v = x.addChild("validate")
|
||||
v["species"] = _valsp
|
||||
v["reactions"] = _valrxn
|
||||
|
||||
|
||||
if _elements:
|
||||
ed = x.addChild("elementData")
|
||||
for e in _elements:
|
||||
e.build(ed)
|
||||
|
||||
for ph in _phases:
|
||||
ph.build(x)
|
||||
s = species_set(name = _name, species = _species)
|
||||
@@ -281,6 +294,11 @@ def write():
|
||||
else:
|
||||
print x
|
||||
|
||||
if _valexport:
|
||||
f = open(_valexport,'w')
|
||||
for s in _species:
|
||||
s.export(f, _valfmt)
|
||||
f.close()
|
||||
|
||||
def addFloat(x, nm, val, fmt='', defunits=''):
|
||||
"""
|
||||
@@ -320,20 +338,65 @@ def getAtomicComp(atoms):
|
||||
return d
|
||||
|
||||
def getReactionSpecies(s):
|
||||
"""Take a reaction string and return a
|
||||
dictionary mapping species names to stoichiometric
|
||||
coefficients. If any species appears more than once,
|
||||
the returned stoichiometric coefficient is the sum.
|
||||
>>> s = 'CH3 + 3 H + 5.2 O2 + 0.7 H'
|
||||
>>> getReactionSpecies(s)
|
||||
>>> {'CH3':1, 'H':3.7, 'O2':5.2}
|
||||
"""
|
||||
|
||||
# get rid of the '+' signs separating species. Only plus signs
|
||||
# surrounded by spaces are replaced, so that plus signs may be
|
||||
# used in species names (e.g. 'Ar3+')
|
||||
toks = s.replace(' + ',' ').split()
|
||||
d = {}
|
||||
n = 1
|
||||
n = 1.0
|
||||
for t in toks:
|
||||
if t > '0' and t < '9':
|
||||
n = int(t)
|
||||
else:
|
||||
if d.has_key(t):
|
||||
d[t] += n
|
||||
|
||||
# try to convert the token to a number.
|
||||
try:
|
||||
n = float(t)
|
||||
if n <= 0.0:
|
||||
raise CTI_Error("zero or negative stoichiometric coefficient:"
|
||||
+s)
|
||||
|
||||
#if t > '0' and t < '9':
|
||||
# n = int(t)
|
||||
#else:
|
||||
|
||||
# token isn't a number, so it must be a species name
|
||||
except:
|
||||
if d.has_key(t): # already seen this token
|
||||
d[t] += n # so increment its value by the last
|
||||
# value of n
|
||||
else:
|
||||
d[t] = n
|
||||
n = 1
|
||||
d[t] = n # first time this token has been seen,
|
||||
# so set its value to n
|
||||
|
||||
n = 1 # reset n to 1.0 for species that do not
|
||||
# specify a stoichiometric coefficient
|
||||
return d
|
||||
|
||||
|
||||
class element:
|
||||
def __init__(self, symbol = '',
|
||||
atomic_mass = 0.01,
|
||||
atomic_number = 0):
|
||||
self._sym = symbol
|
||||
self._atw = atomic_mass
|
||||
self._num = atomic_number
|
||||
global _elements
|
||||
_elements.append(self)
|
||||
|
||||
def build(self, db):
|
||||
e = db.addChild("element")
|
||||
e["name"] = self._sym
|
||||
e["atomicWt"] = `self._atw`
|
||||
e["atomicNumber"] = `self._num`
|
||||
|
||||
|
||||
class species_set:
|
||||
def __init__(self, name = '', species = []):
|
||||
self._s = species
|
||||
@@ -384,12 +447,33 @@ class species:
|
||||
# self.type = SPECIES
|
||||
|
||||
global _species
|
||||
global _enames
|
||||
_species.append(self)
|
||||
global _speciesnames
|
||||
if name in _speciesnames:
|
||||
raise CTI_Error('species '+name+' multiply defined.')
|
||||
_speciesnames.append(name)
|
||||
|
||||
for e in self._atoms.keys():
|
||||
_enames[e] = 1
|
||||
|
||||
def export(self, f, fmt = 'CSV'):
|
||||
global _enames
|
||||
if fmt == 'CSV':
|
||||
str = self._name+','
|
||||
for e in _enames:
|
||||
if self._atoms.has_key(e):
|
||||
str += `self._atoms[e]`+','
|
||||
else:
|
||||
str += '0,'
|
||||
f.write(str)
|
||||
if type(self._thermo) == types.InstanceType:
|
||||
self._thermo.export(f, fmt)
|
||||
else:
|
||||
nt = len(self._thermo)
|
||||
for n in range(nt):
|
||||
self._thermo[n].export(f, fmt)
|
||||
f.write('\n')
|
||||
|
||||
|
||||
def build(self, p):
|
||||
hdr = ' species '+self._name+' '
|
||||
@@ -425,6 +509,8 @@ class thermo:
|
||||
"""Base class for species standard-state thermodynamic properties."""
|
||||
def _build(self, p):
|
||||
return p.addChild("thermo")
|
||||
def export(self, f, fmt = 'CSV'):
|
||||
pass
|
||||
|
||||
|
||||
class NASA(thermo):
|
||||
@@ -438,7 +524,14 @@ class NASA(thermo):
|
||||
raise CTI_Error('NASA coefficient list must have length = 7')
|
||||
self._coeffs = coeffs
|
||||
|
||||
|
||||
|
||||
def export(self, f, fmt='CSV'):
|
||||
if fmt == 'CSV':
|
||||
str = 'NASA,'+`self._t[0]`+','+`self._t[1]`+','
|
||||
for i in range(7):
|
||||
str += '%17.9E, ' % self._coeffs[i]
|
||||
f.write(str)
|
||||
|
||||
def build(self, t):
|
||||
n = t.addChild("NASA")
|
||||
n['Tmin'] = `self._t[0]`
|
||||
@@ -786,7 +879,6 @@ class reaction:
|
||||
|
||||
unit_fctr = (math.pow(_length[_ulen], -ldim) *
|
||||
math.pow(_moles[_umol], -mdim) / _time[_utime])
|
||||
|
||||
if type(kf) == types.InstanceType:
|
||||
k = kf
|
||||
else:
|
||||
@@ -1320,6 +1412,64 @@ class incompressible_solid(phase):
|
||||
k['model'] = 'none'
|
||||
|
||||
|
||||
class lattice:
|
||||
def __init__(self, name = '', site_density = -1.0,
|
||||
vacancy_species = ''):
|
||||
self._name = name
|
||||
self._n = site_density
|
||||
self._vac = vacancy_species
|
||||
if name == '':
|
||||
raise CTI_Error('sublattice name must be specified')
|
||||
if site_density < 0.0:
|
||||
raise CTI_Error('sublattice '+name
|
||||
+' site density must be specified')
|
||||
def build(self,p):
|
||||
lat = p.addChild('Lattice')
|
||||
lat['name'] = self._name
|
||||
addFloat(lat, 'site_density', self._n, defunits = _umol+'/'+_ulen+'3')
|
||||
if self._vac:
|
||||
lat.addChild('vacancy_species',self._vac)
|
||||
|
||||
|
||||
class lattice_solid(phase):
|
||||
"""A solid crystal consisting of one or more sublattices."""
|
||||
def __init__(self,
|
||||
name = '',
|
||||
elements = '',
|
||||
species = '',
|
||||
lattices = [],
|
||||
transport = 'None',
|
||||
initial_state = None,
|
||||
options = []):
|
||||
|
||||
phase.__init__(self, name, 3, elements, species, 'none',
|
||||
initial_state, options)
|
||||
self._lattices = lattices
|
||||
if lattices == []:
|
||||
raise CTI_Error('One or more sublattices must be specified.')
|
||||
self._pure = 0
|
||||
self._tr = transport
|
||||
|
||||
def conc_dim(self):
|
||||
return (0,0)
|
||||
|
||||
def build(self, p):
|
||||
ph = phase.build(self, p)
|
||||
e = ph.addChild("thermo")
|
||||
e['model'] = 'LatticeSolid'
|
||||
|
||||
if self._lattices:
|
||||
lat = e.addChild('LatticeArray')
|
||||
for n in self._lattices:
|
||||
n.build(lat)
|
||||
|
||||
if self._tr:
|
||||
t = ph.addChild('transport')
|
||||
t['model'] = self._tr
|
||||
k = ph.addChild("kinetics")
|
||||
k['model'] = 'none'
|
||||
|
||||
|
||||
class liquid_vapor(phase):
|
||||
"""A fluid with a complete liquid/vapor equation of state.
|
||||
This entry type selects one of a set of predefined fluids with
|
||||
@@ -1485,105 +1635,3 @@ if __name__ == "__main__":
|
||||
execfile(file)
|
||||
write()
|
||||
|
||||
|
||||
##########################################
|
||||
#
|
||||
# $Author$
|
||||
# $Revision$
|
||||
# $Date$
|
||||
# $Log$
|
||||
# Revision 1.9 2005-01-08 22:28:01 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.8 2004/12/02 22:11:28 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.7 2004/11/15 02:33:21 dggoodwin
|
||||
# changed f90 mod file handling in Makefiles
|
||||
#
|
||||
# Revision 1.6 2004/09/29 11:00:39 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.5 2004/09/20 10:25:02 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.4 2004/07/14 11:24:13 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.3 2004/06/09 01:02:31 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.2 2004/06/04 06:05:31 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.1 2004/06/02 04:39:09 dggoodwin
|
||||
# moved ctml_writer.py out of Cantera package
|
||||
#
|
||||
# Revision 1.34 2004/05/30 04:02:55 dggoodwin
|
||||
# converted to pure python
|
||||
#
|
||||
# Revision 1.33 2004/04/23 19:03:21 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.32 2004/04/23 16:35:32 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.31 2004/03/12 05:59:59 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.30 2004/02/08 13:25:21 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.29 2004/02/08 13:22:31 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.28 2004/02/08 13:09:10 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.27 2004/02/03 16:42:54 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.26 2004/02/03 03:31:06 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.25 2003/11/24 16:39:33 dggoodwin
|
||||
# -
|
||||
#
|
||||
# Revision 1.24 2003/11/13 12:29:45 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.23 2003/11/12 18:58:15 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.22 2003/11/01 04:48:20 dggoodwin
|
||||
# added capability to have species names with embedded commas
|
||||
#
|
||||
# Revision 1.21 2003/10/14 06:48:07 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.20 2003/09/22 13:14:34 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.19 2003/08/26 03:39:02 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.18 2003/08/21 14:29:53 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.17 2003/08/20 15:35:32 dggoodwin
|
||||
# *** empty log message ***
|
||||
#
|
||||
# Revision 1.16 2003/08/19 22:02:01 hkmoffa
|
||||
# Fixed an error in an argument list
|
||||
#
|
||||
# Revision 1.15 2003/08/18 05:05:02 dggoodwin
|
||||
# added support for specified reaction order, sticking coefficients,
|
||||
# coverage dependence of rate coefficients; fixed error where site_density
|
||||
# was not being converted to SI.
|
||||
#
|
||||
# Revision 1.14 2003/08/16 20:17:21 dggoodwin
|
||||
# changed handling of reaction pre-exponential units to write converted
|
||||
# value to CTML, rather than pass original value with a units string
|
||||
#
|
||||
#
|
||||
###########################################
|
||||
|
||||
70
Cantera/python/examples/equilibrium/KOH.cti
Normal file
70
Cantera/python/examples/equilibrium/KOH.cti
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
units(length = "cm", time = "s", quantity = "mol", act_energy = "cal/mol")
|
||||
|
||||
|
||||
|
||||
# ideal gas containing all gaseous species in the NASA database
|
||||
# that contain the elements K, O, and H. "Element" E is included
|
||||
# too for charged species.
|
||||
ideal_gas(name = "KOH_plasma",
|
||||
elements = " K O H E",
|
||||
species = """nasa_gas: all""",
|
||||
options = ["skip_undeclared_elements"],
|
||||
initial_state = state(temperature = 300.0,
|
||||
pressure = OneAtm) )
|
||||
|
||||
# solid potassium
|
||||
stoichiometric_solid(name = "K_solid",
|
||||
elements = "K",
|
||||
density = (0.86,'g/cm3'),
|
||||
species = "nasa_condensed: K(cr)")
|
||||
|
||||
# liquid potassium
|
||||
stoichiometric_liquid(name = "K_liquid",
|
||||
elements = "K",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: K(L)")
|
||||
|
||||
# potassium hydroxide "a"
|
||||
stoichiometric_solid(name = "KOH_a",
|
||||
elements = "K O H",
|
||||
density = (2.04,'g/cm3'),
|
||||
species = "nasa_condensed: KOH(a)")
|
||||
|
||||
# potassium hydroxide "b"
|
||||
stoichiometric_solid(name = "KOH_b",
|
||||
elements = "K O H",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: KOH(b)")
|
||||
|
||||
# liquid potassium hydroxide
|
||||
stoichiometric_liquid(name = "KOH_liquid",
|
||||
elements = "K O H",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: KOH(L)")
|
||||
|
||||
stoichiometric_solid(name = "K2O2_solid",
|
||||
elements = "K O",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: K2O2(s)")
|
||||
|
||||
stoichiometric_solid(name = "K2O_solid",
|
||||
elements = "K O",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: K2O(s)")
|
||||
|
||||
stoichiometric_solid(name = "KO2_solid",
|
||||
elements = "K O",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: KO2(s)")
|
||||
|
||||
stoichiometric_solid(name = "ice",
|
||||
elements = "H O",
|
||||
density = (0.917,'g/cm3'),
|
||||
species = "nasa_condensed: H2O(s)")
|
||||
|
||||
stoichiometric_liquid(name = "liquid_water",
|
||||
elements = "H O",
|
||||
density = (1.0,'g/cm3'),
|
||||
species = "nasa_condensed: H2O(L)")
|
||||
|
||||
100
Cantera/python/examples/equilibrium/adiabatic.py
Normal file
100
Cantera/python/examples/equilibrium/adiabatic.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Adiabatic flame temperature and equilibrium composition for a
|
||||
fuel/air mixture as a function of equivalence ratio,
|
||||
including formation of solid carbon.
|
||||
"""
|
||||
|
||||
from Cantera import *
|
||||
import sys
|
||||
|
||||
##############################################################
|
||||
#
|
||||
# Edit these parameters to change the initial temperature, the
|
||||
# pressure, and the phases in the mixture
|
||||
#
|
||||
###############################################################
|
||||
|
||||
temp = 300.0
|
||||
pres = 101325.0
|
||||
|
||||
# phases
|
||||
gas = importPhase('gri30.cti')
|
||||
carbon = importPhase('graphite.cti')
|
||||
|
||||
# the phases that will be included in the calculation, and their
|
||||
# initial moles
|
||||
mix_phases = [ (gas, 1.0), (carbon, 0.0) ]
|
||||
|
||||
# gaseous fuel species
|
||||
fuel_species = 'CH4'
|
||||
|
||||
# air composition
|
||||
air_N2_O2_ratio = 3.76
|
||||
|
||||
# equivalence ratio range
|
||||
phi_min = 0.3
|
||||
phi_max = 3.5
|
||||
npoints = 50
|
||||
|
||||
##################################################
|
||||
|
||||
|
||||
mix = Mixture(mix_phases)
|
||||
nsp = mix.nSpecies()
|
||||
|
||||
# create some arrays to hold the data
|
||||
phi = zeros(npoints,'d')
|
||||
tad = zeros(npoints,'d')
|
||||
xeq = zeros([nsp,npoints],'d')
|
||||
|
||||
# find fuel, nitrogen, and oxygen indices
|
||||
ifuel, io2, in2 = gas.speciesIndex([fuel_species, 'O2', 'N2'])
|
||||
if ifuel < 0:
|
||||
raise "fuel species "+fuel_species+" not present!"
|
||||
|
||||
if gas.nAtoms(fuel_species,'O') > 0 or gas.nAtoms(fuel_species,'N') > 0:
|
||||
raise "Error: only hydrocarbon fuels are supported."
|
||||
|
||||
stoich_O2 = gas.nAtoms(fuel_species,'C') + 0.25*gas.nAtoms(fuel_species,'H')
|
||||
|
||||
|
||||
for i in range(npoints):
|
||||
phi[i] = phi_min + (phi_max - phi_min)*i/(npoints - 1)
|
||||
x = zeros(nsp,'d')
|
||||
x[ifuel] = phi[i]
|
||||
x[io2] = stoich_O2
|
||||
x[in2] = stoich_O2*air_N2_O2_ratio
|
||||
|
||||
# set the gas state
|
||||
gas.set(T = temp, P = pres, X = x)
|
||||
|
||||
# create a mixture of 1 mole of gas, and 0 moles of solid carbon.
|
||||
mix = Mixture(mix_phases)
|
||||
mix.setTemperature(temp)
|
||||
mix.setPressure(pres)
|
||||
|
||||
# equilibrate the mixture adiabatically at constant P
|
||||
mix.equilibrate('HP', maxsteps = 1000,
|
||||
err = 1.0e-6, maxiter = 200, loglevel=0)
|
||||
|
||||
tad[i] = mix.temperature();
|
||||
print 'At phi = %12.4g, Tad = %12.4g' % (phi[i],tad[i])
|
||||
xeq[:,i] = mix.speciesMoles()
|
||||
|
||||
|
||||
# write output CSV file for importing into Excel
|
||||
|
||||
csvfile = 'adiabatic.csv'
|
||||
f = open(csvfile,'w')
|
||||
writeCSV(f,['T (K)']+mix.speciesNames())
|
||||
for n in range(npoints):
|
||||
writeCSV(f,[phi[n], tad[n]]+list(xeq[:,n]))
|
||||
f.close()
|
||||
print 'output written to '+csvfile
|
||||
|
||||
|
||||
# make plots
|
||||
if '--plot' in sys.argv:
|
||||
import plotting
|
||||
plotting.plotEquilData(mix, phi, tad, xeq)
|
||||
|
||||
40
Cantera/python/examples/equilibrium/multiphase_plasma.py
Normal file
40
Cantera/python/examples/equilibrium/multiphase_plasma.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# An equilibrium example with charged species in the gas phase
|
||||
# and multiple condensed phases.
|
||||
|
||||
from Cantera import *
|
||||
|
||||
# create objects representing the gas phase and the condensed
|
||||
# phases. The gas is a mixture of multiple species, and the condensed
|
||||
# phases are all modeled as incompressible stoichiometric
|
||||
# substances. See file KOH.cti for more information.
|
||||
phases = importPhases('KOH.cti',
|
||||
['K_solid',
|
||||
'K_liquid', 'KOH_a', 'KOH_b',
|
||||
'KOH_liquid', 'K2O2_solid',
|
||||
'K2O_solid', 'KO2_solid',
|
||||
'ice', 'liquid_water','KOH_plasma'])
|
||||
|
||||
# create the Mixture object from the list of phases
|
||||
mix = Mixture(phases)
|
||||
|
||||
# open the output file and write the column headings
|
||||
f = open('equil_koh.csv','w')
|
||||
writeCSV(f,['T']+mix.speciesNames())
|
||||
|
||||
# loop over temperature
|
||||
for n in range(500):
|
||||
t = 350.0 + 10.0*n
|
||||
print 'T = ',t
|
||||
mix.set(T= t, P = OneAtm, Moles="K:1.03, H2:2.12, O2:0.9")
|
||||
|
||||
# set the mixture to a state of chemical equilibrium holding
|
||||
# temperature and pressure fixed
|
||||
mix.equilibrate("TP",maxsteps=1000,loglevel=0)
|
||||
|
||||
# write out the moles of each species
|
||||
writeCSV(f,[t]+ list(mix.speciesMoles()))
|
||||
|
||||
# close the output file
|
||||
f.close()
|
||||
|
||||
|
||||
85
Cantera/python/examples/equilibrium/plotting.py
Normal file
85
Cantera/python/examples/equilibrium/plotting.py
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
from matplotlib.pylab import *
|
||||
from matplotlib import get_backend, interactive
|
||||
import sys
|
||||
|
||||
# Print a warning if 'python' rather than 'pythonw' is invoked on a
|
||||
# Mac. Does nothing on other platforms.
|
||||
def warnMac():
|
||||
if sys.platform == 'darwin':
|
||||
if sys.executable == '/usr/bin/python':
|
||||
b = get_backend()
|
||||
if b[-3:] == 'Agg':
|
||||
print 'Error: on a Mac, this script must be run with pythonw instead of python'
|
||||
print 'to display plots'
|
||||
return -1
|
||||
return 0
|
||||
|
||||
|
||||
def plotEquilData(mix, phi, tad, xeq):
|
||||
|
||||
if warnMac() < 0: return
|
||||
npoints = len(phi)
|
||||
|
||||
nsp = mix.nSpecies()
|
||||
|
||||
#titles = ['Major Species', 'Minor Species', 'N Minor Species']
|
||||
# assign species to 3 plots
|
||||
p = {}
|
||||
mm = 0
|
||||
for k in range(nsp):
|
||||
if amax(xeq[k,:]) > 0.01:
|
||||
p[k] = 0 # major species plot
|
||||
else:
|
||||
mm += 1
|
||||
if mix.nAtoms(k,'N') <= 0:
|
||||
p[k] = 1 # non-N minor species plot
|
||||
else:
|
||||
p[k] = 2 # N-containing minor species plot
|
||||
|
||||
clf
|
||||
subplot(2,2,1)
|
||||
plot(phi,tad)
|
||||
xlabel('Equivalence Ratio')
|
||||
ylabel('Temperature (K)')
|
||||
title('Adiabatic Flame Temperature')
|
||||
axis([phi[1], phi[-1], amin(tad)-200.0, amax(tad)+200.0])
|
||||
|
||||
# do three species plots
|
||||
for m in range(3):
|
||||
|
||||
subplot(2,2,2+m);
|
||||
hold(True);
|
||||
|
||||
for i in range(nsp):
|
||||
if p[i] == m:
|
||||
for j in range(npoints):
|
||||
if xeq[i,j] <= 0.0:
|
||||
xeq[i,j] = 1.0e-20
|
||||
if m == 0:
|
||||
plot(phi, xeq[i,:])
|
||||
else:
|
||||
semilogy(phi,xeq[i,:])
|
||||
|
||||
xmax = amax(xeq[i,:])
|
||||
for j in range(npoints):
|
||||
if xeq[i,j] == xmax: break
|
||||
offset = 0.0
|
||||
if j == 0:
|
||||
offset = 0.3
|
||||
elif j >= npoints-1:
|
||||
offset = -0.3
|
||||
text(phi[j]+offset,xeq[i,j],mix.speciesName(i))
|
||||
|
||||
if m == 0:
|
||||
axis([phi[1], phi[-1], 0.0, 1.0]);
|
||||
else:
|
||||
axis([phi[1], phi[-1], 1.0e-14, 1]);
|
||||
|
||||
xlabel('Equivalence Ratio');
|
||||
ylabel('Mole Fraction');
|
||||
#title(titles[m]);
|
||||
hold(False)
|
||||
|
||||
show()
|
||||
|
||||
23
Cantera/python/examples/equilibrium/simple.py
Normal file
23
Cantera/python/examples/equilibrium/simple.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# homogeneous equilibrium of a gas
|
||||
|
||||
from Cantera import *
|
||||
|
||||
# create an object representing the gas phase
|
||||
gas = importPhase("h2o2.cti")
|
||||
|
||||
# set the initial state
|
||||
gas.set(T = 2000.0, P = 0.1*OneAtm, X = "H2:1.0, O2:0.6")
|
||||
|
||||
# equilibrate the gas holding T and P fixed
|
||||
gas.equilibrate("TP")
|
||||
|
||||
# print a summary of the results
|
||||
print gas
|
||||
|
||||
# Individual properties can also be retrieved...
|
||||
x = gas.moleFractions()
|
||||
y = gas.massFractions()
|
||||
mu = gas.chemPotentials()
|
||||
names = gas.speciesNames()
|
||||
for n in range(gas.nSpecies()):
|
||||
print "%20s %10.4g %10.4g %10.4g " % (names[n], x[n], y[n], mu[n])
|
||||
61
Cantera/python/examples/equilibrium/stoich.py
Normal file
61
Cantera/python/examples/equilibrium/stoich.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# Equilibrium of a (nearly) stoichiometric hydrogen/oxygen mixture at
|
||||
# fixed temperature.
|
||||
|
||||
# Cantera has 2 different equilibrium solvers. The 'ChemEquil' solver
|
||||
# uses the element potential method for homogeneous equilibrium in gas
|
||||
# mixtures. It is fast, but sometimes doesn't converge. The
|
||||
# 'MultiPhaseEquil' solver uses the VCS algorithm (Gibbs
|
||||
# minimization), which is slower but more robust. As the name
|
||||
# suggests, it can also handle multiple phases. Here we'll solve a
|
||||
# problem for which the ChemEquil solver fails, but the
|
||||
# MultiPhaseEquil solver has no problem.
|
||||
|
||||
from Cantera import *
|
||||
|
||||
# create an object representing the gas phase
|
||||
gas = importPhase("h2o2.cti")
|
||||
|
||||
temp = 400.0
|
||||
|
||||
# make the composition very close to stoichiometric
|
||||
comp = "H2:1.00000001, O2:0.5"
|
||||
|
||||
# set the initial state
|
||||
gas.set(T = temp, P = OneAtm, X = comp)
|
||||
|
||||
# equilibrate the gas holding T and P fixed. First try the default
|
||||
# (ChemEquil) solver... (This will fail, throwing an exception that
|
||||
# will be caught in the 'except' block, where we will try the other
|
||||
# solver.)
|
||||
try:
|
||||
gas.equilibrate("TP")
|
||||
except:
|
||||
print "ChemEquil solver failed! Try the MultiPhaseEquil solver..."
|
||||
|
||||
# Try again. Reset the gas to the initial state
|
||||
gas.set(T = temp, P = OneAtm, X = comp)
|
||||
|
||||
# setting parameter 'solver' to 1 requests that the
|
||||
# MultiPhaseEquil solver be used (specifying 0 would cause
|
||||
# ChemEquil to be used). Some other useful parameters are rtol
|
||||
# (relative error tolerance, default = 1.0e-9), max_steps (default = 1000),
|
||||
# loglevel (default = 0).
|
||||
gas.equilibrate("TP", solver = 1, rtol = 1.0e-10, loglevel = 4)
|
||||
|
||||
# print a summary of the results
|
||||
print gas
|
||||
|
||||
|
||||
|
||||
# To check that this is an equilibrium state, verify that the chemical
|
||||
# potentials may be computed by summing the element potentials for each atom.
|
||||
# (The element potentials are the chemical potentials of the atomic vapors.)
|
||||
|
||||
mu_H2, mu_OH, mu_H2O, mu_O2, lambda_H, lambda_O = gas.chemPotentials(
|
||||
["H2", "OH", "H2O", "O2", "H", "O"])
|
||||
|
||||
print mu_H2, 2.0*lambda_H
|
||||
print mu_O2, 2.0*lambda_O
|
||||
print mu_OH, lambda_H + lambda_O
|
||||
print mu_H2O, 2.0*lambda_H + lambda_O
|
||||
|
||||
@@ -55,7 +55,7 @@ f.burner.set(massflux = mdot, mole_fractions = comp, temperature = tburner)
|
||||
f.set(tol = tol_ss, tol_time = tol_ts)
|
||||
f.setMaxJacAge(5, 10)
|
||||
f.set(energy = 'off')
|
||||
f.init()
|
||||
#f.init()
|
||||
f.showSolution()
|
||||
|
||||
f.solve(loglevel, refine_grid)
|
||||
|
||||
84
Cantera/python/examples/flames/adiabatic_flame.py
Normal file
84
Cantera/python/examples/flames/adiabatic_flame.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# ADIABATIC_FLAME - A freely-propagating, premixed methane/air flat
|
||||
# flame with multicomponent transport properties
|
||||
#
|
||||
from Cantera import *
|
||||
from Cantera.OneD import *
|
||||
from Cantera.OneD.FreeFlame import FreeFlame
|
||||
|
||||
################################################################
|
||||
#
|
||||
# parameter values
|
||||
#
|
||||
p = OneAtm # pressure
|
||||
tin = 300.0 # unburned gas temperature
|
||||
mdot = 0.04 # kg/m^2/s
|
||||
|
||||
comp = 'CH4:0.45, O2:1, N2:3.76' # premixed gas composition
|
||||
|
||||
initial_grid = [0.0, 0.001, 0.01, 0.02, 0.029, 0.03] # m
|
||||
|
||||
tol_ss = [1.0e-5, 1.0e-9] # [rtol atol] for steady-state
|
||||
# problem
|
||||
tol_ts = [1.0e-5, 1.0e-4] # [rtol atol] for time stepping
|
||||
|
||||
loglevel = 1 # amount of diagnostic output (0
|
||||
# to 5)
|
||||
|
||||
refine_grid = 1 # 1 to enable refinement, 0 to
|
||||
# disable
|
||||
|
||||
|
||||
gas = GRI30('Mix')
|
||||
gas.addTransportModel('Multi')
|
||||
|
||||
# set its state to that of the unburned gas
|
||||
gas.setState_TPX(tin, p, comp)
|
||||
|
||||
f = FreeFlame(gas = gas, grid = initial_grid, tfix = 600.0)
|
||||
|
||||
# set the upstream properties
|
||||
f.inlet.set(mole_fractions = comp, temperature = tin)
|
||||
|
||||
f.set(tol = tol_ss, tol_time = tol_ts)
|
||||
f.showSolution()
|
||||
|
||||
f.set(energy = 'off')
|
||||
f.setRefineCriteria(ratio = 10.0, slope = 1, curve = 1)
|
||||
f.setMaxJacAge(50, 50)
|
||||
f.setTimeStep(1.0e-5, [1, 2, 5, 10, 20])
|
||||
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_adiabatic.xml','no_energy',
|
||||
'solution with the energy equation disabled')
|
||||
|
||||
f.set(energy = 'on')
|
||||
f.setRefineCriteria(ratio = 3.0, slope = 0.1, curve = 0.2)
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_adiabatic.xml','energy',
|
||||
'solution with the energy equation enabled')
|
||||
print 'mixture-averaged flamespeed = ',f.u()[0]
|
||||
|
||||
gas.switchTransportModel('Multi')
|
||||
f.flame.setTransportModel(gas)
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_adiabatic.xml','energy_multi',
|
||||
'solution with the energy equation enabled and multicomponent transport')
|
||||
|
||||
# write the velocity, temperature, density, and mole fractions to a CSV file
|
||||
z = f.flame.grid()
|
||||
T = f.T()
|
||||
u = f.u()
|
||||
V = f.V()
|
||||
fcsv = open('adiabatic_flame.csv','w')
|
||||
writeCSV(fcsv, ['z (m)', 'u (m/s)', 'V (1/s)', 'T (K)', 'rho (kg/m3)']
|
||||
+ list(gas.speciesNames()))
|
||||
for n in range(f.flame.nPoints()):
|
||||
f.setGasState(n)
|
||||
writeCSV(fcsv, [z[n], u[n], V[n], T[n], gas.density()]
|
||||
+list(gas.moleFractions()))
|
||||
fcsv.close()
|
||||
|
||||
print 'solution saved to adiabatic_flame.csv'
|
||||
print 'multicomponent flamespeed = ',u[0]
|
||||
f.showStats()
|
||||
88
Cantera/python/examples/flames/flame1.py
Executable file
88
Cantera/python/examples/flames/flame1.py
Executable file
@@ -0,0 +1,88 @@
|
||||
#
|
||||
# FLAME1 - A burner-stabilized flat flame
|
||||
#
|
||||
# This script simulates a burner-stablized lean hydrogen-oxygen flame
|
||||
# at low pressure.
|
||||
#
|
||||
from Cantera import *
|
||||
from Cantera.OneD import *
|
||||
from Cantera.OneD.BurnerFlame import BurnerFlame
|
||||
|
||||
################################################################
|
||||
#
|
||||
# parameter values
|
||||
#
|
||||
p = 0.05*OneAtm # pressure
|
||||
tburner = 373.0 # burner temperature
|
||||
mdot = 0.06 # kg/m^2/s
|
||||
|
||||
rxnmech = 'h2o2.cti' # reaction mechanism file
|
||||
mix = 'ohmech' # gas mixture model
|
||||
comp = 'H2:1.8, O2:1, AR:7' # premixed gas composition
|
||||
|
||||
# The solution domain is chosen to be 50 cm, and a point very near the
|
||||
# downstream boundary is added to help with the zero-gradient boundary
|
||||
# condition at this boundary.
|
||||
initial_grid = [0.0, 0.02, 0.04, 0.06, 0.08, 0.1,
|
||||
0.15, 0.2, 0.4, 0.49, 0.5] # m
|
||||
|
||||
tol_ss = [1.0e-5, 1.0e-13] # [rtol atol] for steady-state
|
||||
# problem
|
||||
tol_ts = [1.0e-4, 1.0e-9] # [rtol atol] for time stepping
|
||||
|
||||
loglevel = 1 # amount of diagnostic output (0
|
||||
# to 5)
|
||||
|
||||
refine_grid = 1 # 1 to enable refinement, 0 to
|
||||
# disable
|
||||
|
||||
|
||||
################ create the gas object ########################
|
||||
#
|
||||
# This object will be used to evaluate all thermodynamic, kinetic,
|
||||
# and transport properties
|
||||
#
|
||||
gas = IdealGasMix(rxnmech, mix)
|
||||
|
||||
# set its state to that of the unburned gas at the burner
|
||||
gas.set(T = tburner, P = p, X = comp)
|
||||
|
||||
f = BurnerFlame(gas = gas, grid = initial_grid)
|
||||
|
||||
# set the properties at the burner
|
||||
f.burner.set(massflux = mdot, mole_fractions = comp, temperature = tburner)
|
||||
|
||||
f.set(tol = tol_ss, tol_time = tol_ts)
|
||||
f.setMaxJacAge(5, 10)
|
||||
f.set(energy = 'off')
|
||||
f.init()
|
||||
f.showSolution()
|
||||
|
||||
f.solve(loglevel, refine_grid)
|
||||
|
||||
f.setRefineCriteria(ratio = 200.0, slope = 0.05, curve = 0.1)
|
||||
f.set(energy = 'on')
|
||||
f.solve(loglevel,refine_grid)
|
||||
|
||||
f.save('flame1.xml')
|
||||
f.showSolution()
|
||||
|
||||
|
||||
# write the velocity, temperature, and mole fractions to a CSV file
|
||||
z = f.flame.grid()
|
||||
T = f.T()
|
||||
u = f.u()
|
||||
V = f.V()
|
||||
fcsv = open('flame1.csv','w')
|
||||
writeCSV(fcsv, ['z (m)', 'u (m/s)', 'V (1/s)', 'T (K)', 'rho (kg/m3)']
|
||||
+ list(gas.speciesNames()))
|
||||
for n in range(f.flame.nPoints()):
|
||||
f.setGasState(n)
|
||||
writeCSV(fcsv, [z[n], u[n], V[n], T[n], gas.density()]
|
||||
+list(gas.moleFractions()))
|
||||
fcsv.close()
|
||||
|
||||
print 'solution saved to flame1.csv'
|
||||
|
||||
f.showStats()
|
||||
|
||||
97
Cantera/python/examples/flames/flame2.py
Executable file
97
Cantera/python/examples/flames/flame2.py
Executable file
@@ -0,0 +1,97 @@
|
||||
#
|
||||
# FLAME2 - A burner-stabilized, premixed methane/air flat flame
|
||||
# with multicomponent transport properties
|
||||
#
|
||||
from Cantera import *
|
||||
from Cantera.OneD import *
|
||||
from Cantera.OneD.BurnerFlame import BurnerFlame
|
||||
|
||||
################################################################
|
||||
#
|
||||
# parameter values
|
||||
#
|
||||
p = OneAtm # pressure
|
||||
tburner = 373.7 # burner temperature
|
||||
mdot = 0.04 # kg/m^2/s
|
||||
|
||||
comp = 'CH4:0.65, O2:1, N2:3.76' # premixed gas composition
|
||||
|
||||
# The solution domain is chosen to be 1 cm, and a point very near the
|
||||
# downstream boundary is added to help with the zero-gradient boundary
|
||||
# condition at this boundary.
|
||||
initial_grid = [0.0, 0.0025, 0.005, 0.0075, 0.0099, 0.01] # m
|
||||
|
||||
tol_ss = [1.0e-5, 1.0e-9] # [rtol atol] for steady-state
|
||||
# problem
|
||||
tol_ts = [1.0e-5, 1.0e-4] # [rtol atol] for time stepping
|
||||
|
||||
loglevel = 1 # amount of diagnostic output (0
|
||||
# to 5)
|
||||
|
||||
refine_grid = 1 # 1 to enable refinement, 0 to
|
||||
# disable
|
||||
|
||||
|
||||
################ create the gas object ########################
|
||||
#
|
||||
# This object will be used to evaluate all thermodynamic, kinetic, and
|
||||
# transport properties. It is created with two transport managers, to
|
||||
# enable switching from mixture-averaged to multicomponent transport
|
||||
# on the last solution.
|
||||
gas = GRI30('Mix')
|
||||
gas.addTransportModel('Multi')
|
||||
|
||||
# set its state to that of the unburned gas at the burner
|
||||
gas.setState_TPX(tburner, p, comp)
|
||||
|
||||
f = BurnerFlame(gas = gas, grid = initial_grid)
|
||||
|
||||
# set the properties at the burner
|
||||
f.burner.set(massflux = mdot, mole_fractions = comp, temperature = tburner)
|
||||
|
||||
f.set(tol = tol_ss, tol_time = tol_ts)
|
||||
f.showSolution()
|
||||
|
||||
f.set(energy = 'off')
|
||||
f.setRefineCriteria(ratio = 10.0, slope = 1, curve = 1)
|
||||
f.setMaxJacAge(50, 50)
|
||||
f.setTimeStep(1.0e-5, [1, 2, 5, 10, 20])
|
||||
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_flame1.xml','no_energy',
|
||||
'solution with the energy equation disabled')
|
||||
|
||||
f.set(energy = 'on')
|
||||
f.setRefineCriteria(ratio = 3.0, slope = 0.1, curve = 0.2)
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_flame1.xml','energy',
|
||||
'solution with the energy equation enabled')
|
||||
|
||||
gas.switchTransportModel('Multi')
|
||||
f.flame.setTransportModel(gas)
|
||||
f.solve(loglevel, refine_grid)
|
||||
f.save('ch4_flame1.xml','energy_multi',
|
||||
'solution with the energy equation enabled and multicomponent transport')
|
||||
|
||||
# write the velocity, temperature, density, and mole fractions to a CSV file
|
||||
z = f.flame.grid()
|
||||
T = f.T()
|
||||
u = f.u()
|
||||
V = f.V()
|
||||
fcsv = open('flame2.csv','w')
|
||||
writeCSV(fcsv, ['z (m)', 'u (m/s)', 'V (1/s)', 'T (K)', 'rho (kg/m3)']
|
||||
+ list(gas.speciesNames()))
|
||||
for n in range(f.flame.nPoints()):
|
||||
f.setGasState(n)
|
||||
writeCSV(fcsv, [z[n], u[n], V[n], T[n], gas.density()]
|
||||
+list(gas.moleFractions()))
|
||||
fcsv.close()
|
||||
|
||||
print 'solution saved to flame2.csv'
|
||||
|
||||
f.showStats()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
117
Cantera/python/examples/flames/stflame1.py
Normal file
117
Cantera/python/examples/flames/stflame1.py
Normal file
@@ -0,0 +1,117 @@
|
||||
#
|
||||
# STFLAME1 - A detached flat flame stabilized at a stagnation point
|
||||
#
|
||||
|
||||
# This script simulates a lean hydrogen-oxygen flame stabilized in
|
||||
# a strained flowfield at an axisymmetric stagnation point on a
|
||||
# non-reacting surface. The solution begins with a flame attached
|
||||
# to the inlet (burner), and the mass flow rate is progressively
|
||||
# increased, causing the flame to detach and move closer to the
|
||||
# surface. This example illustrates use of the new 'prune' grid
|
||||
# refinement parameter, which allows grid points to be removed if
|
||||
# they are no longer required to resolve the solution. This is
|
||||
# important here, since the flamefront moves as the mass flowrate
|
||||
# is increased. Without using 'prune', a large number of grid
|
||||
# points would be concentrated upsteam of the flame, where the
|
||||
# flamefront had been previously. (To see this, try setting prune
|
||||
# to zero.)
|
||||
|
||||
from Cantera import *
|
||||
from Cantera.OneD import *
|
||||
from Cantera.OneD.StagnationFlow import StagnationFlow
|
||||
|
||||
################################################################
|
||||
#
|
||||
# parameter values
|
||||
#
|
||||
p = 0.05*OneAtm # pressure
|
||||
tburner = 373.0 # burner temperature
|
||||
tsurf = 600.0
|
||||
|
||||
# each mdot value will be solved to convergence, with grid refinement,
|
||||
# and then that solution will be used for the next mdot
|
||||
mdot = [0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12] # kg/m^2/s
|
||||
|
||||
rxnmech = 'h2o2.cti' # reaction mechanism file
|
||||
comp = 'H2:1.8, O2:1, AR:7' # premixed gas composition
|
||||
|
||||
# The solution domain is chosen to be 50 cm, and a point very near the
|
||||
# downstream boundary is added to help with the zero-gradient boundary
|
||||
# condition at this boundary.
|
||||
initial_grid = [0.0, 0.02, 0.04, 0.06, 0.08, 0.1,
|
||||
0.15, 0.2] # m
|
||||
|
||||
tol_ss = [1.0e-5, 1.0e-13] # [rtol atol] for steady-state
|
||||
# problem
|
||||
tol_ts = [1.0e-4, 1.0e-9] # [rtol atol] for time stepping
|
||||
|
||||
loglevel = 1 # amount of diagnostic output (0
|
||||
# to 5)
|
||||
|
||||
refine_grid = 1 # 1 to enable refinement, 0 to
|
||||
# disable
|
||||
ratio = 5.0
|
||||
slope = 0.1
|
||||
curve = 0.2
|
||||
prune = 0.05
|
||||
|
||||
|
||||
|
||||
################ create the gas object ########################
|
||||
#
|
||||
# This object will be used to evaluate all thermodynamic, kinetic,
|
||||
# and transport properties
|
||||
#
|
||||
gas = IdealGasMix(rxnmech)
|
||||
|
||||
# set its state to that of the unburned gas at the burner
|
||||
gas.setState_TPX(tburner, p, comp)
|
||||
|
||||
# Create the stagnation flow object with a non-reactive surface. (To
|
||||
# make the surface reactive, supply a surface reaction mechanism. see
|
||||
# example catcomb.py for how to do this.)
|
||||
f = StagnationFlow(gas = gas, grid = initial_grid)
|
||||
|
||||
# set the properties at the inlet
|
||||
f.inlet.set(massflux = mdot[0], mole_fractions = comp, temperature = tburner)
|
||||
|
||||
# set the surface state
|
||||
f.surface.setTemperature(tsurf)
|
||||
|
||||
f.set(tol = tol_ss, tol_time = tol_ts)
|
||||
f.setMaxJacAge(5, 10)
|
||||
f.set(energy = 'off')
|
||||
f.init(products = 'equil') # assume adiabatic equilibrium products
|
||||
f.showSolution()
|
||||
|
||||
f.solve(loglevel, refine_grid)
|
||||
|
||||
f.setRefineCriteria(ratio = ratio, slope = slope,
|
||||
curve = curve, prune = prune)
|
||||
f.set(energy = 'on')
|
||||
|
||||
m = 0
|
||||
for md in mdot:
|
||||
f.inlet.set(mdot = md)
|
||||
f.solve(loglevel,refine_grid)
|
||||
m = m + 1
|
||||
f.save('stflame1.xml','mdot'+`m`,'mdot = '+`md`+' kg/m2/s')
|
||||
|
||||
|
||||
# write the velocity, temperature, and mole fractions to a CSV file
|
||||
z = f.flow.grid()
|
||||
T = f.T()
|
||||
u = f.u()
|
||||
V = f.V()
|
||||
fcsv = open('stflame1_'+`m`+'.csv','w')
|
||||
writeCSV(fcsv, ['z (m)', 'u (m/s)', 'V (1/s)', 'T (K)']
|
||||
+ list(gas.speciesNames()))
|
||||
for n in range(f.flow.nPoints()):
|
||||
f.setGasState(n)
|
||||
writeCSV(fcsv, [z[n], u[n], V[n], T[n]]+list(gas.moleFractions()))
|
||||
fcsv.close()
|
||||
|
||||
print 'solution saved to flame1.csv'
|
||||
|
||||
f.showStats()
|
||||
|
||||
48
Cantera/python/examples/kinetics/ratecoeffs.py
Normal file
48
Cantera/python/examples/kinetics/ratecoeffs.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# print forward and reverse rate coefficients for all reactions
|
||||
|
||||
from Cantera import *
|
||||
|
||||
|
||||
def show_rate_coefficients(mech, doIrrev = 0):
|
||||
|
||||
""" Print the rate coefficients for a reaction mechanism. The
|
||||
rate coefficients include all factors that multiply the reactant
|
||||
concentrations in the law of mass action. The rate coefficients
|
||||
may depend on temperature and/or pressure, and are evaluated at
|
||||
the temperature and pressure of the object 'mech.'
|
||||
|
||||
If doIrrev has a non-zero value, then the reverse rate coefficients
|
||||
will be computed for all reactions, including irreversible
|
||||
ones. Otherwise, the rate coefficients for irreversible reactions
|
||||
will be set to zero. """
|
||||
|
||||
# get the array of forward rate coefficients
|
||||
kf = mech.fwdRateConstants()
|
||||
|
||||
# get the array of reverse rate coefficients
|
||||
kr = mech.revRateConstants(doIrreversible = doIrrev)
|
||||
|
||||
nr = mech.nReactions()
|
||||
|
||||
# get the array of reaction equations
|
||||
eqs = mech.reactionEqn(range(nr))
|
||||
|
||||
for i in range(nr):
|
||||
print '%40s %12.5g %12.5g ' % (eqs[i], kf[i], kr[i])
|
||||
|
||||
print 'units: kmol, m, s'
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) == 2:
|
||||
mech = importPhase(sys.argv[1])
|
||||
elif len(sys.argv) > 2:
|
||||
mech = importPhase(sys.argv[1], sys.argv[2])
|
||||
else:
|
||||
mech = GRI30()
|
||||
|
||||
show_rate_coefficients(mech)
|
||||
|
||||
|
||||
@@ -10,10 +10,21 @@ platform = sys.platform
|
||||
flibs = '@FLIBS@'
|
||||
#linkargs = '@LCXX_FLAGS@'
|
||||
|
||||
numarray_incl = "@NUMARRAY_INC_DIR@"
|
||||
|
||||
incdirs=["../../build/include", "src", "../clib/src"]
|
||||
|
||||
if numarray_incl <> '':
|
||||
incdirs.append(numarray_incl)
|
||||
|
||||
|
||||
bllibstr = "@BLAS_LAPACK_LIBS@"
|
||||
bllibs = bllibstr.replace('-l',' ')
|
||||
bllist = bllibs.split()
|
||||
|
||||
extra_link = "@EXTRA_LINK@"
|
||||
linkargs = extra_link.split()
|
||||
|
||||
bldirstr = "@LOCAL_LIB_DIRS@"
|
||||
bldirs = bldirstr.replace('-L',' ')
|
||||
dirlist = bldirs.split()
|
||||
@@ -23,7 +34,7 @@ for d in dirlist:
|
||||
|
||||
if platform == "win32":
|
||||
libs = ["clib", "zeroD","oneD","transport",
|
||||
"cantera","recipes"] + bllist + ["ctmath", "cvode", "tpx"]
|
||||
"cantera","recipes"] + bllist + ["ctmath", "cvode", "tpx", "converters"]
|
||||
else:
|
||||
|
||||
# The library 'g2c' is needed if the g77 Fortran compiler is
|
||||
@@ -32,40 +43,54 @@ else:
|
||||
# compiler is used, add the appropriate libraries here.
|
||||
|
||||
libs = ["clib", "zeroD","oneD","transport",
|
||||
"cantera","recipes"] + bllist + ["ctmath", "cvode", "tpx",
|
||||
"cantera","recipes", "converters"] + bllist + ["ctmath", "cvode", "tpx",
|
||||
"stdc++", "g2c", "m"]
|
||||
|
||||
# values:
|
||||
# 0 do nothing
|
||||
# 1 install only ctml_writer.py
|
||||
# 2 install full package
|
||||
# 3 try to install full, but install ctml_writer if full package
|
||||
# install fails
|
||||
buildPython = @BUILD_PYTHON@
|
||||
if buildPython >= 2:
|
||||
|
||||
if @BUILD_PYTHON@ == 2:
|
||||
try:
|
||||
setup(name="Cantera",
|
||||
version="@ctversion@",
|
||||
description="The Cantera Python Interface",
|
||||
long_description="""
|
||||
""",
|
||||
author="Prof. D. G. Goodwin, Caltech",
|
||||
author_email="dgoodwin@caltech.edu",
|
||||
url="http://www.cantera.org",
|
||||
package_dir = {'MixMaster':'../../apps/MixMaster'},
|
||||
packages = ["","Cantera","Cantera.OneD",
|
||||
"MixMaster","MixMaster.Units"],
|
||||
ext_modules=[ Extension("Cantera._cantera",
|
||||
["src/pycantera.cpp"],
|
||||
include_dirs=incdirs,
|
||||
library_dirs = libdir,
|
||||
libraries = libs,
|
||||
extra_link_args = linkargs
|
||||
)
|
||||
],
|
||||
)
|
||||
except:
|
||||
buildPython = 1
|
||||
|
||||
setup(name="Cantera",
|
||||
version="@ctversion@",
|
||||
description="The Cantera Python Interface",
|
||||
long_description="""
|
||||
""",
|
||||
author="Prof. D. G. Goodwin, Caltech",
|
||||
author_email="dgoodwin@caltech.edu",
|
||||
url="http://www.cantera.org",
|
||||
package_dir = {'MixMaster':'../../apps/MixMaster'},
|
||||
packages = ["","Cantera","Cantera.OneD",
|
||||
"MixMaster","MixMaster.Units"],
|
||||
ext_modules=[ Extension("Cantera._cantera",
|
||||
["src/pycantera.cpp"],
|
||||
include_dirs=["../../build/include",
|
||||
"src", "../clib/src"],
|
||||
library_dirs = libdir,
|
||||
libraries = libs)
|
||||
],
|
||||
)
|
||||
else:
|
||||
|
||||
setup(name="Cantera CTI File Processor",
|
||||
version="@ctversion@",
|
||||
description="Converts .cti files to CTML",
|
||||
long_description="""
|
||||
""",
|
||||
author="Prof. D. G. Goodwin, Caltech",
|
||||
author_email="dgoodwin@caltech.edu",
|
||||
url="http://www.cantera.org",
|
||||
py_modules = ["ctml_writer"],
|
||||
)
|
||||
|
||||
if buildPython == 1:
|
||||
try:
|
||||
setup(name="Cantera CTI File Processor",
|
||||
version="@ctversion@",
|
||||
description="Converts .cti files to CTML",
|
||||
long_description="""
|
||||
""",
|
||||
author="Prof. D. G. Goodwin, Caltech",
|
||||
author_email="dgoodwin@caltech.edu",
|
||||
url="http://www.cantera.org",
|
||||
py_modules = ["ctml_writer"],
|
||||
)
|
||||
except:
|
||||
raise 'Error encountered while building or installing the Cantera CTI file preprocessor!'
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initcantera
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctphase
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctflow
|
||||
@@ -67,18 +67,33 @@ ct_addDirectory(PyObject *self, PyObject *args)
|
||||
// return Py_BuildValue("s","");
|
||||
//}
|
||||
|
||||
// static PyObject *
|
||||
// ct_ck2cti(PyObject *self, PyObject *args)
|
||||
// {
|
||||
// int iok;
|
||||
// char *infile, *thermo, *tran, *idtag;
|
||||
// if (!PyArg_ParseTuple(args, "ssss:ck2cti", &infile,
|
||||
// &thermo, &tran, &idtag))
|
||||
// return NULL;
|
||||
// iok = ck_to_cti(infile, thermo, tran, idtag);
|
||||
// if (iok == -1) { return reportCanteraError();}
|
||||
// return Py_BuildValue("i",iok);
|
||||
// }
|
||||
static PyObject *
|
||||
ct_ck2cti(PyObject *self, PyObject *args)
|
||||
{
|
||||
int iok;
|
||||
char *infile, *thermo, *tran, *idtag;
|
||||
int debug, validate;
|
||||
if (!PyArg_ParseTuple(args, "ssssii:ck2cti", &infile,
|
||||
&thermo, &tran, &idtag, &debug, &validate))
|
||||
return NULL;
|
||||
iok = ck_to_cti(infile, thermo, tran, idtag, debug, validate);
|
||||
if (iok == -1) { return reportCanteraError();}
|
||||
return Py_BuildValue("i",iok);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ct_writelogfile(PyObject *self, PyObject *args)
|
||||
{
|
||||
int iok;
|
||||
char *logfile;
|
||||
if (!PyArg_ParseTuple(args, "s:ck2cti", &logfile))
|
||||
return NULL;
|
||||
iok = writelogfile(logfile);
|
||||
if (iok == -1) { return reportCanteraError();}
|
||||
return Py_BuildValue("i",iok);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctkinetics
|
||||
@@ -265,11 +265,12 @@ py_mix_equilibrate(PyObject *self, PyObject *args)
|
||||
int i;
|
||||
char* XY;
|
||||
double err;
|
||||
int maxiter;
|
||||
if (!PyArg_ParseTuple(args, "isdi:mix_equilibrate", &i, &XY, &err, &maxiter))
|
||||
int maxsteps, maxiter, loglevel;
|
||||
if (!PyArg_ParseTuple(args, "isdiii:mix_equilibrate", &i, &XY, &err,
|
||||
&maxsteps, &maxiter, &loglevel))
|
||||
return NULL;
|
||||
|
||||
_val = mix_equilibrate(i,XY,err,maxiter);
|
||||
_val = mix_equilibrate(i,XY,err,maxsteps,maxiter,loglevel);
|
||||
if (int(_val) < -900) return reportCanteraError();
|
||||
return Py_BuildValue("d",_val);
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctnumerics
|
||||
@@ -475,10 +475,11 @@ py_stflow_new(PyObject *self, PyObject *args)
|
||||
int iph;
|
||||
int ikin;
|
||||
int itr;
|
||||
if (!PyArg_ParseTuple(args, "iii:stflow_new", &iph, &ikin, &itr))
|
||||
int itype;
|
||||
if (!PyArg_ParseTuple(args, "iiii:stflow_new", &iph, &ikin, &itr, &itype))
|
||||
return NULL;
|
||||
|
||||
_val = stflow_new(iph,ikin,itr);
|
||||
_val = stflow_new(iph,ikin,itr,itype);
|
||||
if (int(_val) == -1) return reportCanteraError();
|
||||
return Py_BuildValue("i",_val);
|
||||
}
|
||||
@@ -943,3 +944,17 @@ py_sim1D_setTimeStepLimits(PyObject *self, PyObject *args)
|
||||
return Py_BuildValue("i",_val);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
py_sim1D_setFixedTemperature(PyObject *self, PyObject *args)
|
||||
{
|
||||
int _val;
|
||||
int i;
|
||||
double temp;
|
||||
if (!PyArg_ParseTuple(args, "id:sim1D_setFixedTemperature", &i, &temp))
|
||||
return NULL;
|
||||
_val = sim1D_setFixedTemperature(i,temp);
|
||||
if (int(_val) == -1) return reportCanteraError();
|
||||
return Py_BuildValue("i",_val);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctphase
|
||||
@@ -139,7 +139,7 @@ phase_getarray(PyObject *self, PyObject *args)
|
||||
break;
|
||||
case 22:
|
||||
iok = phase_getMolecularWeights(ph,nsp,xd);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
@@ -222,6 +222,8 @@ phase_setfp(PyObject *self, PyObject *args)
|
||||
iok = phase_setTemperature(ph, vv); break;
|
||||
case 2:
|
||||
iok = phase_setDensity(ph, vv); break;
|
||||
case 3:
|
||||
iok = phase_setMolarDensity(ph, vv); break;
|
||||
default:
|
||||
iok = -10;
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctsurf
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initctthermo
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
static PyObject *
|
||||
ct_newThermoFromXML(PyObject *self, PyObject *args)
|
||||
{
|
||||
@@ -232,11 +232,16 @@ thermo_equil(PyObject *self, PyObject *args)
|
||||
int iok = -2;
|
||||
int th;
|
||||
int XY;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii:thermo_equil", &th, &XY))
|
||||
int solver;
|
||||
double rtol;
|
||||
int maxsteps;
|
||||
int loglevel;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiidii:thermo_equil", &th, &XY,
|
||||
&solver, &rtol, &maxsteps, &loglevel))
|
||||
return NULL;
|
||||
|
||||
iok = th_equil(th, XY);
|
||||
iok = th_equil(th, XY, solver, rtol, maxsteps, loglevel);
|
||||
if (iok >= 0)
|
||||
return Py_BuildValue("i",iok);
|
||||
if (iok == -1) return reportCanteraError();
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
EXPORTS
|
||||
initcttransport
|
||||
@@ -86,6 +86,8 @@ static PyMethodDef ct_methods[] = {
|
||||
//{"ct_print", ct_print, METH_VARARGS},
|
||||
{"ct_addDirectory", ct_addDirectory, METH_VARARGS},
|
||||
{"ct_refcnt", ct_refcnt, METH_VARARGS},
|
||||
{"ct_ck2cti", ct_ck2cti, METH_VARARGS},
|
||||
{"ct_writelogfile", ct_writelogfile, METH_VARARGS},
|
||||
//{"readlog", ct_readlog, METH_VARARGS},
|
||||
//{"buildSolutionFromXML", ct_buildSolutionFromXML, METH_VARARGS},
|
||||
|
||||
@@ -150,6 +152,7 @@ static PyMethodDef ct_methods[] = {
|
||||
{"sim1D_setMaxJacAge", py_sim1D_setMaxJacAge, METH_VARARGS},
|
||||
{"sim1D_timeStepFactor", py_sim1D_timeStepFactor, METH_VARARGS},
|
||||
{"sim1D_setTimeStepLimits", py_sim1D_setTimeStepLimits, METH_VARARGS},
|
||||
{"sim1D_setFixedTemperature", py_sim1D_setFixedTemperature, METH_VARARGS},
|
||||
|
||||
{"surf_setsitedensity", py_surf_setsitedensity, METH_VARARGS},
|
||||
{"surf_sitedensity", py_surf_sitedensity, METH_VARARGS},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#pragma warning(disable:4503)
|
||||
#endif
|
||||
|
||||
#include "../../../config.h"
|
||||
#include "../../src/config.h"
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
@@ -42,7 +42,7 @@ static PyObject *ErrorObject;
|
||||
|
||||
#include "ctphase_methods.cpp"
|
||||
#include "ctthermo_methods.cpp"
|
||||
#include "ctkinetics_methods.cpp"
|
||||
#include "ctkinetics_methods.cpp"
|
||||
#include "cttransport_methods.cpp"
|
||||
#include "ctxml_methods.cpp"
|
||||
#include "ctfuncs.cpp"
|
||||
@@ -84,6 +84,11 @@ extern "C" {
|
||||
d = PyModule_GetDict(m);
|
||||
ErrorObject = PyErr_NewException("cantera.error", NULL, NULL);
|
||||
PyDict_SetItemString(d, "error", ErrorObject);
|
||||
#ifdef HAS_NUMERIC
|
||||
PyDict_SetItemString(d, "nummod",PyString_FromString("Numeric"));
|
||||
#else
|
||||
PyDict_SetItemString(d, "nummod",PyString_FromString("numarray"));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ static std::string ss = "print \"\"\" ";
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
/// Logger for Python.
|
||||
/// @ingroup textlogs
|
||||
class Py_Logger : public Logger {
|
||||
public:
|
||||
Py_Logger() {}
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
#define CTPY_UTILS
|
||||
|
||||
#include "Python.h"
|
||||
//#include "../../clib/src/ct.h"
|
||||
|
||||
static PyObject* reportCanteraError() {
|
||||
//showCanteraErrors();
|
||||
char* buf = 0;
|
||||
int buflen = getCanteraError(0, buf) + 1;
|
||||
buf = new char[buflen+1];
|
||||
getCanteraError(buflen, buf);
|
||||
PyErr_SetString(ErrorObject,buf);
|
||||
delete buf;
|
||||
//PyErr_SetString(ErrorObject,"An exception was thrown by Cantera.");
|
||||
//writelogfile("log.html");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -24,119 +22,5 @@ static PyObject* reportError(int n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// template<class V>
|
||||
// int pyNumericSequence_ToVector(PyObject* seq, V& vec)
|
||||
// {
|
||||
// if (!PySequence_Check(seq)) return -1;
|
||||
// int n = PySequence_Size(seq);
|
||||
// vec.resize(n);
|
||||
// PyObject* item;
|
||||
// double x;
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// item = PySequence_GetItem(seq, i);
|
||||
// if (PyFloat_Check(item))
|
||||
// x = PyFloat_AsDouble(item);
|
||||
// else if (PyInt_Check(item))
|
||||
// x = 1.0*PyInt_AsLong(item);
|
||||
// else
|
||||
// return -2;
|
||||
// vec[i] = x;
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
|
||||
// template<class V>
|
||||
// PyObject* pyNumericTuple_FromVector(const V& vec)
|
||||
// {
|
||||
// int n = vec.size();
|
||||
// PyObject* seq = PyTuple_New(n);
|
||||
// PyObject* item;
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// item = PyFloat_FromDouble(1.0*vec[i]);
|
||||
// if (PyTuple_SetItem(seq, i, item) < 0) return NULL;
|
||||
// }
|
||||
// return seq;
|
||||
// }
|
||||
|
||||
|
||||
// template<class V>
|
||||
// PyObject* pyNumericList_FromVector(const V& vec)
|
||||
// {
|
||||
// int n = vec.size();
|
||||
// PyObject* seq = PyList_New(n);
|
||||
// PyObject* item;
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// item = PyFloat_FromDouble(1.0*vec[i]);
|
||||
// if (PyList_SetItem(seq, i, item) < 0) return NULL;
|
||||
// }
|
||||
// return seq;
|
||||
// }
|
||||
|
||||
// template<class V>
|
||||
// PyObject* pyStringTuple_FromVector(const V& vec)
|
||||
// {
|
||||
// int n = vec.size();
|
||||
// PyObject* seq = PyTuple_New(n);
|
||||
// PyObject* item;
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// item = PyString_FromString(vec[i].c_str());
|
||||
// if (PyTuple_SetItem(seq, i, item) < 0) return NULL;
|
||||
// }
|
||||
// return seq;
|
||||
// }
|
||||
|
||||
|
||||
// template<class M>
|
||||
// int pyStrNumMapping_ToMap(PyObject* d, M& m)
|
||||
// {
|
||||
// if (!PyMapping_Check(d)) return -1;
|
||||
// int n = PyMapping_Length(d);
|
||||
// PyObject *keys, *values, *ky, *v;
|
||||
// double x;
|
||||
// string key;
|
||||
// keys = PyMapping_Keys(d);
|
||||
// values = PyMapping_Values(d);
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// ky = PySequence_GetItem(keys, i);
|
||||
// v = PySequence_GetItem(values, i);
|
||||
// key = string(PyString_AsString(ky));
|
||||
// if (PyFloat_Check(v))
|
||||
// x = PyFloat_AsDouble(v);
|
||||
// else if (PyInt_Check(v))
|
||||
// x = 1.0*PyInt_AsLong(v);
|
||||
// else
|
||||
// return -2;
|
||||
// m[key] = x;
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
|
||||
// template<class M>
|
||||
// PyObject* pyStrNumMapping_FromMap(M& m)
|
||||
// {
|
||||
// if (!PyMapping_Check(d)) return -1;
|
||||
// int n = m.size();
|
||||
// double value;
|
||||
// char* key;
|
||||
// PyObject* x;
|
||||
// TYPENAME_KEYWORD M::const_iter ptr;
|
||||
// PyObject* map = PyDict_New();
|
||||
// for (int i = 0; i < n; i++) {
|
||||
// key = ptr->first.c_str();
|
||||
// value = ptr->second;
|
||||
// x = PyFloat_FromDouble(value);
|
||||
// PyMapping_SetItemString(map, key, x);
|
||||
// }
|
||||
// return map;
|
||||
// }
|
||||
|
||||
|
||||
// static int lengthError() {
|
||||
// PyErr_SetString(PyExc_AttributeError,
|
||||
// "wrong length for sequence");
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@ from distutils.core import setup, Extension
|
||||
libdir = ['../../build/lib/i686-pc-win32']
|
||||
|
||||
setup(name="Cantera",
|
||||
version="1.5.5",
|
||||
version="1.6.0",
|
||||
description="The Cantera Python Interface",
|
||||
long_description="""
|
||||
""",
|
||||
|
||||
Reference in New Issue
Block a user