diff --git a/Cantera/matlab/setup_matlab.py.in b/Cantera/matlab/setup_matlab.py.in index cafd37985..c01d9b099 100644 --- a/Cantera/matlab/setup_matlab.py.in +++ b/Cantera/matlab/setup_matlab.py.in @@ -2,7 +2,7 @@ import sys bindir = '@ct_bindir@' -libdir = '-L @buildlib@ @LOCAL_LIB_DIRS@' +libdir = '-L@buildlib@ @LOCAL_LIB_DIRS@' incdir = '@buildinc@' libs = '-lclib @LOCAL_LIBS@ @LIBS@ @FLIBS@' diff --git a/Cantera/matlab/setup_winmatlab.py b/Cantera/matlab/setup_winmatlab.py index 5026808ec..979b213ec 100644 --- a/Cantera/matlab/setup_winmatlab.py +++ b/Cantera/matlab/setup_winmatlab.py @@ -1,13 +1,19 @@ import sys -bindir = '/usr/local/bin' +bindir = '/Applications/Cantera/bin' libdir = '/Users/dgg/dv/sf/cantera/build/lib/powerpc-apple-darwin7.4.0' incdir = '/Users/dgg/dv/sf/cantera/build/include' dflibdir = '' +bllibstr = "-llapack -lf77blas -lcblas -latlas" +bllibs = bllibstr.replace('-l',' ') +bllist = bllibs.split() + +bldir = "/usr/lib/atlas" + libs = ['clib', 'oneD', 'zeroD', 'transport', 'cantera', 'recipes', - 'cvode', 'ctlapack', 'ctmath', 'ctblas', 'tpx'] + 'cvode', 'ctmath', 'tpx'] f = open('setup.m','w') f.write('cd cantera\nbuild_cantera\nexit\n') @@ -32,6 +38,13 @@ fb.write(s) fb.write(' "'+dflibdir+'/dformd.lib" ...\n') fb.write(' "'+dflibdir+'/dfconsol.lib" ...\n') fb.write(' "'+dflibdir+'/dfport.lib" \n') + +if bllist: + s = '' + for lib in bllist: + s += ' '+bldir+'/'+lib+'.lib ...\n' + fb.write(s) + fb.close() fp = open('cantera/ctbin.m','w') diff --git a/Cantera/python/Cantera/OneD/BurnerFlame.py b/Cantera/python/Cantera/OneD/BurnerFlame.py index 55101d61c..cbbf88121 100644 --- a/Cantera/python/Cantera/OneD/BurnerFlame.py +++ b/Cantera/python/Cantera/OneD/BurnerFlame.py @@ -5,6 +5,20 @@ class BurnerFlame(Stack): """A burner-stabilized flat flame.""" def __init__(self, gas = None, burner = None, outlet = None, grid = None): + """ + gas -- object to use to evaluate all gas properties and reaction + rates. Required + burner -- Inlet object representing the burner. Optional; + if not supplied, one will be created with name 'burner' + outlet -- Outlet object representing the outlet. Optional; + if not supplied, one will be created with name 'outlet' + grid -- array of initial grid points + + A domain of type 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: @@ -24,7 +38,12 @@ class BurnerFlame(Stack): def init(self): - """Set the initial guess for the solution.""" + """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() @@ -51,21 +70,29 @@ class BurnerFlame(Stack): 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 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: @@ -74,19 +101,26 @@ class BurnerFlame(Stack): 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 = Numeric.zeros(nsp, 'd') for n in range(nsp): diff --git a/Cantera/python/Cantera/OneD/CounterFlame.py b/Cantera/python/Cantera/OneD/CounterFlame.py index 7f4997153..562430fe4 100644 --- a/Cantera/python/Cantera/OneD/CounterFlame.py +++ b/Cantera/python/Cantera/OneD/CounterFlame.py @@ -28,10 +28,18 @@ def erf(x): 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 @@ -47,7 +55,10 @@ class CounterFlame(Stack): def init(self, fuel = '', oxidizer = 'O2', stoich = -1.0): - """Set the initial guess for the solution. + """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.""" @@ -141,21 +152,52 @@ class CounterFlame(Stack): def solve(self, loglevel = 1, refine_grid = 1): + """Solve the flame. + loglevel -- integer flag controlling the amount of + diagnostic output. Zero suppresses all output, and + 5 produces very verbose output. Default: 1 + refine_grid -- if non-zero, enable grid refinement.""" + 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): + """Set the criteria used to refine the flame. + ratio -- additional points will be added if the ratio of the spacing + on either side of a grid point exceeds this value + 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. + 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. + 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. + + >>> f.setRefineCriteria(ratio = 5.0, slope = 0.2, curve = 0.3, + ... prune = 0.03) + """ Stack.setRefineCriteria(self, domain = self.flame, ratio = ratio, slope = slope, curve = curve, prune = prune) 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: @@ -184,6 +226,8 @@ class CounterFlame(Stack): 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 = Numeric.zeros(nsp, 'd') for n in range(nsp): diff --git a/Cantera/python/Cantera/OneD/StagnationFlow.py b/Cantera/python/Cantera/OneD/StagnationFlow.py index b66c14811..85a149142 100644 --- a/Cantera/python/Cantera/OneD/StagnationFlow.py +++ b/Cantera/python/Cantera/OneD/StagnationFlow.py @@ -5,6 +5,19 @@ class StagnationFlow(Stack): """An axisymmetric flow impinging on a surface at normal incidence.""" def __init__(self, gas = None, surfchem = None, grid = None): + """ + gas -- object to use to evaluate all gas properties and reaction + rates. Required. + surfchem -- object used to evaluate surface reaction rates. If + omitted, surface will be treated as inert. + grid -- array of initial grid points + + A domain of type AxisymmetricFlow named 'flow' will be created to + represent the flow, and one of type 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 @@ -18,7 +31,10 @@ class StagnationFlow(Stack): self._initialized = 0 def init(self, products = 'inlet'): - """Set the initial guess for the solution.""" + """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() @@ -57,21 +73,52 @@ class StagnationFlow(Stack): def solve(self, loglevel = 1, refine_grid = 1): + """Solve the flame. + loglevel -- integer flag controlling the amount of + diagnostic output. Zero suppresses all output, and + 5 produces very verbose output. Default: 1 + refine_grid -- if non-zero, enable grid refinement.""" + 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): + """Set the criteria used to refine the flame. + ratio -- additional points will be added if the ratio of the spacing + on either side of a grid point exceeds this value + 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. + 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. + 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. + + >>> f.setRefineCriteria(ratio = 5.0, slope = 0.2, curve = 0.3, + ... prune = 0.03) + """ Stack.setRefineCriteria(self, domain = self.flow, ratio = ratio, slope = slope, curve = curve, prune = prune) def setProfile(self, component, locs, vals): + """Set a profile in the flame""" self._initialized = 1 Stack.setProfile(self, self.flow, 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.flow.setTolerances(default = tol) if tol_time: @@ -80,19 +127,27 @@ class StagnationFlow(Stack): 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 = Numeric.zeros(nsurf,'d') for n in range(nsurf): @@ -101,6 +156,8 @@ class StagnationFlow(Stack): 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 = Numeric.zeros(nsp, 'd') for n in range(nsp): diff --git a/Cantera/python/Cantera/OneD/onedim.py b/Cantera/python/Cantera/OneD/onedim.py index 20f76dcd9..95c6b8b11 100644 --- a/Cantera/python/Cantera/OneD/onedim.py +++ b/Cantera/python/Cantera/OneD/onedim.py @@ -2,10 +2,10 @@ from Cantera import * from Cantera import _cantera import Numeric -_onoff = {'on':1, 'yes':1, 'off':0, 'no':0} +_onoff = {'on':1, 'yes':1, 'off':0, 'no':0, 1:1, 0:0} class Domain1D: - """One-dimensional domains.""" + """Base class for one-dimensional domains.""" def __init__(self): self._hndl = 0 @@ -39,6 +39,7 @@ class Domain1D: 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)) @@ -56,7 +57,11 @@ class Domain1D: 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. """ + fractions in flow domains. + + >>> d.setBounds(default = (0, 1), + ... Y = (-1.0e-5, 2.0)) + """ d = {} if bounds.has_key('default'): @@ -79,12 +84,23 @@ class Domain1D: _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) @@ -101,6 +117,10 @@ class Domain1D: 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 = {} @@ -128,16 +148,29 @@ class Domain1D: def setupGrid(self, grid): - """Specify the grid.""" + """Specify the grid. + + d.setupGrid([0.0, 0.1, 0.2]) + + """ return _cantera.domain_setupGrid(self._hndl, Numeric.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: @@ -147,8 +180,17 @@ class Domain1D: 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] @@ -158,13 +200,13 @@ class Domain1D: 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) + #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() @@ -190,29 +232,42 @@ class Domain1D: 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': @@ -238,22 +293,28 @@ class Inlet(Bdry1D): 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 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: @@ -265,10 +326,12 @@ class Surface(Bdry1D): 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: @@ -317,19 +380,25 @@ class AxisymmetricFlow(Domain1D): self._p = p def setTransportModel(self, transp): + """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) def pressure(self): + """Pressure [Pa].""" return self._p def setFixedTempProfile(self, pos, temp): """Set the fixed temperature profile. This profile is used - whenever the energy equation is disabled. + whenever the energy equation is disabled. pos - arrray of relative positions from 0 to 1 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) @@ -340,7 +409,7 @@ class AxisymmetricFlow(Domain1D): 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, flag) + return _cantera.stflow_solveSpeciesEqs(self._hndl, _onoff[flag]) def solveEnergyEqn(self, flag = 1): """Enable or disable solving the energy equation. If invoked @@ -349,9 +418,16 @@ class AxisymmetricFlow(Domain1D): it will not be, and instead the temperature profiles will be held to the one specified by the call to setFixedTempProfile. Default: energy equation enabled.""" - return _cantera.stflow_solveEnergyEqn(self._hndl, flag) + 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': @@ -370,8 +446,11 @@ class Stack: 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 = Numeric.zeros(nd,'i') for n in range(nd): @@ -383,60 +462,166 @@ class Stack: _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'. + dom -- domain object + comp -- component number + localPoint -- grid point number within domain 'dom', starting with + zero on the left + 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. + + dom -- domain object + comp -- component name + pos -- sequence of relative positions, from 0 on the + left to 1 on the right + 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, Numeric.asarray(pos), Numeric.asarray(v)) def setFlatProfile(self, dom, comp, v): + """Set a flat profile for one component in one domain. + dom -- domain object + comp -- component name + 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') + + """ _cantera.sim1D_showSolution(self._hndl, fname) def setTimeStep(self, stepsize, nsteps): + """Set the sequence of time steps to try when Newton fails. + + stepsize -- initial time step size [s] + nsteps - sequence of integer step numbers + + >>> s.setTimeStep(1.0e-5, [1, 2, 5, 10]) + + """ _cantera.sim1D_setTimeStep(self._hndl, stepsize, Numeric.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. + loglevel -- integer flag controlling the amount of + diagnostic output. Zero suppresses all output, and + 5 produces very verbose output. Default: 1 + 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. + domain -- domain object + ratio -- additional points will be added if the ratio of the spacing + on either side of a grid point exceeds this value + 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. + 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. + 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 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. + + file -- solution file + id -- solution name within the file + + >>> s.restore(file = 'save.xml', id = 'energy_off') + """ return _cantera.sim1D_restore(self._hndl, file, id) def showStats(self): + """Show the statistics for the last solution.""" return _cantera.sim1D_writeStats(self._hndl) 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. + domain -- domain object + component -- component name + 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): @@ -444,23 +629,48 @@ class Stack: 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. + domain -- domain object + component -- component name + 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. + ss_age -- age criterion during steady-state mode + 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 clearDomains(): + """Clear all domains.""" _cantera.domain_clear() def clearSim1D(): + """Clear all stacks.""" _cantera.sim1D_clear() diff --git a/Cantera/python/examples/npflame1.py b/Cantera/python/examples/npflame1.py index 313d1e993..22fc73919 100644 --- a/Cantera/python/examples/npflame1.py +++ b/Cantera/python/examples/npflame1.py @@ -92,7 +92,7 @@ f.solve(loglevel, 0) # will be removed if the relative slope and curvature for all # components fall below the prune level. Set prune < min(slope, # curve), or to zero to disable removing grid points. -f.setRefineCriteria(ratio = 200.0, slope = 0.1, curve = 0.2, prune = 0.0) +f.setRefineCriteria(ratio = 200.0, slope = 0.1, curve = 0.2, prune = 0.02) f.set(energy = 'on') f.solve(1) diff --git a/Cantera/src/SpeciesThermoFactory.cpp b/Cantera/src/SpeciesThermoFactory.cpp index 0caa2458c..6a81807b3 100755 --- a/Cantera/src/SpeciesThermoFactory.cpp +++ b/Cantera/src/SpeciesThermoFactory.cpp @@ -114,6 +114,8 @@ namespace Cantera { return new SpeciesThermoDuo; case NASA + SIMPLE: return new SpeciesThermoDuo; + case SHOMATE + SIMPLE: + return new SpeciesThermoDuo; default: throw UnknownSpeciesThermo( "SpeciesThermoFactory::newSpeciesThermo",type); diff --git a/Cantera/src/SpeciesThermoMgr.h b/Cantera/src/SpeciesThermoMgr.h index 14e2f749b..c55eb6cd5 100755 --- a/Cantera/src/SpeciesThermoMgr.h +++ b/Cantera/src/SpeciesThermoMgr.h @@ -113,6 +113,7 @@ namespace Cantera { virtual void install(int sp, int type, const doublereal* c, doublereal minTemp, doublereal maxTemp, doublereal refPressure) { + m_p0 = refPressure; if (type == m_thermo1.ID) { m_thermo1.install(sp, 0, c, minTemp, maxTemp, refPressure); speciesToType[sp] = m_thermo1.ID; @@ -143,7 +144,7 @@ namespace Cantera { } virtual doublereal refPressure() const { - return m_thermo1.refPressure(); + return m_p0; } virtual int reportType(int k) const { @@ -176,6 +177,7 @@ namespace Cantera { T1 m_thermo1; T2 m_thermo2; + doublereal m_p0; map speciesToType; }; diff --git a/Cantera/src/converters/CKParser.cpp b/Cantera/src/converters/CKParser.cpp index e9b5ba0bd..599718324 100755 --- a/Cantera/src/converters/CKParser.cpp +++ b/Cantera/src/converters/CKParser.cpp @@ -6,7 +6,10 @@ // Copyright 2001 California Institute of Technology // // $Log$ -// Revision 1.9 2004-07-14 11:24:13 dggoodwin +// Revision 1.10 2004-07-23 00:15:15 dggoodwin +// *** empty log message *** +// +// Revision 1.9 2004/07/14 11:24:13 dggoodwin // *** empty log message *** // // Revision 1.8 2004/07/02 17:34:13 hkmoffa @@ -281,7 +284,7 @@ namespace ckr { const char undoCommentChar = '%'; // carriage return - //const char char13 = char(13); + const char char13 = char(13); // linefeed const char char10 = char(10); diff --git a/Makefile.in b/Makefile.in index 05e2161c4..2fd6a7b00 100755 --- a/Makefile.in +++ b/Makefile.in @@ -17,6 +17,7 @@ build_particles = @BUILD_PARTICLES@ os_is_win = @OS_IS_WIN@ incl_user_code = @INCL_USER_CODE@ do_ranlib = @DO_RANLIB@ +compact_install = @COMPACT_INSTALL@ prefix=@prefix@ @@ -200,11 +201,13 @@ ifeq ($(os_is_win),0) rm -fR @prefix@/cantera/data rm -fR @prefix@/cantera/templates rm -fR @prefix@/cantera/tutorials +ifeq ($(compact_install),0) ln -s @ct_demodir@ @prefix@/cantera/demos ln -s @ct_datadir@ @prefix@/cantera/data ln -s @ct_templdir@ @prefix@/cantera/templates ln -s @ct_tutdir@ @prefix@/cantera/tutorials @INSTALL@ License.* @prefix@/cantera +endif @INSTALL@ tools/src/finish_install.py tools/bin (PYTHONPATH=''; @PYTHON_CMD@ tools/bin/finish_install.py @prefix@ @PYTHON_CMD@) chmod +x @ct_bindir@/ctnew diff --git a/apps/MixMaster/ControlPanel.py b/apps/MixMaster/ControlPanel.py index 826bb3f68..5172f78ba 100644 --- a/apps/MixMaster/ControlPanel.py +++ b/apps/MixMaster/ControlPanel.py @@ -93,8 +93,9 @@ def testevent(event): print 'event ',event.value def make_menu(name, menubar, list): - button=Menubutton(menubar, text=name, padx=3,pady=1) - button.pack(side=LEFT, anchor=W) + 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 diff --git a/apps/MixMaster/KineticsFrame.py b/apps/MixMaster/KineticsFrame.py index 378894a28..a1c289d1f 100644 --- a/apps/MixMaster/KineticsFrame.py +++ b/apps/MixMaster/KineticsFrame.py @@ -275,7 +275,7 @@ class ReactionPathFrame(Frame): self.b = rxnpath.PathBuilder(self.g) self.fmt = StringVar() - self.fmt.set('svg') + self.fmt.set('gif') i = 1 fmtframe = Frame(self) fmtframe.config(relief=GROOVE, bd=4) @@ -332,17 +332,18 @@ class ReactionPathFrame(Frame): 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') + #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) - webbrowser.open('rxnpath.'+fmt) + webbrowser.open('file:///'+os.getcwd()+'/rxnpath.'+fmt) try: self.cv.delete(self.image) except: - pass + pass + self.cv.configure(width=0, height=0) else: os.system(self.dot.get()) self.rp = PhotoImage(file='rxnpath.gif') diff --git a/config/configure b/config/configure index 662e3b7c7..f7ff7c20f 100755 --- a/config/configure +++ b/config/configure @@ -271,7 +271,7 @@ PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="Cantera.README" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CVF_LIBDIR local_inst local_python_inst python_prefix ctversion homedir ct_libdir ct_incdir ct_incroot ct_bindir ct_datadir ct_demodir ct_templdir ct_mandir ct_tutdir ct_docdir ct_dir CANTERA_LIBDIR CANTERA_INCDIR CT_TOOLS_BIN CANTERA_BINDIR CANTERA_EXAMPLES_DIR CANTERA_DATADIR build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os username ctroot buildinc buildlib buildbin MAKE ARCHIVE DO_RANLIB RANLIB SOEXT SHARED PIC LCXX_FLAGS LCXX_END_LIBS USERDIR INCL_USER_CODE KERNEL BUILD_CK LIB_DIR build_lapack build_blas BLAS_LAPACK_LIBS BLAS_LAPACK_DIR LOCAL_LIB_DIRS LOCAL_LIBS CANTERA_PARTICLES_DIR BUILD_PARTICLES CT_SHARED_LIB BUILD_F90 PYTHON_CMD WIN_PYTHON_CMD BUILD_PYTHON MATLAB_CMD BUILD_MATLAB BUILD_CLIB export_name INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CC CFLAGS ac_ct_CC F77 FFLAGS ac_ct_F77 FLIBS precompile_headers CXX_DEPENDS OS_IS_DARWIN OS_IS_WIN OS_IS_CYGWIN SHARED_CTLIB mex_ext F77_EXT CXX_EXT OBJ_EXT EXE_EXT local_math_libs math_libs SO LDSHARED LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CVF_LIBDIR local_inst local_python_inst python_prefix ctversion homedir ct_libdir ct_incdir ct_incroot ct_bindir ct_datadir ct_demodir ct_templdir ct_mandir ct_tutdir ct_docdir ct_dir COMPACT_INSTALL CANTERA_LIBDIR CANTERA_INCDIR CT_TOOLS_BIN CANTERA_BINDIR CANTERA_EXAMPLES_DIR CANTERA_DATADIR build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os username ctroot buildinc buildlib buildbin MAKE ARCHIVE DO_RANLIB RANLIB SOEXT SHARED PIC LCXX_FLAGS LCXX_END_LIBS USERDIR INCL_USER_CODE KERNEL BUILD_CK LIB_DIR build_lapack build_blas BLAS_LAPACK_LIBS BLAS_LAPACK_DIR LOCAL_LIB_DIRS LOCAL_LIBS CANTERA_PARTICLES_DIR BUILD_PARTICLES CT_SHARED_LIB BUILD_F90 PYTHON_CMD WIN_PYTHON_CMD BUILD_PYTHON MATLAB_CMD BUILD_MATLAB BUILD_CLIB export_name INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CC CFLAGS ac_ct_CC F77 FFLAGS ac_ct_F77 FLIBS precompile_headers CXX_DEPENDS OS_IS_DARWIN OS_IS_WIN OS_IS_CYGWIN SHARED_CTLIB mex_ext F77_EXT CXX_EXT OBJ_EXT EXE_EXT local_math_libs math_libs SO LDSHARED LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -1284,7 +1284,9 @@ fi fi -#AC_PREFIX_DEFAULT([/usr/local]) +prdef="/usr/local" +if test "x$OS_IS_DARWIN" = "x1"; then prdef="/Applications/Cantera"; fi +#AC_PREFIX_DEFAULT([$prdef]) local_inst=1 if test "x${prefix}" = "xNONE"; then @@ -1292,7 +1294,8 @@ if test "x${prefix}" = "xNONE"; then prefix=${CANTERA_INSTALL_DIR} # mkdir ${prefix} else - prefix=${ac_default_prefix} + prefix=${prdef} + #${ac_default_prefix} fi local_inst=0 # if test ! -d ${prefix}; then @@ -1363,7 +1366,11 @@ ct_dir=${prefix}/cantera/${ctversion} ct_mandir=${prefix}/share/man fi +# default is unix-like distributed installation (not everything within one directory) +COMPACT_INSTALL=0 + if test "x${OS_IS_WIN}" = "x1"; then +COMPACT_INSTALL=1 ct_libdir=${prefix}/lib/${ctversion} ct_incdir=${prefix}/include/cantera ct_incroot=${prefix}/include @@ -1377,6 +1384,22 @@ ct_dir=${prefix} ct_mandir=${prefix} fi +if test "x${OS_IS_DARWIN}" = "x1"; then +COMPACT_INSTALL=1 +ct_libdir=${prefix}/lib/${ctversion} +ct_incdir=${prefix}/include/cantera +ct_incroot=${prefix}/include +ct_bindir=${prefix}/bin +ct_datadir=${prefix}/data +ct_demodir=${prefix}/demos +ct_templdir=${prefix}/templates +ct_tutdir=${prefix}/tutorials +ct_docdir=${prefix}/doc +ct_dir=${prefix} +ct_mandir=${prefix} +fi + + @@ -3362,7 +3385,7 @@ fi # Provide some information about the compiler. -echo "$as_me:3365:" \ +echo "$as_me:3388:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 @@ -3539,7 +3562,7 @@ _ACEOF # flags. ac_save_FFLAGS=$FFLAGS FFLAGS="$FFLAGS $ac_verb" -(eval echo $as_me:3542: \"$ac_link\") >&5 +(eval echo $as_me:3565: \"$ac_link\") >&5 ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` echo "$ac_f77_v_output" >&5 FFLAGS=$ac_save_FFLAGS @@ -3619,7 +3642,7 @@ _ACEOF # flags. ac_save_FFLAGS=$FFLAGS FFLAGS="$FFLAGS $ac_cv_prog_f77_v" -(eval echo $as_me:3622: \"$ac_link\") >&5 +(eval echo $as_me:3645: \"$ac_link\") >&5 ac_f77_v_output=`eval $ac_link 5>&1 2>&1 | grep -v 'Driving:'` echo "$ac_f77_v_output" >&5 FFLAGS=$ac_save_FFLAGS @@ -4505,6 +4528,7 @@ s,@ct_mandir@,$ct_mandir,;t t s,@ct_tutdir@,$ct_tutdir,;t t s,@ct_docdir@,$ct_docdir,;t t s,@ct_dir@,$ct_dir,;t t +s,@COMPACT_INSTALL@,$COMPACT_INSTALL,;t t s,@CANTERA_LIBDIR@,$CANTERA_LIBDIR,;t t s,@CANTERA_INCDIR@,$CANTERA_INCDIR,;t t s,@CT_TOOLS_BIN@,$CT_TOOLS_BIN,;t t diff --git a/config/configure.in b/config/configure.in index 99f5b737a..090442140 100755 --- a/config/configure.in +++ b/config/configure.in @@ -40,7 +40,9 @@ fi fi AC_SUBST(CVF_LIBDIR) -#AC_PREFIX_DEFAULT([/usr/local]) +prdef="/usr/local" +if test "x$OS_IS_DARWIN" = "x1"; then prdef="/Applications/Cantera"; fi +#AC_PREFIX_DEFAULT([$prdef]) local_inst=1 if test "x${prefix}" = "xNONE"; then @@ -48,7 +50,8 @@ if test "x${prefix}" = "xNONE"; then prefix=${CANTERA_INSTALL_DIR} # mkdir ${prefix} else - prefix=${ac_default_prefix} + prefix=${prdef} + #${ac_default_prefix} fi local_inst=0 # if test ! -d ${prefix}; then @@ -119,7 +122,26 @@ ct_dir=${prefix}/cantera/${ctversion} ct_mandir=${prefix}/share/man fi +# default is unix-like distributed installation (not everything within one directory) +COMPACT_INSTALL=0 + if test "x${OS_IS_WIN}" = "x1"; then +COMPACT_INSTALL=1 +ct_libdir=${prefix}/lib/${ctversion} +ct_incdir=${prefix}/include/cantera +ct_incroot=${prefix}/include +ct_bindir=${prefix}/bin +ct_datadir=${prefix}/data +ct_demodir=${prefix}/demos +ct_templdir=${prefix}/templates +ct_tutdir=${prefix}/tutorials +ct_docdir=${prefix}/doc +ct_dir=${prefix} +ct_mandir=${prefix} +fi + +if test "x${OS_IS_DARWIN}" = "x1"; then +COMPACT_INSTALL=1 ct_libdir=${prefix}/lib/${ctversion} ct_incdir=${prefix}/include/cantera ct_incroot=${prefix}/include @@ -144,6 +166,7 @@ AC_SUBST(ct_mandir) AC_SUBST(ct_tutdir) AC_SUBST(ct_docdir) AC_SUBST(ct_dir) +AC_SUBST(COMPACT_INSTALL) CANTERA_DATADIR=$datadir/cantera/data diff --git a/configure b/configure index cdd5deb51..3d34f11b8 100755 --- a/configure +++ b/configure @@ -183,8 +183,8 @@ ENABLE_TPX='y' # libraries, and set BLAS_LAPACK_DIR to the directory where these # libraries are located. Otherwise, leave these lines commented out. -# BLAS_LAPACK_LIBS='-llapack -lf77blas -lcblas -latlas' -# BLAS_LAPACK_DIR='/usr/lib/atlas' +#BLAS_LAPACK_LIBS='-llapack -lf77blas -lcblas -latlas' +#BLAS_LAPACK_DIR='/usr/lib/atlas' # # The options below do not need to be set if you are using the default @@ -218,7 +218,7 @@ CC=${CC:=gcc} CXXFLAGS=${CXXFLAGS:="-O2 -Wall"} # the C++ flags required for linking -LCXX_FLAGS="-L /usr/lib/atlas" +#LCXX_FLAGS="-L/usr/lib/atlas" # Ending libraries to tack onto the linking of all C++ programs LCXX_END_LIBS=${LCXX_END_LIBS:="-lm"} diff --git a/tools/doc/Cantera.cfg b/tools/doc/Cantera.cfg index bfccf3a39..912e12c3a 100755 --- a/tools/doc/Cantera.cfg +++ b/tools/doc/Cantera.cfg @@ -370,11 +370,10 @@ INPUT = ../../Cantera/src # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc -FILE_PATTERNS = Constituents.h -#*.h \ -# *.cpp \ -# *.c \ -# *.txt +FILE_PATTERNS = *.h \ + *.cpp \ + *.c \ + *.txt # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -970,7 +969,7 @@ HIDE_UNDOC_RELATIONS = YES # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) -HAVE_DOT = YES +HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and