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