int VCS_SOLVE::vcs_elem_rearrange(double* const aw, double* const sa, double* const sm, double* const ss) { size_t ncomponents = m_numComponents; if (m_debug_print_lvl >= 2) { plogf(" "); writeline('-', 77); plogf(" --- Subroutine elem_rearrange() called to "); plogf("check stoich. coefficient matrix\n"); plogf(" --- and to rearrange the element ordering once\n"); } // Use a temporary work array for the element numbers // Also make sure the value of test is unique. bool lindep = true; double test = -1.0E10; while (lindep) { lindep = false; for (size_t i = 0; i < m_nelem; ++i) { test -= 1.0; aw[i] = m_elemAbundancesGoal[i]; if (test == aw[i]) { lindep = true; } } } // Top of a loop of some sort based on the index JR. JR is the current // number independent elements found. size_t jr = 0; while (jr < ncomponents) { size_t k; // Top of another loop point based on finding a linearly independent // species while (true) { // Search the remaining part of the mole fraction vector, AW, for // the largest remaining species. Return its identity in K. k = m_nelem; for (size_t ielem = jr; ielem < m_nelem; ielem++) { if (m_elementActive[ielem] && aw[ielem] != test) { k = ielem; break; } } if (k == m_nelem) { throw CanteraError("vcs_elem_rearrange", "Shouldn't be here. Algorithm misfired."); } // Assign a large negative number to the element that we have just // found, in order to take it out of further consideration. aw[k] = test; // CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX LINE WITH // PREVIOUS LINES OF THE FORMULA MATRIX // // Modified Gram-Schmidt Method, p. 202 Dalquist QR factorization of // a matrix without row pivoting. size_t jl = jr; // Fill in the row for the current element, k, under consideration // The row will contain the Formula matrix value for that element // from the current component. for (size_t j = 0; j < ncomponents; ++j) { sm[j + jr*ncomponents] = m_formulaMatrix(j,k); } if (jl > 0) { // Compute the coefficients of JA column of the the upper // triangular R matrix, SS(J) = R_J_JR (this is slightly // different than Dalquist) R_JA_JA = 1 for (size_t j = 0; j < jl; ++j) { ss[j] = 0.0; for (size_t i = 0; i < ncomponents; ++i) { ss[j] += sm[i + jr*ncomponents] * sm[i + j*ncomponents]; } ss[j] /= sa[j]; } // Now make the new column, (*,JR), orthogonal to the previous // columns for (size_t j = 0; j < jl; ++j) { for (size_t i = 0; i < ncomponents; ++i) { sm[i + jr*ncomponents] -= ss[j] * sm[i + j*ncomponents]; } } } // Find the new length of the new column in Q. It will be used in // the denominator in future row calcs. sa[jr] = 0.0; for (size_t ml = 0; ml < ncomponents; ++ml) { sa[jr] += pow(sm[ml + jr*ncomponents], 2); } // IF NORM OF NEW ROW .LT. 1E-6 REJECT if (sa[jr] > 1.0e-6) { break; } } // REARRANGE THE DATA if (jr != k) { if (m_debug_print_lvl >= 2) { plogf(" --- %-2.2s(%9.2g) replaces %-2.2s(%9.2g) as element %3d\n", m_elementName[k], m_elemAbundancesGoal[k], m_elementName[jr], m_elemAbundancesGoal[jr], jr); } vcs_switch_elem_pos(jr, k); std::swap(aw[jr], aw[k]); } // If we haven't found enough components, go back and find some more. jr++; } return VCS_SUCCESS; }
/* * * This subroutine handles the rearrangement of the constraint * equations represented by the Formula Matrix. Rearrangement is only * necessary when the number of components is less than the number of * elements. For this case, some constraints can never be satisfied * exactly, because the range space represented by the Formula * Matrix of the components can't span the extra space. These * constraints, which are out of the range space of the component * Formula matrix entries, are migrated to the back of the Formula * matrix. * * A prototypical example is an extra element column in * FormulaMatrix[], * which is identically zero. For example, let's say that argon is * has an element column in FormulaMatrix[], but no species in the * mechanism * actually contains argon. Then, nc < ne. Also, without perturbation * of FormulaMatrix[] vcs_basopt[] would produce a zero pivot * because the matrix * would be singular (unless the argon element column was already the * last column of FormulaMatrix[]. * This routine borrows heavily from vcs_basopt's algorithm. It * finds nc constraints which span the range space of the Component * Formula matrix, and assigns them as the first nc components in the * formular matrix. This guarrantees that vcs_basopt[] has a * nonsingular matrix to invert. * * Other Variables * aw[i] = Mole fraction work space (ne in length) * sa[j] = Gramm-Schmidt orthog work space (ne in length) * ss[j] = Gramm-Schmidt orthog work space (ne in length) * sm[i+j*ne] = QR matrix work space (ne*ne in length) * */ int VCS_SOLVE::vcs_elem_rearrange(double * const aw, double * const sa, double * const sm, double * const ss) { size_t j, k, l, i, jl, ml, jr, ielem; bool lindep; size_t ncomponents = m_numComponents; double test = -1.0E10; #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n"); plogf(" --- Subroutine elem_rearrange() called to "); plogf("check stoich. coefficent matrix\n"); plogf(" --- and to rearrange the element ordering once"); plogendl(); } #endif /* * Use a temporary work array for the element numbers * Also make sure the value of test is unique. */ lindep = false; do { lindep = false; for (i = 0; i < m_numElemConstraints; ++i) { test -= 1.0; aw[i] = m_elemAbundancesGoal[i]; if (test == aw[i]) lindep = true; } } while (lindep); /* * Top of a loop of some sort based on the index JR. JR is the * current number independent elements found. */ jr = -1; do { ++jr; /* * Top of another loop point based on finding a linearly * independent species */ do { /* * Search the remaining part of the mole fraction vector, AW, * for the largest remaining species. Return its identity in K. */ k = m_numElemConstraints; for (ielem = jr; ielem < m_numElemConstraints; ielem++) { if (m_elementActive[ielem]) { if (aw[ielem] != test) { k = ielem; break; } } } if (k == m_numElemConstraints) { plogf("vcs_elem_rearrange::Shouldn't be here. Algorithm misfired."); plogendl(); exit(EXIT_FAILURE); } /* * Assign a large negative number to the element that we have * just found, in order to take it out of further consideration. */ aw[k] = test; /* *********************************************************** */ /* **** CHECK LINEAR INDEPENDENCE OF CURRENT FORMULA MATRIX */ /* **** LINE WITH PREVIOUS LINES OF THE FORMULA MATRIX ****** */ /* *********************************************************** */ /* * Modified Gram-Schmidt Method, p. 202 Dalquist * QR factorization of a matrix without row pivoting. */ jl = jr; /* * Fill in the row for the current element, k, under consideration * The row will contain the Formula matrix value for that element * from the current component. */ for (j = 0; j < ncomponents; ++j) { sm[j + jr*ncomponents] = m_formulaMatrix[k][j]; } if (jl > 0) { /* * Compute the coefficients of JA column of the * the upper triangular R matrix, SS(J) = R_J_JR * (this is slightly different than Dalquist) * R_JA_JA = 1 */ for (j = 0; j < jl; ++j) { ss[j] = 0.0; for (i = 0; i < ncomponents; ++i) { ss[j] += sm[i + jr*ncomponents] * sm[i + j*ncomponents]; } ss[j] /= sa[j]; } /* * Now make the new column, (*,JR), orthogonal to the * previous columns */ for (j = 0; j < jl; ++j) { for (l = 0; l < ncomponents; ++l) { sm[l + jr*ncomponents] -= ss[j] * sm[l + j*ncomponents]; } } } /* * Find the new length of the new column in Q. * It will be used in the denominator in future row calcs. */ sa[jr] = 0.0; for (ml = 0; ml < ncomponents; ++ml) { sa[jr] += SQUARE(sm[ml + jr*ncomponents]); } /* **************************************************** */ /* **** IF NORM OF NEW ROW .LT. 1E-6 REJECT ********** */ /* **************************************************** */ if (sa[jr] < 1.0e-6) lindep = true; else lindep = false; } while(lindep); /* ****************************************** */ /* **** REARRANGE THE DATA ****************** */ /* ****************************************** */ if (jr != k) { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf(" --- "); plogf("%-2.2s", (m_elementName[k]).c_str()); plogf("(%9.2g) replaces ", m_elemAbundancesGoal[k]); plogf("%-2.2s", (m_elementName[jr]).c_str()); plogf("(%9.2g) as element %3d", m_elemAbundancesGoal[jr], jr); plogendl(); } #endif vcs_switch_elem_pos(jr, k); vcsUtil_dsw(aw, jr, k); } /* * If we haven't found enough components, go back * and find some more. (nc -1 is used below, because * jr is counted from 0, via the C convention. */ } while (jr < (ncomponents-1)); return VCS_SUCCESS; }