From f0b91575dac317ccc6ebfd469ad26417297a1247 Mon Sep 17 00:00:00 2001 From: Dave Goodwin Date: Thu, 24 Apr 2003 08:55:11 +0000 Subject: [PATCH] *** empty log message *** --- Cantera/clib/src/ctbdry.cpp | 9 ++ Cantera/clib/src/ctbdry.h | 2 + Cantera/python/Cantera/Flow.py | 38 +++++++ Cantera/python/Cantera/OneDim.py | 22 +++++ Cantera/python/Cantera/boundaries1D.py | 3 + Cantera/python/Cantera/flame.py | 132 ++++++++++++++++++++++--- Cantera/python/Cantera/refine.py | 4 +- Cantera/python/src/ctpybndry.cpp | 24 +++++ Cantera/src/oneD/Inlet1D.h | 5 + Makefile.in | 3 +- configure | 2 +- 11 files changed, 228 insertions(+), 16 deletions(-) diff --git a/Cantera/clib/src/ctbdry.cpp b/Cantera/clib/src/ctbdry.cpp index 5f46e57c2..cb5e2a0a9 100755 --- a/Cantera/clib/src/ctbdry.cpp +++ b/Cantera/clib/src/ctbdry.cpp @@ -66,6 +66,15 @@ extern "C" { return 0; } + double DLL_EXPORT bndry_spreadrate(int i) { + return ((Inlet1D*)_bndry(i))->spreadRate(); + } + + int DLL_EXPORT bndry_setSpreadRate(int i, double v) { + ((Inlet1D*)_bndry(i))->setSpreadRate(v); + return 0; + } + int DLL_EXPORT bndry_setmdot(int i, double mdot) { try { _bndry(i)->setMdot(mdot); diff --git a/Cantera/clib/src/ctbdry.h b/Cantera/clib/src/ctbdry.h index e6aea2036..d94ae0244 100755 --- a/Cantera/clib/src/ctbdry.h +++ b/Cantera/clib/src/ctbdry.h @@ -9,6 +9,8 @@ extern "C" { int DLL_IMPORT bndry_del(int i); double DLL_IMPORT bndry_temperature(int i); int DLL_IMPORT bndry_settemperature(int i, double t); + double DLL_IMPORT bndry_spreadrate(int i); + int DLL_IMPORT bndry_setSpreadRate(int i, double v); int DLL_IMPORT bndry_setmdot(int i, double mdot); double DLL_IMPORT bndry_mdot(int i); int DLL_IMPORT bndry_setxin(int i, double* xin); diff --git a/Cantera/python/Cantera/Flow.py b/Cantera/python/Cantera/Flow.py index c9d7ae63c..82e0bebad 100755 --- a/Cantera/python/Cantera/Flow.py +++ b/Cantera/python/Cantera/Flow.py @@ -557,6 +557,44 @@ class Flow1D: return nin + def prune(self, loglevel = 2): + """Prune the grid. + + """ + r = self.refiner + r.components = range(4,self.nsp+4) + if self.energy: + r.components.append(2) + + znew, xn = r.prune(grid = self.z, solution = self.x) + nout = len(self.z) - len(znew) + + if nout > 0: + self.setGrid(znew) + self.x = array(xn,'d') + self.xnew = zeros(shape(xn),'d') + + # update the fixed temperature values if the energy + # equation is not being solved + + if self.energy == 0: + for j in range(self.npts): + zz, tt = self.initial['T'] + t = interp.interp(self.z[j],zz,tt) + self.holdTemperature(j,t) + else: + for j in range(self.npts): + self.holdTemperature(j,self.x[j,2]) + self.setEnergyEqn('on') + + if loglevel > 0: + print 'Prune: ', + print 'removed',nout,'points.' + print 'Grid size = ',len(self.z) + + return nout + + def save(self, filename, id, desc="", append=0): """Save a solution to a file. diff --git a/Cantera/python/Cantera/OneDim.py b/Cantera/python/Cantera/OneDim.py index 489ad7c97..4ac6b10e1 100755 --- a/Cantera/python/Cantera/OneDim.py +++ b/Cantera/python/Cantera/OneDim.py @@ -321,6 +321,28 @@ class OneDim: self._end.append(self._loc) return new_points + def prune(self, loglevel = 2): + """Prune the grid of every flow domain.""" + rem_points = 0 + for f in self._flow: + rem_points += f.prune(loglevel) + if rem_points > 0: + self.collect() + _cantera.onedim_resize(self.__onedim_id) + self._shape = [] + self._size = [] + self._start = [] + self._end = [] + self._loc = 0 + for d in self._domain: + np, nv = d.shape() + self._shape.append((np, nv)) + self._size.append(np*nv) + self._start.append(self._loc) + self._loc += np*nv + self._end.append(self._loc) + return rem_points + def setEnergyFactor(self, e): for f in self._flow: f.setEnergyFactor(e) diff --git a/Cantera/python/Cantera/boundaries1D.py b/Cantera/python/Cantera/boundaries1D.py index 3b82d78ff..c75335383 100755 --- a/Cantera/python/Cantera/boundaries1D.py +++ b/Cantera/python/Cantera/boundaries1D.py @@ -34,6 +34,9 @@ class Boundary1D: self.T = T self.x[0,1] = T _cantera.bndry_settemperature(self.__bndry_id, T) + if V <> -999.0: + self.V = V + _cantera.bndry_setspreadrate(self.__bndry_id, V) if X: self.X = X if type(X) == types.StringType: diff --git a/Cantera/python/Cantera/flame.py b/Cantera/python/Cantera/flame.py index 80c614db5..a0ef89413 100755 --- a/Cantera/python/Cantera/flame.py +++ b/Cantera/python/Cantera/flame.py @@ -17,6 +17,19 @@ class BurnerFlame: flame = BurnerFlame(gas, domain, fuel, oxidizer, inert, grid, pressure) + arguments: + + gas --- an object representing the gas mixture + domain --- [zmin, zmax] + fuel --- a string specifying the fuel stream composition + oxidizer --- a string specifying the oxidizer stream composition + inert --- a string specifying the composition of an inert + stream (optional) + grid --- a sequence defining the initial grid. The first point + should be zmin, and the last one zmax. If omitted, + a default grid will be used. + pressure --- the pressure, which is treated as constant. + example: flame = BurnerFlame(gas = GRI30(), domain = [0.0, 10.0*units.cm], @@ -31,6 +44,7 @@ class BurnerFlame: fuel = '', oxidizer = '', inert = '', grid = None, pressure = -1.0): + # check that all required inputs have been specified if not gas or not domain or not fuel or not oxidizer or not pressure: raise self.__doc__ @@ -38,18 +52,26 @@ class BurnerFlame: self.p = pressure dx = (domain[1] - domain[0]) + + # if no grid specified, use this one that concentrates points + # near the burner if grid == None: grid = dx * array([0.0, 0.01, 0.03, 0.1, 0.3, 0.6, 1.0]) - + self.__flow = Flow1D(flow_type = 'OneDim', gas = gas, grid = grid, pressure = self.p) + #------ these methods are deprecated, but still needed for now. self.inlet = Inlet(gas) self.outlet = Outlet(gas) self.__flow.setBoundaries(left = self.inlet, right = self.outlet) - + #---------------------------------------------------------------- + + # The container contains only the Flow1D object. Should be + # modified at some point to contain an Inlet1D and an Outlet1D + # object. self.__container = OneDim([self.__flow]) self.start = 0 @@ -57,7 +79,6 @@ class BurnerFlame: # get the compositions of the fuel and oxidizer streams, and # calculate the fuel/oxidizer ratio for stoichiometric # combustion - gas.setMoleFractions(fuel) self._xfuel = gas.moleFractions() @@ -73,18 +94,28 @@ class BurnerFlame: self._stoich_FO = stoich.stoich_fuel_to_oxidizer(gas, fuel, oxidizer) - + # TODO: accout for inert stream def setEquivRatio(self, phi): """Set the equivalence ratio.""" f_flow = self._stoich_FO * phi comp = f_flow * self._xfuel + self._xox self.gas.setState_PX(self.p, comp) self.inlet.set(X = self.gas.moleFractions()) + def setEquilProducts(self): - """Set the flame state to chemical equilibrium. + """Generate a starting estimate for the flame state. + + The following procedure is used: + + 1) At the burner, the composition is the specified inlet + composition; + 2) The last 80% of the domain has constant composition and + temperature corresponding to the adiabatic equilibrium + solution; + 3) In the initial 20%, the composition and temperature vary linearly + from the inlet values to the equilibrium values. - This is useful to generate a starting estimate. """ x0 = self.inlet.X self.gas.setState_TPX(self.inlet.T, self.p, x0) @@ -104,30 +135,84 @@ class BurnerFlame: xinit[nm] = x self.__flow.setInitialProfiles(xinit) + def plot(self, plotfile = '', title = '', fmt = 'TECPLOT', zone = 'c0', append = 0): + """Plot the current solution.""" self.__flow.plotter.plot(fname = plotfile, title = title, fmt = fmt, zone = zone, append=append) + def setInitialProfiles(self, **init): + """Specify estimates for the initial profiles. + + """ self.__flow.setInitialProfiles(init) self.start = 1 def restore(self, src = '', solution = ''): + """Start from a previously-saved solution.""" self.__container.restore(0, src, solution) self.start = 1 def setTolerances(self, V = None, T = None, Y = None): + """Set tolerances for convergence for velocity, temperature, + and mass fractions.""" self.__flow.setTolerances( V, V, T, Y) + def prune(self, loglevel = 2): + """Remove unneeded grid points. + + This method attempts to remove each grid point one by one, and + calls 'refine' each time to see whether it puts it back. If it does, + the point is not removed, otherwise it is. + """ + self.__container.prune(loglevel) + + def refine(self, loglevel = 2): + """Refine the grid using the current grid refinement parameters.""" + self.__container.refine(loglevel) + def show(self): + """Print a summary of the current solution to the screen.""" self.__flow.show() def stretch(self, factor): + """Stretch the grid by 'factor'""" self.__flow.setGrid(factor*self.__flow.z) def set(self, **opt): + """Set options. + The options that may be set are: + + energy --- 'on' or 'off'. If 'on', the energy equation is + solved; otherwise, the temperature is held to the specified + profile. + + pressure --- the pressure in Pa. + + mdot --- the inlet mass flow rate per unit area. + + equiv_ratio --- the equivalence ratio + + T_burner --- the burner surface temperature [K]. + + refine --- a triplet specifying the refinement criteria. + See refine.py for more information. + + tol --- error tolerances for u, V, T, and Y. + + max_jac_age --- the maximum number of times to use a Jacobian + before recomputing it. + + timesteps --- number and duration of time steps to take + when Newton iteration fails. The format is + ( number_sequence, initial_stepsize ) + + These parameters can be changed as the solution proceeds.""" + + # TODO: is this necessary? if self.__container == None: self.__container = OneDim([self.__flow,]) @@ -153,23 +238,38 @@ class BurnerFlame: elif o == 'timesteps': self.__container.setOptions(nsteps = v[0], timestep = v[1]) + def solve(self, loglevel = 0): + """ Solve the flame equations. + + If no starting estimate has been given, setEquilProducts() + is called to generate one. + + """ if not self.start: self.setEquilProducts() self.start = 1 solve(self.__container, loglevel = loglevel, refine_grid = 1) - def esolve(self, loglevel = 0, efactor = 1.0e4): - if not self.start: - self.setEquilProducts() - self.start = 1 - esolve(self.__container, efactor = efactor, loglevel = loglevel, refine_grid = 1) +## def esolve(self, loglevel = 0, efactor = 1.0e4): +## if not self.start: +## self.setEquilProducts() +## self.start = 1 +## esolve(self.__container, efactor = efactor, loglevel = loglevel, refine_grid = 1) + def save(self, soln, desc, file = 'flame.xml'): + """Save the current solution. + + soln --- string to identify this solution in the file. + desc --- descriptive text string. + file --- file name. + """ self.__container.save(file, soln, desc) def showStatistics(self): + """Show numerical statistics.""" self.__container.showStatistics() @@ -312,7 +412,13 @@ class StagnationFlame: def enableEnergy(self, pt): self.__flow.setEnergyEqn('on',loglevel=1,pt=pt) - + + def prune(self, loglevel = 2): + self.__container.prune(loglevel) + + def refine(self, loglevel = 2): + self.__container.refine(loglevel) + def set(self, **opt): if self.__container == None: @@ -331,6 +437,8 @@ class StagnationFlame: self.setEquivRatio(v) elif o == 'T_burner': self.__left.set(T = v) + elif o == 'spreadingRate': + self.__left.set(V = v) elif o == 'T_surface': self.__right.set(T = v) elif o == 'refine': diff --git a/Cantera/python/Cantera/refine.py b/Cantera/python/Cantera/refine.py index 39c265e7c..f0aad3b89 100755 --- a/Cantera/python/Cantera/refine.py +++ b/Cantera/python/Cantera/refine.py @@ -108,7 +108,7 @@ class Refiner: np = len(g) self.direction = 1 - gnew, snew = self.refine(g, sol, threshold) + gnew, gn, snew, ok = self.refine(g, sol, threshold) if (len(gnew) > np): g = g0 sol = s0 @@ -124,7 +124,7 @@ class Refiner: return (g, sol) - def refine(self, grid = None, solution = None, threshold = None): + def refine(self, grid = None, solution = None, threshold = None, prune = 1): self.ok = 0 # grid parameters diff --git a/Cantera/python/src/ctpybndry.cpp b/Cantera/python/src/ctpybndry.cpp index bde3d63a4..6197a7e10 100755 --- a/Cantera/python/src/ctpybndry.cpp +++ b/Cantera/python/src/ctpybndry.cpp @@ -68,6 +68,28 @@ py_bndry_settemperature(PyObject *self, PyObject *args) return Py_BuildValue("i",0); } +static PyObject* +py_bndry_spreadrate(PyObject *self, PyObject *args) +{ + int n; + if (!PyArg_ParseTuple(args, "i:bndry_spreadrate", &n)) + return NULL; + double v = bndry_spreadrate(n); + return Py_BuildValue("d",v); +} + +static PyObject* +py_bndry_setspreadrate(PyObject *self, PyObject *args) +{ + int n; + double v; + if (!PyArg_ParseTuple(args, "id:bndry_setspreadrate", &n, &v)) + return NULL; + int iok = bndry_setspreadrate(n, v); + if (iok < 0) return reportError(iok); + return Py_BuildValue("i",0); +} + static PyObject* py_bndry_mdot(PyObject *self, PyObject *args) { @@ -124,6 +146,8 @@ static PyMethodDef ct_methods[] = { {"bndry_setxin", py_bndry_setxin, METH_VARARGS}, {"bndry_setxinbyname", py_bndry_setxinbyname, METH_VARARGS}, {"bndry_settemperature", py_bndry_settemperature, METH_VARARGS}, + {"bndry_setspreadrate", py_bndry_setspreadrate, METH_VARARGS}, + {"bndry_spreadrate", py_bndry_spreadrate, METH_VARARGS}, {"bndry_new", py_bndry_new, METH_VARARGS}, {"bndry_del", py_bndry_del, METH_VARARGS}, {"bndry_mdot", py_bndry_mdot, METH_VARARGS}, diff --git a/Cantera/src/oneD/Inlet1D.h b/Cantera/src/oneD/Inlet1D.h index c588326a2..685d1a4ed 100644 --- a/Cantera/src/oneD/Inlet1D.h +++ b/Cantera/src/oneD/Inlet1D.h @@ -83,6 +83,11 @@ namespace Cantera { needJacUpdate(); } + /// spreading rate + virtual double spreadRate() { + return m_V0; + } + /// Temperature [K]. doublereal temperature() {return m_temp;} diff --git a/Makefile.in b/Makefile.in index a141df6b8..cd0274f3c 100755 --- a/Makefile.in +++ b/Makefile.in @@ -156,7 +156,8 @@ depends: export: @INSTALL@ -d $(export_dir) if (test -d $(ct)); then rm -r -f $(ct); fi - cd $(export_dir); cvs export -D 1/01/2010 cantera-export-$(version) + cd $(export_dir); cvs export -D 1/01/2010 cantera + cd $(export-dir); mv cantera $(ct) cd $(ct); rm -r -f Cantera/matlab/cantera/@Thermo pack: export diff --git a/configure b/configure index 289f8658e..31b69c763 100755 --- a/configure +++ b/configure @@ -150,7 +150,7 @@ LAPACK_FTN_STRING_LEN_AT_END='y' CXX=${CXX:=g++} # C++ compiler flags -CXXFLAGS=${CXXFLAGS:="-O0 -Wall"} +CXXFLAGS=${CXXFLAGS:="-O2 -Wall"} # the C++ flags required for linking #LCXX_FLAGS=