Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ct2ctml.cpp
Go to the documentation of this file.
1 /**
2  * @file ct2ctml.cpp
3  * Driver for the system call to the python executable that converts
4  * cti files to ctml files (see \ref inputfiles).
5  */
6 // Copyright 2001-2005 California Institute of Technology
7 
8 #include "cantera/base/ctml.h"
10 #include "../../ext/libexecstream/exec-stream.h"
11 
12 #include <fstream>
13 #include <sstream>
14 #include <functional>
15 
16 #ifdef _WIN32
17 #include <windows.h>
18 #endif
19 
20 using namespace std;
21 
22 namespace Cantera
23 {
24 
25 //! return the full path to the Python interpreter.
26 /*!
27  * Use the environment variable PYTHON_CMD if it is set. If not, return
28  * the string 'python'.
29  *
30  * Note, there are hidden problems here that really direct us to use
31  * a full pathname for the location of python. Basically the system
32  * call will use the shell /bin/sh, in order to launch python.
33  * This default shell may not be the shell that the user is employing.
34  * Therefore, the default path to python may be different during
35  * a system call than during the default user shell environment.
36  * This is quite a headache. The answer is to always set the
37  * PYTHON_CMD environmental variable in the user environment to
38  * an absolute path to locate the python executable. Then this
39  * issue goes away.
40  */
41 static string pypath()
42 {
43  string s = "python";
44  const char* py = getenv("PYTHON_CMD");
45 
46  if (py) {
47  string sp = stripws(string(py));
48  if (sp.size() > 0) {
49  s = sp;
50  }
51  }
52  return s;
53 }
54 
55 void ct2ctml(const char* file, const int debug)
56 {
57  string xml = ct2ctml_string(file);
58  string out_name = file;
59 #ifdef _WIN32
60  // For Windows, make the path POSIX compliant so code looking for directory
61  // separators is simpler. Just look for '/' not both '/' and '\\'
62  std::replace_if(out_name.begin(), out_name.end(),
63  std::bind2nd(std::equal_to<char>(), '\\'), '/') ;
64 #endif
65  size_t idir = out_name.rfind('/');
66  if (idir != npos) {
67  out_name = out_name.substr(idir+1, out_name.size());
68  }
69  size_t idot = out_name.rfind('.');
70  if (idot != npos) {
71  out_name = out_name.substr(0, idot) + ".xml";
72  } else {
73  out_name += ".xml";
74  }
75  std::ofstream out(out_name.c_str());
76  out << xml;
77 }
78 
79 static std::string call_ctml_writer(const std::string& text, bool isfile)
80 {
81  std::string file, arg;
82  if (isfile) {
83  file = text;
84  arg = "r'" + text + "'";
85  } else {
86  file = "<string>";
87  arg = "text=r'''" + text + "'''";
88  }
89 
90 #ifdef HAS_NO_PYTHON
91  /*
92  * Section to bomb out if python is not
93  * present in the computation environment.
94  */
95  throw CanteraError("ct2ctml",
96  "python cti to ctml conversion requested for file, " + file +
97  ", but not available in this computational environment");
98 #endif
99 
100  string python_output, error_output;
101  int python_exit_code;
102  try {
103  exec_stream_t python;
104  python.set_wait_timeout(exec_stream_t::s_all, 1800000); // 30 minutes
105  stringstream output_stream, error_stream;
106  std::vector<string> args;
107  args.push_back("-c");
108 
109  args.push_back(
110  "from __future__ import print_function\n"
111  "import sys\n"
112  "try:\n"
113  " from cantera import ctml_writer\n"
114  "except ImportError:\n"
115  " print('sys.path: ' + repr(sys.path) + '\\n', file=sys.stderr)\n"
116  " raise\n"
117  "ctml_writer.convert(" + arg + ", outName='STDOUT')\n"
118  "sys.exit(0)\n");
119 
120  python.start(pypath(), args.begin(), args.end());
121  std::string line;
122 
123  while (python.out().good()) {
124  std::getline(python.out(), line);
125  output_stream << line << std::endl;
126  }
127 
128 #ifdef _WIN32
129  // Sleeping for 1 ms prevents a (somewhat inexplicable) deadlock while
130  // reading from the stream.
131  Sleep(1);
132 #endif
133  while (python.err().good()) {
134  std::getline(python.err(), line);
135  error_stream << line << std::endl;
136  }
137  python.close();
138  python_exit_code = python.exit_code();
139  error_output = stripws(error_stream.str());
140  python_output = output_stream.str();
141  } catch (std::exception& err) {
142  // Report failure to execute Python
143  stringstream message;
144  message << "Error executing python while converting input file:\n";
145  message << "Python command was: '" << pypath() << "'\n";
146  message << err.what() << std::endl;
147  throw CanteraError("ct2ctml_string", message.str());
148  }
149 
150  if (python_exit_code != 0) {
151  // Report a failure in the conversion process
152  stringstream message;
153  message << "Error converting input file \"" << file << "\" to CTML.\n";
154  message << "Python command was: '" << pypath() << "'\n";
155  message << "The exit code was: " << python_exit_code << "\n";
156  if (error_output.size() > 0) {
157  message << "-------------- start of converter log --------------\n";
158  message << error_output << std::endl;
159  message << "--------------- end of converter log ---------------";
160  } else {
161  message << "The command did not produce any output." << endl;
162  }
163  throw CanteraError("ct2ctml_string", message.str());
164  }
165 
166  if (error_output.size() > 0) {
167  // Warn if there was any output from the conversion process
168  stringstream message;
169  message << "Warning: Unexpected output from CTI converter\n";
170  message << "-------------- start of converter log --------------\n";
171  message << error_output << std::endl;
172  message << "--------------- end of converter log ---------------\n";
173  writelog(message.str());
174  }
175  return python_output;
176 }
177 
178 std::string ct2ctml_string(const std::string& file)
179 {
180  return call_ctml_writer(file, true);
181 }
182 
183 std::string ct_string2ctml_string(const std::string& cti)
184 {
185  return call_ctml_writer(cti, false);
186 }
187 
188 void ck2cti(const std::string& in_file, const std::string& thermo_file,
189  const std::string& transport_file, const std::string& id_tag)
190 {
191 #ifdef HAS_NO_PYTHON
192  /*
193  * Section to bomb out if python is not
194  * present in the computation environment.
195  */
196  string ppath = in_file;
197  throw CanteraError("ct2ctml",
198  "python ck to cti conversion requested for file, " + ppath +
199  ", but not available in this computational environment");
200 #endif
201 
202  string python_output;
203  int python_exit_code;
204  try {
205  exec_stream_t python;
206  python.set_wait_timeout(exec_stream_t::s_all, 1800000); // 30 minutes
207  python.start(pypath(), "-i");
208  stringstream output_stream;
209 
210  ostream& pyin = python.in();
211  pyin << "if True:\n" << // Use this so that the rest is a single block
212  " import sys\n" <<
213  " sys.stderr = sys.stdout\n" <<
214  " try:\n" <<
215  " from cantera import ck2cti\n" <<
216  " except ImportError:\n" <<
217  " print('sys.path: ' + repr(sys.path))\n" <<
218  " raise\n"
219  " ck2cti.Parser().convertMech(r'" << in_file << "',";
220  if (thermo_file != "" && thermo_file != "-") {
221  pyin << " thermoFile=r'" << thermo_file << "',";
222  }
223  if (transport_file != "" && transport_file != "-") {
224  pyin << " transportFile=r'" << transport_file << "',";
225  }
226  pyin << " phaseName='" << id_tag << "',";
227  pyin << " permissive=True,";
228  pyin << " quiet=True)\n";
229  pyin << " sys.exit(0)\n\n";
230  pyin << "sys.exit(7)\n";
231  python.close_in();
232 
233  std::string line;
234  while (python.out().good()) {
235  std::getline(python.out(), line);
236  output_stream << line << std::endl;;
237  }
238  python.close();
239  python_exit_code = python.exit_code();
240  python_output = stripws(output_stream.str());
241  } catch (std::exception& err) {
242  // Report failure to execute Python
243  stringstream message;
244  message << "Error executing python while converting input file:\n";
245  message << "Python command was: '" << pypath() << "'\n";
246  message << err.what() << std::endl;
247  throw CanteraError("ct2ctml", message.str());
248  }
249 
250  if (python_exit_code != 0) {
251  // Report a failure in the conversion process
252  stringstream message;
253  message << "Error converting input file \"" << in_file << "\" to CTI.\n";
254  message << "Python command was: '" << pypath() << "'\n";
255  message << "The exit code was: " << python_exit_code << "\n";
256  if (python_output.size() > 0) {
257  message << "-------------- start of converter log --------------\n";
258  message << python_output << std::endl;
259  message << "--------------- end of converter log ---------------";
260  } else {
261  message << "The command did not produce any output." << endl;
262  }
263  throw CanteraError("ck2cti", message.str());
264  }
265 
266  if (python_output.size() > 0) {
267  // Warn if there was any output from the conversion process
268  stringstream message;
269  message << "Warning: Unexpected output from CTI converter\n";
270  message << "-------------- start of converter log --------------\n";
271  message << python_output << std::endl;
272  message << "--------------- end of converter log ---------------\n";
273  writelog(message.str());
274  }
275 }
276 
277 void get_CTML_Tree(XML_Node* rootPtr, const std::string& file, const int debug)
278 {
279  warn_deprecated("get_CTML_Tree", "To be removed after Cantera 2.2. "
280  "Use get_XML_File instead.");
281  XML_Node* src = get_XML_File(file);
282  src->copy(rootPtr);
283 }
284 
285 XML_Node getCtmlTree(const std::string& file)
286 {
287  warn_deprecated("getCtmlTree", "To be removed after Cantera 2.2. "
288  "Use get_XML_File instead.");
289  XML_Node root;
290  XML_Node* src = get_XML_File(file);
291  src->copy(&root);
292  return root;
293 }
294 
295 }
std::string ct2ctml_string(const std::string &file)
Get a string with the ctml representation of a cti file.
Definition: ct2ctml.cpp:178
XML_Node * get_XML_File(const std::string &file, int debug)
Return a pointer to the XML tree for a Cantera input file.
Definition: global.cpp:105
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:78
void ct2ctml(const char *file, const int debug)
Convert a cti file into a ctml file.
Definition: ct2ctml.cpp:55
XML_Node getCtmlTree(const std::string &file)
Read an ctml file from a file and fill up an XML tree.
Definition: ct2ctml.cpp:285
std::string stripws(const std::string &s)
Strip the leading and trailing white space from a string.
void ck2cti(const std::string &in_file, const std::string &thermo_file, const std::string &transport_file, const std::string &id_tag)
Convert a Chemkin-format mechanism into a CTI file.
Definition: ct2ctml.cpp:188
void get_CTML_Tree(XML_Node *rootPtr, const std::string &file, const int debug)
Read an ctml file from a file and fill up an XML tree.
Definition: ct2ctml.cpp:277
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
std::string ct_string2ctml_string(const std::string &cti)
Get a string with the ctml representation of a cti input string.
Definition: ct2ctml.cpp:183
void copy(XML_Node *const node_dest) const
Copy all of the information in the current XML_Node tree into the destination XML_Node tree...
Definition: xml.cpp:874
static string pypath()
return the full path to the Python interpreter.
Definition: ct2ctml.cpp:41
Contains declarations for string manipulation functions within Cantera.
void writelog(const std::string &msg)
Write a message to the screen.
Definition: global.cpp:33