Cantera  2.0
vcs_equilibrate.cpp
Go to the documentation of this file.
1 /**
2  * @file vcs_equilibrate.cpp
3  * Driver routines for equilibrium solvers
4  */
5 /*
6  * Copyright (2006) Sandia Corporation. Under the terms of
7  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
8  * U.S. Government retains certain rights in this software.
9  */
11 #include "cantera/equil/vcs_prob.h"
14 #include "vcs_species_thermo.h"
15 #include "vcs_SpeciesProperties.h"
18 #include "cantera/equil/equil.h"
19 
20 #include "cantera/base/ct_defs.h"
21 #include "cantera/thermo/mix_defs.h"
26 
27 #include <string>
28 #include <vector>
29 
30 using namespace std;
31 
32 namespace Cantera
33 {
34 
35 /*
36  * Set a single-phase chemical solution to chemical equilibrium.
37  * This is a convenience function that uses one or the other of
38  * the two chemical equilibrium solvers.
39  *
40  * @param s The object to set to an equilibrium state
41  *
42  * @param XY An integer specifying the two properties to be held
43  * constant.
44  *
45  * @param estimateEquil integer indicating whether the solver
46  * should estimate its own initial condition.
47  * If 0, the initial mole fraction vector
48  * in the %ThermoPhase object is used as the
49  * initial condition.
50  * If 1, the initial mole fraction vector
51  * is used if the element abundances are
52  * satisfied.
53  * if -1, the initial mole fraction vector
54  * is thrown out, and an estimate is
55  * formulated.
56  *
57  * @param printLvl Determines the amount of printing that
58  * gets sent to stdout from the vcs package
59  * (Note, you may have to compile with debug
60  * flags to get some printing).
61  *
62  * @param solver The equilibrium solver to use. If solver = 0,
63  * the ChemEquil solver will be used, and if
64  * solver = 1, the vcs_MultiPhaseEquil solver will
65  * be used (slower than ChemEquil,
66  * but more stable). If solver < 0 (default, then
67  * ChemEquil will be tried first, and if it fails
68  * vcs_MultiPhaseEquil will be tried.
69  *
70  * @param maxsteps The maximum number of steps to take to find
71  * the solution.
72  *
73  * @param maxiter For the MultiPhaseEquil solver only, this is
74  * the maximum number of outer temperature or
75  * pressure iterations to take when T and/or P is
76  * not held fixed.
77  *
78  * @param loglevel Controls amount of diagnostic output. loglevel
79  * = 0 suppresses diagnostics, and increasingly-verbose
80  * messages are written as loglevel increases. The
81  * messages are written to a file in HTML format for viewing
82  * in a web browser. @see HTML_logs
83  */
84 int vcs_equilibrate(thermo_t& s, const char* XY,
85  int estimateEquil, int printLvl,
86  int solver,
87  doublereal rtol, int maxsteps, int maxiter,
88  int loglevel)
89 {
90  MultiPhase* m = 0;
91  int retn = 1;
92  int retnSub = 0;
93 
94  beginLogGroup("equilibrate", loglevel);
95  // retry:
96  addLogEntry("Single-phase equilibrate function");
97  {
98  beginLogGroup("arguments");
99  addLogEntry("phase",s.id());
100  addLogEntry("XY",XY);
101  addLogEntry("solver",solver);
102  addLogEntry("rtol",rtol);
103  addLogEntry("maxsteps",maxsteps);
104  addLogEntry("maxiter",maxiter);
105  addLogEntry("loglevel",loglevel);
106  endLogGroup("arguments");
107  }
108 
109  if (solver == 2) {
110  m = new MultiPhase;
111  try {
112  /*
113  * Set the kmoles of the phase to 1.0, arbitrarily.
114  * It actually doesn't matter.
115  */
116  m->addPhase(&s, 1.0);
117  m->init();
118 
119  retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver,
120  rtol, maxsteps, maxiter, loglevel);
121  if (retn == 1) {
122  addLogEntry("MultiPhaseEquil solver succeeded.");
123  } else {
124  addLogEntry("MultiPhaseEquil solver returned an error code: ", retn);
125  }
126  delete m;
127  } catch (CanteraError& err) {
128  err.save();
129  addLogEntry("MultiPhaseEquil solver failed.");
130  delete m;
131  throw err;
132  }
133  } else if (solver == 1) {
134  m = new MultiPhase;
135  try {
136  m->addPhase(&s, 1.0);
137  m->init();
138  (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1);
139  if (loglevel > 0) {
140  addLogEntry("MultiPhaseEquil solver succeeded.");
141  }
142  delete m;
143  retn = 1;
144  } catch (CanteraError& err) {
145  err.save();
146  if (loglevel > 0) {
147  addLogEntry("MultiPhaseEquil solver failed.");
148  }
149  delete m;
150  throw err;
151  }
152  } else if (solver == 0) {
153  ChemEquil* e = new ChemEquil;
154  try {
155  e->options.maxIterations = maxsteps;
156  e->options.relTolerance = rtol;
157  bool useThermoPhaseElementPotentials = false;
158  if (estimateEquil == 0) {
159  useThermoPhaseElementPotentials = true;
160  }
161  retnSub = e->equilibrate(s, XY,
162  useThermoPhaseElementPotentials, loglevel-1);
163  if (retnSub < 0) {
164  if (loglevel > 0) {
165  addLogEntry("ChemEquil solver failed.");
166  }
167  delete e;
168  throw CanteraError("equilibrate",
169  "ChemEquil equilibrium solver failed");
170  }
171  retn = 1;
172  s.setElementPotentials(e->elementPotentials());
173  delete e;
174  if (loglevel > 0) {
175  addLogEntry("ChemEquil solver succeeded.");
176  }
177  } catch (CanteraError& err) {
178  err.save();
179  if (loglevel > 0) {
180  addLogEntry("ChemEquil solver failed.");
181  }
182  delete e;
183  throw err;
184  }
185  } else {
186  throw CanteraError("vcs_equilibrate",
187  "unknown solver");
188  }
189 
190  /*
191  * We are here only for a success
192  */
193  endLogGroup("equilibrate");
194  return retn;
195 }
196 
197 // Set a multi-phase chemical solution to chemical equilibrium.
198 /*
199  * This function uses the vcs_MultiPhaseEquil interface to the
200  * vcs solver.
201  * The function uses the element abundance vector that is
202  * currently consistent with the composition within the phases
203  * themselves. Two other thermodynamic quantities, determined by the
204  * XY string, are held constant during the equilibration.
205  *
206  * @param s The object to set to an equilibrium state
207  *
208  * @param XY A character string specifying the two properties to
209  * be held constant
210  *
211  * @param estimateEquil integer indicating whether the solver
212  * should estimate its own initial condition.
213  * If 0, the initial mole fraction vector
214  * in the %ThermoPhase object is used as the
215  * initial condition.
216  * If 1, the initial mole fraction vector
217  * is used if the element abundances are
218  * satisfied.
219  * if -1, the initial mole fraction vector
220  * is thrown out, and an estimate is
221  * formulated.
222  *
223  * @param printLvl Determines the amount of printing that
224  * gets sent to stdout from the vcs package
225  * (Note, you may have to compile with debug
226  * flags to get some printing).
227  *
228  * @param maxsteps The maximum number of steps to take to find
229  * the solution.
230  *
231  * @param maxiter For the MultiPhaseEquil solver only, this is
232  * the maximum number of outer temperature or
233  * pressure iterations to take when T and/or P is
234  * not held fixed.
235  *
236  * @param loglevel Controls amount of diagnostic output. loglevel
237  * = 0 suppresses diagnostics, and increasingly-verbose
238  * messages are written as loglevel increases. The
239  * messages are written to a file in HTML format for viewing
240  * in a web browser. @see HTML_logs
241  *
242  * @ingroup equilfunctions
243  */
244 int vcs_equilibrate(MultiPhase& s, const char* XY,
245  int estimateEquil, int printLvl, int solver,
246  doublereal tol, int maxsteps, int maxiter,
247  int loglevel)
248 {
249  int ixy = _equilflag(XY);
250  int retn = vcs_equilibrate_1(s, ixy, estimateEquil, printLvl, solver,
251  tol, maxsteps, maxiter, loglevel);
252  return retn;
253 };
254 
255 
256 // Set a multi-phase chemical solution to chemical equilibrium.
257 /*
258  * This function uses the vcs_MultiPhaseEquil interface to the
259  * vcs solver.
260  * The function uses the element abundance vector that is
261  * currently consistent with the composition within the phases
262  * themselves. Two other thermodynamic quantities, determined by the
263  * XY string, are held constant during the equilibration.
264  *
265  * @param s The object to set to an equilibrium state
266  *
267  * @param XY An integer specifying the two properties to be held
268  * constant.
269  *
270  * @param estimateEquil integer indicating whether the solver
271  * should estimate its own initial condition.
272  * If 0, the initial mole fraction vector
273  * in the %ThermoPhase object is used as the
274  * initial condition.
275  * If 1, the initial mole fraction vector
276  * is used if the element abundances are
277  * satisfied.
278  * if -1, the initial mole fraction vector
279  * is thrown out, and an estimate is
280  * formulated.
281  *
282  * @param printLvl Determines the amount of printing that
283  * gets sent to stdout from the vcs package
284  * (Note, you may have to compile with debug
285  * flags to get some printing).
286  *
287  * @param maxsteps The maximum number of steps to take to find
288  * the solution.
289  *
290  * @param maxiter For the MultiPhaseEquil solver only, this is
291  * the maximum number of outer temperature or
292  * pressure iterations to take when T and/or P is
293  * not held fixed.
294  *
295  * @param loglevel Controls amount of diagnostic output. loglevel
296  * = 0 suppresses diagnostics, and increasingly-verbose
297  * messages are written as loglevel increases. The
298  * messages are written to a file in HTML format for viewing
299  * in a web browser. @see HTML_logs
300  *
301  * @ingroup equilfunctions
302  */
304  int estimateEquil, int printLvl, int solver,
305  doublereal tol, int maxsteps, int maxiter, int loglevel)
306 {
307  static int counter = 0;
308  int retn = 1;
309 
310  beginLogGroup("equilibrate",loglevel);
311  addLogEntry("multiphase equilibrate function");
312  beginLogGroup("arguments");
313  addLogEntry("XY",ixy);
314  addLogEntry("tol",tol);
315  addLogEntry("maxsteps",maxsteps);
316  addLogEntry("maxiter",maxiter);
317  addLogEntry("loglevel",loglevel);
318  endLogGroup("arguments");
319 
320  int printLvlSub = std::max(0, printLvl-1);
321 
322  s.init();
323 
324  if (solver == 2) {
325  try {
327  int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub, tol, maxsteps, loglevel);
328  if (err != 0) {
329  retn = -1;
330  addLogEntry("vcs_equilibrate Error - ", err);
331  } else {
332  addLogEntry("vcs_equilibrate Success - ", err);
333  }
334  endLogGroup("equilibrate");
335  // hard code a csv output file.
336  if (printLvl > 0) {
337  string reportFile = "vcs_equilibrate_res.csv";
338  if (counter > 0) {
339  reportFile = "vcs_equilibrate_res_" + int2str(counter) + ".csv";
340  }
341  eqsolve->reportCSV(reportFile);
342  counter++;
343  }
344  delete eqsolve;
345  } catch (CanteraError& e) {
346  e.save();
347  retn = -1;
348  addLogEntry("Failure.", lastErrorMessage());
349  endLogGroup("equilibrate");
350  throw e;
351  }
352  } else if (solver == 1) {
353  if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) {
354  try {
355  double err = s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel);
356 
357  addLogEntry("Success. Error",err);
358  endLogGroup("equilibrate");
359 
360  return 0;
361  } catch (CanteraError& e) {
362  e.save();
363  addLogEntry("Failure.",lastErrorMessage());
364  endLogGroup("equilibrate");
365 
366  throw e;
367  }
368  } else {
369 
370  addLogEntry("multiphase equilibrium can be done only for TP, HP, SP, or TV");
371  endLogGroup("equilibrate");
372 
373  throw CanteraError("equilibrate","unsupported option");
374  //return -1.0;
375  }
376  } else {
377  throw CanteraError("vcs_equilibrate_1", "unknown solver");
378  }
379  return retn;
380 }
381 
382 //====================================================================================================================
383 // Determine the phase stability of a single phase given the current conditions
384 // in a MultiPhase object
385 /*
386  *
387  * @param s The MultiPhase object to be set to an equilibrium state
388  * @param iphase Phase index within the multiphase object to be
389  * tested for stability.
390  * @param funcStab Function value that tests equilibrium. > 0 indicates stable
391  * < 0 indicates unstable
392  *
393  * @param printLvl Determines the amount of printing that
394  * gets sent to stdout from the vcs package
395  * (Note, you may have to compile with debug
396  * flags to get some printing).
397  *
398  * @param loglevel Controls amount of diagnostic output. loglevel
399  * = 0 suppresses diagnostics, and increasingly-verbose
400  * messages are written as loglevel increases. The
401  * messages are written to a file in HTML format for viewing
402  * in a web browser. @see HTML_logs
403  */
405  double& funcStab, int printLvl, int loglevel)
406 {
407  int iStab = 0;
408  static int counter = 0;
409  beginLogGroup("PhaseStability",loglevel);
410  addLogEntry("multiphase phase stability function");
411  beginLogGroup("arguments");
412  addLogEntry("iphase",iphase);
413  addLogEntry("loglevel",loglevel);
414  endLogGroup("arguments");
415 
416  int printLvlSub = std::max(0, printLvl-1);
417 
418  s.init();
419  try {
421  iStab = eqsolve->determine_PhaseStability(iphase, funcStab, printLvlSub, loglevel);
422  if (iStab != 0) {
423  addLogEntry("Phase is stable - ", iphase);
424  } else {
425  addLogEntry("Phase is not stable - ", iphase);
426  }
427  endLogGroup("PhaseStability");
428  // hard code a csv output file.
429  if (printLvl > 0) {
430  string reportFile = "vcs_phaseStability.csv";
431  if (counter > 0) {
432  reportFile = "vcs_phaseStability_" + int2str(counter) + ".csv";
433  }
434  eqsolve->reportCSV(reportFile);
435  counter++;
436  }
437  delete eqsolve;
438  } catch (CanteraError& e) {
439  addLogEntry("Failure.", lastErrorMessage());
440  endLogGroup("equilibrate");
441  throw e;
442  }
443  return iStab;
444 }
445 //====================================================================================================================
446 }