Cantera  2.0
equilibrate.cpp
Go to the documentation of this file.
1 /**
2  * @file equilibrate.cpp
3  * Driver routines for the chemical equilibrium solvers.
4  *
5  */
6 #include "cantera/equil/equil.h"
8 #include "cantera/equil/MultiPhaseEquil.h"
10 #include "cantera/base/global.h"
11 
12 namespace Cantera
13 {
14 
15 /*
16  * Set a multiphase mixture to a state of chemical equilibrium.
17  * This is the top-level driver for multiphase equilibrium. It
18  * doesn't do much more than call the equilibrate method of class
19  * MultiPhase, except that it adds some messages to the logfile,
20  * if loglevel is set > 0.
21  *
22  * @ingroup equil
23  */
24 doublereal equilibrate(MultiPhase& s, const char* XY,
25  doublereal tol, int maxsteps, int maxiter,
26  int loglevel)
27 {
28  if (loglevel > 0) {
29  beginLogGroup("equilibrate",loglevel);
30  addLogEntry("multiphase equilibrate function");
31  beginLogGroup("arguments");
32  addLogEntry("XY",XY);
33  addLogEntry("tol",tol);
34  addLogEntry("maxsteps",maxsteps);
35  addLogEntry("maxiter",maxiter);
36  addLogEntry("loglevel",loglevel);
37  endLogGroup("arguments");
38  }
39  s.init();
40  int ixy = _equilflag(XY);
41  if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) {
42  try {
43  double err = s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel);
44  if (loglevel > 0) {
45  addLogEntry("Success. Error",err);
46  endLogGroup("equilibrate");
47 
48  }
49  return err;
50  } catch (CanteraError& err) {
51  err.save();
52  if (loglevel > 0) {
53  addLogEntry("Failure.",lastErrorMessage());
54  endLogGroup("equilibrate");
55  }
56  throw err;
57  }
58  } else {
59  if (loglevel > 0) {
60  addLogEntry("multiphase equilibrium can be done only for TP, HP, SP, or TV");
61  endLogGroup("equilibrate");
62  }
63  throw CanteraError("equilibrate","unsupported option");
64  return -1.0;
65  }
66  return 0.0;
67 }
68 
69 /*
70  * Set a single-phase chemical solution to chemical equilibrium.
71  * This is a convenience function that uses one or the other of
72  * the two chemical equilibrium solvers.
73  *
74  * @param s The object to set to an equilibrium state
75  *
76  * @param XY An integer specifying the two properties to be held
77  * constant.
78  *
79  * @param solver The equilibrium solver to use. If solver = 0,
80  * the ChemEquil solver will be used, and if solver = 1, the
81  * MultiPhaseEquil solver will be used (slower than ChemEquil,
82  * but more stable). If solver < 0 (default, then ChemEquil will
83  * be tried first, and if it fails MultiPhaseEquil will be tried.
84  *
85  * @param maxsteps The maximum number of steps to take to find
86  * the solution.
87  *
88  * @param maxiter For the MultiPhaseEquil solver only, this is
89  * the maximum number of outer temperature or pressure iterations
90  * to take when T and/or P is not held fixed.
91  *
92  * @param loglevel Controls amount of diagnostic output. loglevel
93  * = 0 suppresses diagnostics, and increasingly-verbose messages
94  * are written as loglevel increases. The messages are written to
95  * a file in HTML format for viewing in a web browser.
96  * @see HTML_logs
97  *
98  * @ingroup equil
99  */
100 int equilibrate(thermo_t& s, const char* XY, int solver,
101  doublereal rtol, int maxsteps, int maxiter, int loglevel)
102 {
103  bool redo = true;
104  int retn = -1;
105  int nAttempts = 0;
106  int retnSub = 0;
107 
108  if (loglevel > 0) {
109  beginLogGroup("equilibrate", loglevel);
110  addLogEntry("Single-phase equilibrate function");
111  {
112  beginLogGroup("arguments");
113  addLogEntry("phase",s.id());
114  addLogEntry("XY",XY);
115  addLogEntry("solver",solver);
116  addLogEntry("rtol",rtol);
117  addLogEntry("maxsteps",maxsteps);
118  addLogEntry("maxiter",maxiter);
119  addLogEntry("loglevel",loglevel);
120  endLogGroup("arguments");
121  }
122  }
123  while (redo) {
124  if (solver >= 2) {
125  int printLvlSub = 0;
126  int estimateEquil = 0;
127  try {
128  MultiPhase m;
129  m.addPhase(&s, 1.0);
130  m.init();
131  nAttempts++;
132  vcs_equilibrate(m, XY, estimateEquil, printLvlSub, solver,
133  rtol, maxsteps, maxiter, loglevel-1);
134  redo = false;
135  if (loglevel > 0) {
136  addLogEntry("VCSnonideal solver succeeded.");
137  }
138  retn = nAttempts;
139  } catch (CanteraError& err) {
140  err.save();
141  if (loglevel > 0) {
142  addLogEntry("VCSnonideal solver failed.");
143  }
144  if (nAttempts < 2) {
145  if (loglevel > 0) {
146  addLogEntry("Trying single phase ChemEquil solver.");
147  }
148  solver = -1;
149  } else {
150  if (loglevel > 0) {
151  endLogGroup("equilibrate");
152  }
153  throw err;
154  }
155  }
156  } else if (solver == 1) {
157  try {
158  MultiPhase m;
159  m.addPhase(&s, 1.0);
160  m.init();
161  nAttempts++;
162  equilibrate(m, XY, rtol, maxsteps, maxiter, loglevel-1);
163  redo = false;
164  if (loglevel > 0) {
165  addLogEntry("MultiPhaseEquil solver succeeded.");
166  }
167  retn = nAttempts;
168  } catch (CanteraError& err) {
169  err.save();
170  if (loglevel > 0) {
171  addLogEntry("MultiPhaseEquil solver failed.");
172  }
173  if (nAttempts < 2) {
174  if (loglevel > 0) {
175  addLogEntry("Trying single phase ChemEquil solver.");
176  }
177  solver = -1;
178  } else {
179  if (loglevel > 0) {
180  endLogGroup("equilibrate");
181  }
182  throw err;
183  }
184  }
185  } else { // solver <= 0
186  /*
187  * Call the element potential solver
188  */
189  try {
190  ChemEquil e;
191  e.options.maxIterations = maxsteps;
192  e.options.relTolerance = rtol;
193  nAttempts++;
194  bool useThermoPhaseElementPotentials = true;
195  retnSub = e.equilibrate(s, XY, useThermoPhaseElementPotentials,
196  loglevel-1);
197  if (retnSub < 0) {
198  if (loglevel > 0) {
199  addLogEntry("ChemEquil solver failed.");
200  }
201  if (nAttempts < 2) {
202  if (loglevel > 0) {
203  addLogEntry("Trying MultiPhaseEquil solver.");
204  }
205  solver = 1;
206  } else {
207  throw CanteraError("equilibrate",
208  "Both equilibrium solvers failed");
209  }
210  }
211  retn = nAttempts;
212  s.setElementPotentials(e.elementPotentials());
213  redo = false;
214  if (loglevel > 0) {
215  addLogEntry("ChemEquil solver succeeded.");
216  }
217  }
218 
219  catch (CanteraError& err) {
220  err.save();
221  if (loglevel > 0) {
222  addLogEntry("ChemEquil solver failed.");
223  }
224  // If ChemEquil fails, try the MultiPhase solver
225  if (solver < 0) {
226  if (loglevel > 0) {
227  addLogEntry("Trying MultiPhaseEquil solver.");
228  }
229  solver = 1;
230  } else {
231  redo = false;
232  if (loglevel > 0) {
233  endLogGroup("equilibrate");
234  }
235  throw err;
236  }
237  }
238  }
239  } // while (redo)
240  /*
241  * We are here only for a success
242  */
243  if (loglevel > 0) {
244  endLogGroup("equilibrate");
245  }
246  return retn;
247 }
248 }