Cantera  2.1.2
vcs_rank.cpp
Go to the documentation of this file.
1 /*!
2  * @file vcs_rank.cpp
3  * Header file for the internal class that holds the problem.
4  */
5 
6 /*
7  * Copyright (2005) Sandia Corporation. Under the terms of
8  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
9  * U.S. Government retains certain rights in this software.
10  */
11 
14 #include "cantera/equil/vcs_prob.h"
15 
19 
20 #include "cantera/base/clockWC.h"
22 
23 #include <cstdio>
24 using namespace std;
25 
26 namespace VCSnonideal {
27  static int basisOptMax1(const double * const molNum,
28  const int n) {
29  // int largest = 0;
30 
31  for (int i = 0; i < n; ++i) {
32 
33  if (molNum[i] > -1.0E200 && fabs(molNum[i]) > 1.0E-13) {
34  return i;
35  }
36  }
37  for (int i = 0; i < n; ++i) {
38 
39  if (molNum[i] > -1.0E200) {
40  return i;
41  }
42  }
43  return n-1;
44  }
45 
46  int VCS_SOLVE::vcs_rank(const double * awtmp, size_t numSpecies, const double matrix[], size_t numElemConstraints,
47  std::vector<size_t> &compRes, std::vector<size_t>& elemComp, int * const usedZeroedSpecies) const
48  {
49 
50  int lindep;
51  size_t j, k, jl, i, l, ml;
52  int numComponents = 0;
53 
54  compRes.clear();
55  elemComp.clear();
56  vector<double> sm(numElemConstraints*numSpecies);
57  vector<double> sa(numSpecies);
58  vector<double> ss(numSpecies);
59 
60  double test = -0.2512345E298;
61 #ifdef DEBUG_MODE
62  if (m_debug_print_lvl >= 2) {
63  plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n");
64  plogf(" --- Subroutine vcs_rank called to ");
65  plogf("calculate the rank and independent rows /colums of the following matrix\n");
66  if (m_debug_print_lvl >= 5) {
67  plogf(" --- Species | ");
68  for (j = 0; j < numElemConstraints; j++) {
69  plogf(" ");
70  plogf(" %3d ", j);
71  }
72  plogf("\n");
73  plogf(" --- -----------");
74  for (j = 0; j < numElemConstraints; j++) {
75  plogf("---------");
76  }
77  plogf("\n");
78  for (k = 0; k < numSpecies; k++) {
79  plogf(" --- ");
80  plogf(" %3d ", k);
81  plogf(" |");
82  for (j = 0; j < numElemConstraints; j++) {
83  plogf(" %8.2g", matrix[j*numSpecies + k]);
84  }
85  plogf("\n");
86  }
87  plogf(" ---");
88  plogendl();
89  }
90  }
91 #endif
92 
93  /*
94  * Calculate the maximum value of the number of components possible
95  * It's equal to the minimum of the number of elements and the
96  * number of total species.
97  */
98  int ncTrial = std::min(numElemConstraints, numSpecies);
99  numComponents = ncTrial;
100  *usedZeroedSpecies = false;
101 
102  /*
103  * Use a temporary work array for the mole numbers, aw[]
104  */
105  std::vector<double> aw(numSpecies);
106  for (j = 0; j < numSpecies; j++) {
107  aw[j] = awtmp[j];
108  }
109 
110  int jr = -1;
111  /*
112  * Top of a loop of some sort based on the index JR. JR is the
113  * current number of component species found.
114  */
115  do {
116  ++jr;
117  /* - Top of another loop point based on finding a linearly */
118  /* - independent species */
119  do {
120  /*
121  * Search the remaining part of the mole number vector, AW,
122  * for the largest remaining species. Return its identity in K.
123  * The first search criteria is always the largest positive
124  * magnitude of the mole number.
125  */
126  k = basisOptMax1(VCS_DATA_PTR(aw), numSpecies);
127 
128  if ((aw[k] != test) && fabs(aw[k]) == 0.0) {
129  *usedZeroedSpecies = true;
130  }
131 
132 
133  if (aw[k] == test) {
134  numComponents = jr;
135 
136  goto L_CLEANUP;
137  }
138  /*
139  * Assign a small negative number to the component that we have
140  * just found, in order to take it out of further consideration.
141  */
142  aw[k] = test;
143  /* *********************************************************** */
144  /* **** CHECK LINEAR INDEPENDENCE WITH PREVIOUS SPECIES ****** */
145  /* *********************************************************** */
146  /*
147  * Modified Gram-Schmidt Method, p. 202 Dalquist
148  * QR factorization of a matrix without row pivoting.
149  */
150  jl = jr;
151  for (j = 0; j < numElemConstraints; ++j) {
152  sm[j + jr*numElemConstraints] = matrix[j*numSpecies + k];
153  }
154  if (jl > 0) {
155  /*
156  * Compute the coefficients of JA column of the
157  * the upper triangular R matrix, SS(J) = R_J_JR
158  * (this is slightly different than Dalquist)
159  * R_JA_JA = 1
160  */
161  for (j = 0; j < jl; ++j) {
162  ss[j] = 0.0;
163  for (i = 0; i < numElemConstraints; ++i) {
164  ss[j] += sm[i + jr* numElemConstraints] * sm[i + j* numElemConstraints];
165  }
166  ss[j] /= sa[j];
167  }
168  /*
169  * Now make the new column, (*,JR), orthogonal to the
170  * previous columns
171  */
172  for (j = 0; j < jl; ++j) {
173  for (l = 0; l < numElemConstraints; ++l) {
174  sm[l + jr*numElemConstraints] -= ss[j] * sm[l + j*numElemConstraints];
175  }
176  }
177  }
178  /*
179  * Find the new length of the new column in Q.
180  * It will be used in the denominator in future row calcs.
181  */
182  sa[jr] = 0.0;
183  for (ml = 0; ml < numElemConstraints; ++ml) {
184  sa[jr] += SQUARE(sm[ml + jr * numElemConstraints]);
185  }
186  /* **************************************************** */
187  /* **** IF NORM OF NEW ROW .LT. 1E-3 REJECT ********** */
188  /* **************************************************** */
189  if (sa[jr] < 1.0e-6) lindep = true;
190  else lindep = false;
191  } while(lindep);
192  /* ****************************************** */
193  /* **** REARRANGE THE DATA ****************** */
194  /* ****************************************** */
195  compRes.push_back(k);
196  elemComp.push_back(jr);
197 
198  } while (jr < (ncTrial-1));
199 
200  L_CLEANUP: ;
201 
202  if (numComponents == ncTrial && numElemConstraints == numSpecies) {
203  return numComponents;
204  }
205 
206 
207  int numComponentsR = numComponents;
208 
209  ss.resize(numElemConstraints);
210  sa.resize(numElemConstraints);
211 
212 
213  elemComp.clear();
214 
215  aw.resize(numElemConstraints);
216  for (j = 0; j < numSpecies; j++) {
217  aw[j] = 1.0;
218  }
219 
220  jr = -1;
221 
222  do {
223  ++jr;
224 
225  do {
226 
227  k = basisOptMax1(VCS_DATA_PTR(aw), numElemConstraints);
228 
229  if (aw[k] == test) {
230  numComponents = jr;
231  goto LE_CLEANUP;
232  }
233  aw[k] = test;
234 
235 
236  jl = jr;
237  for (j = 0; j < numSpecies; ++j) {
238  sm[j + jr*numSpecies] = matrix[k*numSpecies + j];
239  }
240  if (jl > 0) {
241 
242  for (j = 0; j < jl; ++j) {
243  ss[j] = 0.0;
244  for (i = 0; i < numSpecies; ++i) {
245  ss[j] += sm[i + jr* numSpecies] * sm[i + j* numSpecies];
246  }
247  ss[j] /= sa[j];
248  }
249 
250  for (j = 0; j < jl; ++j) {
251  for (l = 0; l < numSpecies; ++l) {
252  sm[l + jr*numSpecies] -= ss[j] * sm[l + j*numSpecies];
253  }
254  }
255  }
256 
257  sa[jr] = 0.0;
258  for (ml = 0; ml < numSpecies; ++ml) {
259  sa[jr] += SQUARE(sm[ml + jr * numSpecies]);
260  }
261 
262  if (sa[jr] < 1.0e-6) lindep = true;
263  else lindep = false;
264  } while(lindep);
265 
266  elemComp.push_back(k);
267 
268  } while (jr < (ncTrial-1));
269  numComponents = jr;
270  LE_CLEANUP: ;
271 
272 #ifdef DEBUG_MODE
273  if (m_debug_print_lvl >= 2) {
274  plogf(" --- vcs_rank found rank %d\n", numComponents);
275  if (m_debug_print_lvl >= 5) {
276  if (compRes.size() == elemComp.size()) {
277  printf(" --- compRes elemComp\n");
278  for (int i = 0; i < (int) compRes.size(); i++) {
279  printf(" --- %d %d \n", (int) compRes[i], (int) elemComp[i]);
280  }
281  } else {
282  for (int i = 0; i < (int) compRes.size(); i++) {
283  printf(" --- compRes[%d] = %d \n", (int) i, (int) compRes[i]);
284  }
285  for (int i = 0; i < (int) elemComp.size(); i++) {
286  printf(" --- elemComp[%d] = %d \n", (int) i, (int) elemComp[i]);
287  }
288  }
289  }
290  }
291 #endif
292 
293  if (numComponentsR != numComponents) {
294  printf("vcs_rank ERROR: number of components are different: %d %d\n", numComponentsR, numComponents);
295  throw Cantera::CanteraError("vcs_rank ERROR:",
296  " logical inconsistency");
297  exit(-1);
298  }
299  return numComponents;
300  }
301 
302 }
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
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.
Internal declarations for the VCSnonideal package.
Header for the Interface class for the vcs thermo equilibrium solver package,.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
#define plogendl()
define this Cantera function to replace cout << endl;
Definition: vcs_internal.h:37
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:30
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...