int VCS_SOLVE::vcs_setMolesLinProg()
{
    size_t ik, irxn;
    double test = -1.0E-10;

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("   --- call setInitialMoles\n");
    }

    double dg_rt;
    int idir;
    double nu;
    double delta_xi, dxi_min = 1.0e10;
    bool redo = true;
    int retn;
    int iter = 0;
    bool abundancesOK = true;
    bool usedZeroedSpecies;
    vector_fp sm(m_numElemConstraints*m_numElemConstraints, 0.0);
    vector_fp ss(m_numElemConstraints, 0.0);
    vector_fp sa(m_numElemConstraints, 0.0);
    vector_fp wx(m_numElemConstraints, 0.0);
    vector_fp aw(m_numSpeciesTot, 0.0);

    for (ik = 0; ik < m_numSpeciesTot; ik++) {
        if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) {
            m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]);
        }
    }

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
    }

    while (redo) {
        if (!vcs_elabcheck(0)) {
            if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
                plogf(" --- seMolesLinProg  Mole numbers failing element abundances\n");
                plogf(" --- seMolesLinProg  Call vcs_elcorr to attempt fix\n");
            }
            retn = vcs_elcorr(&sm[0], &wx[0]);
            if (retn >= 2) {
                abundancesOK = false;
            } else {
                abundancesOK = true;
            }
        } else {
            abundancesOK = true;
        }
        /*
         *  Now find the optimized basis that spans the stoichiometric
         *  coefficient matrix, based on the current composition, m_molNumSpecies_old[]
         *  We also calculate sc[][], the reaction matrix.
         */
        retn = vcs_basopt(false, &aw[0], &sa[0], &sm[0], &ss[0],
                          test, &usedZeroedSpecies);
        if (retn != VCS_SUCCESS) {
            return retn;
        }

        if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
            plogf("iteration %d\n", iter);
        }
        redo = false;
        iter++;
        if (iter > 15) {
            break;
        }

        // loop over all reactions
        for (irxn = 0; irxn < m_numRxnTot; irxn++) {
            // dg_rt is the Delta_G / RT value for the reaction
            ik = m_numComponents + irxn;
            dg_rt = m_SSfeSpecies[ik];
            dxi_min = 1.0e10;
            const double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn);
            for (size_t jcomp = 0; jcomp < m_numElemConstraints; jcomp++) {
                dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp];
            }
            // fwd or rev direction.
            //  idir > 0 implies increasing the current species
            //  idir < 0 implies decreasing the current species
            idir = (dg_rt < 0.0 ? 1 : -1);
            if (idir < 0) {
                dxi_min = m_molNumSpecies_old[ik];
            }

            for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) {
                nu = sc_irxn[jcomp];
                // set max change in progress variable by
                // non-negativity requirement
                if (nu*idir < 0) {
                    delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu);
                    // if a component has nearly zero moles, redo
                    // with a new set of components
                    if (!redo && delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) {
                        if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
                            plogf("   --- Component too small: %s\n", m_speciesName[jcomp]);
                        }
                        redo = true;
                    }
                    dxi_min = std::min(dxi_min, delta_xi);
                }
            }

            // step the composition by dxi_min, check against zero, since
            // we are zeroing components and species on every step.
            // Redo the iteration, if a component went from positive to zero on this step.
            double dsLocal = idir*dxi_min;
            m_molNumSpecies_old[ik] += dsLocal;
            m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]);
            for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) {
                bool full = false;
                if (m_molNumSpecies_old[jcomp] > 1.0E-15) {
                    full = true;
                }
                m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal;
                m_molNumSpecies_old[jcomp] = max(0.0, m_molNumSpecies_old[jcomp]);
                if (full && m_molNumSpecies_old[jcomp] < 1.0E-60) {
                    redo = true;
                }
            }
        }

        if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
            printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
        }
    }

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl == 1) {
        printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
        plogf("   --- setInitialMoles end\n");
    }
    retn = 0;
    if (!abundancesOK) {
        retn = -1;
    } else if (iter > 15) {
        retn = 1;
    }
    return retn;
}
Example #2
0
/*!
 *   This is done by running
 *   each reaction as far forward or backward as possible, subject
 *   to the constraint that all mole numbers remain
 *   non-negative. Reactions for which \f$ \Delta \mu^0 \f$ are
 *   positive are run in reverse, and ones for which it is negative
 *   are run in the forward direction. The end result is equivalent
 *   to solving the linear programming problem of minimizing the
 *   linear Gibbs function subject to the element and
 *   non-negativity constraints.
 */
int VCS_SOLVE::vcs_setMolesLinProg() {
  int ik, irxn;
  double test = -1.0E-10;

#ifdef DEBUG_MODE
    std::string pprefix(" --- seMolesLinProg ");
    if (m_debug_print_lvl >= 2) {
      plogf("   --- call setInitialMoles\n"); 
    }
#endif


  // m_mu are standard state chemical potentials
  //  Boolean on the end specifies standard chem potentials
  // m_mix->getValidChemPotentials(not_mu, DATA_PTR(m_mu), true);
  // -> This is already done coming into the routine.
  double dg_rt;

  int idir;
  double nu;
  double delta_xi, dxi_min = 1.0e10;
  bool redo = true;
  int jcomp;
  int retn;
  int iter = 0;
  bool abundancesOK = true;
  int usedZeroedSpecies;

  std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
  std::vector<double> ss(m_numElemConstraints, 0.0);
  std::vector<double> sa(m_numElemConstraints, 0.0);
  std::vector<double> wx(m_numElemConstraints, 0.0);
  std::vector<double> aw(m_numSpeciesTot, 0.0);

  for (ik = 0; ik <  m_numSpeciesTot; ik++) {
    if (m_speciesUnknownType[ik] !=  VCS_SPECIES_INTERFACIALVOLTAGE) {
      m_molNumSpecies_old[ik] = MAX(0.0, m_molNumSpecies_old[ik]);
    }
  }

#ifdef DEBUG_MODE
  if (m_debug_print_lvl >= 2) {
    printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
  }
#endif
  
  while (redo) {
 
    if (!vcs_elabcheck(0)) {
#ifdef DEBUG_MODE
      if (m_debug_print_lvl >= 2) {
	plogf("%s Mole numbers failing element abundances\n", pprefix.c_str());  
	plogf("%sCall vcs_elcorr to attempt fix\n",          pprefix.c_str());
      }
#endif
      retn = vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
      if (retn >= 2) {
	abundancesOK = false;
      } else {
	abundancesOK = true;
      }
    } else {
      abundancesOK = true;
    }
    /*
     *  Now find the optimized basis that spans the stoichiometric
     *  coefficient matrix, based on the current composition, m_molNumSpecies_old[]
     *  We also calculate sc[][], the reaction matrix.
     */
    retn = vcs_basopt(FALSE, VCS_DATA_PTR(aw), VCS_DATA_PTR(sa),
			  VCS_DATA_PTR(sm), VCS_DATA_PTR(ss), 
			  test, &usedZeroedSpecies);
    if (retn != VCS_SUCCESS) return retn;

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
      plogf("iteration %d\n", iter);  
    }
#endif
    redo = false;
    iter++;
    if (iter > 15) break;

    // loop over all reactions
    for (irxn = 0; irxn < m_numRxnTot; irxn++) {
	   
      // dg_rt is the Delta_G / RT value for the reaction
      ik = m_numComponents + irxn;
      dg_rt = m_SSfeSpecies[ik];
      dxi_min = 1.0e10;
      const double *sc_irxn = m_stoichCoeffRxnMatrix[irxn];
      for (jcomp = 0; jcomp < m_numElemConstraints; jcomp++) {
	dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp];
      }
      // fwd or rev direction. 
      //  idir > 0 implies increasing the current species
      //  idir < 0  implies decreasing the current species
      idir = (dg_rt < 0.0 ? 1 : -1);
      if (idir < 0) {
	dxi_min = m_molNumSpecies_old[ik];
      }
	    
      for (jcomp = 0; jcomp < m_numComponents; jcomp++) {
	nu = sc_irxn[jcomp];
	      
	// set max change in progress variable by
	// non-negativity requirement
	if (nu*idir < 0) {
	  delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu);
	  // if a component has nearly zero moles, redo
	  // with a new set of components
	  if (!redo) {
	    if (delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) {
#ifdef DEBUG_MODE
	      if (m_debug_print_lvl >= 2) {
		plogf("   --- Component too small: %s\n", m_speciesName[jcomp].c_str()); 
	      }
#endif
	      redo = true;
	    }
	  }
	  if (delta_xi < dxi_min) dxi_min = delta_xi;
	}
      }
	    
      // step the composition by dxi_min, check against zero, since
      // we are zeroing components and species on every step.
      // Redo the iteration, if a component went from positive to zero on this step.
      double dsLocal = idir*dxi_min;
      m_molNumSpecies_old[ik] += dsLocal;
      m_molNumSpecies_old[ik] = MAX(0.0,  m_molNumSpecies_old[ik]);
      for (jcomp = 0; jcomp < m_numComponents; jcomp++) {
	bool full = false;
	if (m_molNumSpecies_old[jcomp] > 1.0E-15) {
	  full = true;
	}
	m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal;
	m_molNumSpecies_old[jcomp] = MAX(0.0, m_molNumSpecies_old[jcomp]);
	if (full) {
	  if (m_molNumSpecies_old[jcomp] < 1.0E-60) {
	    redo = true;
	  }
	}
      }
    }

    // set the moles of the phase objects to match
    //  updateMixMoles();
    // Update the phase objects with the contents of the m_molNumSpecies_old vector
    // vcs_updateVP(0);
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
      printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
    }
#endif
  }

#ifdef DEBUG_MODE
  if (m_debug_print_lvl == 1) {
    printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies);
    plogf("   --- setInitialMoles end\n"); 
  }
#endif
  retn = 0;
  if (!abundancesOK) {
    retn = -1;
  } else if (iter > 15) {
    retn = 1;
  }
  return retn;
}
Example #3
0
int VCS_SOLVE::vcs_inest_TP()
{
    int retn = 0;
    Cantera::clockWC tickTock;

    if (m_doEstimateEquil > 0) {
        /*
         *  Calculate the elemental abundances
         */
        vcs_elab();
        if (vcs_elabcheck(0)) {
            if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
                plogf("%s Initial guess passed element abundances on input\n", pprefix);
                plogf("%s m_doEstimateEquil = 1 so will use the input mole "
                      "numbers as estimates", pprefix);
                plogendl();
            }
            return retn;
        } else if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
            plogf("%s Initial guess failed element abundances on input\n", pprefix);
            plogf("%s m_doEstimateEquil = 1 so will discard input "
                  "mole numbers and find our own estimate", pprefix);
            plogendl();
        }
    }

    /*
     *  Malloc temporary space for usage in this routine and in
     *  subroutines
     *        sm[ne*ne]
     *        ss[ne]
     *        sa[ne]
     *        aw[m]
     */
    std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0);
    std::vector<double> ss(m_numElemConstraints, 0.0);
    std::vector<double> sa(m_numElemConstraints, 0.0);
    std::vector<double> aw(m_numSpeciesTot+ m_numElemConstraints, 0.0);
    /*
     *  Go get the estimate of the solution
     */
    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%sGo find an initial estimate for the equilibrium problem",
              pprefix);
        plogendl();
    }
    double test = -1.0E20;
    vcs_inest(VCS_DATA_PTR(aw), VCS_DATA_PTR(sa), VCS_DATA_PTR(sm),
              VCS_DATA_PTR(ss), test);
    /*
     *  Calculate the elemental abundances
     */
    vcs_elab();

    /*
     *      If we still fail to achieve the correct elemental abundances,
     *      try to fix the problem again by calling the main elemental abundances
     *      fixer routine, used in the main program. This
     *      attempts to tweak the mole numbers of the component species to
     *      satisfy the element abundance constraints.
     *
     *       Note: We won't do this unless we have to since it involves inverting
     *             a matrix.
     */
    bool rangeCheck = vcs_elabcheck(1);
    if (!vcs_elabcheck(0)) {
        if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
            plogf("%sInitial guess failed element abundances\n", pprefix);
            plogf("%sCall vcs_elcorr to attempt fix", pprefix);
            plogendl();
        }
        vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(aw));
        rangeCheck  = vcs_elabcheck(1);
        if (!vcs_elabcheck(0)) {
            plogf("%sInitial guess still fails element abundance equations\n",
                  pprefix);
            plogf("%s - Inability to ever satisfy element abundance "
                  "constraints is probable", pprefix);
            plogendl();
            retn = -1;
        } else {
            if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
                if (rangeCheck) {
                    plogf("%sInitial guess now satisfies element abundances", pprefix);
                    plogendl();
                } else {
                    plogf("%sElement Abundances RANGE ERROR\n", pprefix);
                    plogf("%s - Initial guess satisfies NC=%d element abundances, "
                          "BUT not NE=%d element abundances", pprefix,
                          m_numComponents, m_numElemConstraints);
                    plogendl();
                }
            }
        }
    } else {
        if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
            if (rangeCheck) {
                plogf("%sInitial guess satisfies element abundances", pprefix);
                plogendl();
            } else {
                plogf("%sElement Abundances RANGE ERROR\n", pprefix);
                plogf("%s - Initial guess satisfies NC=%d element abundances, "
                      "BUT not NE=%d element abundances", pprefix,
                      m_numComponents, m_numElemConstraints);
                plogendl();
            }
        }
    }

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E", pprefix,
              vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_new),
                              VCS_DATA_PTR(m_tPhaseMoles_old)));
        plogendl();
    }

    /*
     * Record time
     */
    m_VCount->T_Time_inest += tickTock.secondsWC();
    (m_VCount->T_Calls_Inest)++;
    return retn;
}