Cantera  2.1.2
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/ct_defs.h"
10 #include "cantera/base/ctml.h"
11 #include "cantera/base/global.h"
13 #include "../../ext/libexecstream/exec-stream.h"
14 
15 #include <fstream>
16 #include <sstream>
17 #include <functional>
18 
19 using namespace Cantera;
20 using namespace std;
21 
22 namespace ctml
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 #ifdef HAS_NO_PYTHON
58  /*
59  * Section to bomb out if python is not
60  * present in the computation environment.
61  */
62  string ppath = file;
63  throw CanteraError("ct2ctml",
64  "python cti to ctml conversion requested for file, " + ppath +
65  ", but not available in this computational environment");
66 #endif
67 
68  string python_output;
69  int python_exit_code;
70  try {
71  exec_stream_t python;
72  python.set_wait_timeout(exec_stream_t::s_all, 1800000); // 30 minutes
73  python.start(pypath(), "-i");
74  stringstream output_stream;
75  python.in() <<
76  "if True:\n" << // Use this so that the rest is a single block
77  " import sys\n" <<
78  " sys.stderr = sys.stdout\n" <<
79  " try:\n" <<
80  " from cantera import ctml_writer\n" <<
81  " except ImportError:\n" <<
82  " import ctml_writer\n" <<
83  " ctml_writer.convert(r'" << file << "')\n" <<
84  " sys.exit(0)\n\n"
85  "sys.exit(7)\n";
86  python.close_in();
87  std::string line;
88  while (python.out().good()) {
89  std::getline(python.out(), line);
90  output_stream << line << std::endl;;
91  }
92  python.close();
93  python_exit_code = python.exit_code();
94  python_output = stripws(output_stream.str());
95  } catch (std::exception& err) {
96  // Report failure to execute Python
97  stringstream message;
98  message << "Error executing python while converting input file:\n";
99  message << "Python command was: '" << pypath() << "'\n";
100  message << err.what() << std::endl;
101  throw CanteraError("ct2ctml", message.str());
102  }
103 
104  if (python_exit_code != 0) {
105  // Report a failure in the conversion process
106  stringstream message;
107  message << "Error converting input file \"" << file << "\" to CTML.\n";
108  message << "Python command was: '" << pypath() << "'\n";
109  message << "The exit code was: " << python_exit_code << "\n";
110  if (python_output.size() > 0) {
111  message << "-------------- start of converter log --------------\n";
112  message << python_output << std::endl;
113  message << "--------------- end of converter log ---------------";
114  } else {
115  message << "The command did not produce any output." << endl;
116  }
117  throw CanteraError("ct2ctml", message.str());
118  }
119 
120  if (python_output.size() > 0) {
121  // Warn if there was any output from the conversion process
122  stringstream message;
123  message << "Warning: Unexpected output from CTI converter\n";
124  message << "-------------- start of converter log --------------\n";
125  message << python_output << std::endl;
126  message << "--------------- end of converter log ---------------\n";
127  writelog(message.str());
128  }
129 }
130 
131 void ck2cti(const std::string& in_file, const std::string& thermo_file,
132  const std::string& transport_file, const std::string& id_tag)
133 {
134 #ifdef HAS_NO_PYTHON
135  /*
136  * Section to bomb out if python is not
137  * present in the computation environment.
138  */
139  string ppath = in_file;
140  throw CanteraError("ct2ctml",
141  "python ck to cti conversion requested for file, " + ppath +
142  ", but not available in this computational environment");
143 #endif
144 
145  string python_output;
146  int python_exit_code;
147  try {
148  exec_stream_t python;
149  python.set_wait_timeout(exec_stream_t::s_all, 1800000); // 30 minutes
150  python.start(pypath(), "-i");
151  stringstream output_stream;
152 
153  ostream& pyin = python.in();
154  pyin << "if True:\n" << // Use this so that the rest is a single block
155  " import sys\n" <<
156  " sys.stderr = sys.stdout\n" <<
157  " try:\n" <<
158  " from cantera import ck2cti\n" << // Cython module
159  " except ImportError:\n" <<
160  " import ck2cti\n" << // legacy Python module
161  " ck2cti.Parser().convertMech(r'" << in_file << "',";
162  if (thermo_file != "" && thermo_file != "-") {
163  pyin << " thermoFile=r'" << thermo_file << "',";
164  }
165  if (transport_file != "" && transport_file != "-") {
166  pyin << " transportFile=r'" << transport_file << "',";
167  }
168  pyin << " phaseName='" << id_tag << "',";
169  pyin << " permissive=True,";
170  pyin << " quiet=True)\n";
171  pyin << " sys.exit(0)\n\n";
172  pyin << "sys.exit(7)\n";
173  python.close_in();
174 
175  std::string line;
176  while (python.out().good()) {
177  std::getline(python.out(), line);
178  output_stream << line << std::endl;;
179  }
180  python.close();
181  python_exit_code = python.exit_code();
182  python_output = stripws(output_stream.str());
183  } catch (std::exception& err) {
184  // Report failure to execute Python
185  stringstream message;
186  message << "Error executing python while converting input file:\n";
187  message << "Python command was: '" << pypath() << "'\n";
188  message << err.what() << std::endl;
189  throw CanteraError("ct2ctml", message.str());
190  }
191 
192  if (python_exit_code != 0) {
193  // Report a failure in the conversion process
194  stringstream message;
195  message << "Error converting input file \"" << in_file << "\" to CTI.\n";
196  message << "Python command was: '" << pypath() << "'\n";
197  message << "The exit code was: " << python_exit_code << "\n";
198  if (python_output.size() > 0) {
199  message << "-------------- start of converter log --------------\n";
200  message << python_output << std::endl;
201  message << "--------------- end of converter log ---------------";
202  } else {
203  message << "The command did not produce any output." << endl;
204  }
205  throw CanteraError("ck2cti", message.str());
206  }
207 
208  if (python_output.size() > 0) {
209  // Warn if there was any output from the conversion process
210  stringstream message;
211  message << "Warning: Unexpected output from CTI converter\n";
212  message << "-------------- start of converter log --------------\n";
213  message << python_output << std::endl;
214  message << "--------------- end of converter log ---------------\n";
215  writelog(message.str());
216  }
217 }
218 
219 void get_CTML_Tree(Cantera::XML_Node* rootPtr, const std::string& file, const int debug)
220 {
221  std::string ff, ext = "";
222 
223  // find the input file on the Cantera search path
224  std::string inname = findInputFile(file);
225  writelog("Found file: "+inname+"\n", debug);
226 
227  if (inname == "") {
228  throw CanteraError("get_CTML_Tree", "file "+file+" not found");
229  }
230 
231  /*
232  * Check whether or not the file is XML. If not, it will be first
233  * processed with the preprocessor.
234  */
235  std::string::size_type idot = inname.rfind('.');
236  if (idot != string::npos) {
237  ext = inname.substr(idot, inname.size());
238  }
239  if (ext != ".xml" && ext != ".ctml") {
240  try {
241  ctml::ct2ctml(inname.c_str(), debug);
242  } catch (std::exception& err) {
243  writelog("get_CTML_Tree: caught an exception:\n");
244  writelog(err.what());
245  }
246  string ffull = inname.substr(0,idot) + ".xml";
247  ff = "./" + getBaseName(ffull) + ".xml";
248  if (debug > 0) {
249  writelogf("ffull name = %s\n", ffull.c_str());
250  writelogf("ff name = %s\n", ff.c_str());
251  }
252  } else {
253  ff = inname;
254  }
255  writelog("Attempting to parse xml file " + ff + "\n", debug);
256  ifstream fin(ff.c_str());
257  if (!fin) {
258  throw
259  CanteraError("get_CTML_Tree",
260  "XML file " + ff + " not found");
261  }
262  rootPtr->build(fin);
263  fin.close();
264 }
265 
266 Cantera::XML_Node getCtmlTree(const std::string& file)
267 {
268  Cantera::XML_Node root;
269  get_CTML_Tree(&root, file);
270  return root;
271 }
272 
273 }
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
std::string findInputFile(const std::string &name)
Find an input file.
Definition: global.cpp:191
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:173
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
This file contains definitions of terms that are used in internal routines and are unlikely to need m...
This file contains definitions for utility functions and text for modules, inputfiles, logs, textlogs, HTML_logs (see Input File Handling, Diagnostic Output, Writing messages to the screen and Writing HTML Logfiles).
std::string getBaseName(const std::string &path)
Get the file name without the path or extension.
void ct2ctml(const char *file, const int debug)
Convert a cti file into a ctml file.
Definition: ct2ctml.cpp:55
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:131
void writelogf(const char *fmt,...)
Write a formatted message to the screen.
Definition: global.cpp:48
std::string stripws(const std::string &s)
Strip the leading and trailing white space from a string.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
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:43
void get_CTML_Tree(Cantera::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:219
void build(std::istream &f)
Main routine to create an tree-like representation of an XML file.
Definition: xml.cpp:776
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
Cantera::XML_Node getCtmlTree(const std::string &file)
Read an ctml file from a file and fill up an XML tree.
Definition: ct2ctml.cpp:266