Cantera  2.3.0
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 // This file is part of Cantera. See License.txt in the top-level directory or
7 // at http://www.cantera.org/license.txt for license and copyright information.
8 
11 
12 #include "cantera/base/clockWC.h"
13 
14 namespace Cantera
15 {
16 
17 static char pprefix[20] = " --- vcs_inest: ";
18 
19 void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm,
20  double* const ss, double test)
21 {
22  size_t nspecies = m_numSpeciesTot;
23  size_t nrxn = m_numRxnTot;
24 
25  // CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB AND
26  // molNum(I) .GE. 0.0. Note, both of these programs do this.
28 
29  if (m_debug_print_lvl >= 2) {
30  plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n",
31  pprefix);
32  plogf("%s SPECIES MOLE_NUMBER -SS_ChemPotential\n", pprefix);
33  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
34  plogf("%s ", pprefix);
35  plogf("%-12.12s", m_speciesName[kspec]);
36  plogf(" %15.5g %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]);
37  }
38  plogf("%s Element Abundance Agreement returned from linear "
39  "programming (vcs_inest initial guess):",
40  pprefix);
41  plogendl();
42  plogf("%s Element Goal Actual\n", pprefix);
43  for (size_t j = 0; j < m_numElemConstraints; j++) {
44  if (m_elementActive[j]) {
45  double tmp = 0.0;
46  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
47  tmp += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
48  }
49  plogf("%s ", pprefix);
50  plogf(" %-9.9s", m_elementName[j]);
51  plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp);
52  }
53  }
54  plogendl();
55  }
56 
57  // Make sure all species have positive definite mole numbers Set voltages to
58  // zero for now, until we figure out what to do
59  m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0);
60  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
62  if (m_molNumSpecies_old[kspec] <= 0.0) {
63  // HKM Should eventually include logic here for non SS phases
64  if (!m_SSPhase[kspec]) {
65  m_molNumSpecies_old[kspec] = 1.0e-30;
66  }
67  }
68  } else {
69  m_molNumSpecies_old[kspec] = 0.0;
70  }
71  }
72 
73  // Now find the optimized basis that spans the stoichiometric coefficient
74  // matrix
75  bool conv;
76  vcs_basopt(false, aw, sa, sm, ss, test, &conv);
77 
78  // CALCULATE TOTAL MOLES, CHEMICAL POTENTIALS OF BASIS
79 
80  // Calculate TMoles and m_tPhaseMoles_old[]
81  vcs_tmoles();
82 
83  // m_tPhaseMoles_new[] will consist of just the component moles
84  for (size_t iph = 0; iph < m_numPhases; iph++) {
85  m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20;
86  }
87  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
90  }
91  }
92  double TMolesMultiphase = 0.0;
93  for (size_t iph = 0; iph < m_numPhases; iph++) {
94  if (! m_VolPhaseList[iph]->m_singleSpecies) {
95  TMolesMultiphase += m_tPhaseMoles_new[iph];
96  }
97  }
99  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
101  m_molNumSpecies_new[kspec] = 0.0;
102  }
103  }
105 
106  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
108  if (! m_SSPhase[kspec]) {
109  size_t iph = m_phaseID[kspec];
110  m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]);
111  }
112  } else {
113  m_molNumSpecies_new[kspec] = 0.0;
114  }
115  }
116  vcs_deltag(0, true, VCS_STATECALC_NEW);
117  if (m_debug_print_lvl >= 2) {
118  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
119  plogf("%s", pprefix);
120  plogf("%-12.12s", m_speciesName[kspec]);
121  if (kspec < m_numComponents) {
122  plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec],
123  m_SSfeSpecies[kspec]);
124  } else {
125  plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n",
127  }
128  }
129  }
130 
131  // ESTIMATE REACTION ADJUSTMENTS
132  vector_fp& xtphMax = m_TmpPhase;
133  vector_fp& xtphMin = m_TmpPhase2;
134  m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
135  for (size_t iph = 0; iph < m_numPhases; iph++) {
136  xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32);
137  xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32);
138  }
139  for (size_t irxn = 0; irxn < nrxn; ++irxn) {
140  size_t kspec = m_indexRxnToSpecies[irxn];
141 
142  // For single species phases, we will not estimate the mole numbers. If
143  // the phase exists, it stays. If it doesn't exist in the estimate, it
144  // doesn't come into existence here.
145  if (! m_SSPhase[kspec]) {
146  size_t iph = m_phaseID[kspec];
147  if (m_deltaGRxn_new[irxn] > xtphMax[iph]) {
148  m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph];
149  }
150  if (m_deltaGRxn_new[irxn] < xtphMin[iph]) {
151  m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph];
152  }
153 
154  // HKM -> The TMolesMultiphase is a change of mine. It more evenly
155  // distributes the initial moles amongst multiple multispecies
156  // phases according to the relative values of the standard state
157  // free energies. There is no change for problems with one
158  // multispecies phase. It cut diamond4.vin iterations down from 62
159  // to 14.
160  m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase)
161  * exp(-m_deltaGRxn_new[irxn]);
162 
163  for (size_t k = 0; k < m_numComponents; ++k) {
165  }
166 
167  for (iph = 0; iph < m_numPhases; iph++) {
168  m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec];
169  }
170  }
171  }
172  if (m_debug_print_lvl >= 2) {
173  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
175  plogf("%sdirection (", pprefix);
176  plogf("%-12.12s", m_speciesName[kspec]);
177  plogf(") = %g", m_deltaMolNumSpecies[kspec]);
178  if (m_SSPhase[kspec]) {
179  if (m_molNumSpecies_old[kspec] > 0.0) {
180  plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]);
181  } else {
182  plogf(" (ssPhase doesn't exist -> stability not checked)");
183  }
184  }
185  plogendl();
186  }
187  }
188  }
189 
190  // KEEP COMPONENT SPECIES POSITIVE
191  double par = 0.5;
192  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
194  par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) {
195  par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec];
196  }
197  }
198  par = 1. / par;
199  if (par <= 1.0 && par > 0.0) {
200  par *= 0.8;
201  } else {
202  par = 1.0;
203  }
204 
205  // CALCULATE NEW MOLE NUMBERS
206  size_t lt = 0;
207  size_t ikl = 0;
208  double s1 = 0.0;
209  while (true) {
210  for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
212  m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec];
213  } else {
214  m_deltaMolNumSpecies[kspec] = 0.0;
215  }
216  }
217  for (size_t kspec = m_numComponents; kspec < nspecies; ++kspec) {
219  m_deltaMolNumSpecies[kspec] != 0.0) {
220  m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par;
221  }
222  }
223 
224  // We have a new w[] estimate, go get the TMoles and m_tPhaseMoles_old[]
225  // values
226  vcs_tmoles();
227  if (lt > 0) {
228  break;
229  }
230 
231  // CONVERGENCE FORCING SECTION
232  vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
233  vcs_dfe(VCS_STATECALC_OLD, 0, 0, nspecies);
234  double s = 0.0;
235  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
236  s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec];
237  }
238  if (s == 0.0) {
239  break;
240  }
241  if (s < 0.0 && ikl == 0) {
242  break;
243  }
244 
245  // TRY HALF STEP SIZE
246  if (ikl == 0) {
247  s1 = s;
248  par *= 0.5;
249  ikl = 1;
250  continue;
251  }
252 
253  // FIT PARABOLA THROUGH HALF AND FULL STEPS
254  double xl = (1.0 - s / (s1 - s)) * 0.5;
255  if (xl < 0.0) {
256  // POOR DIRECTION, REDUCE STEP SIZE TO 0.2
257  par *= 0.2;
258  } else {
259  if (xl > 1.0) {
260  // TOO BIG A STEP, TAKE ORIGINAL FULL STEP
261  par *= 2.0;
262  } else {
263  // ACCEPT RESULTS OF FORCER
264  par = par * 2.0 * xl;
265  }
266  }
267  lt = 1;
268  }
269 
270  if (m_debug_print_lvl >= 2) {
271  plogf("%s Final Mole Numbers produced by inest:\n",
272  pprefix);
273  plogf("%s SPECIES MOLE_NUMBER\n", pprefix);
274  for (size_t kspec = 0; kspec < nspecies; ++kspec) {
275  plogf("%s ", pprefix);
276  plogf("%-12.12s", m_speciesName[kspec]);
277  plogf(" %g", m_molNumSpecies_old[kspec]);
278  plogendl();
279  }
280  }
281 }
282 
284 {
285  int retn = 0;
286  clockWC tickTock;
287  if (m_doEstimateEquil > 0) {
288  // Calculate the elemental abundances
289  vcs_elab();
290  if (vcs_elabcheck(0)) {
291  if (m_debug_print_lvl >= 2) {
292  plogf("%s Initial guess passed element abundances on input\n", pprefix);
293  plogf("%s m_doEstimateEquil = 1 so will use the input mole "
294  "numbers as estimates", pprefix);
295  plogendl();
296  }
297  return retn;
298  } else if (m_debug_print_lvl >= 2) {
299  plogf("%s Initial guess failed element abundances on input\n", pprefix);
300  plogf("%s m_doEstimateEquil = 1 so will discard input "
301  "mole numbers and find our own estimate", pprefix);
302  plogendl();
303  }
304  }
305 
306  // temporary space for usage in this routine and in subroutines
311 
312  // Go get the estimate of the solution
313  if (m_debug_print_lvl >= 2) {
314  plogf("%sGo find an initial estimate for the equilibrium problem",
315  pprefix);
316  plogendl();
317  }
318  double test = -1.0E20;
319  vcs_inest(&aw[0], &sa[0], &sm[0], &ss[0], test);
320 
321  // Calculate the elemental abundances
322  vcs_elab();
323 
324  // If we still fail to achieve the correct elemental abundances, try to fix
325  // the problem again by calling the main elemental abundances fixer routine,
326  // used in the main program. This attempts to tweak the mole numbers of the
327  // component species to satisfy the element abundance constraints.
328  //
329  // Note: We won't do this unless we have to since it involves inverting a
330  // matrix.
331  bool rangeCheck = vcs_elabcheck(1);
332  if (!vcs_elabcheck(0)) {
333  if (m_debug_print_lvl >= 2) {
334  plogf("%sInitial guess failed element abundances\n", pprefix);
335  plogf("%sCall vcs_elcorr to attempt fix", pprefix);
336  plogendl();
337  }
338  vcs_elcorr(&sm[0], &aw[0]);
339  rangeCheck = vcs_elabcheck(1);
340  if (!vcs_elabcheck(0)) {
341  plogf("%sInitial guess still fails element abundance equations\n",
342  pprefix);
343  plogf("%s - Inability to ever satisfy element abundance "
344  "constraints is probable", pprefix);
345  plogendl();
346  retn = -1;
347  } else {
348  if (m_debug_print_lvl >= 2) {
349  if (rangeCheck) {
350  plogf("%sInitial guess now satisfies element abundances", pprefix);
351  plogendl();
352  } else {
353  plogf("%sElement Abundances RANGE ERROR\n", pprefix);
354  plogf("%s - Initial guess satisfies NC=%d element abundances, "
355  "BUT not NE=%d element abundances", pprefix,
357  plogendl();
358  }
359  }
360  }
361  } else {
362  if (m_debug_print_lvl >= 2) {
363  if (rangeCheck) {
364  plogf("%sInitial guess satisfies element abundances", pprefix);
365  plogendl();
366  } else {
367  plogf("%sElement Abundances RANGE ERROR\n", pprefix);
368  plogf("%s - Initial guess satisfies NC=%d element abundances, "
369  "BUT not NE=%d element abundances", pprefix,
371  plogendl();
372  }
373  }
374  }
375 
376  if (m_debug_print_lvl >= 2) {
377  plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E", pprefix,
379  &m_tPhaseMoles_old[0]));
380  plogendl();
381  }
382 
383  // Record time
384  m_VCount->T_Time_inest += tickTock.secondsWC();
386  return retn;
387 }
388 
389 }
void vcs_inest(double *const aw, double *const sa, double *const sm, double *const ss, double test)
Estimate equilibrium compositions.
Definition: vcs_inest.cpp:19
std::vector< size_t > m_phaseID
Mapping from the species number to the phase number.
Definition: vcs_solve.h:1703
double vcs_Total_Gibbs(double *w, double *fe, double *tPhMoles)
Calculate the total dimensionless Gibbs free energy.
Definition: vcs_Gibbs.cpp:14
int T_Calls_Inest
Current number of times the initial thermo equilibrium estimator has been called. ...
Definition: vcs_internal.h:62
vector_int m_speciesUnknownType
Specifies the species unknown type.
Definition: vcs_solve.h:1511
vector_fp m_TmpPhase
Temporary vector of length NPhase.
Definition: vcs_solve.h:1604
VCS_COUNTERS * m_VCount
Timing and iteration counters for the vcs object.
Definition: vcs_solve.h:1849
vector_fp m_SSfeSpecies
Standard state chemical potentials for species K at the current temperature and pressure.
Definition: vcs_solve.h:1465
vector_fp m_molNumSpecies_old
Total moles of the species.
Definition: vcs_solve.h:1498
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:1441
int vcs_elcorr(double aa[], double x[])
Definition: vcs_elem.cpp:97
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:1740
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:44
vector_fp m_feSpecies_new
Dimensionless new free energy for all the species in the mechanism at the new tentative T...
Definition: vcs_solve.h:1481
vector_fp m_deltaMolNumSpecies
Reaction Adjustments for each species during the current step.
Definition: vcs_solve.h:1559
vector_fp m_tPhaseMoles_new
total kmols of species in each phase in the tentative soln vector
Definition: vcs_solve.h:1601
vector_fp m_deltaGRxn_new
Delta G(irxn) for the noncomponent species in the mechanism.
Definition: vcs_solve.h:1539
vector_int m_elementActive
Specifies whether an element constraint is active.
Definition: vcs_solve.h:1737
std::vector< std::string > m_elementName
Vector of strings containing the element names.
Definition: vcs_solve.h:1716
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:301
int m_doEstimateEquil
Setting for whether to do an initial estimate.
Definition: vcs_solve.h:1491
int vcs_inest_TP()
Create an initial estimate of the solution to the thermodynamic equilibrium problem.
Definition: vcs_inest.cpp:283
double secondsWC()
Returns the wall clock time in seconds since the last reset.
Definition: clockWC.cpp:32
size_t m_numElemConstraints
Number of element constraints in the problem.
Definition: vcs_solve.h:1393
size_t m_numSpeciesTot
Total number of species in the problems.
Definition: vcs_solve.h:1387
vector_fp m_deltaPhaseMoles
Change in the total moles in each phase.
Definition: vcs_solve.h:1613
#define VCS_STATECALC_NEW
State Calculation based on the new or tentative mole numbers.
Definition: vcs_defs.h:323
double T_Time_inest
Time spent in initial estimator.
Definition: vcs_internal.h:80
vector_fp m_feSpecies_old
Free energy vector from the start of the current iteration.
Definition: vcs_solve.h:1472
vector_fp TPhInertMoles
Total kmoles of inert to add to each phase.
Definition: vcs_solve.h:1626
int m_debug_print_lvl
Debug printing lvl.
Definition: vcs_solve.h:1863
size_t m_numComponents
Number of components calculated for the problem.
Definition: vcs_solve.h:1396
vector_fp m_elemAbundancesGoal
Element abundances vector Goals.
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:1707
vector_fp m_tPhaseMoles_old
Total kmols of species in each phase.
Definition: vcs_solve.h:1592
std::vector< std::string > m_speciesName
Species string name for the kth species.
Definition: vcs_solve.h:1710
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...
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
Definition: vcs_defs.h:320
Array2D m_deltaMolNumPhase
Change in the number of moles of phase, iphase, due to the noncomponent formation reaction...
Definition: vcs_solve.h:1518
Array2D m_formulaMatrix
Formula matrix for the problem.
Definition: vcs_solve.h:1422
#define plogendl()
define this Cantera function to replace cout << endl;
Definition: vcs_internal.h:25
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:157
void vcs_elab()
Computes the current elemental abundances vector.
Definition: vcs_elem.cpp:17
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.
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:18
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
Definition: vcs_defs.h:309
vector_fp m_TmpPhase2
Temporary vector of length NPhase.
Definition: vcs_solve.h:1607
Namespace for the Cantera kernel.
Definition: application.cpp:29
std::vector< size_t > m_indexRxnToSpecies
Mapping between the species index for noncomponent species and the full species index.
Definition: vcs_solve.h:1692
size_t m_numPhases
Number of Phases in the problem.
Definition: vcs_solve.h:1414
size_t m_numRxnTot
Total number of non-component species in the problem.
Definition: vcs_solve.h:1399
vector_fp m_molNumSpecies_new
Tentative value of the mole number vector.
Definition: vcs_solve.h:1529
bool vcs_elabcheck(int ibound)
Definition: vcs_elem.cpp:29