Allow importing phases from XML or CTI strings
This commit is contained in:
parent
a22a767be1
commit
907bbd8b79
10 changed files with 137 additions and 18 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) ;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue