Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vcs_inest.cpp
Go to the documentation of this file.
1 /**
2  * @file vcs_inest.cpp
3  * Implementation methods for obtaining a good initial guess
4  */
5 /*
6  * Copyright (2005) 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  */
10 
13 
14 #include "cantera/base/clockWC.h"
15 
16 namespace Cantera
17 {
18 
19 static char pprefix[20] = " --- vcs_inest: ";
20 
21 void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm,
22  double* const ss, double test)
23 {
24  size_t nspecies = m_numSpeciesTot;
25  size_t nrxn = m_numRxnTot;
26 
27  /*
28  * CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB
29  * AND molNum(I) .GE. 0.0
30  *
31  * Note, both of these programs do this.
32  */
34 
35  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
36  plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n",
37  pprefix);
38  plogf("%s SPECIES MOLE_NUMBER -SS_ChemPotential\n", pprefix);
39  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
40  plogf("%s ", pprefix);
41  plogf("%-12.12s", m_speciesName[kspec].c_str());
42  plogf(" %15.5g %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]);
43  }
44  plogf("%s Element Abundance Agreement returned from linear "
45  "programming (vcs_inest initial guess):",
46  pprefix);
47  plogendl();
48  plogf("%s Element Goal Actual\n", pprefix);
49  for (size_t j = 0; j < m_numElemConstraints; j++) {
50  if (m_elementActive[j]) {
51  double tmp = 0.0;
52  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
53  tmp += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
54  }
55  plogf("%s ", pprefix);
56  plogf(" %-9.9s", (m_elementName[j]).c_str());
57  plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp);
58  }
59  }
60  plogendl();
61  }
62 
63  /*
64  * Make sure all species have positive definite mole numbers
65  * Set voltages to zero for now, until we figure out what to do
66  */
67  m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0);
68  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
70  if (m_molNumSpecies_old[kspec] <= 0.0) {
71  /*
72  * HKM Should eventually include logic here for non SS phases
73  */
74  if (!m_SSPhase[kspec]) {
75  m_molNumSpecies_old[kspec] = 1.0e-30;
76  }
77  }
78  } else {
79  m_molNumSpecies_old[kspec] = 0.0;
80  }
81  }
82 
83  /*
84  * Now find the optimized basis that spans the stoichiometric
85  * coefficient matrix
86  */
87  bool conv;
88  (void) vcs_basopt(false, aw, sa, sm, ss, test, &conv);
89 
90  /* ***************************************************************** */
91  /* **** CALCULATE TOTAL MOLES, ****************** */
92  /* **** CHEMICAL POTENTIALS OF BASIS ****************** */
93  /* ***************************************************************** */
94  /*
95  * Calculate TMoles and m_tPhaseMoles_old[]
96  */
97  vcs_tmoles();
98  /*
99  * m_tPhaseMoles_new[] will consist of just the component moles
100  */
101  for (size_t iph = 0; iph < m_numPhases; iph++) {
102  m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20;
103  }
104  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
107  }
108  }
109  double TMolesMultiphase = 0.0;
110  for (size_t iph = 0; iph < m_numPhases; iph++) {
111  if (! m_VolPhaseList[iph]->m_singleSpecies) {
112  TMolesMultiphase += m_tPhaseMoles_new[iph];
113  }
114  }
116  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
118  m_molNumSpecies_new[kspec] = 0.0;
119  }
120  }
122 
123  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
125  if (! m_SSPhase[kspec]) {
126  size_t iph = m_phaseID[kspec];
127  m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]);
128  }
129  } else {
130  m_molNumSpecies_new[kspec] = 0.0;
131  }
132  }
133  vcs_deltag(0, true, VCS_STATECALC_NEW);
134  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
135  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
136  plogf("%s", pprefix);
137  plogf("%-12.12s", m_speciesName[kspec].c_str());
138  if (kspec < m_numComponents)
139  plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec],
140  m_SSfeSpecies[kspec]);
141  else
142  plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n",
143  m_feSpecies_new[kspec], m_SSfeSpecies[kspec], m_deltaGRxn_new[kspec-m_numComponents]);
144  }
145  }
146  /* ********************************************************** */
147  /* **** ESTIMATE REACTION ADJUSTMENTS *********************** */
148  /* ********************************************************** */
149  double* xtphMax = VCS_DATA_PTR(m_TmpPhase);
150  double* xtphMin = VCS_DATA_PTR(m_TmpPhase2);
151  m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
152  for (size_t iph = 0; iph < m_numPhases; iph++) {
153  xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32);
154  xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32);
155  }
156  for (size_t irxn = 0; irxn < nrxn; ++irxn) {
157  size_t kspec = m_indexRxnToSpecies[irxn];
158  /*
159  * For single species phases, we will not estimate the
160  * mole numbers. If the phase exists, it stays. If it
161  * doesn't exist in the estimate, it doesn't come into
162  * existence here.
163  */
164  if (! m_SSPhase[kspec]) {
165  size_t iph = m_phaseID[kspec];
166  if (m_deltaGRxn_new[irxn] > xtphMax[iph]) {
167  m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph];
168  }
169  if (m_deltaGRxn_new[irxn] < xtphMin[iph]) {
170  m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph];
171  }
172  /*
173  * HKM -> The TMolesMultiphase is a change of mine.
174  * It more evenly distributes the initial moles amongst
175  * multiple multispecies phases according to the
176  * relative values of the standard state free energies.
177  * There is no change for problems with one multispecies
178  * phase.
179  * It cut diamond4.vin iterations down from 62 to 14.
180  */
181  m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase)
182  * exp(-m_deltaGRxn_new[irxn]);
183 
184  for (size_t k = 0; k < m_numComponents; ++k) {
186  }
187 
188  for (iph = 0; iph < m_numPhases; iph++) {
189  m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec];
190  }
191  }
192  }
193  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
194  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
196  plogf("%sdirection (", pprefix);
197  plogf("%-12.12s", m_speciesName[kspec].c_str());
198  plogf(") = %g", m_deltaMolNumSpecies[kspec]);
199  if (m_SSPhase[kspec]) {
200  if (m_molNumSpecies_old[kspec] > 0.0) {
201  plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]);
202  } else {
203  plogf(" (ssPhase doesn't exist -> stability not checked)");
204  }
205  }
206  plogendl();
207  }
208  }
209  }
210  /* *********************************************************** */
211  /* **** KEEP COMPONENT SPECIES POSITIVE ********************** */
212  /* *********************************************************** */
213  double par = 0.5;
214  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
216  if (par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) {
217  par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec];
218  }
219  }
220  }
221  par = 1. / par;
222  if (par <= 1.0 && par > 0.0) {
223  par *= 0.8;
224  } else {
225  par = 1.0;
226  }
227  /* ******************************************** */
228  /* **** CALCULATE NEW MOLE NUMBERS ************ */
229  /* ******************************************** */
230  size_t lt = 0;
231  size_t ikl = 0;
232  double s1 = 0.0;
233  while (true) {
234  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
236  m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec];
237  } else {
238  m_deltaMolNumSpecies[kspec] = 0.0;
239  }
240  }
241  for (size_t kspec = m_numComponents; kspec < nspecies; ++kspec) {
243  if (m_deltaMolNumSpecies[kspec] != 0.0) {
244  m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par;
245  }
246  }
247  }
248  /*
249  * We have a new w[] estimate, go get the
250  * TMoles and m_tPhaseMoles_old[] values
251  */
252  vcs_tmoles();
253  if (lt > 0) {
254  break;
255  }
256  /* ******************************************* */
257  /* **** CONVERGENCE FORCING SECTION ********** */
258  /* ******************************************* */
259  vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
260  vcs_dfe(VCS_STATECALC_OLD, 0, 0, nspecies);
261  double s = 0.0;
262  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
263  s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec];
264  }
265  if (s == 0.0) {
266  break;
267  }
268  if (s < 0.0) {
269  if (ikl == 0) {
270  break;
271  }
272  }
273  /* ***************************************** */
274  /* *** TRY HALF STEP SIZE ****************** */
275  /* ***************************************** */
276  if (ikl == 0) {
277  s1 = s;
278  par *= 0.5;
279  ikl = 1;
280  continue;
281  }
282  /* **************************************************** */
283  /* **** FIT PARABOLA THROUGH HALF AND FULL STEPS ****** */
284  /* **************************************************** */
285  double xl = (1.0 - s / (s1 - s)) * 0.5;
286  if (xl < 0.0) {
287  /* *************************************************** */
288  /* *** POOR DIRECTION, REDUCE STEP SIZE TO 0.2 ******* */
289  /* *************************************************** */
290  par *= 0.2;
291  } else {
292  if (xl > 1.0) {
293  /* *************************************************** */
294  /* **** TOO BIG A STEP, TAKE ORIGINAL FULL STEP ****** */
295  /* *************************************************** */
296  par *= 2.0;
297  } else {
298  /* *************************************************** */
299  /* **** ACCEPT RESULTS OF FORCER ********************* */
300  /* *************************************************** */
301  par = par * 2.0 * xl;
302  }
303  }
304  lt = 1;
305  }
306 
307  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
308  plogf("%s Final Mole Numbers produced by inest:\n",
309  pprefix);
310  plogf("%s SPECIES MOLE_NUMBER\n", pprefix);
311  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
312  plogf("%s ", pprefix);
313  plogf("%-12.12s", m_speciesName[kspec].c_str());
314  plogf(" %g", m_molNumSpecies_old[kspec]);
315  plogendl();
316  }
317  }
318 }
319 
321 {
322  int retn = 0;
323  clockWC tickTock;
324 
325  if (m_doEstimateEquil > 0) {
326  /*
327  * Calculate the elemental abundances
328  */
329  vcs_elab();
330  if (vcs_elabcheck(0)) {
331  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
332  plogf("%s Initial guess passed element abundances on input\n", pprefix);
333  plogf("%s m_doEstimateEquil = 1 so will use the input mole "
334  "numbers as estimates", pprefix);
335  plogendl();
336  }
337  return retn;
338  } else if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
339  plogf("%s Initial guess failed element abundances on input\n", pprefix);
340  plogf("%s m_doEstimateEquil = 1 so will discard input "
341  "mole numbers and find our own estimate", pprefix);
342  plogendl();
343  }
344  }
345 
346  /*
347  * Malloc temporary space for usage in this routine and in
348  * subroutines
349  * sm[ne*ne]
350  * ss[ne]
351  * sa[ne]
352  * aw[m]
353  */
354  std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
355  std::vector<double> ss(m_numElemConstraints, 0.0);
356  std::vector<double> sa(m_numElemConstraints, 0.0);
357  std::vector<double> aw(m_numSpeciesTot+ m_numElemConstraints, 0.0);
358  /*
359  * Go get the estimate of the solution
360  */
361  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
362  plogf("%sGo find an initial estimate for the equilibrium problem",
363  pprefix);
364  plogendl();
365  }
366  double test = -1.0E20;
368  VCS_DATA_PTR(ss), test);
369  /*
370  * Calculate the elemental abundances
371  */
372  vcs_elab();
373 
374  /*
375  * If we still fail to achieve the correct elemental abundances,
376  * try to fix the problem again by calling the main elemental abundances
377  * fixer routine, used in the main program. This
378  * attempts to tweak the mole numbers of the component species to
379  * satisfy the element abundance constraints.
380  *
381  * Note: We won't do this unless we have to since it involves inverting
382  * a matrix.
383  */
384  bool rangeCheck = vcs_elabcheck(1);
385  if (!vcs_elabcheck(0)) {
386  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
387  plogf("%sInitial guess failed element abundances\n", pprefix);
388  plogf("%sCall vcs_elcorr to attempt fix", pprefix);
389  plogendl();
390  }
392  rangeCheck = vcs_elabcheck(1);
393  if (!vcs_elabcheck(0)) {
394  plogf("%sInitial guess still fails element abundance equations\n",
395  pprefix);
396  plogf("%s - Inability to ever satisfy element abundance "
397  "constraints is probable", pprefix);
398  plogendl();
399  retn = -1;
400  } else {
401  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
402  if (rangeCheck) {
403  plogf("%sInitial guess now satisfies element abundances", pprefix);
404  plogendl();
405  } else {
406  plogf("%sElement Abundances RANGE ERROR\n", pprefix);
407  plogf("%s - Initial guess satisfies NC=%d element abundances, "
408  "BUT not NE=%d element abundances", pprefix,
409  m_numComponents, m_numElemConstraints);
410  plogendl();
411  }
412  }
413  }
414  } else {
415  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
416  if (rangeCheck) {
417  plogf("%sInitial guess satisfies element abundances", pprefix);
418  plogendl();
419  } else {
420  plogf("%sElement Abundances RANGE ERROR\n", pprefix);
421  plogf("%s - Initial guess satisfies NC=%d element abundances, "
422  "BUT not NE=%d element abundances", pprefix,
423  m_numComponents, m_numElemConstraints);
424  plogendl();
425  }
426  }
427  }
428 
429  if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
430  plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E", pprefix,
433  plogendl();
434  }
435 
436  /*
437  * Record time
438  */
439  m_VCount->T_Time_inest += tickTock.secondsWC();
440  (m_VCount->T_Calls_Inest)++;
441  return retn;
442 }
443 
444 }
void vcs_inest(double *const aw, double *const sa, double *const sm, double *const ss, double test)
Estimate equilibrium compositions.
Definition: vcs_inest.cpp:21
std::vector< size_t > m_phaseID
Mapping from the species number to the phase number.
Definition: vcs_solve.h:1832
std::vector< double > m_TmpPhase2
Temporary vector of length NPhase.
Definition: vcs_solve.h:1725
double vcs_Total_Gibbs(double *w, double *fe, double *tPhMoles)
Calculate the total dimensionless Gibbs free energy.
Definition: vcs_Gibbs.cpp:16
int T_Calls_Inest
Current number of times the initial thermo equilibrium estimator has been called. ...
Definition: vcs_internal.h:68
VCS_COUNTERS * m_VCount
Timing and iteration counters for the vcs object.
Definition: vcs_solve.h:1979
Declarations for a simple class that implements an Ansi C wall clock timer (see Cantera::clockWC).
Array2D m_stoichCoeffRxnMatrix
Stoichiometric coefficient matrix for the reaction mechanism expressed in Reduced Canonical Form...
Definition: vcs_solve.h:1552
std::vector< double > m_feSpecies_new
Dimensionless new free energy for all the species in the mechanism at the new tentatite T...
Definition: vcs_solve.h:1593
int vcs_elcorr(double aa[], double x[])
Definition: vcs_elem.cpp:103
#define VCS_DATA_PTR(vvv)
Points to the data in a std::vector<> object.
Definition: vcs_internal.h:18
void vcs_dfe(const int stateCalc, const int ll, const size_t lbot, const size_t ltop)
Calculate the dimensionless chemical potentials of all species or of certain groups of species...
std::vector< vcs_VolPhase * > m_VolPhaseList
Array of Phase Structures. Length = number of phases.
Definition: vcs_solve.h:1869
double vcs_tmoles()
Calculates the total number of moles of species in all phases.
The class provides the wall clock timer in seconds.
Definition: clockWC.h:51
void vcs_deltag(const int l, const bool doDeleted, const int vcsState, const bool alterZeroedPhases=true)
This subroutine calculates reaction free energy changes for all noncomponent formation reactions...
std::vector< double > m_molNumSpecies_old
Total moles of the species.
Definition: vcs_solve.h:1612
std::vector< std::string > m_elementName
Vector of strings containing the element names.
Definition: vcs_solve.h:1845
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and E...
Header for the object representing each phase within vcs.
#define VCS_SPECIES_TYPE_MOLNUM
Unknown refers to mole number of a single species.
Definition: vcs_defs.h:343
int m_doEstimateEquil
Setting for whether to do an initial estimate.
Definition: vcs_solve.h:1605
int vcs_inest_TP()
Create an initial estimate of the solution to the thermodynamic equilibrium problem.
Definition: vcs_inest.cpp:320
double secondsWC()
Returns the wall clock time in seconds since the last reset.
Definition: clockWC.cpp:35
std::vector< double > m_tPhaseMoles_new
total kmols of species in each phase in the tentative soln vector
Definition: vcs_solve.h:1719
size_t m_numElemConstraints
Number of element constraints in the problem.
Definition: vcs_solve.h:1499
size_t m_numSpeciesTot
Total number of species in the problems.
Definition: vcs_solve.h:1493
std::vector< int > m_speciesUnknownType
Specifies the species unknown type.
Definition: vcs_solve.h:1625
#define VCS_STATECALC_NEW
State Calculation based on the new or tentative mole numbers.
Definition: vcs_defs.h:368
double T_Time_inest
Time spent in initial estimator.
Definition: vcs_internal.h:86
std::vector< double > m_tPhaseMoles_old
Total kmols of species in each phase.
Definition: vcs_solve.h:1710
std::vector< double > m_deltaPhaseMoles
Change in the total moles in each phase.
Definition: vcs_solve.h:1731
int m_debug_print_lvl
Debug printing lvl.
Definition: vcs_solve.h:1995
size_t m_numComponents
Number of components calculated for the problem.
Definition: vcs_solve.h:1502
std::vector< double > m_molNumSpecies_new
Tentative value of the mole number vector.
Definition: vcs_solve.h:1644
std::vector< double > m_SSfeSpecies
Standard state chemical potentials for species K at the current temperature and pressure.
Definition: vcs_solve.h:1577
std::vector< char > m_SSPhase
Boolean indicating whether a species belongs to a single-species phase.
Definition: vcs_solve.h:1836
std::vector< std::string > m_speciesName
Species string name for the kth species.
Definition: vcs_solve.h:1839
std::vector< double > m_TmpPhase
Temporary vector of length NPhase.
Definition: vcs_solve.h:1722
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
Definition: vcs_defs.h:365
Array2D m_deltaMolNumPhase
Change in the number of moles of phase, iphase, due to the noncomponent formation reaction...
Definition: vcs_solve.h:1632
Array2D m_formulaMatrix
Formula matrix for the problem.
Definition: vcs_solve.h:1534
std::vector< int > m_elementActive
Specifies whether an element constraint is active.
Definition: vcs_solve.h:1866
#define plogendl()
define this Cantera function to replace cout << endl;
Definition: vcs_internal.h:31
void vcs_elab()
Computes the current elemental abundances vector.
Definition: vcs_elem.cpp:13
int vcs_setMolesLinProg()
Estimate the initial mole numbers by constrained linear programming.
int vcs_basopt(const bool doJustComponents, double aw[], double sa[], double sm[], double ss[], double test, bool *const usedZeroedSpecies)
Choose the optimum species basis for the calculations.
std::vector< double > m_deltaMolNumSpecies
Reaction Adjustments for each species during the current step.
Definition: vcs_solve.h:1674
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:24
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
Definition: vcs_defs.h:352
std::vector< size_t > m_indexRxnToSpecies
Mapping between the species index for noncomponent species and the full species index.
Definition: vcs_solve.h:1821
size_t m_numPhases
Number of Phases in the problem.
Definition: vcs_solve.h:1526
size_t m_numRxnTot
Total number of non-component species in the problem.
Definition: vcs_solve.h:1505
std::vector< double > TPhInertMoles
Total kmoles of inert to add to each phase.
Definition: vcs_solve.h:1755
std::vector< double > m_elemAbundancesGoal
Element abundances vector Goals.
Definition: vcs_solve.h:1695
std::vector< double > m_feSpecies_old
Free energy vector from the start of the current iteration.
Definition: vcs_solve.h:1584
std::vector< double > m_deltaGRxn_new
Delta G(irxn) for the noncomponent species in the mechanism.
Definition: vcs_solve.h:1654
bool vcs_elabcheck(int ibound)
Definition: vcs_elem.cpp:25