Esempio n. 1
0
/*
 *  This routine is mostly concerned with changing the private data
 *  to be consistent with that needed for solution. It is called for
 *  every invocation of the vcs_solve() except for the cleanup invocation.
 *
 * Tasks:
 *  1)  Initialization of arrays to zero.
 *  2)  Calculate total number of moles in all phases
 *
 *  return code
 *     VCS_SUCCESS = everything went OK
 *     VCS_PUB_BAD = There is an irreconcilable difference in the
 *                   public data structure from when the problem was
 *                   initially set up.
 */
int VCS_SOLVE::vcs_prep() {
    /*
     *        Initialize various arrays in the data to zero
     */
    vcs_vdzero(m_feSpecies_old, m_numSpeciesTot);
    vcs_vdzero(m_feSpecies_new, m_numSpeciesTot);
    vcs_vdzero(m_molNumSpecies_new, m_numSpeciesTot);
    vcs_dzero(&(m_deltaMolNumPhase[0][0]), m_numSpeciesTot * m_numPhases);
    vcs_izero(&(m_phaseParticipation[0][0]), m_numSpeciesTot * m_numPhases);
    vcs_dzero(VCS_DATA_PTR(m_deltaPhaseMoles), m_numPhases);
    vcs_dzero(VCS_DATA_PTR(m_tPhaseMoles_new), m_numPhases);
    /*
     *   Calculate the total number of moles in all phases.
     */
    vcs_tmoles();
    return VCS_SUCCESS;
}
Esempio n. 2
0
void vcs_VolPhase::_updateActCoeff() const
{
    if (m_isIdealSoln) {
        m_UpToDate_AC = true;
        return;
    }
    TP_ptr->getActivityCoefficients(VCS_DATA_PTR(ActCoeff));
    m_UpToDate_AC = true;
}
Esempio n. 3
0
/*
 *  Calculates the element abundance vectors from the mole
 *  numbers
 */
void VCS_PROB::set_gai()
{
    double* ElemAbund = VCS_DATA_PTR(gai);
    double* const* const fm = FormulaMatrix.baseDataAddr();
    vcs_dzero(ElemAbund, ne);

    for (size_t j = 0; j < ne; j++) {
        for (size_t kspec = 0; kspec < nspecies; kspec++) {
            ElemAbund[j] += fm[j][kspec] * w[kspec];
        }
    }
}
Esempio n. 4
0
  /*
   *  This function knows all of the element information with VCS_SOLVE, and
   *  can therefore switch element positions
   *
   *  @param ipos  first global element index
   *  @param jpos  second global element index
   */
  void VCS_SOLVE::vcs_switch_elem_pos(size_t ipos, size_t jpos) {
    if (ipos == jpos) return;
    size_t j;
    double dtmp;
    vcs_VolPhase *volPhase;
#ifdef DEBUG_MODE
    if (ipos > (m_numElemConstraints - 1) ||
	jpos > (m_numElemConstraints - 1)) {
      plogf("vcs_switch_elem_pos: ifunc = 0: inappropriate args: %d %d\n",
	    ipos, jpos);
      plogendl();
      exit(EXIT_FAILURE);
    }
#endif  
    /*
     * Change the element Global Index list in each vcs_VolPhase object
     * to reflect the switch in the element positions.
     */
    for (size_t iph = 0; iph < m_numPhases; iph++) {
      volPhase = m_VolPhaseList[iph];
      for (size_t e = 0; e < volPhase->nElemConstraints(); e++) {
	if (volPhase->elemGlobalIndex(e) == ipos) {
	  volPhase->setElemGlobalIndex(e, jpos);
	}
	if (volPhase->elemGlobalIndex(e) == jpos) {
	  volPhase->setElemGlobalIndex(e, ipos);
	}
      } 
    }
    vcsUtil_dsw(VCS_DATA_PTR(m_elemAbundancesGoal), ipos, jpos);
    vcsUtil_dsw(VCS_DATA_PTR(m_elemAbundances), ipos, jpos);
    vcsUtil_ssw(VCS_DATA_PTR(m_elementMapIndex), ipos, jpos);
    vcsUtil_isw(VCS_DATA_PTR(m_elType),  ipos, jpos);
    vcsUtil_isw(VCS_DATA_PTR(m_elementActive),  ipos, jpos);
    for (j = 0; j < m_numSpeciesTot; ++j) {
      SWAP(m_formulaMatrix[ipos][j], m_formulaMatrix[jpos][j], dtmp);
    }
    vcsUtil_stsw(m_elementName, ipos, jpos);
  }
Esempio n. 5
0
void VCS_PROB::set_gai()
{
    gai.assign(gai.size(), 0.0);
    double* ElemAbund = VCS_DATA_PTR(gai);

    for (size_t j = 0; j < ne; j++) {
        for (size_t kspec = 0; kspec < nspecies; kspec++) {
            if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                ElemAbund[j] += FormulaMatrix(kspec,j) * w[kspec];
            }
        }
    }
}
Esempio n. 6
0
void vcs_VolPhase::setPtrThermoPhase(ThermoPhase* tp_ptr)
{
    TP_ptr = tp_ptr;
    Temp_ = TP_ptr->temperature();
    Pres_ = TP_ptr->pressure();
    setState_TP(Temp_, Pres_);
    p_VCS_UnitsFormat = VCS_UNITS_MKS;
    m_phi = TP_ptr->electricPotential();
    size_t nsp = TP_ptr->nSpecies();
    size_t nelem = TP_ptr->nElements();
    if (nsp !=  m_numSpecies) {
        if (m_numSpecies != 0) {
            plogf("Warning Nsp != NVolSpeces: %d %d \n", nsp, m_numSpecies);
        }
        resize(VP_ID_, nsp, nelem, PhaseName.c_str());
    }
    TP_ptr->getMoleFractions(VCS_DATA_PTR(Xmol_));
    creationMoleNumbers_ = Xmol_;
    _updateMoleFractionDependencies();

    /*
     *  figure out ideal solution tag
     */
    if (nsp == 1) {
        m_isIdealSoln = true;
    } else {
        int eos = TP_ptr->eosType();
        switch (eos) {
        case cIdealGas:
        case cIncompressible:
        case cSurf:
        case cMetal:
        case cStoichSubstance:
        case cSemiconductor:
        case cLatticeSolid:
        case cLattice:
        case cEdge:
        case cIdealSolidSolnPhase:
            m_isIdealSoln = true;
            break;
        default:
            m_isIdealSoln = false;
        };
    }
}
Esempio n. 7
0
double vcs_VolPhase::_updateVolPM() const
{
    TP_ptr->getPartialMolarVolumes(VCS_DATA_PTR(PartialMolarVol));
    m_totalVol = 0.0;
    for (size_t k = 0; k < m_numSpecies; k++) {
        m_totalVol += PartialMolarVol[k] * Xmol_[k];
    }
    m_totalVol *= v_totalMoles;

    if (m_totalMolesInert > 0.0) {
        if (m_gasPhase) {
            double volI = m_totalMolesInert * GasConstant * Temp_ / Pres_;
            m_totalVol += volI;
        } else {
            throw CanteraError("vcs_VolPhase::_updateVolPM", "unknown situation");
        }
    }
    m_UpToDate_VolPM = true;
    return m_totalVol;
}
Esempio n. 8
0
void vcs_VolPhase::_updateLnActCoeffJac()
{
    double phaseTotalMoles = v_totalMoles;
    if (phaseTotalMoles < 1.0E-14) {
        phaseTotalMoles = 1.0;
    }

    /*
     * Evaluate the current base activity coefficients if necessary
     */
    if (!m_UpToDate_AC) {
        _updateActCoeff();
    }
    if (!TP_ptr) {
        return;
    }
    TP_ptr->getdlnActCoeffdlnN(m_numSpecies, &np_dLnActCoeffdMolNumber(0,0));
    for (size_t j = 0; j < m_numSpecies; j++) {
        double moles_j_base = phaseTotalMoles * Xmol_[j];
        double* const np_lnActCoeffCol = np_dLnActCoeffdMolNumber.ptrColumn(j);
        if (moles_j_base < 1.0E-200) {
            moles_j_base = 1.0E-7 * moles_j_base + 1.0E-13 * phaseTotalMoles + 1.0E-150;
        }
        for (size_t k = 0; k < m_numSpecies; k++) {
            np_lnActCoeffCol[k] = np_lnActCoeffCol[k] * phaseTotalMoles / moles_j_base;
        }
    }

    double deltaMoles_j = 0.0;
    // Make copies of ActCoeff and Xmol_ for use in taking differences
    std::vector<double> ActCoeff_Base(ActCoeff);
    std::vector<double> Xmol_Base(Xmol_);
    double TMoles_base = phaseTotalMoles;

    /*
     *  Loop over the columns species to be deltad
     */
    for (size_t j = 0; j < m_numSpecies; j++) {
        /*
         * Calculate a value for the delta moles of species j
         * -> Note Xmol_[] and Tmoles are always positive or zero
         *    quantities.
         */
        double moles_j_base = phaseTotalMoles * Xmol_Base[j];
        deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-13 * phaseTotalMoles + 1.0E-150;
        /*
         * Now, update the total moles in the phase and all of the
         * mole fractions based on this.
         */
        phaseTotalMoles = TMoles_base + deltaMoles_j;
        for (size_t k = 0; k < m_numSpecies; k++) {
            Xmol_[k] = Xmol_Base[k] * TMoles_base / phaseTotalMoles;
        }
        Xmol_[j] = (moles_j_base + deltaMoles_j) / phaseTotalMoles;

        /*
         * Go get new values for the activity coefficients.
         * -> Note this calls setState_PX();
         */
        _updateMoleFractionDependencies();
        _updateActCoeff();
        /*
         * Revert to the base case Xmol_, v_totalMoles
         */
        v_totalMoles = TMoles_base;
        Xmol_ = Xmol_Base;
    }
    /*
     * Go get base values for the activity coefficients.
     * -> Note this calls setState_TPX() again;
     * -> Just wanted to make sure that cantera is in sync
     *    with VolPhase after this call.
     */
    setMoleFractions(VCS_DATA_PTR(Xmol_Base));
    _updateMoleFractionDependencies();
    _updateActCoeff();
}
Esempio n. 9
0
void vcs_VolPhase::_updateVolStar() const
{
    TP_ptr->getStandardVolumes(VCS_DATA_PTR(StarMolarVol));
    m_UpToDate_VolStar = true;
}
Esempio n. 10
0
void vcs_VolPhase::setMolesFromVCS(const int stateCalc,
                                   const double* molesSpeciesVCS)
{
    v_totalMoles = m_totalMolesInert;

    if (molesSpeciesVCS == 0) {
        AssertThrowMsg(m_owningSolverObject, "vcs_VolPhase::setMolesFromVCS",
                       "shouldn't be here");
        if (stateCalc == VCS_STATECALC_OLD) {
            molesSpeciesVCS = VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_old);
        } else if (stateCalc == VCS_STATECALC_NEW) {
            molesSpeciesVCS = VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_new);
        } else if (DEBUG_MODE_ENABLED) {
            throw CanteraError("vcs_VolPhase::setMolesFromVCS", "shouldn't be here");        }
    } else if (DEBUG_MODE_ENABLED && m_owningSolverObject) {
        if (stateCalc == VCS_STATECALC_OLD) {
            if (molesSpeciesVCS != VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_old)) {
                throw CanteraError("vcs_VolPhase::setMolesFromVCS", "shouldn't be here");
            }
        } else if (stateCalc == VCS_STATECALC_NEW) {
            if (molesSpeciesVCS != VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_new)) {
                throw CanteraError("vcs_VolPhase::setMolesFromVCS", "shouldn't be here");
            }
        }
    }

    for (size_t k = 0; k < m_numSpecies; k++) {
        if (m_speciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            size_t kglob = IndSpecies[k];
            v_totalMoles += std::max(0.0, molesSpeciesVCS[kglob]);
        }
    }
    if (v_totalMoles > 0.0) {
        for (size_t k = 0; k < m_numSpecies; k++) {
            if (m_speciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                size_t kglob = IndSpecies[k];
                double tmp = std::max(0.0, molesSpeciesVCS[kglob]);
                Xmol_[k] = tmp / v_totalMoles;
            }
        }
        m_existence = VCS_PHASE_EXIST_YES;
    } else {
        // This is where we will start to store a better approximation
        // for the mole fractions, when the phase doesn't exist.
        // This is currently unimplemented.
        m_existence = VCS_PHASE_EXIST_NO;
    }
    /*
     * Update the electric potential if it is a solution variable
     * in the equation system
     */
    if (m_phiVarIndex != npos) {
        size_t kglob = IndSpecies[m_phiVarIndex];
        if (m_numSpecies == 1) {
            Xmol_[m_phiVarIndex] = 1.0;
        } else {
            Xmol_[m_phiVarIndex] = 0.0;
        }
        double phi = molesSpeciesVCS[kglob];
        setElectricPotential(phi);
        if (m_numSpecies == 1) {
            m_existence = VCS_PHASE_EXIST_YES;
        }
    }
    _updateMoleFractionDependencies();
    if (m_totalMolesInert > 0.0) {
        m_existence = VCS_PHASE_EXIST_ALWAYS;
    }

    /*
     * If stateCalc is old and the total moles is positive,
     * then we have a valid state. If the phase went away, it would
     * be a valid starting point for F_k's. So, save the state.
     */
    if (stateCalc == VCS_STATECALC_OLD) {
        if (v_totalMoles > 0.0) {
            creationMoleNumbers_ = Xmol_;
        }
    }

    /*
     * Set flags indicating we are up to date with the VCS state vector.
     */
    m_UpToDate = true;
    m_vcsStateStatus = stateCalc;
}
Esempio n. 11
0
void vcs_VolPhase::_updateGStar() const
{
    TP_ptr->getStandardChemPotentials(VCS_DATA_PTR(StarChemicalPotential));
    m_UpToDate_GStar = true;
}
Esempio n. 12
0
/*
 *  Use the contents of the VCS_PROB to specify the contents of the
 *  private data, VCS_SOLVE.
 *
 *  @param pub  Pointer to VCS_PROB that will be used to
 *              initialize the current equilibrium problem
 */
int VCS_SOLVE::vcs_prob_specifyFully(const VCS_PROB* pub)
{
    vcs_VolPhase* Vphase = 0;
    const char* ser =
        "vcs_pub_to_priv ERROR :ill defined interface -> bailout:\n\t";

    /*
     *  First Check to see whether we have room for the current problem
     *  size
     */
    size_t nspecies  = pub->nspecies;
    if (NSPECIES0 < nspecies) {
        plogf("%sPrivate Data is dimensioned too small\n", ser);
        return VCS_PUB_BAD;
    }
    size_t nph = pub->NPhase;
    if (NPHASE0 < nph) {
        plogf("%sPrivate Data is dimensioned too small\n", ser);
        return VCS_PUB_BAD;
    }
    size_t nelements = pub->ne;
    if (m_numElemConstraints < nelements) {
        plogf("%sPrivate Data is dimensioned too small\n", ser);
        return VCS_PUB_BAD;
    }

    /*
     * OK, We have room. Now, transfer the integer numbers
     */
    m_numElemConstraints = nelements;
    m_numSpeciesTot = nspecies;
    m_numSpeciesRdc = m_numSpeciesTot;
    /*
     *  nc = number of components -> will be determined later.
     *       but set it to its maximum possible value here.
     */
    m_numComponents = nelements;
    /*
     *   m_numRxnTot = number of noncomponents, also equal to the
     *                 number of reactions
     *                 Note, it's possible that the number of elements is greater than
     *                 the number of species. In that case set the number of reactions
     *                 to zero.
     */
    if (nelements > nspecies) {
        m_numRxnTot = 0;
    } else {
        m_numRxnTot = nspecies - nelements;
    }
    m_numRxnRdc = m_numRxnTot;
    /*
     *  number of minor species rxn -> all species rxn are major at the start.
     */
    m_numRxnMinorZeroed = 0;
    /*
     *  NPhase = number of phases
     */
    m_numPhases = nph;

#ifdef DEBUG_MODE
    m_debug_print_lvl = pub->vcs_debug_print_lvl;
#else
    m_debug_print_lvl = std::min(2, pub->vcs_debug_print_lvl);
#endif

    /*
     * FormulaMatrix[] -> Copy the formula matrix over
     */
    for (size_t i = 0; i < nspecies; i++) {
        bool nonzero = false;
        for (size_t j = 0; j < nelements; j++) {
            if (pub->FormulaMatrix[j][i] != 0.0) {
                nonzero = true;
            }
            m_formulaMatrix[j][i] = pub->FormulaMatrix[j][i];
        }
        if (!nonzero) {
            plogf("vcs_prob_specifyFully:: species %d %s has a zero formula matrix!\n", i,
                  pub->SpName[i].c_str());
            return VCS_PUB_BAD;
        }
    }

    /*
     *  Copy over the species molecular weights
     */
    vcs_vdcopy(m_wtSpecies, pub->WtSpecies, nspecies);

    /*
     * Copy over the charges
     */
    vcs_vdcopy(m_chargeSpecies, pub->Charge, nspecies);

    /*
     * Malloc and Copy the VCS_SPECIES_THERMO structures
     *
     */
    for (size_t kspec = 0; kspec < nspecies; kspec++) {
        if (m_speciesThermoList[kspec] != NULL) {
            delete m_speciesThermoList[kspec];
        }
        VCS_SPECIES_THERMO* spf = pub->SpeciesThermo[kspec];
        m_speciesThermoList[kspec] = spf->duplMyselfAsVCS_SPECIES_THERMO();
        if (m_speciesThermoList[kspec] == NULL) {
            plogf(" duplMyselfAsVCS_SPECIES_THERMO returned an error!\n");
            return VCS_PUB_BAD;
        }
    }

    /*
     * Copy the species unknown type
     */
    vcs_icopy(VCS_DATA_PTR(m_speciesUnknownType),
              VCS_DATA_PTR(pub->SpeciesUnknownType), nspecies);

    /*
     *  iest => Do we have an initial estimate of the species mole numbers ?
     */
    m_doEstimateEquil = pub->iest;

    /*
     * w[] -> Copy the equilibrium mole number estimate if it exists.
     */
    if (pub->w.size() != 0) {
        vcs_vdcopy(m_molNumSpecies_old, pub->w, nspecies);
    } else {
        m_doEstimateEquil = -1;
        vcs_dzero(VCS_DATA_PTR(m_molNumSpecies_old), nspecies);
    }

    /*
     * Formulate the Goal Element Abundance Vector
     */
    if (pub->gai.size() != 0) {
        for (size_t i = 0; i < nelements; i++) {
            m_elemAbundancesGoal[i] = pub->gai[i];
            if (pub->m_elType[i] == VCS_ELEM_TYPE_LATTICERATIO) {
                if (m_elemAbundancesGoal[i] < 1.0E-10) {
                    m_elemAbundancesGoal[i] = 0.0;
                }
            }
        }
    } else {
        if (m_doEstimateEquil == 0) {
            double sum = 0;
            for (size_t j = 0; j < nelements; j++) {
                m_elemAbundancesGoal[j] = 0.0;
                for (size_t kspec = 0; kspec < nspecies; kspec++) {
                    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                        sum += m_molNumSpecies_old[kspec];
                        m_elemAbundancesGoal[j] += m_formulaMatrix[j][kspec] * m_molNumSpecies_old[kspec];
                    }
                }
                if (pub->m_elType[j] == VCS_ELEM_TYPE_LATTICERATIO) {
                    if (m_elemAbundancesGoal[j] < 1.0E-10 * sum) {
                        m_elemAbundancesGoal[j] = 0.0;
                    }
                }
            }
        } else {
            plogf("%sElement Abundances, m_elemAbundancesGoal[], not specified\n", ser);
            return VCS_PUB_BAD;
        }
    }

    /*
     * zero out values that will be filled in later
     */
    /*
     * TPhMoles[]      -> Untouched here. These will be filled in vcs_prep.c
     * TPhMoles1[]
     * DelTPhMoles[]
     *
     *
     * T, Pres, copy over here
     */
    if (pub->T  > 0.0) {
        m_temperature = pub->T;
    } else {
        m_temperature = 293.15;
    }
    if (pub->PresPA > 0.0) {
        m_pressurePA = pub->PresPA;
    } else {
        m_pressurePA = Cantera::OneAtm;
    }
    /*
     *   TPhInertMoles[] -> must be copied over here
     */
    for (size_t iph = 0; iph < nph; iph++) {
        Vphase = pub->VPhaseList[iph];
        TPhInertMoles[iph] = Vphase->totalMolesInert();
    }

    /*
     *  if__ : Copy over the units for the chemical potential
     */
    m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;

    /*
     *      tolerance requirements -> copy them over here and later
     */
    m_tolmaj = pub->tolmaj;
    m_tolmin = pub->tolmin;
    m_tolmaj2 = 0.01 * m_tolmaj;
    m_tolmin2 = 0.01 * m_tolmin;

    /*
     * m_speciesIndexVector[] is an index variable that keep track
     * of solution vector rotations.
     */
    for (size_t i = 0; i < nspecies; i++) {
        m_speciesMapIndex[i] = i;
    }

    /*
     *   IndEl[] is an index variable that keep track of element vector
     *   rotations.
     */
    for (size_t i = 0; i < nelements; i++) {
        m_elementMapIndex[i] = i;
    }

    /*
     *  Define all species to be major species, initially.
     */
    for (size_t i = 0; i < nspecies; i++) {
        // m_rxnStatus[i] = VCS_SPECIES_MAJOR;
        m_speciesStatus[i] = VCS_SPECIES_MAJOR;
    }
    /*
     * PhaseID: Fill in the species to phase mapping
     *             -> Check for bad values at the same time.
     */
    if (pub->PhaseID.size() != 0) {
        std::vector<size_t> numPhSp(nph, 0);
        for (size_t kspec = 0; kspec < nspecies; kspec++) {
            size_t iph = pub->PhaseID[kspec];
            if (iph >= nph) {
                plogf("%sSpecies to Phase Mapping, PhaseID, has a bad value\n",
                      ser);
                plogf("\tPhaseID[%d] = %d\n", kspec, iph);
                plogf("\tAllowed values: 0 to %d\n", nph - 1);
                return VCS_PUB_BAD;
            }
            m_phaseID[kspec] = pub->PhaseID[kspec];
            m_speciesLocalPhaseIndex[kspec] = numPhSp[iph];
            numPhSp[iph]++;
        }
        for (size_t iph = 0; iph < nph; iph++) {
            Vphase = pub->VPhaseList[iph];
            if (numPhSp[iph] != Vphase->nSpecies()) {
                plogf("%sNumber of species in phase %d, %s, doesn't match\n",
                      ser, iph, Vphase->PhaseName.c_str());
                return VCS_PUB_BAD;
            }
        }
    } else {
        if (m_numPhases == 1) {
            for (size_t kspec = 0; kspec < nspecies; kspec++) {
                m_phaseID[kspec] = 0;
                m_speciesLocalPhaseIndex[kspec] = kspec;
            }
        } else {
            plogf("%sSpecies to Phase Mapping, PhaseID, is not defined\n", ser);
            return VCS_PUB_BAD;
        }
    }

    /*
     *  Copy over the element types
     */
    m_elType.resize(nelements, VCS_ELEM_TYPE_ABSPOS);
    m_elementActive.resize(nelements, 1);

    /*
     *      Copy over the element names and types
     */
    for (size_t i = 0; i < nelements; i++) {
        m_elementName[i] = pub->ElName[i];
        m_elType[i] = pub->m_elType[i];
        m_elementActive[i] = pub->ElActive[i];
        if (!strncmp(m_elementName[i].c_str(), "cn_", 3)) {
            m_elType[i] = VCS_ELEM_TYPE_CHARGENEUTRALITY;
            if (pub->m_elType[i] != VCS_ELEM_TYPE_CHARGENEUTRALITY) {
                plogf("we have an inconsistency!\n");
                exit(EXIT_FAILURE);
            }
        }
    }

    for (size_t i = 0; i < nelements; i++) {
        if (m_elType[i] ==  VCS_ELEM_TYPE_CHARGENEUTRALITY) {
            if (m_elemAbundancesGoal[i] != 0.0) {
                if (fabs(m_elemAbundancesGoal[i]) > 1.0E-9) {
                    plogf("Charge neutrality condition %s is signicantly nonzero, %g. Giving up\n",
                          m_elementName[i].c_str(), m_elemAbundancesGoal[i]);
                    exit(EXIT_FAILURE);
                } else {
                    if (m_debug_print_lvl >= 2) {
                        plogf("Charge neutrality condition %s not zero, %g. Setting it zero\n",
                              m_elementName[i].c_str(), m_elemAbundancesGoal[i]);
                    }
                    m_elemAbundancesGoal[i] = 0.0;
                }

            }
        }
    }

    /*
     *      Copy over the species names
     */
    for (size_t i = 0; i < nspecies; i++) {
        m_speciesName[i] = pub->SpName[i];
    }
    /*
     *  Copy over all of the phase information
     *  Use the object's assignment operator
     */
    for (size_t iph = 0; iph < nph; iph++) {
        *(m_VolPhaseList[iph]) = *(pub->VPhaseList[iph]);
        /*
         * Fix up the species thermo pointer in the vcs_SpeciesThermo object
         * It should point to the species thermo pointer in the private
         * data space.
         */
        Vphase = m_VolPhaseList[iph];
        for (size_t k = 0; k < Vphase->nSpecies(); k++) {
            vcs_SpeciesProperties* sProp = Vphase->speciesProperty(k);
            size_t kT = Vphase->spGlobalIndexVCS(k);
            sProp->SpeciesThermo = m_speciesThermoList[kT];
        }
    }

    /*
     * Specify the Activity Convention information
     */
    for (size_t iph = 0; iph < nph; iph++) {
        Vphase = m_VolPhaseList[iph];
        m_phaseActConvention[iph] = Vphase->p_activityConvention;
        if (Vphase->p_activityConvention != 0) {
            /*
             * We assume here that species 0 is the solvent.
             * The solvent isn't on a unity activity basis
             * The activity for the solvent assumes that the
             * it goes to one as the species mole fraction goes to
             * one; i.e., it's really on a molarity framework.
             * So SpecLnMnaught[iSolvent] = 0.0, and the
             * loop below starts at 1, not 0.
             */
            size_t iSolvent = Vphase->spGlobalIndexVCS(0);
            double mnaught = m_wtSpecies[iSolvent] / 1000.;
            for (size_t k = 1; k < Vphase->nSpecies(); k++) {
                size_t kspec = Vphase->spGlobalIndexVCS(k);
                m_actConventionSpecies[kspec] = Vphase->p_activityConvention;
                m_lnMnaughtSpecies[kspec] = log(mnaught);
            }
        }
    }

    /*
     *      Copy the title info
     */
    if (pub->Title.size() == 0) {
        m_title = "Unspecified Problem Title";
    } else {
        m_title = pub->Title;
    }

    /*
     *  Copy the volume info
     */
    m_totalVol = pub->Vol;
    if (m_PMVolumeSpecies.size() != 0) {
        vcs_dcopy(VCS_DATA_PTR(m_PMVolumeSpecies), VCS_DATA_PTR(pub->VolPM), nspecies);
    }

    /*
     *      Return the success flag
     */
    return VCS_SUCCESS;
}
Esempio n. 13
0
/*
 *   The VCS_PUB structure is  returned to the user.
 *
 *  @param pub  Pointer to VCS_PROB that will get the results of the
 *              equilibrium calculation transfered to it.
 */
int VCS_SOLVE::vcs_prob_update(VCS_PROB* pub)
{
    size_t k1 = 0;

    vcs_tmoles();
    m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
                              VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_PMVolumeSpecies));

    for (size_t i = 0; i < m_numSpeciesTot; ++i) {
        /*
         *         Find the index of I in the index vector, m_speciesIndexVector[].
         *         Call it K1 and continue.
         */
        for (size_t j = 0; j < m_numSpeciesTot; ++j) {
            k1 = j;
            if (m_speciesMapIndex[j] == i) {
                break;
            }
        }
        /*
         * - Switch the species data back from K1 into I
         */
        if (pub->SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            pub->w[i] = m_molNumSpecies_old[k1];
        } else {
            pub->w[i] = 0.0;
            // plogf("voltage species = %g\n", m_molNumSpecies_old[k1]);
        }
        //pub->mf[i] = m_molNumSpecies_new[k1];
        pub->m_gibbsSpecies[i] = m_feSpecies_old[k1];
        pub->VolPM[i] = m_PMVolumeSpecies[k1];
    }

    pub->T    = m_temperature;
    pub->PresPA = m_pressurePA;
    pub->Vol  = m_totalVol;
    size_t kT = 0;
    for (size_t iph = 0; iph < pub->NPhase; iph++) {
        vcs_VolPhase* pubPhase = pub->VPhaseList[iph];
        vcs_VolPhase* vPhase = m_VolPhaseList[iph];
        pubPhase->setTotalMolesInert(vPhase->totalMolesInert());
        pubPhase->setTotalMoles(vPhase->totalMoles());
        pubPhase->setElectricPotential(vPhase->electricPotential());
        double sumMoles = pubPhase->totalMolesInert();
        pubPhase->setMoleFractionsState(vPhase->totalMoles(),
                                        VCS_DATA_PTR(vPhase->moleFractions()),
                                        VCS_STATECALC_TMP);
        const std::vector<double> & mfVector = pubPhase->moleFractions();
        for (size_t k = 0; k < pubPhase->nSpecies(); k++) {
            kT = pubPhase->spGlobalIndexVCS(k);
            pub->mf[kT] = mfVector[k];
            if (pubPhase->phiVarIndex() == k) {
                k1 = vPhase->spGlobalIndexVCS(k);
                double tmp = m_molNumSpecies_old[k1];
                if (! vcs_doubleEqual(pubPhase->electricPotential() , tmp)) {
                    plogf("We have an inconsistency in voltage, %g, %g\n",
                          pubPhase->electricPotential(), tmp);
                    exit(EXIT_FAILURE);
                }
            }

            if (! vcs_doubleEqual(pub->mf[kT], vPhase->molefraction(k))) {
                plogf("We have an inconsistency in mole fraction, %g, %g\n",
                      pub->mf[kT], vPhase->molefraction(k));
                exit(EXIT_FAILURE);
            }
            if (pubPhase->speciesUnknownType(k) != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                sumMoles +=  pub->w[kT];
            }
        }
        if (! vcs_doubleEqual(sumMoles, vPhase->totalMoles())) {
            plogf("We have an inconsistency in total moles, %g %g\n",
                  sumMoles, pubPhase->totalMoles());
            exit(EXIT_FAILURE);
        }

    }

    pub->m_Iterations            = m_VCount->Its;
    pub->m_NumBasisOptimizations = m_VCount->Basis_Opts;

    return VCS_SUCCESS;
}
Esempio n. 14
0
  int VCS_SOLVE::vcs_elcorr(double aa[], double x[])
   
    /**************************************************************************
     *
     * vcs_elcorr:
     *
     * This subroutine corrects for element abundances. At the end of the 
     * surbroutine, the total moles in all phases are recalculated again,
     * because we have changed the number of moles in this routine.
     *
     * Input
     *  -> temporary work vectors:
     *     aa[ne*ne]
     *     x[ne]
     *
     * Return Values:
     *      0 = Nothing of significance happened,   
     *          Element abundances were and still are good.
     *      1 = The solution changed significantly; 
     *          The element abundances are now good.
     *      2 = The solution changed significantly,
     *          The element abundances are still bad.
     *      3 = The solution changed significantly,
     *          The element abundances are still bad and a component 
     *          species got zeroed out.
     *
     *  Internal data to be worked on::
     *
     *  ga    Current element abundances
     *  m_elemAbundancesGoal   Required elemental abundances
     *  m_molNumSpecies_old     Current mole number of species.
     *  m_formulaMatrix[][]  Formular matrix of the species
     *  ne    Number of elements
     *  nc    Number of components.
     *
     * NOTES:
     *  This routine is turning out to be very problematic. There are 
     *  lots of special cases and problems with zeroing out species.
     *
     *  Still need to check out when we do loops over nc vs. ne.
     *  
     *************************************************************************/
  {
    int i, j, retn = 0, kspec, goodSpec, its; 
    double xx, par, saveDir, dir;

#ifdef DEBUG_MODE
    double l2before = 0.0, l2after = 0.0;
    std::vector<double> ga_save(m_numElemConstraints, 0.0);
    vcs_dcopy(VCS_DATA_PTR(ga_save), VCS_DATA_PTR(m_elemAbundances), m_numElemConstraints);
    if (m_debug_print_lvl >= 2) {
      plogf("   --- vcsc_elcorr: Element abundances correction routine");
      if (m_numElemConstraints != m_numComponents) {
	plogf(" (m_numComponents != m_numElemConstraints)");
      }
      plogf("\n");
    }

    for (i = 0; i < m_numElemConstraints; ++i) {
      x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i];
    }
    l2before = 0.0;
    for (i = 0; i < m_numElemConstraints; ++i) {
      l2before += x[i] * x[i];
    }
    l2before = sqrt(l2before/m_numElemConstraints);
#endif

    /*
     * Special section to take out single species, single component,
     * moles. These are species which have non-zero entries in the
     * formula matrix, and no other species have zero values either.
     *
     */
    int numNonZero = 0;
    bool changed = false;
    bool multisign = false;
    for (i = 0; i < m_numElemConstraints; ++i) {
      numNonZero = 0;
      multisign = false;
      for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	  double eval = m_formulaMatrix[i][kspec];
	  if (eval < 0.0) {
	    multisign = true;
	  }
	  if (eval != 0.0) {
	    numNonZero++;
	  }
	}
      }
      if (!multisign) {
	if (numNonZero < 2) {
	  for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	      double eval = m_formulaMatrix[i][kspec];
	      if (eval > 0.0) {
		m_molNumSpecies_old[kspec] = m_elemAbundancesGoal[i] / eval;
		changed = true;
	      }
	    }
	  }
	} else {
	  int numCompNonZero = 0;
	  int compID = -1;
	  for (kspec = 0; kspec < m_numComponents; kspec++) {
	    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	      double eval = m_formulaMatrix[i][kspec];
	      if (eval > 0.0) {
		compID = kspec;
		numCompNonZero++;
	      }
	    }
	  }
	  if (numCompNonZero == 1) {
	    double diff = m_elemAbundancesGoal[i];
	    for (kspec = m_numComponents; kspec < m_numSpeciesTot; kspec++) {
	      if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
		double eval = m_formulaMatrix[i][kspec];
		diff -= eval * m_molNumSpecies_old[kspec];
	      }
	      m_molNumSpecies_old[compID] = MAX(0.0,diff/m_formulaMatrix[i][compID]);
	      changed = true;
	    }
	  }
	}
      }
    }
    if (changed) {
      vcs_elab();
    }

    /*
     *  Section to check for maximum bounds errors on all species
     *  due to elements.
     *    This may only be tried on element types which are VCS_ELEM_TYPE_ABSPOS.
     *    This is because no other species may have a negative number of these.
     *
     *  Note, also we can do this over ne, the number of elements, not just
     *  the number of components.
     */
    changed = false;
    for (i = 0; i < m_numElemConstraints; ++i) {
      int elType = m_elType[i];
      if (elType == VCS_ELEM_TYPE_ABSPOS) {
	for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	  if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	    double atomComp = m_formulaMatrix[i][kspec];
	    if (atomComp > 0.0) {
	      double maxPermissible = m_elemAbundancesGoal[i] / atomComp;
	      if (m_molNumSpecies_old[kspec] > maxPermissible) {
	      
#ifdef DEBUG_MODE
		if (m_debug_print_lvl >= 3) {
		  plogf("  ---  vcs_elcorr: Reduced species %s from %g to %g "
			"due to %s max bounds constraint\n",
			m_speciesName[kspec].c_str(), m_molNumSpecies_old[kspec], 
			maxPermissible, m_elementName[i].c_str());
		}
#endif
		m_molNumSpecies_old[kspec] = maxPermissible;
		changed = true;
		if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) {
		  m_molNumSpecies_old[kspec] = 0.0;
		  if (m_SSPhase[kspec]) {
		    m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
		  } else {
		    m_speciesStatus[kspec] = VCS_SPECIES_ACTIVEBUTZERO;
		  } 
#ifdef DEBUG_MODE
		  if (m_debug_print_lvl >= 2) {
		    plogf("  ---  vcs_elcorr: Zeroed species %s and changed "
			  "status to %d due to max bounds constraint\n",
			  m_speciesName[kspec].c_str(), m_speciesStatus[kspec]);
		  }
#endif
		}
	      }
	    }
	  }
	}
      }
    }

    // Recalculate the element abundances if something has changed.
    if (changed) {
      vcs_elab();
    }

    /*
     * Ok, do the general case. Linear algebra problem is 
     * of length nc, not ne, as there may be degenerate rows when
     * nc .ne. ne.
     */
    for (i = 0; i < m_numComponents; ++i) {
      x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i];
      if (fabs(x[i]) > 1.0E-13) retn = 1;
      for (j = 0; j < m_numComponents; ++j) {
	aa[j + i*m_numElemConstraints] = m_formulaMatrix[j][i];
      }
    }
    i = vcsUtil_mlequ(aa, m_numElemConstraints, m_numComponents, x, 1);
    if (i == 1) {
      plogf("vcs_elcorr ERROR: mlequ returned error condition\n");
      return VCS_FAILED_CONVERGENCE;
    }
    /*
     * Now apply the new direction without creating negative species.
     */
    par = 0.5;
    for (i = 0; i < m_numComponents; ++i) {
      if (m_molNumSpecies_old[i] > 0.0) {
	xx = -x[i] / m_molNumSpecies_old[i];
	if (par < xx) par = xx;
      }
    }
    if (par > 100.0) {
      par = 100.0;
    }
    par = 1.0 / par;
    if (par < 1.0 && par > 0.0) {
      retn = 2;
      par *= 0.9999;
      for (i = 0; i < m_numComponents; ++i) {
	double tmp = m_molNumSpecies_old[i] + par * x[i];
	if (tmp > 0.0) {
	  m_molNumSpecies_old[i] = tmp;
	} else {
	  if (m_SSPhase[i]) {
	    m_molNumSpecies_old[i] =  0.0;
	  }  else {
	    m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001;
	  }
	}
      }
    } else {
      for (i = 0; i < m_numComponents; ++i) {
	double tmp = m_molNumSpecies_old[i] + x[i];
	if (tmp > 0.0) {
	  m_molNumSpecies_old[i] = tmp;
	} else { 
	  if (m_SSPhase[i]) {
	    m_molNumSpecies_old[i] =  0.0;
	  }  else {
	    m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001;
	  }
	}
      }
    }
   
    /*
     *   We have changed the element abundances. Calculate them again
     */
    vcs_elab();
    /*
     *   We have changed the total moles in each phase. Calculate them again
     */
    vcs_tmoles();
    
    /*
     *       Try some ad hoc procedures for fixing the problem
     */
    if (retn >= 2) {
      /*
       *       First find a species whose adjustment is a win-win
       *       situation.
       */
      for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	  continue;
	}
	saveDir = 0.0;
	goodSpec = TRUE;
	for (i = 0; i < m_numComponents; ++i) {
	  dir = m_formulaMatrix[i][kspec] *  (m_elemAbundancesGoal[i] - m_elemAbundances[i]);
	  if (fabs(dir) > 1.0E-10) {
	    if (dir > 0.0) {
	      if (saveDir < 0.0) {
		goodSpec = FALSE;
		break;
	      }
	    } else {
	      if (saveDir > 0.0) {
		goodSpec = FALSE;
		break;
	      }		   
	    }
	    saveDir = dir;
	  } else {
	    if (m_formulaMatrix[i][kspec] != 0.) {
	      goodSpec = FALSE;
	      break;
	    }
	  }
	}
	if (goodSpec) {
	  its = 0;
	  xx = 0.0;
	  for (i = 0; i < m_numComponents; ++i) {
	    if (m_formulaMatrix[i][kspec] != 0.0) {
	      xx += (m_elemAbundancesGoal[i] - m_elemAbundances[i]) / m_formulaMatrix[i][kspec];
	      its++;
	    }
	  }
	  if (its > 0) xx /= its;
	  m_molNumSpecies_old[kspec] += xx;
	  m_molNumSpecies_old[kspec] = MAX(m_molNumSpecies_old[kspec], 1.0E-10);
	  /*
	   *   If we are dealing with a deleted species, then
	   *   we need to reinsert it into the active list.
	   */
	  if (kspec >= m_numSpeciesRdc) {
	    vcs_reinsert_deleted(kspec);	
	    m_molNumSpecies_old[m_numSpeciesRdc - 1] = xx;
	    vcs_elab();
	    goto L_CLEANUP;
	  }
	  vcs_elab();  
	}
      }     
    }
    if (vcs_elabcheck(0)) {
      retn = 1;
      goto L_CLEANUP;
    }
  
    for (i = 0; i < m_numElemConstraints; ++i) {
      if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY ||
	  (m_elType[i] == VCS_ELEM_TYPE_ABSPOS && m_elemAbundancesGoal[i] == 0.0)) { 
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (m_elemAbundances[i] > 0.0) {
	    if (m_formulaMatrix[i][kspec] < 0.0) {
	      m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec] ;
	      if (m_molNumSpecies_old[kspec] < 0.0) {
		m_molNumSpecies_old[kspec] = 0.0;
	      }
	      vcs_elab();
	      break;
	    }
	  }
	  if (m_elemAbundances[i] < 0.0) {
	    if (m_formulaMatrix[i][kspec] > 0.0) {
	      m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec];
	      if (m_molNumSpecies_old[kspec] < 0.0) {
		m_molNumSpecies_old[kspec] = 0.0;
	      }
	      vcs_elab();
	      break;
	    }
	  }
	}
      }
    }
    if (vcs_elabcheck(1)) {
      retn = 1;      
      goto L_CLEANUP;
    }

    /*
     *  For electron charges element types, we try positive deltas
     *  in the species concentrations to match the desired
     *  electron charge exactly.
     */
    for (i = 0; i < m_numElemConstraints; ++i) {
      double dev = m_elemAbundancesGoal[i] - m_elemAbundances[i];
      if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) {
	bool useZeroed = true;
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (dev < 0.0) {
	    if (m_formulaMatrix[i][kspec] < 0.0) {
	      if (m_molNumSpecies_old[kspec] > 0.0) {
		useZeroed = false;
	      }
	    }
	  } else {
	    if (m_formulaMatrix[i][kspec] > 0.0) {
	      if (m_molNumSpecies_old[kspec] > 0.0) {
		useZeroed = false;
	      }
	    }
	  }
	}
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (m_molNumSpecies_old[kspec] > 0.0 || useZeroed) {
	    if (dev < 0.0) {
	      if (m_formulaMatrix[i][kspec] < 0.0) {
		double delta = dev / m_formulaMatrix[i][kspec] ;
		m_molNumSpecies_old[kspec] += delta;
		if (m_molNumSpecies_old[kspec] < 0.0) {
		  m_molNumSpecies_old[kspec] = 0.0;
		}
		vcs_elab();
		break;
	      }
	    }
	    if (dev > 0.0) {
	      if (m_formulaMatrix[i][kspec] > 0.0) {
		double delta = dev / m_formulaMatrix[i][kspec] ;
		m_molNumSpecies_old[kspec] += delta;
		if (m_molNumSpecies_old[kspec] < 0.0) {
		  m_molNumSpecies_old[kspec] = 0.0;
		}
		vcs_elab();
		break;
	      }
	    }
	  }
	}
      }
    }
    if (vcs_elabcheck(1)) {
      retn = 1;      
      goto L_CLEANUP;
    }

  L_CLEANUP: ;
    vcs_tmoles();
#ifdef DEBUG_MODE
    l2after = 0.0;
    for (i = 0; i < m_numElemConstraints; ++i) {
      l2after += SQUARE(m_elemAbundances[i] - m_elemAbundancesGoal[i]);
    }
    l2after = sqrt(l2after/m_numElemConstraints);
    if (m_debug_print_lvl >= 2) {
      plogf("   ---    Elem_Abund:  Correct             Initial  "
	    "              Final\n");
      for (i = 0; i < m_numElemConstraints; ++i) {
	plogf("   ---       "); plogf("%-2.2s", m_elementName[i].c_str());
	plogf(" %20.12E %20.12E %20.12E\n", m_elemAbundancesGoal[i], ga_save[i], m_elemAbundances[i]);
      }
      plogf("   ---            Diff_Norm:         %20.12E %20.12E\n",
	    l2before, l2after);
    }
#endif
    return retn;
  }
Esempio n. 15
0
/**************************************************************************
 *
 *  vcs_report:
 *
 *     Print out a report on the state of the equilibrium problem to
 *     standard output.
 *     This prints out the current contents of the VCS_SOLVE class, V.
 *     The "old" solution vector is printed out.
 ***************************************************************************/
int VCS_SOLVE::vcs_report(int iconv) {
    bool printActualMoles = true, inertYes = false;
    size_t i, j, l, k, kspec;
    size_t nspecies = m_numSpeciesTot;
    double  g;

    char originalUnitsState = m_unitsState;


    std::vector<size_t> sortindex(nspecies,0);
    std::vector<double> xy(nspecies,0.0);

    /* ************************************************************** */
    /* **** SORT DEPENDENT SPECIES IN DECREASING ORDER OF MOLES ***** */
    /* ************************************************************** */

    for (i = 0; i < nspecies; ++i) {
        sortindex[i] = i;
        xy[i] = m_molNumSpecies_old[i];
    }
    /*
     *       Sort the XY vector, the mole fraction vector,
     *       and the sort index vector, sortindex, according to
     *       the magnitude of the mole fraction vector.
     */
    for (l = m_numComponents; l < m_numSpeciesRdc; ++l) {
        k = vcs_optMax(VCS_DATA_PTR(xy), 0, l, m_numSpeciesRdc);
        if (k != l) {
            vcsUtil_dsw(VCS_DATA_PTR(xy), k, l);
            vcsUtil_ssw(VCS_DATA_PTR(sortindex), k, l);
        }
    }

    /*
     *  Decide whether we have to nondimensionalize the equations.
     *     -> For the printouts from this routine, we will use nondimensional
     *        representations. This may be expanded in the future.
     */
    if (m_unitsState == VCS_DIMENSIONAL_G) {
        vcs_nondim_TP();
    }
    double molScale = 1.0;
    if (printActualMoles) {
        molScale = m_totalMoleScale;
    }

    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesTot);
    /* ******************************************************** */
    /* *** PRINT OUT RESULTS ********************************** */
    /* ******************************************************** */

    plogf("\n\n\n\n");
    print_line("-", 80);
    print_line("-", 80);
    plogf("\t\t VCS_TP REPORT\n");
    print_line("-", 80);
    print_line("-", 80);
    if (iconv < 0) {
        plogf(" ERROR: CONVERGENCE CRITERION NOT SATISFIED.\n");
    } else if (iconv == 1) {
        plogf(" RANGE SPACE ERROR: Equilibrium Found but not all Element Abundances are Satisfied\n");
    }
    /*
     *   Calculate some quantities that may need updating
     */
    vcs_tmoles();
    m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
                              VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_PMVolumeSpecies));

    plogf("\t\tTemperature  = %15.2g Kelvin\n", m_temperature);
    plogf("\t\tPressure     = %15.5g Pa \n", m_pressurePA);
    plogf("\t\ttotal Volume = %15.5g m**3\n", m_totalVol * molScale);
    if (!printActualMoles) {
        plogf("\t\tMole Scale = %15.5g kmol (all mole numbers and volumes are scaled by this value)\n",
              molScale);
    }

    /*
     * -------- TABLE OF SPECIES IN DECREASING MOLE NUMBERS --------------
     */
    plogf("\n\n");
    print_line("-", 80);
    plogf(" Species                 Equilibrium kmoles   ");
    plogf("Mole Fraction    ChemPot/RT    SpecUnkType\n");
    print_line("-", 80);
    for (i = 0; i < m_numComponents; ++i) {
        plogf(" %-12.12s", m_speciesName[i].c_str());
        print_space(13);
        plogf("%14.7E     %14.7E    %12.4E", m_molNumSpecies_old[i] * molScale,
              m_molNumSpecies_new[i] * molScale, m_feSpecies_old[i]);
        plogf("   %3d", m_speciesUnknownType[i]);
        plogf("\n");
    }
    for (i = m_numComponents; i < m_numSpeciesRdc; ++i) {
        l = sortindex[i];
        plogf(" %-12.12s", m_speciesName[l].c_str());
        print_space(13);

        if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_MOLNUM) {
            plogf("%14.7E     %14.7E    %12.4E", m_molNumSpecies_old[l] * molScale,
                  m_molNumSpecies_new[l] * molScale, m_feSpecies_old[l]);
            plogf("  KMolNum ");
        } else if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            plogf("        NA         %14.7E    %12.4E", 1.0, m_feSpecies_old[l]);
            plogf("   Voltage = %14.7E", m_molNumSpecies_old[l] * molScale);
        } else {
            plogf("we have a problem\n");
            exit(EXIT_FAILURE);
        }
        plogf("\n");
    }
    for (i = 0; i < m_numPhases; i++) {
        if (TPhInertMoles[i] > 0.0) {
            inertYes = true;
            if (i == 0) {
                plogf(" Inert Gas Species        ");
            } else {
                plogf(" Inert Species in phase %16s ",
                      (m_VolPhaseList[i])->PhaseName.c_str());
            }
            plogf("%14.7E     %14.7E    %12.4E\n", TPhInertMoles[i] * molScale,
                  TPhInertMoles[i] /  m_tPhaseMoles_old[i], 0.0);
        }
    }
    if (m_numSpeciesRdc != nspecies) {
        plogf("\n SPECIES WITH LESS THAN 1.0E-32 KMOLES:\n\n");
        for (kspec = m_numSpeciesRdc; kspec < nspecies; ++kspec) {
            plogf(" %-12.12s", m_speciesName[kspec].c_str());
            // Note m_deltaGRxn_new[] stores in kspec slot not irxn slot, after solve
            plogf("             %14.7E     %14.7E    %12.4E",
                  m_molNumSpecies_old[kspec]*molScale,
                  m_molNumSpecies_new[kspec]*molScale, m_deltaGRxn_new[kspec]);
            if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) {
                plogf("  KMol_Num");
            } else if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                plogf("   Voltage");
            } else {
                plogf("   Unknown");
            }

            plogf("\n");
        }
    }
    print_line("-", 80);
    plogf("\n");

    /*
     * ---------- TABLE OF SPECIES FORMATION REACTIONS ------------------
     */
    plogf("\n");
    print_line("-", m_numComponents*10 + 45);
    plogf("               |ComponentID|");
    for (j = 0; j < m_numComponents; j++) {
        plogf("        %3d", j);
    }
    plogf(" |           |\n");
    plogf("               | Components|");
    for (j = 0; j < m_numComponents; j++) {
        plogf(" %10.10s", m_speciesName[j].c_str());
    }
    plogf(" |           |\n");
    plogf(" NonComponent  |   Moles   |");
    for (j = 0; j < m_numComponents; j++) {
        plogf(" %10.3g", m_molNumSpecies_old[j] * molScale);
    }
    plogf(" | DG/RT Rxn |\n");
    print_line("-", m_numComponents*10 + 45);
    for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) {
        size_t kspec = m_indexRxnToSpecies[irxn];
        plogf(" %3d ", kspec);
        plogf("%-10.10s", m_speciesName[kspec].c_str());
        plogf("|%10.3g |", m_molNumSpecies_old[kspec]*molScale);
        for (j = 0; j < m_numComponents; j++) {
            plogf("     %6.2f", m_stoichCoeffRxnMatrix[irxn][j]);
        }
        plogf(" |%10.3g |", m_deltaGRxn_new[irxn]);
        plogf("\n");
    }
    print_line("-", m_numComponents*10 + 45);
    plogf("\n");

    /*
     * ------------------ TABLE OF PHASE INFORMATION ---------------------
     */
    std::vector<double> gaPhase(m_numElemConstraints, 0.0);
    std::vector<double> gaTPhase(m_numElemConstraints, 0.0);
    double totalMoles = 0.0;
    double gibbsPhase = 0.0;
    double gibbsTotal = 0.0;
    plogf("\n\n");
    plogf("\n");
    print_line("-", m_numElemConstraints*10 + 58);
    plogf("                  | ElementID |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf("        %3d", j);
    }
    plogf(" |                     |\n");
    plogf("                  | Element   |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.10s", (m_elementName[j]).c_str());
    }
    plogf(" |                     |\n");
    plogf("    PhaseName     |KMolTarget |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.3g", m_elemAbundancesGoal[j]);
    }
    plogf(" |     Gibbs Total     |\n");
    print_line("-", m_numElemConstraints*10 + 58);
    for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
        plogf(" %3d ", iphase);
        vcs_VolPhase *VPhase = m_VolPhaseList[iphase];
        plogf("%-12.12s |",VPhase->PhaseName.c_str());
        plogf("%10.3e |", m_tPhaseMoles_old[iphase]*molScale);
        totalMoles +=  m_tPhaseMoles_old[iphase];
        if (m_tPhaseMoles_old[iphase] != VPhase->totalMoles()) {
            if (! vcs_doubleEqual(m_tPhaseMoles_old[iphase], VPhase->totalMoles())) {
                plogf("We have a problem\n");
                exit(EXIT_FAILURE);
            }
        }
        vcs_elabPhase(iphase, VCS_DATA_PTR(gaPhase));
        for (j = 0; j < m_numElemConstraints; j++) {
            plogf(" %10.3g", gaPhase[j]);
            gaTPhase[j] += gaPhase[j];
        }
        gibbsPhase = vcs_GibbsPhase(iphase, VCS_DATA_PTR(m_molNumSpecies_old),
                                    VCS_DATA_PTR(m_feSpecies_old));
        gibbsTotal += gibbsPhase;
        plogf(" | %18.11E |\n", gibbsPhase);
    }
    print_line("-", m_numElemConstraints*10 + 58);
    plogf("    TOTAL         |%10.3e |", totalMoles);
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.3g", gaTPhase[j]);
    }
    plogf(" | %18.11E |\n", gibbsTotal);

    print_line("-", m_numElemConstraints*10 + 58);
    plogf("\n");

    /*
     * ----------- GLOBAL SATISFACTION INFORMATION -----------------------
     */

    /*
     *    Calculate the total dimensionless Gibbs Free Energy
     *     -> Inert species are handled as if they had a standard free
     *        energy of zero
     */

    g = vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old),
                        VCS_DATA_PTR(m_tPhaseMoles_old));
    plogf("\n\tTotal Dimensionless Gibbs Free Energy = G/RT = %15.7E\n", g);
    if (inertYes)
        plogf("\t\t(Inert species have standard free energy of zero)\n");

    plogf("\nElemental Abundances (kmol): ");
    plogf("         Actual                    Target         Type      ElActive\n");
    for (i = 0; i < m_numElemConstraints; ++i) {
        print_space(26);
        plogf("%-2.2s", (m_elementName[i]).c_str());
        plogf("%20.12E  %20.12E", m_elemAbundances[i]*molScale, m_elemAbundancesGoal[i]*molScale);
        plogf("   %3d     %3d\n", m_elType[i], m_elementActive[i]);
    }
    plogf("\n");

    /*
     * ------------------ TABLE OF SPECIES CHEM POTS ---------------------
     */
    plogf("\n");
    print_line("-", 93);
    plogf("Chemical Potentials of the Species: (dimensionless)\n");

    double rt = vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature);
    plogf("\t\t(RT = %g ", rt);
    vcs_printChemPotUnits(m_VCS_UnitsFormat);
    plogf(")\n");
    plogf("    Name        TKMoles     StandStateChemPot   "
          "   ln(AC)       ln(X_i)      |   F z_i phi   |    ChemPot    | (-lnMnaught)");
    plogf("|  (MolNum ChemPot)|");
    plogf("\n");
    print_line("-", 147);
    for (i = 0; i < nspecies; ++i) {
        l = sortindex[i];
        size_t pid = m_phaseID[l];
        plogf(" %-12.12s", m_speciesName[l].c_str());
        plogf(" %14.7E ", m_molNumSpecies_old[l]*molScale);
        plogf("%14.7E  ", m_SSfeSpecies[l]);
        plogf("%14.7E  ", log(m_actCoeffSpecies_old[l]));
        double tpmoles = m_tPhaseMoles_old[pid];
        double phi = m_phasePhi[pid];
        double eContrib = phi * m_chargeSpecies[l] * m_Faraday_dim;
        double lx = 0.0;
        if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            lx = 0.0;
        } else {
            if (tpmoles > 0.0 && m_molNumSpecies_old[l] > 0.0) {
                double tmp = MAX(VCS_DELETE_MINORSPECIES_CUTOFF, m_molNumSpecies_old[l]);
                lx = log(tmp) - log(tpmoles);
            } else {
                lx = m_feSpecies_old[l] - m_SSfeSpecies[l]
                     - log(m_actCoeffSpecies_old[l]) + m_lnMnaughtSpecies[l];
            }
        }
        plogf("%14.7E  |", lx);
        plogf("%14.7E | ", eContrib);
        double tmp = m_SSfeSpecies[l] + log(m_actCoeffSpecies_old[l])
                     + lx - m_lnMnaughtSpecies[l] + eContrib;
        if (fabs(m_feSpecies_old[l] - tmp) > 1.0E-7) {
            plogf("\n\t\twe have a problem - doesn't add up\n");
            exit(EXIT_FAILURE);
        }
        plogf(" %12.4E |", m_feSpecies_old[l]);
        if( m_lnMnaughtSpecies[l] != 0.0) {
            plogf("(%11.5E)", - m_lnMnaughtSpecies[l]);
        } else {
            plogf("             ");
        }

        plogf("|  %20.9E |", m_feSpecies_old[l] * m_molNumSpecies_old[l] * molScale);
        plogf("\n");
    }
    for (i = 0; i < 125; i++) plogf(" ");
    plogf(" %20.9E\n", g);
    print_line("-", 147);

    /*
     * ------------- TABLE OF SOLUTION COUNTERS --------------------------
     */
    plogf("\n");
    plogf("\nCounters:         Iterations          Time (seconds)\n");
    if (m_timing_print_lvl > 0) {
        plogf("    vcs_basopt:   %5d             %11.5E\n",
              m_VCount->Basis_Opts, m_VCount->Time_basopt);
        plogf("    vcs_TP:       %5d             %11.5E\n",
              m_VCount->Its, m_VCount->Time_vcs_TP);
    } else {
        plogf("    vcs_basopt:   %5d             %11s\n",
              m_VCount->Basis_Opts,"    NA     ");
        plogf("    vcs_TP:       %5d             %11s\n",
              m_VCount->Its,"    NA     " );
    }
    print_line("-", 80);
    print_line("-", 80);

    /*
     *   Set the Units state of the system back to where it was when we
     *   entered the program.
     */
    if (originalUnitsState != m_unitsState) {
        if (originalUnitsState == VCS_DIMENSIONAL_G ) vcs_redim_TP();
        else                                          vcs_nondim_TP();
    }
    /*
     *   Return a successful completion flag
     */
    return VCS_SUCCESS;
} /* vcs_report() ************************************************************/
Esempio n. 16
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;
}
Esempio n. 17
0
void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm,
                          double* const ss, double test)
{
    size_t nspecies = m_numSpeciesTot;
    size_t nrxn = m_numRxnTot;

    /*
     *       CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB
     *           AND molNum(I) .GE. 0.0
     *
     *   Note, both of these programs do this.
     */
    vcs_setMolesLinProg();

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n",
              pprefix);
        plogf("%s     SPECIES          MOLE_NUMBER      -SS_ChemPotential\n", pprefix);
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s     ", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            plogf(" %15.5g  %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]);
        }
        plogf("%s Element Abundance Agreement returned from linear "
              "programming (vcs_inest initial guess):",
              pprefix);
        plogendl();
        plogf("%s     Element           Goal         Actual\n", pprefix);
        for (size_t j = 0; j < m_numElemConstraints; j++) {
            if (m_elementActive[j]) {
                double tmp = 0.0;
                for (size_t kspec = 0; kspec < nspecies; ++kspec) {
                    tmp +=  m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
                }
                plogf("%s     ", pprefix);
                plogf("   %-9.9s", (m_elementName[j]).c_str());
                plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp);
            }
        }
        plogendl();
    }

    /*
     *     Make sure all species have positive definite mole numbers
     *     Set voltages to zero for now, until we figure out what to do
     */
    m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0);
    for (size_t kspec = 0; kspec < nspecies; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            if (m_molNumSpecies_old[kspec] <= 0.0) {
                /*
                 * HKM Should eventually include logic here for non SS phases
                 */
                if (!m_SSPhase[kspec]) {
                    m_molNumSpecies_old[kspec] = 1.0e-30;
                }
            }
        } else {
            m_molNumSpecies_old[kspec] = 0.0;
        }
    }

    /*
     *      Now find the optimized basis that spans the stoichiometric
     *      coefficient matrix
     */
    bool conv;
    (void) vcs_basopt(false, aw, sa, sm, ss, test, &conv);

    /* ***************************************************************** */
    /* **** CALCULATE TOTAL MOLES,                    ****************** */
    /* **** CHEMICAL POTENTIALS OF BASIS              ****************** */
    /* ***************************************************************** */
    /*
     * Calculate TMoles and m_tPhaseMoles_old[]
     */
    vcs_tmoles();
    /*
     * m_tPhaseMoles_new[] will consist of just the component moles
     */
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20;
    }
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
            m_tPhaseMoles_new[m_phaseID[kspec]] += m_molNumSpecies_old[kspec];
        }
    }
    double TMolesMultiphase = 0.0;
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        if (! m_VolPhaseList[iph]->m_singleSpecies) {
            TMolesMultiphase += m_tPhaseMoles_new[iph];
        }
    }
    m_molNumSpecies_new = m_molNumSpecies_old;
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_MOLNUM) {
            m_molNumSpecies_new[kspec] = 0.0;
        }
    }
    m_feSpecies_new = m_SSfeSpecies;

    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
            if (! m_SSPhase[kspec]) {
                size_t iph = m_phaseID[kspec];
                m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]);
            }
        } else {
            m_molNumSpecies_new[kspec] = 0.0;
        }
    }
    vcs_deltag(0, true, VCS_STATECALC_NEW);
    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            if (kspec < m_numComponents)
                plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec],
                      m_SSfeSpecies[kspec]);
            else
                plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n",
                      m_feSpecies_new[kspec], m_SSfeSpecies[kspec], m_deltaGRxn_new[kspec-m_numComponents]);
        }
    }
    /* ********************************************************** */
    /* **** ESTIMATE REACTION ADJUSTMENTS *********************** */
    /* ********************************************************** */
    double* xtphMax = VCS_DATA_PTR(m_TmpPhase);
    double* xtphMin = VCS_DATA_PTR(m_TmpPhase2);
    m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32);
        xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32);
    }
    for (size_t irxn = 0; irxn < nrxn; ++irxn) {
        size_t kspec = m_indexRxnToSpecies[irxn];
        /*
         * For single species phases, we will not estimate the
         * mole numbers. If the phase exists, it stays. If it
         * doesn't exist in the estimate, it doesn't come into
         * existence here.
         */
        if (! m_SSPhase[kspec]) {
            size_t iph = m_phaseID[kspec];
            if (m_deltaGRxn_new[irxn] > xtphMax[iph]) {
                m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph];
            }
            if (m_deltaGRxn_new[irxn] < xtphMin[iph]) {
                m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph];
            }
            /*
             *   HKM -> The TMolesMultiphase is a change of mine.
             *          It more evenly distributes the initial moles amongst
             *          multiple multispecies phases according to the
             *          relative values of the standard state free energies.
             *          There is no change for problems with one multispecies
             *          phase.
             *            It cut diamond4.vin iterations down from 62 to 14.
             */
            m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase)
                                          * exp(-m_deltaGRxn_new[irxn]);

            for (size_t k = 0; k < m_numComponents; ++k) {
                m_deltaMolNumSpecies[k] += m_stoichCoeffRxnMatrix(k,irxn) * m_deltaMolNumSpecies[kspec];
            }

            for (iph = 0; iph < m_numPhases; iph++) {
                m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec];
            }
        }
    }
    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                plogf("%sdirection (", pprefix);
                plogf("%-12.12s", m_speciesName[kspec].c_str());
                plogf(") = %g", m_deltaMolNumSpecies[kspec]);
                if (m_SSPhase[kspec]) {
                    if (m_molNumSpecies_old[kspec] > 0.0) {
                        plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]);
                    } else {
                        plogf(" (ssPhase doesn't exist -> stability not checked)");
                    }
                }
                plogendl();
            }
        }
    }
    /* *********************************************************** */
    /* **** KEEP COMPONENT SPECIES POSITIVE ********************** */
    /* *********************************************************** */
    double par = 0.5;
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            if (par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) {
                par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec];
            }
        }
    }
    par = 1. / par;
    if (par <= 1.0 && par > 0.0) {
        par *= 0.8;
    } else {
        par = 1.0;
    }
    /* ******************************************** */
    /* **** CALCULATE NEW MOLE NUMBERS ************ */
    /* ******************************************** */
    size_t lt = 0;
    size_t ikl = 0;
    double s1 = 0.0;
    while (true) {
        for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec];
            } else {
                m_deltaMolNumSpecies[kspec] = 0.0;
            }
        }
        for (size_t kspec = m_numComponents; kspec < nspecies; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                if (m_deltaMolNumSpecies[kspec] != 0.0) {
                    m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par;
                }
            }
        }
        /*
         * We have a new w[] estimate, go get the
         * TMoles and m_tPhaseMoles_old[] values
         */
        vcs_tmoles();
        if (lt > 0) {
            break;
        }
        /* ******************************************* */
        /* **** CONVERGENCE FORCING SECTION ********** */
        /* ******************************************* */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, nspecies);
        double s = 0.0;
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec];
        }
        if (s == 0.0) {
            break;
        }
        if (s < 0.0) {
            if (ikl == 0) {
                break;
            }
        }
        /* ***************************************** */
        /* *** TRY HALF STEP SIZE ****************** */
        /* ***************************************** */
        if (ikl == 0) {
            s1 = s;
            par *= 0.5;
            ikl = 1;
            continue;
        }
        /* **************************************************** */
        /* **** FIT PARABOLA THROUGH HALF AND FULL STEPS ****** */
        /* **************************************************** */
        double xl = (1.0 - s / (s1 - s)) * 0.5;
        if (xl < 0.0) {
            /* *************************************************** */
            /* *** POOR DIRECTION, REDUCE STEP SIZE TO 0.2 ******* */
            /* *************************************************** */
            par *= 0.2;
        } else {
            if (xl > 1.0) {
                /* *************************************************** */
                /* **** TOO BIG A STEP, TAKE ORIGINAL FULL STEP ****** */
                /* *************************************************** */
                par *= 2.0;
            } else {
                /* *************************************************** */
                /* **** ACCEPT RESULTS OF FORCER ********************* */
                /* *************************************************** */
                par = par * 2.0 * xl;
            }
        }
        lt = 1;
    }

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%s     Final Mole Numbers produced by inest:\n",
              pprefix);
        plogf("%s     SPECIES      MOLE_NUMBER\n", pprefix);
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s     ", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            plogf(" %g", m_molNumSpecies_old[kspec]);
            plogendl();
        }
    }
}
Esempio n. 18
0
  int VCS_SOLVE::vcs_rank(const double * awtmp, size_t numSpecies,  const double matrix[], size_t numElemConstraints,
			  std::vector<size_t> &compRes, std::vector<size_t>& elemComp, int * const usedZeroedSpecies) const 
  {

    int    lindep;
    size_t j, k, jl, i, l, ml;
    int numComponents = 0;

    compRes.clear();
    elemComp.clear();
    vector<double> sm(numElemConstraints*numSpecies);
    vector<double> sa(numSpecies);
    vector<double> ss(numSpecies);

    double test = -0.2512345E298;
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
      plogf("   "); for(i=0; i<77; i++) plogf("-"); plogf("\n");
      plogf("   --- Subroutine vcs_rank called to ");
      plogf("calculate the rank and independent rows /colums of the following matrix\n");     
      if (m_debug_print_lvl >= 5) {
	plogf("   ---     Species |  ");
	for (j = 0; j < numElemConstraints; j++) {
	  plogf(" "); 
	  plogf("   %3d  ", j);
	}
	plogf("\n");
	plogf("   ---     -----------");
	for (j = 0; j < numElemConstraints; j++) {
	  plogf("---------");
	}
	plogf("\n");
	for (k = 0; k < numSpecies; k++) {
	  plogf("   --- ");
	  plogf("  %3d  ", k);
	  plogf("     |");
	  for (j = 0; j < numElemConstraints; j++) {
	    plogf(" %8.2g", matrix[j*numSpecies + k]);
	  }
	  plogf("\n");
	}
	plogf("   ---");
	plogendl();
      }
    }
#endif
   
    /*
     *  Calculate the maximum value of the number of components possible
     *     It's equal to the minimum of the number of elements and the
     *     number of total species.
     */
    int ncTrial = std::min(numElemConstraints, numSpecies);
    numComponents = ncTrial;
    *usedZeroedSpecies = false;

    /* 
     *     Use a temporary work array for the mole numbers, aw[] 
     */
    std::vector<double> aw(numSpecies);
    for (j = 0; j < numSpecies; j++) {
      aw[j] = awtmp[j];
    }

    int jr = -1;
    /*
     *   Top of a loop of some sort based on the index JR. JR is the 
     *   current number of component species found. 
     */
    do {
      ++jr;
      /* - Top of another loop point based on finding a linearly */
      /* - independent species */
      do {
	/*
	 *    Search the remaining part of the mole number vector, AW, 
	 *    for the largest remaining species. Return its identity in K. 
	 *    The first search criteria is always the largest positive
	 *    magnitude of the mole number.
	 */
	k = basisOptMax1(VCS_DATA_PTR(aw), numSpecies);

	if ((aw[k] != test) && fabs(aw[k]) == 0.0) {
	  *usedZeroedSpecies = true;
	}

    
	if (aw[k] == test) {
	  numComponents = jr;

	  goto L_CLEANUP;
	}
	/*
	 *  Assign a small negative number to the component that we have
	 *  just found, in order to take it out of further consideration.
	 */
	aw[k] = test;
	/* *********************************************************** */
	/* **** CHECK LINEAR INDEPENDENCE WITH PREVIOUS SPECIES ****** */
	/* *********************************************************** */
	/*    
	 *          Modified Gram-Schmidt Method, p. 202 Dalquist 
	 *          QR factorization of a matrix without row pivoting. 
	 */
	jl = jr;
	for (j = 0; j < numElemConstraints; ++j) {
	  sm[j + jr*numElemConstraints] = matrix[j*numSpecies + 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 (j = 0; j < jl; ++j) {
	    ss[j] = 0.0;
	    for (i = 0; i < numElemConstraints; ++i) {
	      ss[j] += sm[i + jr* numElemConstraints] * sm[i + j* numElemConstraints];
	    }
	    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 < numElemConstraints; ++l) {
	      sm[l + jr*numElemConstraints] -= ss[j] * sm[l + j*numElemConstraints];
	    }
	  }
	}
	/*
	 *        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 < numElemConstraints; ++ml) {
	  sa[jr] += SQUARE(sm[ml + jr * numElemConstraints]);
	}
	/* **************************************************** */
	/* **** IF NORM OF NEW ROW  .LT. 1E-3 REJECT ********** */
	/* **************************************************** */
	if (sa[jr] < 1.0e-6)  lindep = true;
	else                  lindep = false;
      } while(lindep);
      /* ****************************************** */
      /* **** REARRANGE THE DATA ****************** */
      /* ****************************************** */
      compRes.push_back(k);
      elemComp.push_back(jr);
 
    } while (jr < (ncTrial-1));

  L_CLEANUP: ;
 
    if (numComponents  == ncTrial && numElemConstraints == numSpecies) {
      return numComponents;
    }
  

    int  numComponentsR = numComponents;

    ss.resize(numElemConstraints);
    sa.resize(numElemConstraints);
 
 
    elemComp.clear();
  
    aw.resize(numElemConstraints);
    for (j = 0; j < numSpecies; j++) {
      aw[j] = 1.0;
    }

    jr = -1;

    do {
      ++jr;

      do {

	k = basisOptMax1(VCS_DATA_PTR(aw), numElemConstraints);
    
	if (aw[k] == test) {
	  numComponents = jr;
	  goto LE_CLEANUP;
	}
	aw[k] = test;


	jl = jr;
	for (j = 0; j < numSpecies; ++j) {
	  sm[j + jr*numSpecies] = matrix[k*numSpecies + j];
	}
	if (jl > 0) {

	  for (j = 0; j < jl; ++j) {
	    ss[j] = 0.0;
	    for (i = 0; i < numSpecies; ++i) {
	      ss[j] += sm[i + jr* numSpecies] * sm[i + j* numSpecies];
	    }
	    ss[j] /= sa[j];
	  }

	  for (j = 0; j < jl; ++j) {
	    for (l = 0; l < numSpecies; ++l) {
	      sm[l + jr*numSpecies] -= ss[j] * sm[l + j*numSpecies];
	    }
	  }
	}

	sa[jr] = 0.0;
	for (ml = 0; ml < numSpecies; ++ml) {
	  sa[jr] += SQUARE(sm[ml + jr * numSpecies]);
	}

	if (sa[jr] < 1.0e-6)  lindep = true;
	else                  lindep = false;
      } while(lindep);
  
      elemComp.push_back(k);

    } while (jr < (ncTrial-1));
    numComponents = jr;
  LE_CLEANUP: ;

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
      plogf("   --- vcs_rank found rank %d\n", numComponents);
      if (m_debug_print_lvl >= 5) {
	if (compRes.size() == elemComp.size()) {
	  printf("   ---       compRes    elemComp\n");
	  for (int i = 0; i < (int) compRes.size(); i++) {
	    printf("   ---          %d          %d \n", (int) compRes[i], (int) elemComp[i]);
	  }
	} else {
	  for (int i = 0; i < (int) compRes.size(); i++) {
	    printf("   ---   compRes[%d] =   %d \n", (int) i, (int) compRes[i]);
	  }
	  for (int i = 0; i < (int) elemComp.size(); i++) {
	    printf("   ---   elemComp[%d] =   %d \n", (int) i, (int) elemComp[i]);
	  }
	} 
      }
    }
#endif

    if (numComponentsR != numComponents) {
      printf("vcs_rank ERROR: number of components are different: %d %d\n", numComponentsR,  numComponents);
      throw Cantera::CanteraError("vcs_rank ERROR:",
			 " logical inconsistency");
      exit(-1);
    }
    return numComponents;
  }
Esempio n. 19
0
double VCS_SOLVE::vcs_line_search(const size_t irxn, const double dx_orig)
#endif
{
    int its = 0;
    size_t k;
    size_t kspec = m_indexRxnToSpecies[irxn];
    const int MAXITS = 10;
    double dx = dx_orig;
    double* sc_irxn = m_stoichCoeffRxnMatrix[irxn];
    double* molNumBase = VCS_DATA_PTR(m_molNumSpecies_old);
    double* acBase = VCS_DATA_PTR(m_actCoeffSpecies_old);
    double* ac = VCS_DATA_PTR(m_actCoeffSpecies_new);
    double molSum = 0.0;
    double slope;
    /*
     * Calculate the deltaG value at the dx = 0.0 point
     */
    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    double deltaGOrig = deltaG_Recalc_Rxn(VCS_STATECALC_OLD, irxn, molNumBase, acBase, VCS_DATA_PTR(m_feSpecies_old));
    double forig = fabs(deltaGOrig) + 1.0E-15;
    if (deltaGOrig > 0.0) {
        if (dx_orig > 0.0) {
            dx = 0.0;
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                //plogf("    --- %s :Warning possible error dx>0 dg > 0\n", SpName[kspec]);
            }
            sprintf(ANOTE, "Rxn reduced to zero step size in line search: dx>0 dg > 0");
#endif
            return dx;
        }
    } else if (deltaGOrig < 0.0) {
        if (dx_orig < 0.0) {
            dx = 0.0;
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                //plogf("   --- %s :Warning possible error dx<0 dg < 0\n", SpName[kspec]);
            }
            sprintf(ANOTE, "Rxn reduced to zero step size in line search: dx<0 dg < 0");
#endif
            return dx;
        }
    } else if (deltaGOrig == 0.0) {
        return 0.0;
    }
    if (dx_orig == 0.0) {
        return 0.0;
    }

    vcs_dcopy(VCS_DATA_PTR(m_molNumSpecies_new), molNumBase, m_numSpeciesRdc);
    molSum = molNumBase[kspec];
    m_molNumSpecies_new[kspec] = molNumBase[kspec] + dx_orig;
    for (k = 0; k < m_numComponents; k++) {
        m_molNumSpecies_new[k] = molNumBase[k] + sc_irxn[k] * dx_orig;
        molSum += molNumBase[k];
    }
    vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);

    double deltaG1 = deltaG_Recalc_Rxn(VCS_STATECALC_NEW, irxn, VCS_DATA_PTR(m_molNumSpecies_new),
                                       ac, VCS_DATA_PTR(m_feSpecies_new));

    /*
     * If deltaG hasn't switched signs when going the full distance
     * then we are heading in the appropriate direction, and
     * we should accept the current full step size
     */
    if (deltaG1 * deltaGOrig > 0.0) {
        dx = dx_orig;
        goto finalize;
    }
    /*
     * If we have decreased somewhat, the deltaG return after finding
     * a better estimate for the line search.
     */
    if (fabs(deltaG1) < 0.8 * forig) {
        if (deltaG1 * deltaGOrig < 0.0) {
            slope = (deltaG1 - deltaGOrig) / dx_orig;
            dx = -deltaGOrig / slope;
        } else {
            dx = dx_orig;
        }
        goto finalize;
    }

    dx = dx_orig;

    for (its = 0; its < MAXITS; its++) {
        /*
         * Calculate the approximation to the total Gibbs free energy at
         * the dx  *= 0.5 point
         */
        dx *= 0.5;
        m_molNumSpecies_new[kspec] = molNumBase[kspec] + dx;
        for (k = 0; k < m_numComponents; k++) {
            m_molNumSpecies_new[k] = molNumBase[k] + sc_irxn[k] * dx;
        }
        vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
        double deltaG = deltaG_Recalc_Rxn(VCS_STATECALC_NEW, irxn, VCS_DATA_PTR(m_molNumSpecies_new),
                                          ac, VCS_DATA_PTR(m_feSpecies_new));
        /*
         * If deltaG hasn't switched signs when going the full distance
         * then we are heading in the appropriate direction, and
         * we should accept the current step
         */
        if (deltaG * deltaGOrig > 0.0) {
            goto finalize;
        }
        /*
         * If we have decreased somewhat, the deltaG return after finding
         * a better estimate for the line search.
         */
        if (fabs(deltaG) / forig < (1.0 - 0.1 * dx / dx_orig)) {
            if (deltaG * deltaGOrig < 0.0) {
                slope = (deltaG - deltaGOrig) / dx;
                dx = -deltaGOrig / slope;
            }
            goto finalize;
        }
    }

finalize:
    vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
    if (its >= MAXITS) {
#ifdef DEBUG_MODE
        sprintf(ANOTE, "Rxn reduced to zero step size from %g to %g (MAXITS)", dx_orig, dx);
        return dx;
#endif
    }
#ifdef DEBUG_MODE
    if (dx != dx_orig) {
        sprintf(ANOTE, "Line Search reduced step size from %g to %g", dx_orig, dx);
    }
#endif

    return dx;
}
Esempio n. 20
0
void VCS_PROB::reportCSV(const std::string& reportFile)
{
    size_t k;
    size_t istart;

    double vol = 0.0;
    string sName;

    FILE* FP = fopen(reportFile.c_str(), "w");
    if (!FP) {
        plogf("Failure to open file\n");
        exit(EXIT_FAILURE);
    }
    double Temp = T;

    std::vector<double> volPM(nspecies, 0.0);
    std::vector<double> activity(nspecies, 0.0);
    std::vector<double> ac(nspecies, 0.0);
    std::vector<double> mu(nspecies, 0.0);
    std::vector<double> mu0(nspecies, 0.0);
    std::vector<double> molalities(nspecies, 0.0);

    vol = 0.0;
    size_t iK = 0;
    for (size_t iphase = 0; iphase < NPhase; iphase++) {
        istart = iK;
        vcs_VolPhase* volP = VPhaseList[iphase];
        //const Cantera::ThermoPhase *tptr = volP->ptrThermoPhase();
        size_t nSpeciesPhase = volP->nSpecies();
        volPM.resize(nSpeciesPhase, 0.0);
        volP->sendToVCS_VolPM(VCS_DATA_PTR(volPM));

        double TMolesPhase = volP->totalMoles();
        double VolPhaseVolumes = 0.0;
        for (k = 0; k < nSpeciesPhase; k++) {
            iK++;
            VolPhaseVolumes += volPM[istart + k] * mf[istart + k];
        }
        VolPhaseVolumes *= TMolesPhase;
        vol += VolPhaseVolumes;
    }

    fprintf(FP,"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
            " -----------------------------\n");
    fprintf(FP,"Temperature  = %11.5g kelvin\n", Temp);
    fprintf(FP,"Pressure     = %11.5g Pascal\n", PresPA);
    fprintf(FP,"Total Volume = %11.5g m**3\n", vol);
    fprintf(FP,"Number Basis optimizations = %d\n", m_NumBasisOptimizations);
    fprintf(FP,"Number VCS iterations = %d\n", m_Iterations);

    iK = 0;
    for (size_t iphase = 0; iphase < NPhase; iphase++) {
        istart = iK;

        vcs_VolPhase* volP = VPhaseList[iphase];
        const Cantera::ThermoPhase<doublereal>* tp = volP->ptrThermoPhase();
        string phaseName = volP->PhaseName;
        size_t nSpeciesPhase = volP->nSpecies();
        volP->sendToVCS_VolPM(VCS_DATA_PTR(volPM));
        double TMolesPhase = volP->totalMoles();
        //AssertTrace(TMolesPhase == m_mix->phaseMoles(iphase));
        activity.resize(nSpeciesPhase, 0.0);
        ac.resize(nSpeciesPhase, 0.0);

        mu0.resize(nSpeciesPhase, 0.0);
        mu.resize(nSpeciesPhase, 0.0);
        volPM.resize(nSpeciesPhase, 0.0);
        molalities.resize(nSpeciesPhase, 0.0);

        int actConvention = tp->activityConvention();
        tp->getActivities(VCS_DATA_PTR(activity));
        tp->getActivityCoefficients(VCS_DATA_PTR(ac));
        tp->getStandardChemPotentials(VCS_DATA_PTR(mu0));

        tp->getPartialMolarVolumes(VCS_DATA_PTR(volPM));
        tp->getChemPotentials(VCS_DATA_PTR(mu));
        double VolPhaseVolumes = 0.0;
        for (k = 0; k < nSpeciesPhase; k++) {
            VolPhaseVolumes += volPM[k] * mf[istart + k];
        }
        VolPhaseVolumes *= TMolesPhase;
        vol += VolPhaseVolumes;


        if (actConvention == 1) {
            const Cantera::MolalityVPSSTP* mTP = static_cast<const Cantera::MolalityVPSSTP*>(tp);
            tp->getChemPotentials(VCS_DATA_PTR(mu));
            mTP->getMolalities(VCS_DATA_PTR(molalities));
            tp->getChemPotentials(VCS_DATA_PTR(mu));

            if (iphase == 0) {
                fprintf(FP,"        Name,      Phase,  PhaseMoles,  Mole_Fract, "
                        "Molalities,  ActCoeff,   Activity,"
                        "ChemPot_SS0,   ChemPot,   mole_num,       PMVol, Phase_Volume\n");

                fprintf(FP,"            ,           ,      (kmol),            , "
                        "          ,          ,           ,"
                        "   (J/kmol),  (J/kmol),     (kmol), (m**3/kmol),     (m**3)\n");
            }
            for (k = 0; k < nSpeciesPhase; k++) {
                sName = tp->speciesName(k);
                fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
                        "%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
                        sName.c_str(),
                        phaseName.c_str(), TMolesPhase,
                        mf[istart + k], molalities[k], ac[k], activity[k],
                        mu0[k]*1.0E-6, mu[k]*1.0E-6,
                        mf[istart + k] * TMolesPhase,
                        volPM[k],  VolPhaseVolumes);
            }

        } else {
            if (iphase == 0) {
                fprintf(FP,"        Name,       Phase,  PhaseMoles,  Mole_Fract,  "
                        "Molalities,   ActCoeff,    Activity,"
                        "  ChemPotSS0,     ChemPot,   mole_num,       PMVol, Phase_Volume\n");

                fprintf(FP,"            ,            ,      (kmol),            ,  "
                        "          ,           ,            ,"
                        "    (J/kmol),    (J/kmol),     (kmol), (m**3/kmol),       (m**3)\n");
            }
            for (k = 0; k < nSpeciesPhase; k++) {
                molalities[k] = 0.0;
            }
            for (k = 0; k < nSpeciesPhase; k++) {
                sName = tp->speciesName(k);
                fprintf(FP,"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
                        "%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
                        sName.c_str(),
                        phaseName.c_str(), TMolesPhase,
                        mf[istart + k],  molalities[k], ac[k],
                        activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
                        mf[istart + k] * TMolesPhase,
                        volPM[k],  VolPhaseVolumes);
            }
        }

#ifdef DEBUG_MODE
        /*
         * Check consistency: These should be equal
         */
        tp->getChemPotentials(VCS_DATA_PTR(m_gibbsSpecies)+istart);
        for (k = 0; k < nSpeciesPhase; k++) {
            if (!vcs_doubleEqual(m_gibbsSpecies[istart+k], mu[k])) {
                fprintf(FP,"ERROR: incompatibility!\n");
                fclose(FP);
                plogf("ERROR: incompatibility!\n");
                exit(EXIT_FAILURE);
            }
        }
#endif
        iK += nSpeciesPhase;
    }
    fclose(FP);
}
Esempio n. 21
0
/*
 *  This routine is always followed by vcs_prep(). Therefore, tasks
 *  that need to be done for every call to vcsc() should be placed in
 *  vcs_prep() and not in this routine.
 *
 *  The problem structure refers to:
 *
 *     the number and identity of the species.
 *     the formula matrix and thus the number of components.
 *     the number and identity of the phases.
 *     the equation of state
 *     the method and parameters for determining the standard state
 *     The method and parameters for determining the activity coefficients.
 *
 * Tasks:
 *    0) Fill in the SSPhase[] array.
 *    1) Check to see if any multispecies phases actually have only one
 *       species in that phase. If true, reassign that phase and species
 *       to be a single-species phase.
 *    2) Determine the number of components in the problem if not already
 *       done so. During this process the order of the species is changed
 *       in the private data structure. All references to the species
 *       properties must employ the ind[] index vector.
 *
 *  @param printLvl Print level of the routine
 *
 *  @return the return code
 *        VCS_SUCCESS = everything went OK
 *
 */
int VCS_SOLVE::vcs_prep_oneTime(int printLvl) {
    size_t kspec, i;
    int retn = VCS_SUCCESS;
    double pres, test;
    double *aw, *sa, *sm, *ss;
    bool modifiedSoln = false;
    bool conv;

    m_debug_print_lvl = printLvl;


    /*
     *  Calculate the Single Species status of phases
     *  Also calculate the number of species per phase
     */
    vcs_SSPhase();

    /*
     *      Set an initial estimate for the number of noncomponent species
     *      equal to nspecies - nelements. This may be changed below
     */
    m_numRxnTot = m_numSpeciesTot - m_numElemConstraints;
    m_numRxnRdc = m_numRxnTot;
    m_numSpeciesRdc = m_numSpeciesTot;
    for (i = 0; i < m_numRxnRdc; ++i) {
        m_indexRxnToSpecies[i] = m_numElemConstraints + i;
    }

    for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
        size_t pID = m_phaseID[kspec];
        size_t spPhIndex = m_speciesLocalPhaseIndex[kspec];
        vcs_VolPhase *vPhase =  m_VolPhaseList[pID];
        vcs_SpeciesProperties *spProp = vPhase->speciesProperty(spPhIndex);
        double sz = 0.0;
        size_t eSize = spProp->FormulaMatrixCol.size();
        for (size_t e = 0; e < eSize; e++) {
            sz += fabs(spProp->FormulaMatrixCol[e]);
        }
        if (sz > 0.0) {
            m_spSize[kspec] = sz;
        } else {
            m_spSize[kspec] = 1.0;
        }
    }

    /* ***************************************************** */
    /* **** DETERMINE THE NUMBER OF COMPONENTS ************* */
    /* ***************************************************** */

    /*
     *       Obtain a valid estimate of the mole fraction. This will
     *       be used as an initial ordering vector for prioritizing
     *       which species are defined as components.
     *
     *       If a mole number estimate was supplied from the
     *       input file, use that mole number estimate.
     *
     *       If a solution estimate wasn't supplied from the input file,
     *       supply an initial estimate for the mole fractions
     *       based on the relative reverse ordering of the
     *       chemical potentials.
     *
     *       For voltage unknowns, set these to zero for the moment.
     */
    test = -1.0e-10;
    if (m_doEstimateEquil < 0) {
        double sum  = 0.0;
        for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
            if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
                sum += fabs(m_molNumSpecies_old[kspec]);
            }
        }
        if (fabs(sum) < 1.0E-6) {
            modifiedSoln = true;
            if (m_pressurePA <= 0.0)  pres = 1.01325E5;
            else                      pres = m_pressurePA;
            retn = vcs_evalSS_TP(0, 0, m_temperature, pres);
            for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
                if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
                    m_molNumSpecies_old[kspec] = - m_SSfeSpecies[kspec];
                } else {
                    m_molNumSpecies_old[kspec] = 0.0;
                }
            }
        }
        test = -1.0e20;
    }

    /*
     *      NC = number of components is in the vcs.h common block
     *     This call to BASOPT doesn't calculate the stoichiometric
     *     reaction matrix.
     */
    std::vector<double> awSpace( m_numSpeciesTot + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
    aw = VCS_DATA_PTR(awSpace);
    if (aw == NULL) {
        plogf("vcs_prep_oneTime: failed to get memory: global bailout\n");
        return VCS_NOMEMORY;
    }
    sa = aw + m_numSpeciesTot;
    sm = sa + m_numElemConstraints;
    ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
    retn = vcs_basopt(true, aw, sa, sm, ss, test, &conv);
    if (retn != VCS_SUCCESS) {
        plogf("vcs_prep_oneTime:");
        plogf(" Determination of number of components failed: %d\n",
              retn);
        plogf("          Global Bailout!\n");
        return retn;
    }

    if (m_numElemConstraints != m_numComponents) {
        m_numRxnTot = m_numRxnRdc = m_numSpeciesTot - m_numComponents;
        for (i = 0; i < m_numRxnRdc; ++i) {
            m_indexRxnToSpecies[i] = m_numComponents + i;
        }
    }

    /*
     *   The elements might need to be rearranged.
     */
    awSpace.resize(m_numElemConstraints + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
    aw = VCS_DATA_PTR(awSpace);
    sa = aw + m_numElemConstraints;
    sm = sa + m_numElemConstraints;
    ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
    retn = vcs_elem_rearrange(aw, sa, sm, ss);
    if (retn != VCS_SUCCESS) {
        plogf("vcs_prep_oneTime:");
        plogf(" Determination of element reordering failed: %d\n",
              retn);
        plogf("          Global Bailout!\n");
        return retn;
    }

    // If we mucked up the solution unknowns because they were all
    // zero to start with, set them back to zero here
    if (modifiedSoln) {
        for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
            m_molNumSpecies_old[kspec] = 0.0;
        }
    }
    return VCS_SUCCESS;
}
Esempio n. 22
0
void vcs_VolPhase::_updateG0() const
{
    TP_ptr->getGibbs_ref(VCS_DATA_PTR(SS0ChemicalPotential));
    m_UpToDate_G0 = true;
}
Esempio n. 23
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;
}
Esempio n. 24
0
 //====================================================================================================================
  double vcs_PhaseStabilitySolve::vcs_phaseStabilitySubSolve(const int iph) {

    /*
     * We will use the _new state calc here
     */
    int kspec, irxn, k, i, kc, kc_spec;
    vcs_VolPhase *Vphase = fVS_->m_VolPhaseList[iph];
    doublereal deltaGRxn;

    // We will do a full newton calculation later, but for now, ...
    bool doSuccessiveSubstitution = true;
    double funcPhaseStability;
    vector<doublereal> X_est(Vphase->nSpecies(), 0.0);
    vector<doublereal> delFrac(Vphase->nSpecies(), 0.0);
    vector<doublereal> E_phi(Vphase->nSpecies(), 0.0);
    vector<doublereal> fracDelta_new(Vphase->nSpecies(), 0.0);
    vector<doublereal> fracDelta_old(Vphase->nSpecies(), 0.0);
    vector<doublereal> fracDelta_raw(Vphase->nSpecies(), 0.0);
    vector<int>        creationGlobalRxnNumbers(Vphase->nSpecies(), -1);
    vcs_dcopy(VCS_DATA_PTR(fVS_->m_deltaGRxn_Deficient), VCS_DATA_PTR(fVS_->m_deltaGRxn_old), fVS_->m_numRxnRdc);

    std::vector<doublereal> m_feSpecies_Deficient(fVS_->m_numComponents, 0.0);
    doublereal damp = 1.0;
    doublereal dampOld = 1.0;
    doublereal normUpdate = 1.0;
    doublereal normUpdateOld = 1.0;
    doublereal sum = 0.0;
    doublereal dirProd = 0.0;
    doublereal dirProdOld = 0.0;

    // get the activity coefficients
    Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, VCS_DATA_PTR(fVS_->m_actCoeffSpecies_new));

    // Get the storred estimate for the composition of the phase if 
    // it gets created
    fracDelta_new = Vphase->creationMoleNumbers(creationGlobalRxnNumbers);


    bool oneIsComponent = false;
    std::vector<int> componentList;

    for (k = 0; k < Vphase->nSpecies(); k++) {
      kspec = Vphase->spGlobalIndexVCS(k);
      if (kspec < fVS_->m_numComponents) {
        oneIsComponent = true;
        componentList.push_back(k);
      }
    }

    for (k = 0; k < fVS_->m_numComponents; k++) {
      m_feSpecies_Deficient[k]  = fVS_->m_feSpecies_old[k];
    }
    normUpdate = 0.1 * vcs_l2norm(fracDelta_new);
    damp = 1.0E-2;

    if (doSuccessiveSubstitution) {

#ifdef DEBUG_MODE
      int KP = 0;
      if (fVS_->m_debug_print_lvl >= 2) {
        plogf("   --- vcs_phaseStabilityTest() called\n");
        plogf("   ---  Its   X_old[%2d]  FracDel_old[%2d]  deltaF[%2d] FracDel_new[%2d]"
              "  normUpdate     damp     FuncPhaseStability\n", KP, KP, KP, KP);
        plogf("   --------------------------------------------------------------"
              "--------------------------------------------------------\n");
      } else if (fVS_->m_debug_print_lvl == 1) {
        plogf("   --- vcs_phaseStabilityTest() called for phase %d\n", iph);
      }
#endif

      for (k = 0; k < Vphase->nSpecies(); k++) {
        if (fracDelta_new[k] < 1.0E-13) {
          fracDelta_new[k] = 1.0E-13;
        }
      }
      bool converged = false;
      for (int its = 0; its < 200  && (!converged); its++) {

        dampOld = damp;
        normUpdateOld = normUpdate;
        fracDelta_old = fracDelta_new;
        dirProdOld = dirProd;



        // Given a set of fracDelta's, we calculate the fracDelta's
        // for the component species, if any
        for (i = 0; i < (int) componentList.size(); i++) {
          kc = componentList[i];
          kc_spec = Vphase->spGlobalIndexVCS(kc);
          fracDelta_old[kc] = 0.0;
          for (k = 0; k <  Vphase->nSpecies(); k++) {
            kspec = Vphase->spGlobalIndexVCS(k);
            irxn = kspec - fVS_->m_numComponents;
            if (irxn >= 0) {
              fracDelta_old[kc] += fVS_->m_stoichCoeffRxnMatrix[irxn][kc_spec] *  fracDelta_old[k];
            }
          }
        }
        // Now, calculate the predicted mole fractions, X_est[k]
        double sumFrac = 0.0;
        for (k = 0; k < Vphase->nSpecies(); k++) {
          sumFrac += fracDelta_old[k];
        }
        // Necessary because this can be identically zero. -> we need to fix this algorithm!
        if (sumFrac <= 0.0) {
          sumFrac = 1.0;
        }
        double sum_Xcomp = 0.0;
        for (k = 0; k < Vphase->nSpecies(); k++) {
          X_est[k] = fracDelta_old[k] / sumFrac;
          kc_spec = Vphase->spGlobalIndexVCS(k);
          if (kc_spec < fVS_->m_numComponents) {
            sum_Xcomp += X_est[k];
          }
        }


        /*
         * Feed the newly formed estimate of the mole fractions back into the
         * ThermoPhase object
         */
        Vphase->setMoleFractionsState(0.0, VCS_DATA_PTR(X_est), VCS_STATECALC_PHASESTABILITY);

        /*
         *   get the activity coefficients
         */
        Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, VCS_DATA_PTR(fVS_->m_actCoeffSpecies_new));

        /*
         * First calculate altered chemical potentials for component species
         * belonging to this phase.
         */
        for (i = 0; i < (int) componentList.size(); i++) {
          kc = componentList[i];
          kc_spec = Vphase->spGlobalIndexVCS(kc);
          if ( X_est[kc] > VCS_DELETE_MINORSPECIES_CUTOFF) {
            m_feSpecies_Deficient[kc_spec] = fVS_->m_feSpecies_old[kc_spec] + log(fVS_->m_actCoeffSpecies_new[kc_spec] * X_est[kc]);
          } else {
            m_feSpecies_Deficient[kc_spec] = fVS_->m_feSpecies_old[kc_spec] + log(fVS_->m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF);
          }
        }

        for (i = 0; i < (int) componentList.size(); i++) {
          kc = componentList[i];
          kc_spec = Vphase->spGlobalIndexVCS(kc);

          for (k = 0; k <  Vphase->nSpecies(); k++) {
            kspec = Vphase->spGlobalIndexVCS(k);
            irxn = kspec - fVS_->m_numComponents;
            if (irxn >= 0) {
              if (i == 0) {
                fVS_->m_deltaGRxn_Deficient[irxn] = fVS_->m_deltaGRxn_old[irxn];
              }
              double *dtmp_ptr = fVS_->m_stoichCoeffRxnMatrix[irxn];
              if (dtmp_ptr[kc_spec] != 0.0) {
                fVS_->m_deltaGRxn_Deficient[irxn] += dtmp_ptr[kc_spec] * (m_feSpecies_Deficient[kc_spec]- fVS_->m_feSpecies_old[kc_spec]);
              }
            }

          }
        }
        /*
         *  Calculate the E_phi's
         */
        sum = 0.0;
        funcPhaseStability = sum_Xcomp - 1.0;
        for (k = 0; k <  Vphase->nSpecies(); k++) {
          kspec = Vphase->spGlobalIndexVCS(k);
          irxn = kspec - fVS_->m_numComponents;
          if (irxn >= 0) {
            deltaGRxn = fVS_->m_deltaGRxn_Deficient[irxn];
            if (deltaGRxn >  50.0) deltaGRxn =  50.0;
            if (deltaGRxn < -50.0) deltaGRxn = -50.0;
            E_phi[k] = std::exp(-deltaGRxn) / fVS_->m_actCoeffSpecies_new[kspec];
            sum +=  E_phi[k];
            funcPhaseStability += E_phi[k];
          } else {
            E_phi[k] = 0.0;
          }
        }

        /*
         * Calculate the raw estimate of the new fracs
         */
        for (k = 0; k <  Vphase->nSpecies(); k++) {
          kspec = Vphase->spGlobalIndexVCS(k);
          irxn = kspec - fVS_->m_numComponents;
          double b =  E_phi[k] / sum * (1.0 - sum_Xcomp);
          if (irxn >= 0) {
            fracDelta_raw[k] = b;
          }
        }


        // Given a set of fracDelta's, we calculate the fracDelta's
        // for the component species, if any
        for (i = 0; i < (int) componentList.size(); i++) {
          kc = componentList[i];
          kc_spec = Vphase->spGlobalIndexVCS(kc);
          fracDelta_raw[kc] = 0.0;
          for (k = 0; k <  Vphase->nSpecies(); k++) {
            kspec = Vphase->spGlobalIndexVCS(k);
            irxn = kspec - fVS_->m_numComponents;
            if (irxn >= 0) {
              fracDelta_raw[kc] += fVS_->m_stoichCoeffRxnMatrix[irxn][kc_spec] * fracDelta_raw[k];
            }
          }
        }

        /*
         * Now possibly dampen the estimate.
         */
        doublereal sumADel = 0.0;
        for (k = 0; k <  Vphase->nSpecies(); k++) {
          delFrac[k] = fracDelta_raw[k] - fracDelta_old[k];
          sumADel += fabs(delFrac[k]);
        }
        normUpdate = vcs_l2norm(delFrac);

        dirProd = 0.0;
        for (k = 0; k <  Vphase->nSpecies(); k++) {
          dirProd += fracDelta_old[k] * delFrac[k];
        }
        bool crossedSign = false;
        if (dirProd * dirProdOld < 0.0) {
          crossedSign = true;
        }


        damp = 0.5;
        if (dampOld < 0.25) {
          damp = 2.0 * dampOld;
        }
        if (crossedSign) {
          if (normUpdate *1.5 > normUpdateOld) {
            damp = 0.5 * dampOld;
          } else if (normUpdate *2.0 > normUpdateOld) {
            damp = 0.8 * dampOld;
          }
        } else {
          if (normUpdate > normUpdateOld * 2.0) {
            damp = 0.6 * dampOld;
          } else if (normUpdate > normUpdateOld * 1.2) {
            damp = 0.9 * dampOld;
          }
        }

        for (k = 0; k < Vphase->nSpecies(); k++) {
          if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) {
            damp = MAX(0.3*fabs(fracDelta_old[k]) / fabs( delFrac[k]),
                       1.0E-8/fabs( delFrac[k]));
          }
          if (delFrac[k] < 0.0) {
            if (2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) {
              damp = fracDelta_old[k] / (2.0 * (-delFrac[k]));
            }
          }
          if (delFrac[k] > 0.0) {
            if (2.0 * damp * delFrac[k] > fracDelta_old[k]) {
              damp = fracDelta_old[k] / (2.0 * delFrac[k]);
            }
          }
        }
        if (damp < 0.000001) {
          damp = 0.000001;
        }

        for (k = 0; k <  Vphase->nSpecies(); k++) {
          fracDelta_new[k] = fracDelta_old[k] + damp * (delFrac[k]);
        }

#ifdef DEBUG_MODE
        if (fVS_->m_debug_print_lvl >= 2) {
          plogf("  --- %3d %12g %12g %12g %12g %12g %12g %12g\n", its, X_est[KP], fracDelta_old[KP],
                delFrac[KP], fracDelta_new[KP], normUpdate, damp, funcPhaseStability);
        }
#endif

        if (normUpdate < 1.0E-5) {
          converged = true;
        }

      }

      if (converged) {
        Vphase->setMoleFractionsState(0.0, VCS_DATA_PTR(X_est),
                                      VCS_STATECALC_PHASESTABILITY);
        Vphase->setCreationMoleNumbers(VCS_DATA_PTR(fracDelta_new), creationGlobalRxnNumbers);
      }


    } else {
      printf("not done yet\n");
      exit(-1);
    }
#ifdef DEBUG_MODE
    if (fVS_->m_debug_print_lvl >= 2) {
      plogf("  ------------------------------------------------------------"
            "-------------------------------------------------------------\n");
    } else if (fVS_->m_debug_print_lvl == 1) {
      if (funcPhaseStability > 0.0) {
        plogf("  --- phase %d with func = %g is to be born\n", iph, funcPhaseStability);
      } else {
        plogf("  --- phase %d with func = %g stays dead\n", iph, funcPhaseStability);
      }
    }
#endif
    return funcPhaseStability;
  }