Cantera  2.0
vcs_setMolesLinProg.cpp
Go to the documentation of this file.
1 /*!
2  * @file vcs_setMolesLinProg.cpp
3  *
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 #include "vcs_species_thermo.h"
15 
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cmath>
19 #include <iostream>
20 
21 #ifdef hpux
22 #define dbocls_ dbocls
23 #endif
24 #ifdef DEBUG_MODE
25 //extern int vcs_debug_print_lvl;
26 #endif
27 #ifndef MAX
28 #define MAX(x,y) (( (x) > (y) ) ? (x) : (y))
29 #endif
30 
31 
32 extern "C" void dbocls_(double* W, int* MDW, int* MCON, int* MROWS,
33  int* NCOLS,
34  double* BL, double* BU, int* IND, int* IOPT,
35  double* X, double* RNORMC, double* RNORM,
36  int* MODE, double* RW, int* IW);
37 
38 using namespace std;
39 
40 namespace VCSnonideal
41 {
42 
43 #ifdef DEBUG_MODE
44 static void printProgress(const vector<string> &spName,
45  const vector<double> &soln,
46  const vector<double> &ff)
47 {
48  int nsp = soln.size();
49  double sum = 0.0;
50  plogf(" --- Summary of current progress:\n");
51  plogf(" --- Name Moles - SSGibbs \n");
52  plogf(" -------------------------------------------------------------------------------------\n");
53  for (int k = 0; k < nsp; k++) {
54  plogf(" --- %20s %12.4g - %12.4g\n", spName[k].c_str(), soln[k], ff[k]);
55  sum += soln[k] * ff[k];
56  }
57  plogf(" --- Total sum to be minimized = %g\n", sum);
58 }
59 #endif
60 
61 #ifdef ALTLINPROG
62 //! Estimate the initial mole numbers.
63 /*!
64  * This is done by running
65  * each reaction as far forward or backward as possible, subject
66  * to the constraint that all mole numbers remain
67  * non-negative. Reactions for which \f$ \Delta \mu^0 \f$ are
68  * positive are run in reverse, and ones for which it is negative
69  * are run in the forward direction. The end result is equivalent
70  * to solving the linear programming problem of minimizing the
71  * linear Gibbs function subject to the element and
72  * non-negativity constraints.
73  */
74 int VCS_SOLVE::vcs_setMolesLinProg()
75 {
76  size_t ik, irxn;
77  double test = -1.0E-10;
78 
79 #ifdef DEBUG_MODE
80  std::string pprefix(" --- seMolesLinProg ");
81  if (m_debug_print_lvl >= 2) {
82  plogf(" --- call setInitialMoles\n");
83  }
84 #endif
85 
86 
87  // m_mu are standard state chemical potentials
88  // Boolean on the end specifies standard chem potentials
89  // m_mix->getValidChemPotentials(not_mu, DATA_PTR(m_mu), true);
90  // -> This is already done coming into the routine.
91  double dg_rt;
92 
93  int idir;
94  double nu;
95  double delta_xi, dxi_min = 1.0e10;
96  bool redo = true;
97  int retn;
98  int iter = 0;
99  bool abundancesOK = true;
100  bool usedZeroedSpecies;
101 
102  std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
103  std::vector<double> ss(m_numElemConstraints, 0.0);
104  std::vector<double> sa(m_numElemConstraints, 0.0);
105  std::vector<double> wx(m_numElemConstraints, 0.0);
106  std::vector<double> aw(m_numSpeciesTot, 0.0);
107 
108  for (ik = 0; ik < m_numSpeciesTot; ik++) {
109  if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) {
110  m_molNumSpecies_old[ik] = MAX(0.0, m_molNumSpecies_old[ik]);
111  }
112  }
113 
114 #ifdef DEBUG_MODE
115  if (m_debug_print_lvl >= 2) {
116  printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
117  }
118 #endif
119 
120  while (redo) {
121 
122  if (!vcs_elabcheck(0)) {
123 #ifdef DEBUG_MODE
124  if (m_debug_print_lvl >= 2) {
125  plogf("%s Mole numbers failing element abundances\n", pprefix.c_str());
126  plogf("%sCall vcs_elcorr to attempt fix\n", pprefix.c_str());
127  }
128 #endif
129  retn = vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
130  if (retn >= 2) {
131  abundancesOK = false;
132  } else {
133  abundancesOK = true;
134  }
135  } else {
136  abundancesOK = true;
137  }
138  /*
139  * Now find the optimized basis that spans the stoichiometric
140  * coefficient matrix, based on the current composition, m_molNumSpecies_old[]
141  * We also calculate sc[][], the reaction matrix.
142  */
143  retn = vcs_basopt(false, VCS_DATA_PTR(aw), VCS_DATA_PTR(sa),
144  VCS_DATA_PTR(sm), VCS_DATA_PTR(ss),
145  test, &usedZeroedSpecies);
146  if (retn != VCS_SUCCESS) {
147  return retn;
148  }
149 
150 #ifdef DEBUG_MODE
151  if (m_debug_print_lvl >= 2) {
152  plogf("iteration %d\n", iter);
153  }
154 #endif
155  redo = false;
156  iter++;
157  if (iter > 15) {
158  break;
159  }
160 
161  // loop over all reactions
162  for (irxn = 0; irxn < m_numRxnTot; irxn++) {
163 
164  // dg_rt is the Delta_G / RT value for the reaction
165  ik = m_numComponents + irxn;
166  dg_rt = m_SSfeSpecies[ik];
167  dxi_min = 1.0e10;
168  const double* sc_irxn = m_stoichCoeffRxnMatrix[irxn];
169  for (size_t jcomp = 0; jcomp < m_numElemConstraints; jcomp++) {
170  dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp];
171  }
172  // fwd or rev direction.
173  // idir > 0 implies increasing the current species
174  // idir < 0 implies decreasing the current species
175  idir = (dg_rt < 0.0 ? 1 : -1);
176  if (idir < 0) {
177  dxi_min = m_molNumSpecies_old[ik];
178  }
179 
180  for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) {
181  nu = sc_irxn[jcomp];
182 
183  // set max change in progress variable by
184  // non-negativity requirement
185  if (nu*idir < 0) {
186  delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu);
187  // if a component has nearly zero moles, redo
188  // with a new set of components
189  if (!redo) {
190  if (delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) {
191 #ifdef DEBUG_MODE
192  if (m_debug_print_lvl >= 2) {
193  plogf(" --- Component too small: %s\n", m_speciesName[jcomp].c_str());
194  }
195 #endif
196  redo = true;
197  }
198  }
199  if (delta_xi < dxi_min) {
200  dxi_min = delta_xi;
201  }
202  }
203  }
204 
205  // step the composition by dxi_min, check against zero, since
206  // we are zeroing components and species on every step.
207  // Redo the iteration, if a component went from positive to zero on this step.
208  double dsLocal = idir*dxi_min;
209  m_molNumSpecies_old[ik] += dsLocal;
210  m_molNumSpecies_old[ik] = MAX(0.0, m_molNumSpecies_old[ik]);
211  for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) {
212  bool full = false;
213  if (m_molNumSpecies_old[jcomp] > 1.0E-15) {
214  full = true;
215  }
216  m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal;
217  m_molNumSpecies_old[jcomp] = MAX(0.0, m_molNumSpecies_old[jcomp]);
218  if (full) {
219  if (m_molNumSpecies_old[jcomp] < 1.0E-60) {
220  redo = true;
221  }
222  }
223  }
224  }
225 
226  // set the moles of the phase objects to match
227  // updateMixMoles();
228  // Update the phase objects with the contents of the m_molNumSpecies_old vector
229  // vcs_updateVP(0);
230 #ifdef DEBUG_MODE
231  if (m_debug_print_lvl >= 2) {
232  printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
233  }
234 #endif
235  }
236 
237 #ifdef DEBUG_MODE
238  if (m_debug_print_lvl == 1) {
239  printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
240  plogf(" --- setInitialMoles end\n");
241  }
242 #endif
243  retn = 0;
244  if (!abundancesOK) {
245  retn = -1;
246  } else if (iter > 15) {
247  retn = 1;
248  }
249  return retn;
250 }
251 
252 #else // ALTLINPROG
253 
254 int linprogmax(double* XMOLES, double* CC, double* AX, double* BB,
255  size_t NE, size_t M, size_t NE0)
256 
257 /*-----------------------------------------------------------------------
258 * Find XMOLES(I), i = 1, M such that
259 * Maximize CC dot W, subject to the NE constraints:
260 *
261 * [AX] [XMOLES] = [BB]
262 * and XMOLES(i) > 0
263 *
264 * Input
265 * ---------
266 * AX(NE, M) - matrix of constraints AX(I,J) = ax(i + j*ne0)
267 * BB(NE) - contraint values
268 * CC(M) - Vector of "Good Values" to maximize
269 *
270 * Output
271 * ---------
272 * XMOLES(M) - optimal value of XMOLES()
273 *----------------------------------------------------------------------*/
274 {
275  int MROWS, MCON, NCOLS, NX, NI, MDW, i, j, MODE;
276  double sum, F[1], RNORMC, RNORM, *W, *BL, *BU, *RW, *X;
277  int* IND, *IW, *IOPT;
278 
279  MROWS = 1;
280  MCON = (int) NE;
281  NCOLS = (int) M;
282  MDW = MCON + NCOLS;
283  NX = 0;
284  NI = 0;
285 
286  sum = 0.0;
287  for (i = 0; i < NCOLS; i++) {
288  sum += fabs(CC[i]);
289  }
290  F[0] = sum * 1000.;
291  if (F[0] <= 0.0) {
292  F[0] = 1000.;
293  }
294 
295  BL = (double*) malloc(2*(NCOLS+MCON) * sizeof(double));
296  BU = BL + (NCOLS+MCON);
297  IND = (int*) malloc((NCOLS+MCON) * sizeof(int));
298  RW = (double*) malloc((6*NCOLS + 5*MCON) * sizeof(double));
299  IW = (int*) malloc((2*NCOLS + 2*MCON) * sizeof(int));
300  IOPT = (int*) malloc((17 + NI) * sizeof(int));
301  X = (double*) malloc((2*(NCOLS+MCON) + 2 + NX) * sizeof(double));
302  W = (double*) malloc((MDW*(NCOLS+MCON+1)) * sizeof(double));
303  if (W == NULL) {
304  plogf("linproxmax ERROR: can not malloc memory of size %d bytes\n",
305  (int)((MDW*(NCOLS+MCON+1)) * sizeof(double)));
306  if (BL != NULL) {
307  free((void*) BL);
308  }
309  if (IND != NULL) {
310  free((void*) IND);
311  }
312  if (RW != NULL) {
313  free((void*) RW);
314  }
315  if (IW != NULL) {
316  free((void*) IW);
317  }
318  if (IOPT != NULL) {
319  free((void*) IOPT);
320  }
321  if (W != NULL) {
322  free((void*) W);
323  }
324  return -1;
325  }
326  for (j = 0; j < MCON; j++) {
327  for (i = 0; i < NCOLS; i++) {
328  W[j + i*MDW] = AX[j + i*NE0];
329  }
330  }
331  for (i = 0; i < NCOLS; i++) {
332  W[MCON + i*MDW] = CC[i];
333  }
334  W[MCON + (NCOLS)*MDW] = F[0];
335  IOPT[0] = 99;
336 
337  for (j = 0; j < NCOLS; j++) {
338  IND[j] = 1;
339  BL[j] = 0.0;
340  BU[j] = 1.0e200;
341  }
342  for (j = 0; j < MCON; j++) {
343  IND[j + NCOLS] = 3;
344  BL[j + NCOLS] = BB[j];
345  BU[j + NCOLS] = BL[j + NCOLS];
346  }
347 
348 
349  dbocls_(W, &MDW, &MCON, &MROWS, &NCOLS, BL, BU, IND, IOPT,
350  X, &RNORMC, &RNORM, &MODE, RW, IW);
351  if (MODE != 0) {
352  plogf("Return from DBOCLS was not normal, MODE = %d\n", MODE);
353  plogf(" refer to subroutine DBOCLS for resolution\n");
354  plogf(" RNORMC = %g\n", RNORMC);
355  }
356 
357  for (j = 0; j < NCOLS; j++) {
358  XMOLES[j] = X[j];
359  }
360 #ifdef DEBUG_MODE
361  //sum = 0.0;
362  //for (j = 0; j < NCOLS; j++) {
363  // sum += XMOLES[j] * CC[j];
364  //}
365  //if (vcs_debug_print_lvl >= 2) {
366  // plogf(" -- linmaxc: Final Maximized Value = %g\n", sum);
367  //}
368 #endif
369 
370  free((void*)W);
371  free((void*)BL);
372  free((void*)IND);
373  free((void*)RW);
374  free((void*)IW);
375  free((void*)IOPT);
376  free((void*)X);
377 
378  return 0;
379 }
380 #endif // ALTLINPROG
381 }