Cantera  2.0
ck2ct.cpp
Go to the documentation of this file.
1 /**
2  * @file ck2ct.cpp
3  * Convert CK-format reaction mechanism files to Cantera input format.
4  */
5 #include <iostream>
6 #include <string>
7 #include <ctype.h>
8 
9 #include "cantera/base/config.h"
10 
11 #ifdef HAS_SSTREAM
12 #include <sstream>
13 #endif
14 using namespace std;
15 
16 #include "CKReader.h"
17 #include "Reaction.h"
18 #include "writelog.h"
19 
20 #include "ck2ct.h"
22 #include <time.h>
23 #include "cantera/base/ct_defs.h"
24 #include "cantera/base/ctml.h"
25 
26 
27 using namespace Cantera;
28 
29 namespace pip
30 {
31 
32 struct trdata {
33  int geom;
34  doublereal welldepth, diam, dipole, polar, rot;
35 };
36 
37 static map<string, trdata> _trmap;
38 static bool _with_transport = false;
39 
40 static void getTransportData(string trfile)
41 {
42 
43  _with_transport = true;
44  ifstream s(trfile.c_str());
45  if (!s) throw CanteraError("getTransportData",
46  "could not open transport database "+trfile);
47 
48  /*
49  * The first thing we will do is to read the entire transport
50  * database and place its contents into a map structure,
51  * indexed by the name of the species.
52  */
53  string rest;
54  while (! s.eof()) {
55  /*
56  * HKM Note: the USE_STRINGSTREAM block works for files
57  * with comments in them. The other block gets hung up
58  * somehow. Should probably default to the USE_STRINGSTREAM
59  * option.
60  */
61 #ifdef HAS_SSTREAM
62  /*
63  * Read a line from the file
64  *
65  * SOLARIS 10 NOTES: Optimized version of solaris seg faults
66  * without the '\n' argument for some reason, probably
67  * an internal solaris stl bug.
68  */
69  getline(s, rest,'\n');
70  /*
71  * In the transport database, we allow comment lines that
72  * consist of '#' and '!' as the first character in the
73  * in the line. We also don't bother to parse short lines that
74  * can't possibly have enough data in them to comprise a
75  * properly formatted record.
76  */
77  if (rest.size() > 5 && rest[0] != '#' && rest[0] != '!') {
78  /*
79  * copy the string into a stringstream and parse the line
80  * into the trdata object
81  */
82  std::istringstream ioline(rest);
83  trdata t;
84  string nm;
85  ioline >> nm >> t.geom >> t.welldepth >> t.diam
86  >> t.dipole >> t.polar >> t.rot;
87  /*
88  * Add the trdata object into the map database by making a
89  * copy of it, and index it by the species name.
90  */
91  if (nm != "") {
92  _trmap[nm] = t; // t.name] = t;
93  }
94  }
95 #else
96  trdata t;
97  string nm;
98  s >> nm;
99  if (nm[0] != '!' && !s.eof()) {
100  s >> t.geom >> t.welldepth >> t.diam
101  >> t.dipole >> t.polar >> t.rot;
102 
103  // get the rest of the line, in case there are comments
104  getline(s, rest, '\n');
105  if (nm != "") {
106  _trmap[nm] = t; // t.name] = t;
107  }
108  }
109 #endif
110  }
111 }
112 
113 
114 // add a NASA polynomial parameterization
115 static void addNASA(FILE* f,
116  const vector_fp& low, const vector_fp& high,
117  doublereal minx, doublereal midx,
118  doublereal maxx)
119 {
120 
121  fprintf(f," thermo = (\n");
122  fprintf(f," NASA( [%8.2f, %8.2f], ", minx, midx);
123  fprintf(f,"[%17.9E, %17.9E, \n", low[0], low[1]);
124  fprintf(f," %17.9E, %17.9E, %17.9E,\n",
125  low[2], low[3], low[4]);
126  fprintf(f," %17.9E, %17.9E] ),\n", low[5], low[6]);
127  fprintf(f," NASA( [%8.2f, %8.2f], ", midx, maxx);
128  fprintf(f,"[%17.9E, %17.9E, \n", high[0], high[1]);
129  fprintf(f," %17.9E, %17.9E, %17.9E,\n",
130  high[2], high[3], high[4]);
131  fprintf(f," %17.9E, %17.9E] )\n", high[5], high[6]);
132  fprintf(f," )");
133 }
134 
135 
136 
137 //! Add a NASA polynomial parameterization to the cti file
138 /*!
139  * This little tidbit of code writes out the polynomials to the cti file
140  */
141 static void addNASA9(FILE* f,
142  const std::vector<vector_fp*> &region_coeffs,
143  const vector_fp& minTemps, const vector_fp& maxTemps)
144 {
145  size_t nReg = region_coeffs.size();
146  if (minTemps.size() != nReg) {
147  throw CanteraError("addNASA9", "incompat");
148  }
149  if (maxTemps.size() != nReg) {
150  throw CanteraError("addNASA9", "incompat");
151  }
152 
153  fprintf(f," thermo = (\n");
154  for (size_t i = 0; i < nReg; i++) {
155  double minT = minTemps[i];
156  double maxT = maxTemps[i];
157  const vector_fp& coeffs = *(region_coeffs[i]);
158  if ((int) coeffs.size() != 9) {
159  throw CanteraError("addNASA9", "incompat");
160  }
161  fprintf(f," NASA9( [%8.2f, %8.2f], ", minT, maxT);
162  fprintf(f,"[%17.9E, %17.9E, %17.9E,\n", coeffs[0],
163  coeffs[1], coeffs[2]);
164  fprintf(f," %17.9E, %17.9E, %17.9E,\n",
165  coeffs[3], coeffs[4], coeffs[5]);
166  fprintf(f," %17.9E, %17.9E, %17.9E] )",
167  coeffs[6], coeffs[7], coeffs[8]);
168  if (i < nReg - 1) {
169  fprintf(f,",\n");
170  } else {
171  fprintf(f,"\n");
172  }
173  }
174  fprintf(f," )");
175 }
176 
177 
178 static void addTransportParams(FILE* f, string name)
179 {
180 
181  trdata td;
182  if (_with_transport && _trmap.find(name) != _trmap.end()) {
183  td = _trmap[name];
184  } else {
185  throw CanteraError("addTransportParams",
186  "no transport data for species "+name);
187  }
188 
189  fprintf(f,",\n transport = gas_transport(\n");
190  int geom = td.geom;
191  switch (geom) {
192  case 0:
193  fprintf(f," geom = \"atom\",\n");
194  break;
195  case 1:
196  fprintf(f," geom = \"linear\",\n");
197  break;
198  case 2:
199  fprintf(f," geom = \"nonlinear\",\n");
200  break;
201  default:
202  throw CanteraError("addTransportParams",
203  "Unrecognized geometry flag for species " + name);
204  }
205  fprintf(f," diam = %g,\n",td.diam);
206  fprintf(f," well_depth = %g",td.welldepth);
207  if (td.polar != 0.0) {
208  fprintf(f,",\n polar = %g",td.polar);
209  }
210  if (td.dipole != 0.0) {
211  fprintf(f,",\n dipole = %g",td.dipole);
212  }
213  if (td.rot != 0.0) {
214  fprintf(f,",\n rot_relax = %g",td.rot);
215  }
216  fprintf(f,")");
217 }
218 
219 
220 static void addFalloff(FILE* f, string type,
221  const vector_fp& params)
222 {
223  if (type == "Troe") {
224  fprintf(f, "%s", (",\n falloff = Troe(A = " +
225  fp2str(params[0]) + ", T3 = " +
226  fp2str(params[1]) + ", T1 = " +
227  fp2str(params[2])).c_str());
228  if (params.size() >= 4) {
229  fprintf(f, "%s", (", T2 = " + fp2str(params[3])).c_str());
230  }
231  fprintf(f, ")");
232  } else if (type == "SRI") {
233  fprintf(f, "%s", (",\n falloff = SRI(A = " +
234  fp2str(params[0]) + ", B = " +
235  fp2str(params[1]) + ", C = " +
236  fp2str(params[2])).c_str());
237  if (params.size() >= 5) {
238  fprintf(f, "%s", (", D = " + fp2str(params[3]) +
239  ", E = " + fp2str(params[4])).c_str());
240  }
241  fprintf(f, ")");
242  }
243 }
244 
245 /**
246  * Write out a species cti block to the output file.
247  *
248  */
249 static void addSpecies(FILE* f, string idtag, const ckr::Species& sp)
250 {
251  string spname = sp.name;
252  if (spname.size() == 0) {
253  throw CanteraError("addSpecies",
254  "Species name is empty");
255  }
256  fprintf(f,"\nspecies(name = \"%s\",\n",spname.c_str());
257  int nel = static_cast<int>(sp.elements.size());
258  int m, num;
259  string nm, str="";
260  for (m = 0; m < nel; m++) {
261  /*
262  * Copy the element name into the string, nm. Lower case the
263  * second letter, if needed.
264  */
265  nm = sp.elements[m].name;
266  nm[0] = (char) toupper(nm[0]);
267  if (nm.size() == 2) {
268  nm[1] = (char) tolower(nm[1]);
269  }
270  /*
271  * Obtain the current number of atoms in the species.
272  * Linearize the number (HKM question? can we employ real values here
273  * instead?)
274  */
275  num = int(sp.elements[m].number);
276  /*
277  * Add the name and number to end of the string, str
278  */
279  str += " "+nm+":"+int2str(num)+" ";
280 
281  }
282 
283  fprintf(f," atoms = \"%s\",\n", str.c_str());
284  // Add the NASA block according to the thermoFormatType value
285  if (sp.thermoFormatType == 0) {
286  if (sp.lowCoeffs.size() == 0) {
287  throw CanteraError("addSpecies",
288  "Low Nasa Thermo Polynomial was not found");
289  }
290  if (sp.highCoeffs.size() == 0) {
291  throw CanteraError("addSpecies",
292  "High Nasa Thermo Polynomial was not found");
293  }
294  if (sp.tlow >= sp.thigh) {
295  throw CanteraError("addSpecies",
296  "Low temp limit is greater or equal to high temp limit");
297  }
298  addNASA(f, sp.lowCoeffs, sp.highCoeffs,
299  sp.tlow, sp.tmid, sp.thigh);
300  } else if (sp.thermoFormatType == 1) {
301  // This new typs is a multiregion 9 coefficient formulation
302  addNASA9(f, sp.region_coeffs, sp.minTemps, sp.maxTemps);
303  } else {
304  throw CanteraError("addSpecies", "Unknown thermoFormatType");
305  }
306 
307  if (_with_transport) {
308  addTransportParams(f, sp.name);
309  }
310  if (sp.id != "" || sp.m_commentsRef != "") {
311  fprintf(f,",\n note = \"");
312  if (sp.id != "") {
313  fprintf(f, "%s", sp.id.c_str());
314  }
315  if (sp.m_commentsRef != "") {
316  fprintf(f, " %s", sp.m_commentsRef.c_str());
317  }
318  fprintf(f, "\"");
319  }
320  fprintf(f,"\n )\n");
321 }
322 
323 
324 static void addReaction(FILE* f, string idtag, int i,
325  const ckr::Reaction& rxn,
326  const ckr::ReactionUnits& runits, doublereal version)
327 {
328 
329  fprintf(f, "%s", ("\n# Reaction " + int2str(i+1) + "\n").c_str());
330  int nc = static_cast<int>(rxn.comment.size());
331  vector<string> options;
332 
333  for (int nn = 0; nn < nc; nn++)
334  if (rxn.comment[nn] != "") fprintf(f, "# %s \n",
335  rxn.comment[nn].c_str());
336 
337  string eqn = ckr::reactionEquation(rxn);
338 
339  if (rxn.isThreeBodyRxn) {
340  fprintf(f, "three_body_reaction( \"%s\",", eqn.c_str());
341  } else if (rxn.isFalloffRxn) {
342  fprintf(f, "falloff_reaction( \"%s\",", eqn.c_str());
343  } else {
344  fprintf(f, "reaction( \"%s\",", eqn.c_str());
345  }
346 
347  if (rxn.isFalloffRxn) {
348 
349  if (rxn.kf.type == ckr::Arrhenius) {
350  fprintf(f,"\n kf = [%10.5E, %g, %g]", rxn.kf.A, rxn.kf.n, rxn.kf.E);
351  }
352  if (rxn.kf_aux.type == ckr::Arrhenius) {
353  fprintf(f,",\n kf0 = [%10.5E, %g, %g]", rxn.kf_aux.A, rxn.kf_aux.n, rxn.kf_aux.E);
354  }
355  if (rxn.falloffType == ckr::Lindemann) {
356  addFalloff(f, "Lindemann",rxn.falloffParameters);
357  } else if (rxn.falloffType == ckr::Troe) {
358  addFalloff(f, "Troe",rxn.falloffParameters);
359  } else if (rxn.falloffType == ckr::SRI) {
360  addFalloff(f, "SRI",rxn.falloffParameters);
361  } else {
362  throw CanteraError("addReaction","unknown falloff type");
363  }
364  } else {
365  if (rxn.kf.type == ckr::Arrhenius) {
366  fprintf(f," [%10.5E, %g, %g]", rxn.kf.A, rxn.kf.n, rxn.kf.E);
367  } else {
368  throw CanteraError("addReaction",
369  "unknown kf_type to reaction: " + int2str(rxn.kf.type));
370  }
371  }
372 
373  // reaction orders
374  int nord = static_cast<int>(rxn.fwdOrder.size());
375  if (nord > 0) {
376  map<string, double>::const_iterator b = rxn.fwdOrder.begin(),
377  e = rxn.fwdOrder.end();
378  string estr = "";
379  for (; b != e; ++b) {
380  estr += " "+b->first+":"+fp2str(b->second)+" ";
381  }
382  fprintf(f, ",\n order = \"%s\"", estr.c_str());
383  }
384 
385  int ne = static_cast<int>(rxn.e3b.size());
386  if (rxn.thirdBody != "<none>") {
387  if (rxn.thirdBody != "M") {
388  ;
389  } else if (ne > 0.0) {
390  map<string, double>::const_iterator b = rxn.e3b.begin(),
391  e = rxn.e3b.end();
392  string estr = "";
393  for (; b != e; ++b) {
394  estr += " "+b->first+":"+fp2str(b->second)+" ";
395  }
396  fprintf(f, ",\n efficiencies = \"%s\"", estr.c_str());
397  }
398  }
399  if (rxn.kf.A <= 0.0) {
400  options.push_back("negative_A");
401  }
402  if (rxn.isDuplicate) {
403  options.push_back("duplicate");
404  }
405  size_t nopt = options.size();
406  if (nopt > 0) {
407  fprintf(f, ",\n options = [");
408  for (size_t n = 0; n < nopt; n++) {
409  fprintf(f, "\"%s\"", options[n].c_str());
410  if (n < nopt-1) {
411  fprintf(f, ", ");
412  }
413  }
414  fprintf(f, "]");
415  }
416  fprintf(f, ")\n");
417 }
418 
419 void writeline(FILE* f)
420 {
421  fprintf(f, "#-------------------------------------------------------------------------------\n");
422 }
423 
424 /*!
425  * This routine is the main routine.
426  *
427  * @param r reference to a ckreader object that has already
428  * read a chemkin formatted mechanism. This is the input to the routine.
429  *
430  * @param root Reference to the root node of an XML description of the
431  * mechanism. The node will be filled up with the description
432  * of the mechanism. This is the output to the routine.
433  */
434 void ck2ct(FILE* f, string idtag, ckr::CKReader& r, bool hastransport)
435 {
436 
437  popError();
438  doublereal version = 1.0;
439 
440  fprintf(f, "units(length = \"cm\", time = \"s\", quantity = \"mol\", ");
441  string e_unit = " ";
442  int eunit = r.units.ActEnergy;
443  if (eunit == ckr::Cal_per_Mole) {
444  e_unit = "cal/mol";
445  } else if (eunit == ckr::Kcal_per_Mole) {
446  e_unit = "kcal/mol";
447  } else if (eunit == ckr::Joules_per_Mole) {
448  e_unit = "J/mol";
449  } else if (eunit == ckr::Kjoules_per_Mole) {
450  e_unit = "kJ/mol";
451  } else if (eunit == ckr::Kelvin) {
452  e_unit = "K";
453  } else if (eunit == ckr::Electron_Volts) {
454  e_unit = "eV";
455  }
456  fprintf(f, "act_energy = \"%s\")\n\n", e_unit.c_str());
457 
458 
459  fprintf(f,"\nideal_gas(name = \"%s\",\n",idtag.c_str());
460 
461  string enames;
462  int nel = static_cast<int>(r.elements.size());
463  int i;
464  map<string, string> emap;
465  string elnm;
466  for (i = 0; i < nel; i++) {
467  elnm = r.elements[i].name;
468  elnm[0] = (char) toupper(elnm[0]);
469  if (elnm.size() == 2) {
470  elnm[1] = (char) tolower(elnm[1]);
471  }
472  emap[r.elements[i].name] = elnm;
473  enames += " "+elnm+" ";
474  }
475  fprintf(f," elements = \"%s\",\n",enames.c_str());
476 
477  string spnames = "";
478  int nsp = static_cast<int>(r.species.size());
479  for (i = 0; i < nsp; i++) {
480  spnames += " "+r.species[i].name+" ";
481  if ((i+1) % 10 == 0) {
482  spnames += "\n ";
483  }
484  }
485  fprintf(f," species = \"\"\"%s\"\"\",\n", spnames.c_str());
486  fprintf(f," reactions = \"all\",\n");
487  if (hastransport) {
488  fprintf(f," transport = \"Mix\",\n");
489  }
490  fprintf(f," initial_state = state(temperature = 300.0,\n");
491  fprintf(f," pressure = OneAtm)");
492  fprintf(f, " )\n");
493 
494  fprintf(f, "\n\n\n");
495  writeline(f);
496  fprintf(f, "# Species data \n");
497  writeline(f);
498 
499  for (i = 0; i < nsp; i++) {
500  addSpecies(f, idtag, r.species[i]);
501  }
502 
503  fprintf(f, "\n\n\n");
504  writeline(f);
505  fprintf(f, "# Reaction data \n");
506  writeline(f);
507 
508 
509  int nrxns = static_cast<int>(r.reactions.size());
510 
511  int irxn = 0;
512  string idktag = idtag;
513  for (i = 0; i < nrxns; i++) {
514 
515  // if krev.A is non-zero, then the reverse rate coefficient is
516  // being explicitly specified rather than being computed from
517  // thermochemistry. In this case, convert the reaction into
518  // two irreversible reactions.
519 
520  if (r.reactions[i].krev.A != 0.0) {
521  fprintf(f, "\n# [CK Reaction (+%d)]\n",i+1);
522  addReaction(f, idktag, irxn,
523  ckr::forwardReaction(r.reactions[i]), r.units, version);
524  irxn++;
525  fprintf(f, "# [CK Reaction (-%d)]\n",i+1);
526  addReaction(f, idktag, irxn,
527  ckr::reverseReaction(r.reactions[i]), r.units, version);
528  irxn++;
529  }
530 
531  // Otherwise, just add the whole reaction, which may or may
532  // not be reversible.
533  else {
534  if (i != irxn) {
535  fprintf(f, "\n# [CK Reaction (%d)]\n",i+1);
536  }
537  addReaction(f, idktag, irxn, r.reactions[i],
538  r.units, version);
539  irxn++;
540  }
541  }
542 }
543 
544 /*
545  static int fixtext(string infile, string outfile) {
546  ifstream fin(infile.c_str());
547  ofstream fout(outfile.c_str());
548  if (!fout) {
549  throw CanteraError("fixtext","could not open "+outfile+" for writing.");
550  }
551  char ch;
552  char last_eol = ' ';
553  const char char10 = char(10);
554  const char char13 = char(13);
555  string line;
556  while (1 > 0) {
557  line = "";
558  while (1 > 0) {
559  fin.get(ch);
560  if (fin.eof()) break;
561  if (ch == char13 || (ch == char10
562  && (last_eol != char13))) {
563  last_eol = ch;
564  break;
565  }
566  if (isprint(ch)) line += ch;
567  }
568  fout << line << endl;
569  if (fin.eof()) break;
570  }
571  fin.close();
572  fout.close();
573  return 0;
574  }
575 */
576 
577 int convert_ck(const char* in_file, const char* db_file,
578  const char* tr_file, const char* id_tag, bool debug, bool validate)
579 {
580  ckr::CKReader r;
581 
582  r.validate = validate;
583  r.debug = debug;
584  //int i=1;
585 
586  string infile = string(in_file);
587  string dbfile = string(db_file);
588  string trfile = string(tr_file);
589  //string outfile = string(out_file);
590  string idtag = string(id_tag);
591  string logfile;
592  if (dbfile == "-") {
593  dbfile = "";
594  }
595  if (trfile == "-") {
596  trfile = "";
597  }
598 
599  string::size_type idot = infile.rfind('.');
600  string ctifile, ext;
601  if (idot != string::npos) {
602  ext = infile.substr(idot, infile.size());
603  ctifile = infile.substr(0,idot)+".cti";
604  } else {
605  ctifile = infile+".cti";
606  }
607 
608  FILE* f = fopen(ctifile.c_str(),"w");
609 
610  struct tm* newtime;
611  time_t aclock;
612  ::time(&aclock); /* Get time in seconds */
613  newtime = localtime(&aclock); /* Convert time to struct tm form */
614 
615  try {
616 
617  //string tmpinfile = tmpDir()+
618  //fixtext(infile, tmpinfile);
619 
620  //string tmpdbfile = "";
621  //string tmptrfile = "";
622  //if (dbfile != "") {
623  // tmpdbfile = tmpDir()+"/.tmp_"+dbfile;
624  // fixtext(dbfile, tmpdbfile);
625  //}
626  //if (trfile != "") {
627  // tmptrfile = tmpDir()+"/.tmp_"+trfile;
628  // fixtext(trfile, tmptrfile);
629  //}
630 
631  logfile = "ck2cti.log";
632  if (!r.read(infile, dbfile, logfile)) {
633  throw CanteraError("convert_ck",
634  "error encountered in input file " + string(infile)
635  + "\nsee file ck2cti.log for more information.\n");
636  }
637 
638  fprintf(f, "#\n");
639  fprintf(f, "# Generated from file %s\n# by ck2cti on %s#\n",
640  infile.c_str(), asctime(newtime));
641  if (trfile != "") {
642  fprintf(f, "# Transport data from file %s.\n\n",
643  trfile.c_str());
644  getTransportData(trfile);
645  }
646  bool hastransport = (trfile != "");
647  ck2ct(f, idtag, r, hastransport);
648  } catch (CanteraError& err) {
649  err.save();
650  fclose(f);
651  return -1;
652  }
653  fclose(f);
654  return 0;
655 }
656 }
657 
658