diff --git a/Cantera/clib/src/ct.cpp b/Cantera/clib/src/ct.cpp index 0ccdc083e..ec1617df6 100755 --- a/Cantera/clib/src/ct.cpp +++ b/Cantera/clib/src/ct.cpp @@ -504,7 +504,10 @@ extern "C" { } } Kinetics* kin = newKineticsMgr(*x, phases); - return Storage::storage()->addKinetics(kin); + if (kin) + return Storage::storage()->addKinetics(kin); + else + return 0; } catch (CanteraError) { return -1; } } diff --git a/Cantera/clib/src/ctxml.cpp b/Cantera/clib/src/ctxml.cpp index cf9a896b6..c144ed01b 100644 --- a/Cantera/clib/src/ctxml.cpp +++ b/Cantera/clib/src/ctxml.cpp @@ -1,6 +1,7 @@ // Cantera includes #include "ctml.h" +#include "importCTML.h" #include "Cabinet.h" #include "Storage.h" @@ -28,8 +29,10 @@ extern "C" { int DLL_EXPORT xml_new(const char* name = 0) { XML_Node* x; - if (!name) x = new XML_Node; - else x = new XML_Node(string(name)); + if (!name) + x = new XML_Node; + else + x = new XML_Node(string(name)); return Cabinet::cabinet()->add(x); } @@ -66,6 +69,14 @@ extern "C" { catch (CanteraError) { return -1; } } + int DLL_EXPORT xml_preprocess_and_build(int i, const char* file) { + try { + get_CTML_Tree(_xml(i), string(file)); + return 0; + } + catch (CanteraError) { return -1; } + } + int DLL_EXPORT xml_attrib(int i, const char* key, char* value) { try { string ky = string(key); diff --git a/Cantera/clib/src/ctxml.h b/Cantera/clib/src/ctxml.h index a6aaf2f97..3abe553db 100644 --- a/Cantera/clib/src/ctxml.h +++ b/Cantera/clib/src/ctxml.h @@ -10,6 +10,7 @@ extern "C" { int DLL_IMPORT xml_copy(int i); int DLL_IMPORT xml_assign(int i, int j); int DLL_IMPORT xml_build(int i, const char* file); + int DLL_IMPORT xml_preprocess_and_build(int i, const char* file); int DLL_IMPORT xml_attrib(int i, const char* key, char* value); int DLL_IMPORT xml_addAttrib(int i, const char* key, const char* value); int DLL_IMPORT xml_addComment(int i, const char* comment); diff --git a/Cantera/matlab/cantera/@Solution/Solution.m b/Cantera/matlab/cantera/@Solution/Solution.m index 95feb8885..da74776ec 100755 --- a/Cantera/matlab/cantera/@Solution/Solution.m +++ b/Cantera/matlab/cantera/@Solution/Solution.m @@ -41,7 +41,8 @@ if isa(x,'Solution') elseif isa(x,'XML_Node') xp = x; else - doc = XML_Node('doc', x); + doc = XML_Node('doc'); + build(doc, x, 1); xp = child(doc,'ctml/phase'); end t = ThermoPhase(xp); diff --git a/Cantera/matlab/cantera/@XML_Node/build.m b/Cantera/matlab/cantera/@XML_Node/build.m index a7c46d51f..3f8746ae5 100644 --- a/Cantera/matlab/cantera/@XML_Node/build.m +++ b/Cantera/matlab/cantera/@XML_Node/build.m @@ -1,9 +1,13 @@ -function x = build(x, file) +function x = build(x, file, pre) -if nargin ~= 2 | ~isa(file,'char') +if nargin < 2 | ~isa(file,'char') error('Syntax error. Type "help build" for more information.') end -iok = ctmethods(10, 4, x.id, file); +if nargin == 2 + iok = ctmethods(10, 4, x.id, file); +else + iok = ctmethods(10, 15, x.id, file); +end diff --git a/Cantera/matlab/cantera/private/xmlmethods.cpp b/Cantera/matlab/cantera/private/xmlmethods.cpp index a4c1b46ca..0b90542a0 100644 --- a/Cantera/matlab/cantera/private/xmlmethods.cpp +++ b/Cantera/matlab/cantera/private/xmlmethods.cpp @@ -103,7 +103,10 @@ void xmlmethods( int nlhs, mxArray *plhs[], j = getInt(prhs[3]); iok = xml_removeChild(i, j); break; - + case 15: + file = getString(prhs[3]); + iok = xml_preprocess_and_build(i, file); + break; default: mexErrMsgTxt("unknown job parameter"); } diff --git a/Cantera/python/Cantera/Interface.py b/Cantera/python/Cantera/Interface.py index 295c4e6a5..795f96ce8 100644 --- a/Cantera/python/Cantera/Interface.py +++ b/Cantera/python/Cantera/Interface.py @@ -20,18 +20,25 @@ class Interface(SurfacePhase, Kinetics): self._owner = 0 self.verbose = 1 - fn = string.split(src,'#') - fn = fn[0] + fn = src.split('#') id = "" - if len(fn) > 1: id = fn[1] + if len(fn) > 1: + id = fn[1] + fn = fn[0] fname = os.path.basename(fn) ff = os.path.splitext(fname) # get the 'phase' element + + if src and not root: + root = XML.XML_Node(name = 'doc', src = fn, preprocess = 1) + if id: - s = XML.find_XML(src=src, root=root, id=id) + s = root.child(id = id) + #s = XML.find_XML(src=src, root=root, id=id) else: - s = XML.find_XML(src=src, root=root, name="phase") + s = root.child(name = "phase") + #s = XML.find_XML(src=src, root=root, name="phase") # get the equation of state model SurfacePhase.__init__(self, xml_phase=s) diff --git a/Cantera/python/Cantera/XML.py b/Cantera/python/Cantera/XML.py index 20b9772c7..c55fe8928 100644 --- a/Cantera/python/Cantera/XML.py +++ b/Cantera/python/Cantera/XML.py @@ -10,7 +10,7 @@ import exceptions class XML_Node: """A node in an XML tree.""" - def __init__(self, name="--", src="", wrap=0, root=None): + def __init__(self, name="--", src="", wrap=0, root=None, preprocess=0): """ Return an instance representing a node in an XML tree. If 'src' is specified, then the XML tree found in file 'src' is @@ -25,7 +25,7 @@ class XML_Node: else: self._xml_id = _cantera.xml_new(name) if src: - _cantera.xml_build(self._xml_id, src) + _cantera.xml_build(self._xml_id, src, preprocess) self._root = self def __del__(self): diff --git a/Cantera/python/Cantera/ctml_writer.py b/Cantera/python/Cantera/ctml_writer.py index 073795120..8a80ddac3 100644 --- a/Cantera/python/Cantera/ctml_writer.py +++ b/Cantera/python/Cantera/ctml_writer.py @@ -187,7 +187,7 @@ class species(writer): def __init__(self, name = 'missing name!', - atoms = 'missing atoms!', + atoms = '', comment = '', thermo = None, transport = None, @@ -293,7 +293,7 @@ class const_cp(thermo): """Constant specific heat.""" def __init__(self, tmax = -1.0, tmin = -1.0, - t0 = 0.0, cp0 = 0.0, h0 = 0.0, s0 = 0.0): + t0 = 298.15, cp0 = 0.0, h0 = 0.0, s0 = 0.0): self._t = [tmin, tmax] self._c = [t0, h0, s0, cp0] @@ -364,22 +364,14 @@ class sticking_prob(writer): self._sp = species def build(self, p): - ig = ideal_gas() - for ph in _phases: - if ph.has_species(self._sp): - if ph._eos.__class__ == ig.__class__: - pass - else: - raise ('sticking probabilities only implemented for ' - +'species in ideal gas mixtures') - a = p.addChild('Stick') + a['species'] = self._sp addFloat(a,'A',self._c[0],fmt = '%14.6E') a.addChild('n',`self._c[1]`) - if type(self._c[2]) == types.FloatType: - addFloat(a,'E',(self._c[2],_ue)) + if isnum(self._c[2]): + addFloat(a,'E',(self._c[2],_ue), fmt = '%f') else: - addFloat(a,'E',self._c[2]) + addFloat(a,'E',self._c[2], fmt = '%f') class reaction(writer): @@ -404,6 +396,7 @@ class reaction(writer): self._r = getReactionSpecies(r) self._p = getReactionSpecies(p) self._kf = kf + self._igspecies = [] self._type = '' _reactions.append(self) @@ -420,7 +413,7 @@ class reaction(writer): nstr = '0'+`self._num` else: nstr = `self._num` - id = 'reaction_'+nstr + id = nstr p.addComment(" reaction "+id+" ") r = p.addChild('reaction') r['id'] = id @@ -447,6 +440,8 @@ class reaction(writer): for ph in _phases: if ph.has_species(s): nm, nl = ph.conc_dim() + if ph.is_ideal_gas(): + self._igspecies.append(s) break if nm < 0: print self._r @@ -477,6 +472,8 @@ class reaction(writer): kfnode = r.addChild('rateCoeff') if self._type == '': self._kf = [self._kf] + elif self._type == 'surface': + self._kf = [self._kf] elif self._type == 'threeBody': self._kf = [self._kf] mdim += 1 @@ -602,6 +599,15 @@ class falloff_reaction(reaction): self._falloff.build(kfnode) +class surface_reaction(reaction): + + def __init__(self, + equation = '', + kf = None, + id = ''): + reaction.__init__(self, equation, kf, id) + self._type = 'surface' + #-------------- @@ -609,15 +615,15 @@ class state: def __init__(self, temperature = None, pressure = None, - moleFractions = None, - massFractions = None, + mole_fractions = None, + mass_fractions = None, density = None, coverages = None): self._t = temperature self._p = pressure self._rho = density - self._x = moleFractions - self._y = massFractions + self._x = mole_fractions + self._y = mass_fractions self._c = coverages def build(self, ph): @@ -627,7 +633,7 @@ class state: if self._rho: addFloat(st, 'density', self._rho) if self._x: st.addChild('moleFractions', self._x) if self._y: st.addChild('massFractions', self._y) - if self._c: st.addChild('moleFractions', self._c) + if self._c: st.addChild('coverages', self._c) class phase(writer): @@ -696,7 +702,9 @@ class phase(writer): global _phases _phases.append(self) - + def is_ideal_gas(self): + return 0 + def is_pure(self): return 0 @@ -777,7 +785,7 @@ class ideal_gas(phase): species = '', reactions = 'none', kinetics = 'GasKinetics', - transport = 'Mix', + transport = 'None', initial_state = None): phase.__init__(self, name, 3, elements, species, reactions, @@ -795,10 +803,78 @@ class ideal_gas(phase): k['model'] = self._kin t = ph.addChild('transport') t['model'] = self._tr + + def is_ideal_gas(self): + return 1 + +class pure_solid(phase): + """A pure solid.""" + def __init__(self, + name = '', + elements = '', + species = '', + density = -1.0, + transport = 'None', + initial_state = None): + phase.__init__(self, name, 3, elements, species, 'none', + initial_state) + self._dens = density + self._pure = 1 + if self._dens < 0.0: + raise 'density must be specified.' + self._pure = 0 + self._tr = transport + + + def build(self, p): + ph = phase.build(self, p) + e = ph.addChild("thermo") + e['model'] = 'SolidCompound' + addFloat(e, 'density', self._dens) + if self._tr: + t = ph.addChild('transport') + t['model'] = self._tr - +class ideal_interface(phase): + """An ideal interface.""" + def __init__(self, + name = '', + elements = '', + species = '', + reactions = 'none', + site_density = 0.0, + phases = [], + kinetics = 'Interface', + transport = 'None', + initial_state = None): + + self._type = 'surface' + phase.__init__(self, name, 2, elements, species, reactions, + initial_state) + self._pure = 0 + self._kin = kinetics + self._tr = transport + self._phases = phases + self._sitedens = site_density + + def build(self, p): + ph = phase.build(self, p) + e = ph.addChild("thermo") + e['model'] = 'Surface' + addFloat(e, 'site_density',self._sitedens) + k = ph.addChild("kinetics") + k['model'] = self._kin + t = ph.addChild('transport') + t['model'] = self._tr + p = ph.addChild('phaseArray',self._phases) + + + def conc_dim(self): + return (1, -2) + + #------------------ equations of state -------------------------- class eos(writer): diff --git a/Cantera/python/Cantera/importFromFile.py b/Cantera/python/Cantera/importFromFile.py index 84f14cf8f..8c7e05c89 100755 --- a/Cantera/python/Cantera/importFromFile.py +++ b/Cantera/python/Cantera/importFromFile.py @@ -1,9 +1,45 @@ import solution +import Interface +import XML + +def preprocess(f): + fn = f.split('.') + prepr = 1 + base = f + if len(fn) == 2: + base = fn[0] + if fn[1] == '.xml' or fn[1] == '.ctml': + prepr = 0 + if prepr: + from Cantera import pip + pip.process(f) + src = base+'.xml' + else: + src = f + return src def importPhase(file = '', name = ''): + return importPhases(file, [name])[0] + +def importPhases(file = '', names = []): + """Import multiple phase definitions. + By importing all required phases in one file with one function call, + the preprocessor and CTML parser only need to run once. + """ + s = [] + root = XML.XML_Node(name = 'doc', src = file, preprocess = 1) + for nm in names: + src = '#'+nm + s.append(solution.Solution(src, root = root)) + return s + +def importInterface(file = '', name = '', phases = []): + #file = preprocess(file) + root = XML.XML_Node(name = 'doc', src = file, preprocess = 1) if name: src = file+'#'+name else: src = file - return solution.Solution(src) - + print phases + return Interface.Interface(src = src, root = root, phases = phases) + diff --git a/Cantera/python/Cantera/pip.py b/Cantera/python/Cantera/pip.py index 7628ed37f..9146a7c56 100644 --- a/Cantera/python/Cantera/pip.py +++ b/Cantera/python/Cantera/pip.py @@ -22,8 +22,10 @@ write() fo.write(txt) fo.close() cmd = sys.executable+' '+fname+' '+name+' '+base - os.system(cmd) + err = os.system(cmd) os.remove(fname) + if err: + sys.exit(-1) diff --git a/Cantera/python/Cantera/solution.py b/Cantera/python/Cantera/solution.py index 365e0e5c9..13c6a382b 100755 --- a/Cantera/python/Cantera/solution.py +++ b/Cantera/python/Cantera/solution.py @@ -37,26 +37,20 @@ class Solution(ThermoPhase, Kinetics, Transport): self.verbose = 1 fn = src.split('#') id = "" - if len(fn) > 1: id = fn[1] - fn = fn[0] + if len(fn) > 1: + id = fn[1] + fn = fn[0] fname = os.path.basename(fn) ff = os.path.splitext(fname) - if ff[1] <> '.xml' and ff[1] <> '.ctml': - #if ff[1] == '.py' or ff[1] == '.in': - from Cantera import pip - pip.process(fname) - #else: - # ctmodule.ck2ctml(src, thermo_db, transport_db, ff[0]+'.xml', - # ff[0]) - src = ff[0]+'.xml' - - # get the 'phase' element + if src and not root: + root = XML.XML_Node(name = 'doc', src = fn, preprocess = 1) + if id: - s = XML.find_XML(src=src, root=root, id=id) + s = root.child(id = id) else: - s = XML.find_XML(src=src, root=root, name="phase") + s = root.child(name = "phase") # get the equation of state model ThermoPhase.__init__(self, xml_phase=s) @@ -68,8 +62,6 @@ class Solution(ThermoPhase, Kinetics, Transport): Transport.__init__(self, xml_phase=s, phase=self, model = transport, loglevel=4) - #self.setState_TP(300.0, OneAtm) - def __repr__(self): return _cantera.phase_report(self._phase_id, self.verbose) diff --git a/Cantera/python/src/ctxml_methods.cpp b/Cantera/python/src/ctxml_methods.cpp index cfd2c2cec..8d8d1ae4b 100644 --- a/Cantera/python/src/ctxml_methods.cpp +++ b/Cantera/python/src/ctxml_methods.cpp @@ -23,11 +23,15 @@ py_xml_del(PyObject *self, PyObject *args) static PyObject* py_xml_build(PyObject *self, PyObject *args) { - int n; + int n, pre; char* file; - if (!PyArg_ParseTuple(args, "is:xml_build", &n, &file)) + if (!PyArg_ParseTuple(args, "isi:xml_build", &n, &file, &pre)) return NULL; - int iok = xml_build(n, file); + int iok; + if (pre > 0) + iok = xml_preprocess_and_build(n, file); + else + iok = xml_build(n, file); if (iok < 0) return reportError(iok); return Py_BuildValue("i",0); }