Allow importing phases from XML or CTI strings

This commit is contained in:
Ray Speth 2014-07-30 16:59:51 +00:00
parent a22a767be1
commit 907bbd8b79
10 changed files with 137 additions and 18 deletions

View file

@ -785,6 +785,15 @@ void ct2ctml(const char* file, const int debug = 0);
*/
std::string ct2ctml_string(const std::string& file);
//! Get a string with the ctml representation of a cti input string.
/*!
* @param cti String containing the cti representation
* @return String containing the xml representation of the input
*
* @ingroup inputfiles
*/
std::string ct_string2ctml_string(const std::string& cti);
//! Convert a Chemkin-format mechanism into a CTI file.
/*!
* @param in_file input file containing species and reactions

View file

@ -203,6 +203,9 @@ doublereal actEnergyToSI(const std::string& unit);
//! @copydoc Application::get_XML_File
XML_Node* get_XML_File(const std::string& file, int debug = 0);
//! @copydoc Application::get_XML_from_string
XML_Node* get_XML_from_string(const std::string& text);
//! @copydoc Application::close_XML_File
void close_XML_File(const std::string& file);

View file

@ -18,6 +18,7 @@ cdef extern from "cantera/base/global.h" namespace "Cantera":
cdef size_t CxxNpos "Cantera::npos"
cdef void CxxAppdelete "Cantera::appdelete" ()
cdef XML_Node* CxxGetXmlFile "Cantera::get_XML_File" (string) except +
cdef XML_Node* CxxGetXmlFromString "Cantera::get_XML_from_string" (string) except +
cdef extern from "cantera/thermo/mix_defs.h":
cdef int thermo_type_ideal_gas "Cantera::cIdealGas"

View file

@ -1,9 +1,10 @@
cdef class _SolutionBase:
def __cinit__(self, infile='', phaseid='', phases=(), source=None):
def __cinit__(self, infile='', phaseid='', phases=(), origin=None,
source=None):
# Shallow copy of an existing Solution (for slicing support)
cdef _SolutionBase other
if source is not None:
other = <_SolutionBase?>source
if origin is not None:
other = <_SolutionBase?>origin
# keep a reference to the parent to prevent the underlying
# C++ objects from being deleted
@ -18,7 +19,12 @@ cdef class _SolutionBase:
return
# Instantiate a set of new Cantera C++ objects
rootNode = CxxGetXmlFile(stringify(infile))
if infile:
rootNode = CxxGetXmlFile(stringify(infile))
elif source:
rootNode = CxxGetXmlFromString(stringify(source))
else:
raise ValueError('No phase definition provided')
# Get XML data
cdef XML_Node* phaseNode
@ -58,7 +64,7 @@ cdef class _SolutionBase:
assert self.transport is not NULL
def __getitem__(self, selection):
copy = self.__class__(source=self)
copy = self.__class__(origin=self)
if isinstance(selection, slice):
selection = range(selection.start or 0,
selection.stop or self.n_species,

View file

@ -2617,21 +2617,30 @@ class Lindemann(object):
#get_atomic_wts()
validate()
def convert(filename, outName=None):
def convert(filename=None, outName=None, text=None):
import os
filename = os.path.expanduser(filename)
base = os.path.basename(filename)
root, _ = os.path.splitext(base)
dataset(root)
if filename is not None:
filename = os.path.expanduser(filename)
base = os.path.basename(filename)
root, _ = os.path.splitext(base)
dataset(root)
elif outName is None:
outName = 'STDOUT'
try:
with open(filename, 'rU') as f:
code = compile(f.read(), filename, 'exec')
exec(code)
if filename is not None:
with open(filename, 'rU') as f:
code = compile(f.read(), filename, 'exec')
else:
code = compile(text, '<string>', 'exec')
exec(code)
except SyntaxError as err:
# Show more context than the default SyntaxError message
# to help see problems in multi-line statements
text = open(filename, 'rU').readlines()
if filename:
text = open(filename, 'rU').readlines()
else:
text = text.split('\n')
_printerr('%s in "%s" on line %i:\n' % (err.__class__.__name__,
err.filename,
err.lineno))
@ -2646,7 +2655,11 @@ def convert(filename, outName=None):
except Exception as err:
import traceback
text = open(filename, 'rU').readlines()
if filename:
text = open(filename, 'rU').readlines()
else:
text = text.split('\n')
filename = '<string>'
tb = traceback.extract_tb(sys.exc_info()[2])
lineno = tb[-1][1]
if tb[-1][0] == filename:

View file

@ -544,6 +544,39 @@ class ImportTest(utilities.CanteraTest):
gas2 = ct.Solution('../data/air-no-reactions.xml', 'notair')
self.check(gas2, 'notair', 900, 5*101325, 7, 2)
def test_import_phase_cti_text(self):
cti_def = """
ideal_gas(name='spam', elements='O H',
species='gri30: all',
options='skip_undeclared_elements',
initial_state=state(temperature=350, pressure=2e6))
"""
gas = ct.Solution(source=cti_def)
self.check(gas, 'spam', 350, 2e6, 8, 2)
def test_import_phase_xml_text(self):
xml_def = """
<?xml version="1.0"?>
<ctml>
<validate reactions="yes" species="yes"/>
<phase dim="3" id="spam">
<elementArray datasrc="elements.xml">O</elementArray>
<speciesArray datasrc="gri30.xml#species_data">all
<skip element="undeclared"/>
</speciesArray>
<state>
<temperature units="K">350.0</temperature>
<pressure units="Pa">2000000.0</pressure>
</state>
<thermo model="IdealGas"/>
<kinetics model="GasKinetics"/>
<transport model="None"/>
</phase>
</ctml>"""
gas = ct.Solution(source=xml_def)
self.check(gas, 'spam', 350, 2e6, 2, 1)
def test_checkReactionBalance(self):
with self.assertRaises(Exception):
ct.Solution('../data/h2o2_unbalancedReaction.xml')

View file

@ -285,6 +285,26 @@ XML_Node* Application::get_XML_File(const std::string& file, int debug)
return x;
}
XML_Node* Application::get_XML_from_string(const std::string& text)
{
ScopedLock xmlLock(xml_mutex);
std::pair<XML_Node*, int>& entry = xmlfiles[text];
if (entry.first) {
// Return existing cached XML tree
return entry.first;
}
std::stringstream s;
size_t start = text.find_first_not_of(" \t\r\n");
if (text.substr(start,5) == "<?xml") {
s << text;
} else {
s << ctml::ct_string2ctml_string(text);
}
entry.first = new XML_Node();
entry.first->build(s);
return entry.first;
}
void Application::close_XML_File(const std::string& file)
{
ScopedLock xmlLock(xml_mutex);

View file

@ -300,6 +300,17 @@ public:
*/
XML_Node* get_XML_File(const std::string& file, int debug=0) ;
//! Read a CTI or CTML string and fill up an XML tree.
/*!
* Return a pointer to the XML tree corresponding to the specified
* CTI or XML string. If the given string has been processed before,
* the cached XML tree will be returned. Otherwise, the XML tree
* will be generated and stored in the cache.
* @param text CTI or CTML string
* @return Root of the corresponding XML tree
*/
XML_Node* get_XML_from_string(const std::string& text);
//! Close an XML File
/*!
* Close a file that is opened by this application object

View file

@ -80,8 +80,17 @@ void ct2ctml(const char* file, const int debug)
out << xml;
}
std::string ct2ctml_string(const std::string& file)
static std::string call_ctml_writer(const std::string& text, bool isfile)
{
std::string file, arg;
if (isfile) {
file = text;
arg = "r'" + text + "'";
} else {
file = "<string>";
arg = "text=r'''" + text + "'''";
}
#ifdef HAS_NO_PYTHON
/*
* Section to bomb out if python is not
@ -109,7 +118,7 @@ std::string ct2ctml_string(const std::string& file)
"except ImportError:\n"
" print('sys.path: ' + repr(sys.path) + '\\n', file=sys.stderr)\n"
" raise\n"
"ctml_writer.convert(r'" + file + "', 'STDOUT')\n"
"ctml_writer.convert(" + arg + ", outName='STDOUT')\n"
"sys.exit(0)\n");
python.start(pypath(), args.begin(), args.end());
@ -170,6 +179,15 @@ std::string ct2ctml_string(const std::string& file)
return python_output;
}
std::string ct2ctml_string(const std::string& file)
{
return call_ctml_writer(file, true);
}
std::string ct_string2ctml_string(const std::string& cti)
{
return call_ctml_writer(cti, false);
}
void ck2cti(const std::string& in_file, const std::string& thermo_file,
const std::string& transport_file, const std::string& id_tag)

View file

@ -118,6 +118,11 @@ XML_Node* get_XML_File(const std::string& file, int debug)
return xtmp;
}
XML_Node* get_XML_from_string(const std::string& text)
{
return app()->get_XML_from_string(text);
}
void close_XML_File(const std::string& file)
{
app()->close_XML_File(file) ;