/**
 * @file vcs_solve_TP.cpp Implementation file that contains the
 *     main algorithm for finding an equilibrium
 */
/*
 * Copyright (2005) Sandia Corporation. Under the terms of
 * Contract DE-AC04-94AL85000 with Sandia Corporation, the
 * U.S. Government retains certain rights in this software.
 */

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cassert>

#include "vcs_solve.h"
#include "vcs_internal.h"
#include "vcs_VolPhase.h"
#include "vcs_species_thermo.h"

#include "cantera/base/clockWC.h"
#include "cantera/base/stringUtils.h"

using namespace std;

namespace VCSnonideal
{


/***************************************************************************/
/************ Prototypes for static functions ******************************/


static void print_space(size_t num);



#ifdef DEBUG_MODE
#  ifdef DEBUG_NOT
static void prneav(void);
static int  prnfm(void);
#  endif
#endif
/*****************************************************************************/


#ifdef DEBUG_MODE
void VCS_SOLVE::checkDelta1(double* const dsLocal,
                            double* const delTPhMoles, int kspec)
{
    std::vector<double> dchange(m_numPhases, 0.0);
    for (int k = 0; k < kspec; k++) {
        if (m_speciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            int iph = m_phaseID[k];
            dchange[iph] += dsLocal[k];
        }
    }
    for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
        double denom = MAX(m_totalMolNum, 1.0E-4);
        if (!vcs_doubleEqual(dchange[iphase]/denom, delTPhMoles[iphase]/denom)) {
            plogf("checkDelta1: we have found a problem\n");
            exit(EXIT_FAILURE);
        }
    }
}
#endif
/*****************************************************************************/

// Main routine that solves for equilibrium at constant T and P
// using a variant of the VCS method
/*
 * This is the main routine  taht solves for equilibrium at constant T and P
 * using a variant of the VCS method. Nonideal phases can be accommodated
 * as well.
 *
 * Any number of single-species phases and  multi-species phases
 * can be handled by the present version.
 *
 *     Input
 * ------------
 *   @param print_lvl     1 -> Print results to standard output
 *                        0 -> don't report on anything
 *
 *   @param printDetails  1 -> Print intermediate results.
 *
 *   @param maxit         Maximum number of iterations for the algorithm
 *
 *   @return     0 = Equilibrium Achieved
 *               1 = Range space error encountered. The element abundance criteria are
 *                   only partially satisfied. Specifically, the first NC= (number of
 *                   components) conditions are satisfied. However, the full NE
 *                   (number of elements) conditions are not satisfied. The equilibrirum
 *                   condition is returned.
 *              -1 = Maximum number of iterations is exceeded. Convergence was not
 *                   found.
 */
int VCS_SOLVE::vcs_solve_TP(int print_lvl, int printDetails, int maxit)
{
    int retn = VCS_SUCCESS, soldel, solveFail;
    double test, RT;
    size_t j, k, l, l1, kspec, irxn, i;
    bool conv = false, allMinorZeroedSpecies = false, forced, lec;
    size_t iph;
    double dx, xx, par;
    size_t it1 = 0;
    size_t npb, iti, lnospec;
    bool dofast;
    int rangeErrorFound = 0;
    bool giveUpOnElemAbund = false;
    int finalElemAbundAttempts = 0;
    bool uptodate_minors = true;
    bool justDeletedMultiPhase = false;
    bool usedZeroedSpecies; /* return flag from basopt indicating that
                  one of the components had a zero concentration */
    size_t doPhaseDeleteIph = npos;
    vcs_VolPhase* Vphase;
    double*     sc_irxn = NULL;  /* Stoichiometric coefficients for cur rxn  */
    double* dnPhase_irxn;
    double atomComp;
    size_t iphasePop;
    int forceComponentCalc = 1;
    size_t iphaseDelete;  /* integer that determines which phase is being deleted */
    std::vector<size_t> phasePopPhaseIDs(0);
#ifdef DEBUG_MODE
    char ANOTE[128];
    /*
     * Set the debug print lvl to the same as the print lvl.
     */
    m_debug_print_lvl = printDetails;
#endif
    if (printDetails > 0 && print_lvl == 0) {
        print_lvl = 1;
    }
    /*
     *    Initialize and set up all counters
     */
    vcs_counters_init(0);
    Cantera::clockWC ticktock;

    /*
     *  Malloc temporary space for usage in this routine and in
     *  subroutines
     *        sm[ne*ne]
     *        ss[ne]
     *        sa[ne]
     *        aw[m]
     *        wx[ne]
     *        xy[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, 0.0);
    std::vector<double> wx(m_numElemConstraints, 0.0);

    solveFail = false;


    /* ****************************************************** */
    /* **** Evaluate the elemental composition         ****** */
    /* ****************************************************** */
    vcs_elab();

    /* ******************************************************* */
    /* **** Printout the initial conditions for problem ****** */
    /* ******************************************************* */

    if (print_lvl != 0) {
        plogf("VCS CALCULATION METHOD\n\n ");
        plogf("%s\n", m_title.c_str());
        plogf("\n\n%5d SPECIES\n%5d ELEMENTS\n", m_numSpeciesTot, m_numElemConstraints);
        plogf("%5d COMPONENTS\n", m_numComponents);
        plogf("%5d PHASES\n", m_numPhases);

        plogf(" PRESSURE%22.8g %3s\n", m_pressurePA, "Pa ");
        plogf(" TEMPERATURE%19.3f K\n", m_temperature);
        Vphase = m_VolPhaseList[0];
        if (Vphase->nSpecies() > 0) {
            plogf(" PHASE1 INERTS%17.3f\n", TPhInertMoles[0]);
        }
        if (m_numPhases > 1) {
            plogf(" PHASE2 INERTS%17.3f\n", TPhInertMoles[1]);
        }
        plogf("\n ELEMENTAL ABUNDANCES             CORRECT");
        plogf("          FROM ESTIMATE           Type\n\n");
        for (i = 0; i < m_numElemConstraints; ++i) {
            print_space(26);
            plogf("%-2.2s", (m_elementName[i]).c_str());
            plogf("%20.12E%20.12E     %3d\n", m_elemAbundancesGoal[i], m_elemAbundances[i],
                  m_elType[i]);
        }
        if (m_doEstimateEquil < 0) {
            plogf("\n MODIFIED LINEAR PROGRAMMING ESTIMATE OF EQUILIBRIUM - forced\n");
        } else if (m_doEstimateEquil > 0) {
            plogf("\n MODIFIED LINEAR PROGRAMMING ESTIMATE OF EQUILIBRIUM - where necessary\n");
        }
        if (m_doEstimateEquil == 0) {
            plogf("\n USER ESTIMATE OF EQUILIBRIUM\n");
        }
        if (m_VCS_UnitsFormat == VCS_UNITS_KCALMOL) {
            plogf(" Stan. Chem. Pot. in kcal/mole\n");
        }
        if (m_VCS_UnitsFormat == VCS_UNITS_UNITLESS) {
            plogf(" Stan. Chem. Pot. is MU/RT\n");
        }
        if (m_VCS_UnitsFormat == VCS_UNITS_KJMOL) {
            plogf(" Stan. Chem. Pot. in KJ/mole\n");
        }
        if (m_VCS_UnitsFormat == VCS_UNITS_KELVIN) {
            plogf(" Stan. Chem. Pot. in Kelvin\n");
        }
        if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
            plogf(" Stan. Chem. Pot. in J/kmol\n");
        }
        plogf("\n SPECIES            FORMULA VECTOR   ");
        print_space(41);
        plogf("   STAN_CHEM_POT  EQUILIBRIUM_EST.  Species_Type\n\n");
        print_space(20);
        for (i = 0; i < m_numElemConstraints; ++i) {
            plogf("%-4.4s    ", m_elementName[i].c_str());
        }
        plogf("   PhaseID\n");
        RT = vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature);
        for (i = 0; i < m_numSpeciesTot; ++i) {
            plogf(" %-18.18s", m_speciesName[i].c_str());
            for (j = 0; j < m_numElemConstraints; ++j) {
                plogf("% -7.3g ", m_formulaMatrix[j][i]);
            }
            plogf("  %3d  ", m_phaseID[i]);
            print_space(std::max(55-int(m_numElemConstraints)*8, 0));
            plogf("%12.5E  %12.5E", RT * m_SSfeSpecies[i], m_molNumSpecies_old[i]);
            if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) {
                plogf("       Mol_Num");
            } else if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                plogf("       Voltage");
            } else {
                plogf("       Unknown");
            }
            plogendl();
        }
    }

    for (i = 0; i < m_numSpeciesTot; ++i) {
        if (m_molNumSpecies_old[i] < 0.0) {
            plogf("On Input species %-12s has a "
                  "negative MF, setting it small",
                  m_speciesName[i].c_str());
            plogendl();
            iph = m_phaseID[i];
            double tmp = m_tPhaseMoles_old[iph] * VCS_RELDELETE_SPECIES_CUTOFF * 10;
            if (VCS_DELETE_MINORSPECIES_CUTOFF*10. > tmp) {
                tmp = VCS_DELETE_MINORSPECIES_CUTOFF*10.;
            }
            m_molNumSpecies_old[i] = tmp;
        }
    }

    /*
     *  Evaluate the total moles of species in the problem
     */
    vcs_tmoles();

    /*
     * Evaluate all chemical potentials at the old mole numbers at the
     * outset of the calculation.
     */
    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc);

    /* *********************************************************** */
    /* **** DETERMINE BASIS SPECIES, EVALUATE STOICHIOMETRY ****** */
    /* *********************************************************** */
    /*
     *   This is an entry point for later in the calculation
     */
L_COMPONENT_CALC:
    ;
    test = -1.0e-10;
    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;
    }

    // Update the phase objects with the contents of the soln vector
    vcs_updateVP(VCS_STATECALC_OLD);
    vcs_deltag(0, false, VCS_STATECALC_OLD);
    // Turn off the force componentCalc flag
    forceComponentCalc = 0;

    if (conv) {
        goto L_RETURN_BLOCK;
    }
    it1 = 1;

    /*************************************************************************/
    /************** EVALUATE INITIAL SPECIES STATUS VECTOR *******************/
    /*************************************************************************/
    allMinorZeroedSpecies = vcs_evaluate_speciesType();
    lec = false;

    /*************************************************************************/
    /************** EVALUATE THE ELELEMT ABUNDANCE CHECK    ******************/
    /*************************************************************************/
    if (! vcs_elabcheck(0)) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Element Abundance check failed");
            plogendl();
        }
#endif
        vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc);
        // Update the phase objects with the contents of the soln vector
        vcs_updateVP(VCS_STATECALC_OLD);
        vcs_deltag(0, false, VCS_STATECALC_OLD);
    }
#ifdef DEBUG_MODE
    else {
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Element Abundance check passed");
            plogendl();
        }
    }
#endif

    iti = 0;
    goto L_MAINLOOP_ALL_SPECIES;

    /* ********************************************************* */
    /* **** SET INITIAL VALUES FOR ITERATION ******************* */
    /* **** EVALUATE REACTION ADJUSTMENTS    ******************* */
    /* ********************************************************* */
    /*
     *  This is the top of the loop ----------------------------------------
     *  Every 4th iteration ITI = 0. Else, It's equal to a negative number
     */
L_MAINLOOP_MM4_SPECIES:
    ;
    iti = ((it1/4) *4) - it1;
    /*
     *      Entry point when the code wants to force an ITI=0 calculation
     */
L_MAINLOOP_ALL_SPECIES:
    ;
    if (iti == 0) {
        /*
         *          Evaluate the minor non-componenent species chemical
         *          potentials and delta G for their formation reactions
         *          We have already evaluated the major non-components
         */
        if (!uptodate_minors) {
            vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
            vcs_dfe(VCS_STATECALC_OLD, 1, 0, m_numSpeciesRdc);
            vcs_deltag(1, false, VCS_STATECALC_OLD);
        }
        uptodate_minors = true;
    } else {
        uptodate_minors = false;
    }

    if (printDetails) {
        plogf("\n");
        vcs_print_line("=", 110);
        plogf(" Iteration = %3d, Iterations since last evaluation of "
              "optimal basis = %3d",
              m_VCount->Its, it1 - 1);
        if (iti == 0) {
            plogf(" (all species)\n");
        } else {
            plogf(" (only major species)\n");
        }
    }
    /*
     *  Calculate the total moles in each phase -> old solution
     *   -> Needed for numerical stability when phases disappear.
     *   -> the phase moles tend to drift off without this step.
     */
#ifdef DEBUG_MODE
    check_tmoles();
#endif
    vcs_tmoles();
    /*************************************************************************/
    /************** COPY OLD into NEW and ZERO VECTORS ***********************/
    /*************************************************************************/
    /*
     *  Copy the old solution into the new solution as an initial guess
     */
    vcs_dcopy(VCS_DATA_PTR(m_feSpecies_new), VCS_DATA_PTR(m_feSpecies_old), m_numSpeciesRdc);
    vcs_dcopy(VCS_DATA_PTR(m_actCoeffSpecies_new), VCS_DATA_PTR(m_actCoeffSpecies_old), m_numSpeciesRdc);
    vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_new), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc);
    vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_Deficient), VCS_DATA_PTR(m_deltaGRxn_old), m_numRxnRdc);
    vcs_dcopy(VCS_DATA_PTR(m_tPhaseMoles_new), VCS_DATA_PTR(m_tPhaseMoles_old), m_numPhases);

    /*
     *     Zero out the entire vector of updates. We sometimes would
     *     query these values below, and we want to be sure that no
     *     information is left from previous iterations.
     */
    vcs_dzero(VCS_DATA_PTR(m_deltaMolNumSpecies), m_numSpeciesTot);

    /*************************************************************************/
    /************** DETERMINE IF DEAD PHASES POP INTO EXISTENCE **************/
    /*************************************************************************/
    /*
     * First step is a major branch in the algorithm.
     * We first determine if a phase pops into existence.
     */
    phasePopPhaseIDs.clear();
    iphasePop = vcs_popPhaseID(phasePopPhaseIDs);
    /*
     *
     */
    soldel = -1;
    if (iphasePop != npos) {
        soldel = vcs_popPhaseRxnStepSizes(iphasePop);
        if (soldel == 3) {
            iphasePop = npos;
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   --- vcs_popPhaseRxnStepSizes() was called but stoich "
                      "prevented phase %d popping\n");
            }
#endif
        }
    }

    /*************************************************************************/
    /* DETERMINE THE REACTION STEP SIZES FOR MAIN STEP AND IF PHASES DIE *****/
    /*************************************************************************/
    /*
     * Don't do this step if there is a phase pop
     */
    iphaseDelete = npos;
    if (iphasePop == npos) {
        /*
         * Figure out the new reaction step sizes
         * for the major species (do minor species in the future too)
         */
        kspec = npos;
        iphaseDelete = vcs_RxnStepSizes(forceComponentCalc, kspec);
    }
#ifdef DEBUG_MODE
    else {
        if (m_debug_print_lvl >= 2) {
            plogf("   --- vcs_RxnStepSizes not called because alternative"
                  "phase creation delta was used instead\n");
        }
    }
#endif
    lec = false;
    doPhaseDeleteIph = npos;
    /*
     *    Zero out the net change in moles of multispecies phases
     */
    vcs_dzero(VCS_DATA_PTR(m_deltaPhaseMoles), m_numPhases);

    /*
     * Check on too many iterations.
     *         If we have too many iterations, Clean up and exit code even though we haven't
     *         converged. -> we have run out of iterations!
     */
    if (m_VCount->Its > maxit) {
        solveFail = -1;
        goto L_RETURN_BLOCK;
    }

    /* ********************************************************************** */
    /* ***************** MAIN LOOP IN CALCULATION *************************** */
    /* ***************** LOOP OVER IRXN TO DETERMINE STEP SIZE ************** */
    /* ********************************************************************** */
    /*
     *   Loop through all of the reactions, irxn, pertaining to the
     *   formation reaction for species kspec in canonical form.
     *
     *   At the end of this loop, we will have a new estimate for the
     *   mole numbers for all species consistent with an extent
     *   of reaction for all noncomponent species formation
     *   reactions. We will have also ensured that all predicted
     *   non-component mole numbers are greater than zero.
     *
     *         Old_Solution               New_Solution             Description
     * -----------------------------------------------------------------------------
     *  m_molNumSpecies_old[kspec]   m_molNumSpecies_new[kspec]   Species Mole Numbers
     *                               m_deltaMolNumSpecies[kspec]  Delta in the Species Mole Numbers
     *
     *
     *
     */
    if (iphaseDelete != npos) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Main Loop Treatment -> Circumvented due to Phase Deletion ");
            plogendl();
        }
#endif

        for (k = 0; k < m_numSpeciesTot; k++) {
            m_molNumSpecies_new[k] = m_molNumSpecies_old[k] +  m_deltaMolNumSpecies[k];
            iph = m_phaseID[k];
            m_tPhaseMoles_new[iph] += m_deltaMolNumSpecies[k];
        }
        if (kspec >= m_numComponents) {
            if (m_molNumSpecies_new[k] != 0.0) {
                printf("vcs_solve_tp:: we shouldn't be here!\n");
                exit(EXIT_FAILURE);
            }
            if (m_SSPhase[kspec] == 1) {
                m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
            } else {
                printf("vcs_solve_tp:: we shouldn't be here!\n");
                exit(EXIT_FAILURE);
            }
            ++m_numRxnMinorZeroed;
            allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc);
        }
        /*
         *        Set the flags indicating the mole numbers in the vcs_VolPhase
         *        objects are out of date.
         */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);

        /*
         *         Calculate the new chemical potentials using the tentative
         *         solution values. We only calculate a subset of these, because
         *         we have only updated a subset of the W().
         */
        vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesTot);

        /*
         *         Evaluate DeltaG for all components if ITI=0, and for
         *         major components only if ITI NE 0
         */
        vcs_deltag(0, false, VCS_STATECALC_NEW);
    } else {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Main Loop Treatment of each non-component species ");
            if (iti == 0) {
                plogf("- Full Calculation:\n");
            } else {
                plogf("- Major Components Calculation:\n");
            }
            plogf("   --- Species     IC    ");
            plogf(" KMoles  Tent_KMoles Rxn_Adj   |    Comment \n");
        }
#endif
        for (irxn = 0; irxn < m_numRxnRdc; irxn++) {
            kspec = m_indexRxnToSpecies[irxn];
            sc_irxn = m_stoichCoeffRxnMatrix[irxn];
            iph = m_phaseID[kspec];
            Vphase = m_VolPhaseList[iph];
#ifdef DEBUG_MODE
            ANOTE[0] = '\0';
#endif
            if (iphasePop != npos) {
                if (iph == iphasePop) {
                    dx =  m_deltaMolNumSpecies[kspec];
                    m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] +  m_deltaMolNumSpecies[kspec];
#ifdef DEBUG_MODE
                    sprintf(ANOTE, "Phase pop");
#endif
                } else {
                    dx = 0.0;
                    m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
                }
            } else {


                if (m_speciesStatus[kspec] == VCS_SPECIES_INTERFACIALVOLTAGE) {
                    /********************************************************************/
                    /************************ VOLTAGE SPECIES ***************************/
                    /********************************************************************/
                    bool soldel_ret;
#ifdef DEBUG_MODE
                    dx = vcs_minor_alt_calc(kspec, irxn, &soldel_ret, ANOTE);
#else
                    dx = vcs_minor_alt_calc(kspec, irxn, &soldel_ret);
#endif
                    soldel = soldel_ret;
                    m_deltaMolNumSpecies[kspec] = dx;
                } else if (m_speciesStatus[kspec] < VCS_SPECIES_MINOR) {
                    /********************************************************************/
                    /********************** ZEROED OUT SPECIES **************************/
                    /********************************************************************/
                    bool resurrect = (m_deltaMolNumSpecies[kspec] > 0.0);
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 3) {
                        plogf("   --- %s currently zeroed (SpStatus=%-2d):",
                              m_speciesName[kspec].c_str(), m_speciesStatus[kspec]);
                        plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n",
                              irxn, m_deltaGRxn_new[irxn], m_molNumSpecies_new[kspec],
                              m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec]);
                    }
#endif

                    if (m_deltaGRxn_new[irxn] >= 0.0 || !resurrect) {
                        m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
                        m_deltaMolNumSpecies[kspec] = 0.0;
                        resurrect = false;
#ifdef DEBUG_MODE
                        sprintf(ANOTE, "Species stays zeroed: DG = %11.4E", m_deltaGRxn_new[irxn]);
                        if (m_deltaGRxn_new[irxn] < 0.0) {
                            if (m_speciesStatus[kspec] == VCS_SPECIES_STOICHZERO) {
                                sprintf(ANOTE, "Species stays zeroed even though dg neg due to "
                                        "STOICH/PHASEPOP constraint: DG = %11.4E",
                                        m_deltaGRxn_new[irxn]);
                            } else {
                                sprintf(ANOTE, "Species stays zeroed even though dg neg: DG = %11.4E, ds zeroed",
                                        m_deltaGRxn_new[irxn]);
                            }
                        }
#endif
                    } else {
                        for (size_t j = 0; j < m_numElemConstraints; ++j) {
                            int elType = m_elType[j];
                            if (elType == VCS_ELEM_TYPE_ABSPOS) {
                                atomComp = m_formulaMatrix[j][kspec];
                                if (atomComp > 0.0) {
                                    double maxPermissible = m_elemAbundancesGoal[j] / atomComp;
                                    if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) {
#ifdef DEBUG_MODE
                                        sprintf(ANOTE, "Species stays zeroed even though dG "
                                                "neg, because of %s elemAbund",
                                                m_elementName[j].c_str());
#endif
                                        resurrect = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    /*
                     * Resurrect the species
                     */
                    if (resurrect) {
                        bool phaseResurrected = false;
                        if (Vphase->exists() == VCS_PHASE_EXIST_NO) {
                            //Vphase->setExistence(1);
                            phaseResurrected = true;
                        }

                        if (phaseResurrected) {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   --- Zeroed species changed to major: ");
                                plogf("%-12s\n", m_speciesName[kspec].c_str());
                            }
#endif
                            m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
                            allMinorZeroedSpecies = false;
                        } else {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   --- Zeroed species changed to minor: ");
                                plogf("%-12s\n", m_speciesName[kspec].c_str());
                            }
#endif
                            m_speciesStatus[kspec] = VCS_SPECIES_MINOR;
                        }
                        if (m_deltaMolNumSpecies[kspec] > 0.0) {
                            dx = m_deltaMolNumSpecies[kspec] * 0.01;
                            m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
                        } else {
                            m_molNumSpecies_new[kspec] = m_totalMolNum * VCS_DELETE_PHASE_CUTOFF * 10.;
                            dx = m_molNumSpecies_new[kspec] - m_molNumSpecies_old[kspec];
                        }
                        m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
                        sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", m_deltaGRxn_new[irxn]);
#endif
                    } else {
                        m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
                        m_deltaMolNumSpecies[kspec] = 0.0;
                        dx = 0.0;
                    }
                } else if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) {
                    /********************************************************************/
                    /***************************** MINOR SPECIES ************************/
                    /********************************************************************/
                    /*
                     *    Unless ITI isn't equal to zero we zero out changes
                     *    to minor species.
                     */
                    if (iti != 0) {
                        m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
                        m_deltaMolNumSpecies[kspec] = 0.0;
                        dx = 0.0;
#ifdef DEBUG_MODE
                        sprintf(ANOTE,"minor species not considered");
                        if (m_debug_print_lvl >= 2) {
                            plogf("   --- ");
                            plogf("%-12s", m_speciesName[kspec].c_str());
                            plogf("%3d%11.4E%11.4E%11.4E | %s",
                                  m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
                                  m_deltaMolNumSpecies[kspec], ANOTE);
                            plogendl();
                        }
#endif
                        continue;
                    }
                    /*
                     *        Minor species alternative calculation
                     *       ---------------------------------------
                     *    This is based upon the following approximation:
                     *    The mole fraction changes due to these reactions don't affect
                     *    the mole numbers of the component species. Therefore the
                     *    following approximation is valid for an ideal solution
                     *       0 = DG(I) + log(WT(I)/W(I))
                     *       (DG contains the contribution from FF(I) + log(W(I)/TL) )
                     *    Thus,
                     *        WT(I) = W(I) EXP(-DG(I))
                     *    If soldel is true on return, then we branch to the section
                     *    that deletes a species from the current set of active species.
                     */
                    bool soldel_ret;
#ifdef DEBUG_MODE
                    dx = vcs_minor_alt_calc(kspec, irxn, &soldel_ret, ANOTE);
#else
                    dx = vcs_minor_alt_calc(kspec, irxn, &soldel_ret);
#endif
                    soldel = soldel_ret;
                    m_deltaMolNumSpecies[kspec] = dx;
                    m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;

                    if (soldel) {
                        /*******************************************************************/
                        /*****  DELETE MINOR SPECIES LESS THAN  VCS_DELETE_SPECIES_CUTOFF  */
                        /*****  MOLE NUMBER                                                */
                        /*******************************************************************/
#ifdef DEBUG_MODE
                        if (m_debug_print_lvl >= 2) {
                            plogf("   --- Delete minor species in multispec phase: %-12s",
                                  m_speciesName[kspec].c_str());
                            plogendl();
                        }
#endif
                        m_deltaMolNumSpecies[kspec] = 0.0;
                        /*
                         *       Delete species, kspec. The alternate return is for the case
                         *       where all species become deleted. Then, we need to
                         *       branch to the code where we reevaluate the deletion
                         *       of all species.
                         */
                        lnospec = vcs_delete_species(kspec);
                        if (lnospec) {
                            goto L_RECHECK_DELETED;
                        }
                        /*
                         *       Go back to consider the next species in the list.
                         *       Note, however, that the next species in the list is now
                         *       in slot l. In deleting the previous species L, We have
                         *       exchanged slot MR with slot l, and then have
                         *       decremented MR.
                         *       Therefore, we will decrement the species counter, here.
                         */
                        --irxn;
#ifdef DEBUG_MODE
                        goto L_MAIN_LOOP_END_NO_PRINT;
#else
                        goto L_MAIN_LOOP_END;
#endif
                    }
                } else {
                    /********************************************************************/
                    /*********************** MAJOR SPECIES ******************************/
                    /********************************************************************/
#ifdef DEBUG_MODE
                    sprintf(ANOTE, "Normal Major Calc");
#endif
                    /*
                     * Check for superconvergence of the formation reaction. Do
                     * nothing if it is superconverged. Skip to the end of the
                     * irxn loop if it is superconverged.
                     */
                    if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) {
                        m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
                        m_deltaMolNumSpecies[kspec] = 0.0;
                        dx = 0.0;
#ifdef DEBUG_MODE
                        sprintf(ANOTE, "major species is converged");
                        if (m_debug_print_lvl >= 2) {
                            plogf("   --- ");
                            plogf("%-12s", m_speciesName[kspec].c_str());
                            plogf("%3d%11.4E%11.4E%11.4E | %s",
                                  m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
                                  m_deltaMolNumSpecies[kspec], ANOTE);
                            plogendl();
                        }
#endif
                        continue;
                    }
                    /*
                     *      Set the initial step size, dx, equal to the value produced
                     *      by the routine, vcs_RxnStepSize().
                     *
                     *          Note the multiplition logic is to make sure that
                     *          dg[] didn't change sign due to w[] changing in the
                     *          middle of the iteration. (it can if a single species
                     *          phase goes out of existence).
                     */
                    if ((m_deltaGRxn_new[irxn] * m_deltaMolNumSpecies[kspec]) <= 0.0) {
                        dx = m_deltaMolNumSpecies[kspec];
                    } else {
                        dx = 0.0;
                        m_deltaMolNumSpecies[kspec] = 0.0;
#ifdef DEBUG_MODE
                        sprintf(ANOTE, "dx set to 0, DG flipped sign due to "
                                "changed initial point");
#endif
                    }
                    /*
                     *      Form a tentative value of the new species moles
                     */
                    m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;

                    /*
                     *      Check for non-positive mole fraction of major species.
                     *      If we find one, we branch to a section below. Then,
                     *      depending upon the outcome, we branch to sections below,
                     *      or we restart the entire iteration.
                     */
                    if (m_molNumSpecies_new[kspec] <= 0.0) {
#ifdef DEBUG_MODE
                        sprintf(ANOTE, "initial nonpos kmoles= %11.3E",
                                m_molNumSpecies_new[kspec]);
#endif
                        /* ************************************************* */
                        /* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */
                        /* ************************************************* */
                        /*
                         *          We are here when a tentative value of a mole fraction
                         *          created by a tentative value of M_DELTAMOLNUMSPECIES(*) is negative.
                         *          We branch from here depending upon whether this
                         *          species is in a single species phase or in
                         *          a multispecies phase.
                         */
                        if (!(m_SSPhase[kspec])) {
                            /*
                             *   Section for multispecies phases:
                             *     - Cut reaction adjustment for positive kmoles of
                             *       major species in multispecies phases.
                             *       Decrease its concentration by a factor of 10.
                             */
                            dx = -0.9 * m_molNumSpecies_old[kspec];
                            m_deltaMolNumSpecies[kspec] = dx;
                            m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
                        } else {
                            /*
                             *   Section for single species phases:
                             *       Calculate a dx that will wipe out the
                             *       moles in the phase.
                             */
                            dx = -m_molNumSpecies_old[kspec];
                            /*
                             *       Calculate an update that doesn't create a negative mole
                             *       number for a component species. Actually, restrict this
                             *       a little more so that the component values can only be
                             *       reduced by two 99%,
                             */
                            for (j = 0; j < m_numComponents; ++j) {
                                if (sc_irxn[j] != 0.0) {
                                    wx[j] = m_molNumSpecies_old[j] + sc_irxn[j] * dx;
                                    if (wx[j] <= m_molNumSpecies_old[j] * 0.01 - 1.0E-150) {
                                        dx = std::max(dx,  m_molNumSpecies_old[j] * -0.99 / sc_irxn[j]);
                                    }
                                } else {
                                    wx[j] = m_molNumSpecies_old[j];
                                }
                            }
                            m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
                            if (m_molNumSpecies_new[kspec] > 0.0) {
                                m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
                                sprintf(ANOTE,
                                        "zeroing SS phase created a neg component species "
                                        "-> reducing step size instead");
#endif
                            } else {
                                /*
                                 *     We are going to zero the single species phase.
                                 *     Set the existence flag
                                 */
                                iph = m_phaseID[kspec];
                                Vphase = m_VolPhaseList[iph];
                                //Vphase->setExistence(0);
#ifdef DEBUG_MODE
                                sprintf(ANOTE, "zeroing out SS phase: ");
#endif
                                /*
                                 *     Change the base mole numbers for the iteration.
                                 *     We need to do this here, because we have decided
                                 *     to eliminate  the phase in this special section
                                 *     outside the main loop.
                                 */
                                m_molNumSpecies_new[kspec] = 0.0;
                                doPhaseDeleteIph = iph;

#ifdef DEBUG_MODE
                                if (m_debug_print_lvl >= 2) {
                                    if (m_speciesStatus[kspec] >= 0) {
                                        plogf("   --- SS species changed to zeroedss: ");
                                        plogf("%-12s", m_speciesName[kspec].c_str());
                                        plogendl();
                                    }
                                }
#endif
                                m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
                                ++m_numRxnMinorZeroed;
                                allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc);

                                for (size_t kk = 0; kk < m_numSpeciesTot; kk++) {
                                    m_deltaMolNumSpecies[kk] = 0.0;
                                    m_molNumSpecies_new[kk] = m_molNumSpecies_old[kk];
                                }
                                m_deltaMolNumSpecies[kspec] = dx;
                                m_molNumSpecies_new[kspec] = 0.0;

                                for (k = 0; k < m_numComponents; ++k) {
                                    m_deltaMolNumSpecies[k] = 0.0;
                                }
                                for (iph = 0; iph < m_numPhases; iph++) {
                                    m_deltaPhaseMoles[iph] = 0.0;
                                }

                            }
                        }

                    }

#ifdef VCS_LINE_SEARCH
                    /*********************************************************************/
                    /*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/
                    /*********************************************************************/
                    /*
                     * Skip the line search if we are birthing a species
                     */
                    if ((dx != 0.0) &&
                            (m_molNumSpecies_old[kspec] > 0.0) &&
                            (doPhaseDeleteIph == -1) &&
                            (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) {
                        double dx_old = dx;

#ifdef DEBUG_MODE
                        dx = vcs_line_search(irxn, dx_old, ANOTE);
#else
                        dx = vcs_line_search(irxn, dx_old);
#endif
                        vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
                    }
                    m_deltaMolNumSpecies[kspec] = dx;
#endif
                }/* End of Loop on ic[irxn] -> the type of species */
            }
            /***********************************************************************/
            /****** CALCULATE KMOLE NUMBER CHANGE FOR THE COMPONENT BASIS **********/
            /***********************************************************************/
            if (dx != 0.0 && (m_speciesUnknownType[kspec] !=
                              VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) {
                /*
                 *         Change the amount of the component compounds according
                 *         to the reaction delta that we just computed.
                 *         This should keep the amount of material constant.
                 */
#ifdef DEBUG_MODE
                if (fabs(m_deltaMolNumSpecies[kspec] -dx) >
                        1.0E-14*(fabs(m_deltaMolNumSpecies[kspec]) + fabs(dx) + 1.0E-32)) {
                    plogf(" ds[kspec] = %20.16g dx = %20.16g , kspec = %d\n",
                          m_deltaMolNumSpecies[kspec], dx, kspec);
                    plogf("we have a problem!");
                    plogendl();
                    exit(EXIT_FAILURE);
                }
#endif
                for (k = 0; k < m_numComponents; ++k) {
                    m_deltaMolNumSpecies[k] += sc_irxn[k] * dx;
                }
                /*
                 *         Calculate the tentative change in the total number of
                 *         moles in all of the phases
                 */
                dnPhase_irxn = m_deltaMolNumPhase[irxn];
                for (iph = 0; iph < m_numPhases; iph++) {
                    m_deltaPhaseMoles[iph] += dx * dnPhase_irxn[iph];
                }
            }

#ifdef DEBUG_MODE
            checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies),
                        VCS_DATA_PTR(m_deltaPhaseMoles), kspec+1);
#endif
            /*
             *          Branch point for returning -
             */
#ifndef DEBUG_MODE
L_MAIN_LOOP_END:
            ;
#endif
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec];
                plogf("   --- ");
                plogf("%-12.12s", m_speciesName[kspec].c_str());
                plogf("%3d%11.4E%11.4E%11.4E | %s",
                      m_speciesStatus[kspec], m_molNumSpecies_old[kspec],
                      m_molNumSpecies_new[kspec],
                      m_deltaMolNumSpecies[kspec], ANOTE);
                plogendl();
            }
L_MAIN_LOOP_END_NO_PRINT:
            ;
#endif
            if (doPhaseDeleteIph != npos) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    plogf("   --- ");
                    plogf("%-12.12s Main Loop Special Case deleting phase with species: ",
                          m_speciesName[doPhaseDeleteKspec].c_str());
                    plogendl();
                }
#endif
                break;
            }
        }  /**************** END OF MAIN LOOP OVER FORMATION REACTIONS ************/

#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            for (k = 0; k < m_numComponents; k++) {
                plogf("   --- ");
                plogf("%-12.12s", m_speciesName[k].c_str());
                plogf("  c%11.4E%11.4E%11.4E |\n",
                      m_molNumSpecies_old[k],
                      m_molNumSpecies_old[k]+m_deltaMolNumSpecies[k], m_deltaMolNumSpecies[k]);
            }
            plogf("   ");
            vcs_print_line("-", 80);
            plogf("   --- Finished Main Loop");
            plogendl();
        }
#endif

        /*************************************************************************/
        /*********** LIMIT REDUCTION OF BASIS SPECIES TO 99% *********************/
        /*************************************************************************/
        /*
         *        We have a tentative m_deltaMolNumSpecies[]. Now apply other criteria
         *        to limit its magnitude.
         *
         *
         */
        par = 0.5;
        for (k = 0; k < m_numComponents; ++k) {
            if (m_molNumSpecies_old[k] > 0.0) {
                xx = -m_deltaMolNumSpecies[k] / m_molNumSpecies_old[k];
                if (par < xx) {
                    par = xx;
#ifdef DEBUG_MODE
                    ll = k;
#endif
                }
            } else {
                if (m_deltaMolNumSpecies[k] < 0.0) {
                    /*
                     * If we are here, we then do a step which violates element
                     * conservation.
                     */
                    iph = m_phaseID[k];
                    m_deltaPhaseMoles[iph] -= m_deltaMolNumSpecies[k];
                    m_deltaMolNumSpecies[k] = 0.0;
                }
            }
        }
        par = 1.0 / par;
        if (par <= 1.01 && par > 0.0) {
            /* Reduce the size of the step by the multiplicative factor, par */
            par *= 0.99;
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   --- Reduction in step size due to component ");
                plogf("%s", m_speciesName[ll].c_str());
                plogf(" going negative = %11.3E", par);
                plogendl();
            }
#endif
            for (i = 0; i < m_numSpeciesTot; ++i) {
                m_deltaMolNumSpecies[i] *= par;
            }
            for (iph = 0; iph < m_numPhases; iph++) {
                m_deltaPhaseMoles[iph] *= par;
            }
        } else {
            par = 1.0;
        }
#ifdef DEBUG_MODE
        checkDelta1(VCS_DATA_PTR(m_deltaMolNumSpecies),
                    VCS_DATA_PTR(m_deltaPhaseMoles), m_numSpeciesTot);
#endif

        /*
         *      Now adjust the wt[kspec]'s so that the reflect the decrease in
         *      the overall length of m_deltaMolNumSpecies[kspec] just calculated. At the end
         *      of this section wt[], m_deltaMolNumSpecies[], tPhMoles, and tPhMoles1 should all be
         *      consistent with a new estimate of the state of the system.
         */
        for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
            m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec];
            if (m_molNumSpecies_new[kspec] < 0.0 && (m_speciesUnknownType[kspec]
                    != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) {
                plogf("vcs_solve_TP: ERROR on step change wt[%d:%s]: %g < 0.0",
                      kspec, m_speciesName[kspec].c_str(), m_molNumSpecies_new[kspec]);
                plogendl();
                exit(EXIT_FAILURE);
            }
        }

        /*
         *        Calculate the tentative total mole numbers for each phase
         */
        for (iph = 0; iph < m_numPhases; iph++) {
            m_tPhaseMoles_new[iph] = m_tPhaseMoles_old[iph] + m_deltaPhaseMoles[iph];
        }

        /*
         *        Set the flags indicating the mole numbers in the vcs_VolPhase
         *        objects are out of date.
         */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);

        /*
         *         Calculate the new chemical potentials using the tentative
         *         solution values. We only calculate a subset of these, because
         *         we have only updated a subset of the W().
         */
        vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesTot);

        /*
         *         Evaluate DeltaG for all components if ITI=0, and for
         *         major components only if ITI NE 0
         */
        vcs_deltag(0, false, VCS_STATECALC_NEW);

        /* *************************************************************** */
        /* **** CONVERGENCE FORCER SECTION ******************************* */
        /* *************************************************************** */
        if (printDetails) {
            plogf("   --- Total Old       Dimensionless Gibbs Free Energy = %20.13E\n",
                  vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old),
                                  VCS_DATA_PTR(m_tPhaseMoles_old)));
            plogf("   --- Total tentative Dimensionless Gibbs Free Energy = %20.13E",
                  vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new),
                                  VCS_DATA_PTR(m_tPhaseMoles_new)));
            plogendl();
        }

        forced = vcs_globStepDamp();

        /*
         *       Print out the changes to the solution that FORCER produced
         */
        if (printDetails && forced) {

            plogf(" -----------------------------------------------------\n");
            plogf("   --- FORCER SUBROUTINE changed the solution:\n");
            plogf("   --- SPECIES Status INIT MOLES TENT_MOLES");
            plogf("  FINAL KMOLES  INIT_DEL_G/RT  TENT_DEL_G/RT  FINAL_DELTA_G/RT\n");
            for (i = 0; i < m_numComponents; ++i) {
                plogf("  --- %-12.12s", m_speciesName[i].c_str());
                plogf("    %14.6E %14.6E %14.6E\n",  m_molNumSpecies_old[i],
                      m_molNumSpecies_old[i] + m_deltaMolNumSpecies[i], m_molNumSpecies_new[i]);
            }
            for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) {
                irxn = kspec - m_numComponents;
                plogf("  --- %-12.12s", m_speciesName[kspec].c_str());
                plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", m_speciesStatus[kspec],
                      m_molNumSpecies_old[kspec],
                      m_molNumSpecies_old[kspec]+m_deltaMolNumSpecies[kspec],
                      m_molNumSpecies_new[kspec], m_deltaGRxn_old[irxn],
                      m_deltaGRxn_tmp[irxn], m_deltaGRxn_new[irxn]);
            }
            print_space(26);
            plogf("Norms of Delta G():%14.6E%14.6E\n",
                  l2normdg(VCS_DATA_PTR(m_deltaGRxn_old)),
                  l2normdg(VCS_DATA_PTR(m_deltaGRxn_new)));
            plogf("   Total kmoles of gas    = %15.7E\n", m_tPhaseMoles_old[0]);
            if ((m_numPhases > 1) && (!(m_VolPhaseList[1])->m_singleSpecies)) {
                plogf("   Total kmoles of liquid = %15.7E\n", m_tPhaseMoles_old[1]);
            } else {
                plogf("   Total kmoles of liquid = %15.7E\n", 0.0);
            }
            plogf("   Total New Dimensionless Gibbs Free Energy = %20.13E\n",
                  vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new),
                                  VCS_DATA_PTR(m_tPhaseMoles_new)));
            plogf(" -----------------------------------------------------");
            plogendl();
        }
    }
    /* *************************************************************** */
    /* **** ITERATION SUMMARY PRINTOUT SECTION *********************** */
    /* *************************************************************** */

    if (printDetails) {
        plogf("   ");
        vcs_print_line("-", 103);
        plogf("   --- Summary of the Update ");
        if (iti == 0) {
            plogf(" (all species):");
        } else {
            plogf(" (only major species):");
        }
        if (m_totalMoleScale != 1.0) {
            plogf(" (Total Mole Scale = %g)", m_totalMoleScale);
        }
        plogf("\n");
        plogf("   ---      Species Status Initial_KMoles Final_KMoles Initial_Mu/RT");
        plogf("     Mu/RT     Init_Del_G/RT   Delta_G/RT\n");
        for (i = 0; i < m_numComponents; ++i) {
            plogf("   ---   %-12.12s", m_speciesName[i].c_str());
            plogf("    ");
            plogf("%14.6E%14.6E%14.6E%14.6E\n", m_molNumSpecies_old[i],
                  m_molNumSpecies_new[i], m_feSpecies_old[i], m_feSpecies_new[i]);
        }
        for (i = m_numComponents; i < m_numSpeciesRdc; ++i) {
            l1 = i - m_numComponents;
            plogf("   ---   %-12.12s", m_speciesName[i].c_str());
            plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n",
                  m_speciesStatus[i], m_molNumSpecies_old[i],
                  m_molNumSpecies_new[i], m_feSpecies_old[i], m_feSpecies_new[i],
                  m_deltaGRxn_old[l1], m_deltaGRxn_new[l1]);
        }
        for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) {
            l1 = kspec - m_numComponents;
            plogf("   ---   %-12.12s", m_speciesName[kspec].c_str());
            plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n",
                  m_speciesStatus[kspec], m_molNumSpecies_old[kspec],
                  m_molNumSpecies_new[kspec], m_feSpecies_old[kspec], m_feSpecies_new[kspec],
                  m_deltaGRxn_old[l1], m_deltaGRxn_new[l1]);
        }
        plogf("   ---");
        print_space(56);
        plogf("Norms of Delta G():%14.6E%14.6E",
              l2normdg(VCS_DATA_PTR(m_deltaGRxn_old)),
              l2normdg(VCS_DATA_PTR(m_deltaGRxn_new)));
        plogendl();

        plogf("   ---           Phase_Name    KMoles(after update)\n");
        plogf("   ---   ");
        vcs_print_line("-", 50);
        for (iph = 0; iph < m_numPhases; iph++) {
            Vphase = m_VolPhaseList[iph];
            plogf("   ---   %18s = %15.7E\n", Vphase->PhaseName.c_str(), m_tPhaseMoles_new[iph]);
        }
        plogf("   ");
        vcs_print_line("-", 103);
        plogf("   --- Total Old Dimensionless Gibbs Free Energy = %20.13E\n",
              vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old),
                              VCS_DATA_PTR(m_tPhaseMoles_old)));
        plogf("   --- Total New Dimensionless Gibbs Free Energy = %20.13E",
              vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_feSpecies_new),
                              VCS_DATA_PTR(m_tPhaseMoles_new)));
        plogendl();
#ifdef DEBUG_MODE
        if (m_VCount->Its > 550) {
            plogf("   --- Troublesome solve");
            plogendl();
        }
#endif
    }

    /*************************************************************************/
    /******************* RESET VALUES AT END OF ITERATION ********************/
    /******************* UPDATE MOLE NUMBERS *********************************/
    /*************************************************************************/
    /*
     *       If the solution wasn't changed in the forcer routine,
     *       then copy the tentative mole numbers and Phase moles
     *       into the actual mole numbers and phase moles.
     *       We will consider this current step to be completed.
     *
     *   Accept the step. -> the tentative solution now becomes
     *                the real solution. If FORCED is true, then
     *                we have already done this inside the FORCED
     *                loop.
     */
    vcs_updateMolNumVolPhases(VCS_STATECALC_NEW);
    vcs_dcopy(VCS_DATA_PTR(m_tPhaseMoles_old), VCS_DATA_PTR(m_tPhaseMoles_new), m_numPhases);
    vcs_dcopy(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_molNumSpecies_new),
              m_numSpeciesRdc);
    vcs_dcopy(VCS_DATA_PTR(m_actCoeffSpecies_old),
              VCS_DATA_PTR(m_actCoeffSpecies_new), m_numSpeciesRdc);
    vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_old), VCS_DATA_PTR(m_deltaGRxn_new), m_numRxnRdc);
    vcs_dcopy(VCS_DATA_PTR(m_feSpecies_old), VCS_DATA_PTR(m_feSpecies_new), m_numSpeciesRdc);

    vcs_setFlagsVolPhases(true, VCS_STATECALC_OLD);
    /*
     *       Increment the iteration counters
     */
    ++(m_VCount->Its);
    ++it1;
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Increment counter increased, step is accepted: %4d",
              m_VCount->Its);
        plogendl();
    }
#endif
    /*************************************************************************/
    /******************* HANDLE DELETION OF MULTISPECIES PHASES **************/
    /*************************************************************************/
    /*
     *   We delete multiphases, when the total moles in the multiphase
     *   is reduced below a relative threshold.
     *   Set microscopic multispecies phases with total relative
     *   number of moles less than  VCS_DELETE_PHASE_CUTOFF to
     *   absolute zero.
     */
    justDeletedMultiPhase = false;
    for (iph = 0; iph < m_numPhases; iph++) {
        Vphase = m_VolPhaseList[iph];
        if (!(Vphase->m_singleSpecies)) {
            if (m_tPhaseMoles_old[iph] != 0.0 &&
                    m_tPhaseMoles_old[iph]/m_totalMolNum <= VCS_DELETE_PHASE_CUTOFF) {
                soldel = 1;

                for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
                    if (m_phaseID[kspec] == iph && m_molNumSpecies_old[kspec] > 0.0) {
                        irxn = kspec - m_numComponents;
                    }
                }
                if (soldel) {
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 1) {
                        plogf("   --- Setting microscopic phase %d to zero", iph);
                        plogendl();
                    }
#endif
                    justDeletedMultiPhase = true;
                    vcs_delete_multiphase(iph);
                }
            }
        }
    }
    /*
     *       If we have deleted a multispecies phase because the
     *       equilibrium moles decreased, then we will update all
     *       the component basis calculation, and therefore all
     *       of the thermo functions just to be safe.
     */
    if (justDeletedMultiPhase) {
        justDeletedMultiPhase = false;
        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) {
#ifdef DEBUG_MODE
            plogf("   --- BASOPT returned with an error condition\n");
#endif
            exit(EXIT_FAILURE);
        }
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc);

        vcs_deltag(0, true, VCS_STATECALC_OLD);
        iti = 0;
        goto  L_MAINLOOP_ALL_SPECIES ;

    }
    /*************************************************************************/
    /***************** CHECK FOR ELEMENT ABUNDANCE****************************/
    /*************************************************************************/
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Normal element abundance check");
    }
#endif
    vcs_elab();
    if (! vcs_elabcheck(0)) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf(" - failed -> redoing element abundances.");
            plogendl();
        }
#endif
        vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc);
        vcs_deltag(0, true,  VCS_STATECALC_OLD);
        uptodate_minors = true;
    }
#ifdef DEBUG_MODE
    else {
        if (m_debug_print_lvl >= 2) {
            plogf(" - passed");
            plogendl();
        }
    }
#endif
    /*************************************************************************/
    /***************** CHECK FOR OPTIMUM BASIS *******************************/
    /*************************************************************************/
    /*
     *   HKM -> We first evaluate whether the components species are
     *          ordered according to their mole numbers. If they are,
     *          then we can essential do an order(NR) operation instead
     *          of an order(NR*NC) operation to determine whether
     *          a new basis is needed.
     *
     *   HKM -> This section used to be branched to initially if
     *          there was a machine estimate. I took it out to simplify
     *          the code logic.
     */
    dofast = (m_numComponents != 1);
    for (i = 1; i < m_numComponents; ++i) {
        if ((m_molNumSpecies_old[i - 1] * m_spSize[i-1]) < (m_molNumSpecies_old[i] * m_spSize[i])) {
            dofast = false;
            break;
        }
    }
    dofast = false;
    if (dofast) {
        for (i = 0; i < m_numRxnRdc; ++i) {
            l = m_indexRxnToSpecies[i];
            if (m_speciesUnknownType[l] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                for (j = m_numComponents - 1; j != npos; j--) {
                    bool doSwap = false;
                    if (m_SSPhase[j]) {
                        doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                 (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                        if (!m_SSPhase[i]) {
                            if (doSwap) {
                                doSwap = (m_molNumSpecies_old[l]) > (m_molNumSpecies_old[j] * 1.01);
                            }
                        }
                    } else {
                        if (m_SSPhase[i]) {
                            doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                     (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                            if (!doSwap) {
                                doSwap = (m_molNumSpecies_old[l]) > (m_molNumSpecies_old[j] * 1.01);
                            }
                        } else {
                            doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                     (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                        }
                    }
                    if (doSwap) {
                        if (m_stoichCoeffRxnMatrix[i][j] != 0.0) {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   --- Get a new basis because %s", m_speciesName[l].c_str());
                                plogf(" is better than comp %s", m_speciesName[j].c_str());
                                plogf(" and share nonzero stoic: %-9.1f",
                                      m_stoichCoeffRxnMatrix[i][j]);
                                plogendl();
                            }
#endif
                            goto L_COMPONENT_CALC;
                        }
                    } else {
                        break;
                    }
#ifdef DEBUG_NOT
                    if (m_speciesStatus[l] == VCS_SPECIES_ZEROEDMS) {
                        if (m_molNumSpecies_old[j] == 0.0) {
                            if (m_stoichCoeffRxnMatrix[i][j] != 0.0) {
                                if (dg[i] < 0.0) {
#ifdef DEBUG_MODE
                                    if (m_debug_print_lvl >= 2) {
                                        plogf("   --- Get a new basis because %s", m_speciesName[l].c_str());
                                        plogf(" has dg < 0.0 and comp %s has zero mole num", m_speciesName[j].c_str());
                                        plogf(" and share nonzero stoic: %-9.1f",
                                              m_stoichCoeffRxnMatrix[i][j]);
                                        plogendl();
                                    }
#endif
                                    goto L_COMPONENT_CALC;
                                }
                            }
                        }
                    }
#endif
                }
            }
        }
    } else {
        for (i = 0; i < m_numRxnRdc; ++i) {
            l = m_indexRxnToSpecies[i];
            if (m_speciesUnknownType[l] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                for (j = 0; j < m_numComponents; ++j) {
                    bool doSwap = false;
                    if (m_SSPhase[j]) {
                        doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                 (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                        if (!m_SSPhase[l]) {
                            if (doSwap) {
                                doSwap = (m_molNumSpecies_old[l]) > (m_molNumSpecies_old[j] * 1.01);
                            }
                        }
                    } else {
                        if (m_SSPhase[l]) {
                            doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                     (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                            if (!doSwap) {
                                doSwap = (m_molNumSpecies_old[l]) > (m_molNumSpecies_old[j] * 1.01);
                            }
                        } else {
                            doSwap = (m_molNumSpecies_old[l] * m_spSize[l]) >
                                     (m_molNumSpecies_old[j] * m_spSize[j] * 1.01);
                        }
                    }
                    if (doSwap) {
                        if (m_stoichCoeffRxnMatrix[i][j] != 0.0) {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   --- Get a new basis because ");
                                plogf("%s", m_speciesName[l].c_str());
                                plogf(" is better than comp ");
                                plogf("%s", m_speciesName[j].c_str());
                                plogf(" and share nonzero stoic: %-9.1f",
                                      m_stoichCoeffRxnMatrix[i][j]);
                                plogendl();
                            }
#endif
                            goto L_COMPONENT_CALC;
                        }
                    }
#ifdef DEBUG_NOT
                    if (m_speciesStatus[l] == VCS_SPECIES_ZEROEDMS) {
                        if (m_molNumSpecies_old[j] == 0.0) {
                            if (m_stoichCoeffRxnMatrix[i][j] != 0.0) {
                                if (dg[i] < 0.0) {
#ifdef DEBUG_MODE
                                    if (m_debug_print_lvl >= 2) {
                                        plogf("   --- Get a new basis because %s", m_speciesName[l].c_str());
                                        plogf(" has dg < 0.0 and comp %s has zero mole num",
                                              m_speciesName[j].c_str());
                                        plogf(" and share nonzero stoic: %-9.1f",
                                              m_stoichCoeffRxnMatrix[i][j]);
                                        plogendl();
                                    }
#endif
                                    goto L_COMPONENT_CALC;
                                }
                            }
                        }
                    }
#endif
                }
            }
        }
    }
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Check for an optimum basis passed");
        plogendl();
    }
#endif
    /*************************************************************************/
    /********************** RE-EVALUATE MAJOR-MINOR VECTOR IF NECESSARY ******/
    /*************************************************************************/
    /*
     *     Skip this section if we haven't done a full calculation.
     *     Go right to the check equilibrium section
     */
    if (iti == 0) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Reevaluate major-minor status of noncomponents:\n");
        }
#endif
        m_numRxnMinorZeroed = 0;
        for (irxn = 0; irxn < m_numRxnRdc; irxn++) {
            kspec = m_indexRxnToSpecies[irxn];

            int speciesType = vcs_species_type(kspec);
            if (speciesType < VCS_SPECIES_MINOR) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    if (m_speciesStatus[kspec] >= VCS_SPECIES_MINOR) {
                        plogf("   ---    major/minor species is now zeroed out: %s\n",
                              m_speciesName[kspec].c_str());
                    }
                }
#endif
                ++m_numRxnMinorZeroed;
            } else if (speciesType == VCS_SPECIES_MINOR) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    if (m_speciesStatus[kspec] != VCS_SPECIES_MINOR) {
                        if (m_speciesStatus[kspec] == VCS_SPECIES_MAJOR) {
                            plogf("   ---   Noncomponent turned from major to minor: ");
                        } else if (kspec < m_numComponents) {
                            plogf("   ---   Component turned into a minor species: ");
                        } else {
                            plogf("   ---   Zeroed Species turned into a "
                                  "minor species: ");
                        }
                        plogf("%s\n", m_speciesName[kspec].c_str());
                    }
                }
#endif
                ++m_numRxnMinorZeroed;
            } else if (speciesType == VCS_SPECIES_MAJOR) {
                if (m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) {
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 2) {
                        if (m_speciesStatus[kspec] ==  VCS_SPECIES_MINOR) {
                            plogf("   ---   Noncomponent turned from minor to major: ");
                        } else if (kspec < m_numComponents) {
                            plogf("   ---   Component turned into a major: ");
                        } else {
                            plogf("   ---   Noncomponent turned from zeroed to major: ");
                        }
                        plogf("%s\n", m_speciesName[kspec].c_str());
                    }
#endif
                    m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
                    /*
                     *   For this special case, we must reevaluate thermo functions
                     */
                    if (iti != 0) {
                        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
                        vcs_dfe(VCS_STATECALC_OLD, 0, kspec, kspec+1);
                        vcs_deltag(0, false, VCS_STATECALC_OLD);
                    }
                }
            }
            m_speciesStatus[kspec] = speciesType;
        }
        /*
         *         This logical variable indicates whether all current
         *         non-component species are minor or nonexistent
         */
        allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc);
    }
    /*************************************************************************/
    /***************** EQUILIBRIUM CHECK FOR MAJOR SPECIES *******************/
    /*************************************************************************/
L_EQUILIB_CHECK:
    ;
    if (! allMinorZeroedSpecies) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Equilibrium check for major species: ");
        }
#endif
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = irxn + m_numComponents;
            if (m_speciesStatus[kspec] == VCS_SPECIES_MAJOR && (fabs(m_deltaGRxn_new[irxn]) > m_tolmaj)) {
                if (m_VCount->Its >= maxit) {
                    solveFail = -1;
                    /*
                     *         Clean up and exit code even though we haven't
                     *         converged. -> we have run out of iterations!
                     */
                    goto L_RETURN_BLOCK;
                } else {
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 2) {
                        plogf("%s failed\n", m_speciesName[m_indexRxnToSpecies[irxn]].c_str());
                    }
#endif
                    // Convergence amongst major species has not been achieved
                    /*
                     *   Go back and do another iteration with variable ITI
                     */
                    if (forceComponentCalc) {
                        goto L_COMPONENT_CALC;
                    }
                    goto L_MAINLOOP_MM4_SPECIES;
                }
            }
        }
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf(" MAJOR SPECIES CONVERGENCE achieved");
            plogendl();
        }
#endif
    }
#ifdef DEBUG_MODE
    else {
        if (m_debug_print_lvl >= 2) {
            plogf(" MAJOR SPECIES CONVERGENCE achieved "
                  "(because there are no major species)");
            plogendl();
        }
    }
#endif
    // Convergence amongst major species has been achieved

    /*************************************************************************/
    /*************** EQUILIBRIUM CHECK FOR MINOR SPECIES *********************/
    /*************************************************************************/
    if (m_numRxnMinorZeroed != 0) {
        /*
         *       Calculate the chemical potential and reaction DeltaG
         *       for minor species, if needed.
         */
        if (iti != 0) {
            vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
            vcs_dfe(VCS_STATECALC_OLD, 1, 0, m_numSpeciesRdc);
            vcs_deltag(1, false, VCS_STATECALC_OLD);
            uptodate_minors = true;
        }
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- Equilibrium check for minor species: ");
        }
#endif
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = irxn + m_numComponents;
            if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR && (fabs(m_deltaGRxn_new[irxn]) > m_tolmin)) {
                if (m_VCount->Its >= maxit) {
                    solveFail = -1;
                    /*
                     *       Clean up and exit code. -> Even though we have not
                     *        converged, we have run out of iterations !
                     */
                    goto L_RETURN_BLOCK;
                }
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    plogf("%s failed\n", m_speciesName[m_indexRxnToSpecies[irxn]].c_str());
                }
#endif
                /*
                 *  Set iti to zero to force a full calculation, and go back
                 *  to the main loop to do another iteration.
                 */
                iti = 0;
                if (forceComponentCalc) {
                    goto L_COMPONENT_CALC;
                }
                goto L_MAINLOOP_ALL_SPECIES;
            }
        }
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf(" CONVERGENCE achieved\n");
        }
#endif
    }
    /*************************************************************************/
    /*********************** FINAL ELEMENTAL ABUNDANCE CHECK *****************/
    /*************************************************************************/
    /*
     *    Recalculate the element abundance vector again
     */
    vcs_updateVP(VCS_STATECALC_OLD);
    vcs_elab();

    /*        LEC is only true when we are near the end game */
    if (lec) {
        if (!giveUpOnElemAbund) {
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   --- Check the Full Element Abundances: ");
            }
#endif
            /*
             *  Final element abundance check:
             *        If we fail then we need to go back and correct
             *        the element abundances, and then go do a major step
             */
            if (! vcs_elabcheck(1)) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    if (! vcs_elabcheck(0)) {
                        plogf(" failed\n");
                    } else {
                        plogf(" passed for NC but failed for NE: RANGE ERROR\n");
                    }
                }
#endif
                // delete?
                goto L_ELEM_ABUND_CHECK;
            }
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf(" passed\n");
            }
#endif
        }
        /*
         *   If we have deleted a species then we need to recheck the
         *   the deleted species, before exiting
         */
        if (m_numSpeciesRdc != m_numSpeciesTot) {
            goto L_RECHECK_DELETED;
        }
        /* - Final checks are passed -> go check out */
        goto L_RETURN_BLOCK;
    }
    lec = true;
    /* *************************************************** */
    /* **** CORRECT ELEMENTAL ABUNDANCES ***************** */
    /* *************************************************** */
L_ELEM_ABUND_CHECK:
    ;
    /*
     *  HKM - Put in an element abundance check. The element abundances
     *        were being corrected even if they were perfectly OK to
     *        start with. This is actually an expensive operation, so
     *        I took it out. Also vcs_dfe() doesn't need to be called if
     *        no changes were made.
     */
    rangeErrorFound = 0;
    if (! vcs_elabcheck(1)) {
        bool ncBefore = vcs_elabcheck(0);
        vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx));
        bool ncAfter = vcs_elabcheck(0);
        bool neAfter = vcs_elabcheck(1);
        /*
         *      Go back to evaluate the total moles of gas and liquid.
         */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesRdc);
        vcs_deltag(0, false, VCS_STATECALC_OLD);
        if (!ncBefore) {
            if (ncAfter) {
                /*
                 * We have breathed new life into the old problem. Now the
                 * element abundances up to NC agree. Go back and
                 * restart the main loop calculation, resetting the
                 * end conditions.
                 */
                lec = false;
                iti = 0;
                goto L_MAINLOOP_ALL_SPECIES;
            } else {
                /*
                 * We are still hosed
                 */
                if (finalElemAbundAttempts >= 3) {
                    giveUpOnElemAbund = true;
                    goto L_EQUILIB_CHECK;
                } else {
                    finalElemAbundAttempts++;
                    lec = false;
                    iti = 0;
                    goto L_MAINLOOP_ALL_SPECIES;
                }
            }
        } else {
            if (ncAfter) {
                if (neAfter) {
                    /*
                     * Recovery of end element abundances
                     * -> go do equilibrium check again and then
                     *    check out.
                     */
                    goto L_EQUILIB_CHECK;
                } else {
                    /*
                     * Probably an unrecoverable range error
                     */
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 2) {
                        plogf(" ---  vcs_solve_tp: RANGE SPACE ERROR ENCOUNTERED\n");
                        plogf(" ---  vcs_solve_tp: - Giving up on NE Element Abundance satisfaction \n");
                        plogf(" ---  vcs_solve_tp: - However, NC Element Abundance criteria is satisfied \n");
                        plogf(" ---  vcs_solve_tp: - Returning the calculated equilibrium condition ");
                        plogendl();
                    }
#endif
                    rangeErrorFound = 1;
                    giveUpOnElemAbund = true;
                    goto L_EQUILIB_CHECK;
                }
            }
        }
    }
    // Calculate delta g's
    vcs_deltag(0, false, VCS_STATECALC_OLD);
    // Go back to equilibrium check as a prep to eventually checking out
    goto L_EQUILIB_CHECK;

    /* *************************************************** */
    /* **** RECHECK DELETED SPECIES ********************** */
    /* *************************************************** */
    /*
     *         We are here for two reasons. One is if we have
     *         achieved convergence, but some species have been eliminated
     *         from the problem because they were in multispecies phases
     *         and their mole fractions drifted less than
     *         VCS_DELETE_SPECIES_CUTOFF .
     *         The other reason why we are here is because all of the
     *         non-component species in the problem have been eliminated
     *         for one reason or another.
     */
L_RECHECK_DELETED:
    ;
    npb = vcs_recheck_deleted();
    /*
     *        If we haven't found any species that needed adding we are done.
     */
    if (npb <= 0) {
        goto L_RETURN_BLOCK_B;
    }
    /*
     *        If we have found something to add, recalculate everything
     *        for minor species and go back to do a full iteration
     */
    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    vcs_dfe(VCS_STATECALC_OLD, 1, 0, m_numSpeciesRdc);
    vcs_deltag(0, false, VCS_STATECALC_OLD);
    iti = 0;
    goto L_MAINLOOP_ALL_SPECIES;
    /*************************************************************************/
    /******************** CLEANUP AND RETURN BLOCK ***************************/
    /*************************************************************************/
L_RETURN_BLOCK:
    ;

    npb = vcs_recheck_deleted();
    /*
     *        If we haven't found any species that needed adding we are done.
     */
    if (npb > 0) {
        /*
         *        If we have found something to add, recalculate everything
         *        for minor species and go back to do a full iteration
         */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 1, 0, m_numSpeciesRdc);
        vcs_deltag(0, false, VCS_STATECALC_OLD);
        iti = 0;
        goto L_MAINLOOP_ALL_SPECIES;
    }

L_RETURN_BLOCK_B:
    ;

    /*
     *  Add back deleted species in non-zeroed phases. Estimate their
     *  mole numbers.
     */
    npb = vcs_add_all_deleted();
    if (npb > 0) {
        iti = 0;
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 1) {
            plogf("  --- add_all_deleted(): some rxns not converged. RETURNING TO LOOP!");
            plogendl();
        }
#endif
        goto L_MAINLOOP_ALL_SPECIES;
    }

    /*
     * Make sure the volume phase objects hold the same state and
     * information as the vcs object. This also update the Cantera objects
     * with this information.
     */
    vcs_updateVP(VCS_STATECALC_OLD);
    /*
     *    Store the final Delta G values for each non-component species
     *    in the species slot rather than the reaction slot
     */
    // kspec = m_numSpeciesTot;
    // i = m_numRxnTot;
    //for (irxn = 0; irxn < m_numRxnTot; ++irxn) {
    //   --kspec;
    // --i;
    //  m_deltaGRxn_new[kspec] = m_deltaGRxn_new[i];
    //}
    // vcs_dzero(VCS_DATA_PTR(m_deltaGRxn_new), m_numComponents);
    /*
     *       Evaluate the final mole fractions
     *        storing them in wt[]
     */
    vcs_vdzero(m_molNumSpecies_new, m_numSpeciesTot);
    for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
        if (m_SSPhase[kspec]) {
            m_molNumSpecies_new[kspec] = 1.0;
        } else {
            iph = m_phaseID[kspec];
            if (m_tPhaseMoles_old[iph] != 0.0) {
                m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] / m_tPhaseMoles_old[iph];
            } else {
                /*
                 * For MultiSpecies phases that are zeroed out,
                 * return the mole fraction vector from the VolPhase object.
                 * This contains the mole fraction that would be true if
                 * the phase just pops into existence.
                 */
                i = m_speciesLocalPhaseIndex[kspec];
                Vphase = m_VolPhaseList[iph];
                m_molNumSpecies_new[kspec] = Vphase->molefraction(i);
            }
        }
    }
    // Return an error code if a Range Space Error is thought to have occurred.
    if (rangeErrorFound) {
        solveFail = 1;
    }
    /*
     *           Free temporary storage used in this routine
     *           and increment counters
     */
    /*
     *           Calculate counters
     */
    double tsecond = ticktock.secondsWC();
    m_VCount->Time_vcs_TP = tsecond;
    m_VCount->T_Time_vcs_TP += m_VCount->Time_vcs_TP;
    (m_VCount->T_Calls_vcs_TP)++;
    m_VCount->T_Its += m_VCount->Its;
    m_VCount->T_Basis_Opts += m_VCount->Basis_Opts;
    m_VCount->T_Time_basopt += m_VCount->Time_basopt;
    /*
     *          Return a Flag indicating whether convergence occurred
     */
    return solveFail;
}
/*********************************************************************************/

//  Minor species alternative calculation
/*
 *    This is based upon the following approximation:
 *    The mole fraction changes due to these reactions don't affect
 *    the mole numbers of the component species. Therefore the following
 *    approximation is valid for a small component of an ideal phase:
 *
 *       0 = m_deltaGRxn_old(I) + log(molNum_new(I)/molNum_old(I))
 *
 *       m_deltaGRxn_old contains the contribution from
 *
 *        m_feSpecies_old(I) =
 *              m_SSfeSpecies(I) +
 *              log(ActCoeff[i] * molNum_old(I) / m_tPhaseMoles_old(iph))
 *    Thus,
 *
 *        molNum_new(I)= molNum_old(I) * EXP(-m_deltaGRxn_old(I))
 *
 *    Most of this section is mainly restricting the update to reasonable
 *    values.
 *    We restrict the update a factor of 1.0E10 up and 1.0E-10 down
 *    because we run into trouble with the addition operator due to roundoff
 *    if we go larger than ~1.0E15. Roundoff will then sometimes produce
 *    zero mole fractions.
 *
 *    Note: This routine was generalized to incorporate
 *          nonideal phases and phases on the molality basis
 *
 *    Input:
 *     ------
 *     @param kspec   The current species and corresponding formation
 *                    reaction number.
 *     @param irxn    The current species and corresponding formation
 *                    reaction number.
 *
 *    Output:
 *    ---------
 *     @param do_delete:  BOOLEAN which if true on return, then we branch
 *                        to the section that deletes a species from the
 *                        current set of active species.
 *
 *     @param dx          The change in mole number
 */
double VCS_SOLVE::vcs_minor_alt_calc(size_t kspec, size_t irxn, bool* do_delete
#ifdef DEBUG_MODE
                                     , char* ANOTE
#endif
                                    ) const
{
    double dx = 0.0, a;
    double w_kspec = m_molNumSpecies_old[kspec];
    double molNum_kspec_new;
    double wTrial, tmp;
    double dg_irxn = m_deltaGRxn_old[irxn];
    doublereal  s;
    size_t iph = m_phaseID[kspec];

    *do_delete = false;
    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
        if (w_kspec <= 0.0) {
            w_kspec = VCS_DELETE_MINORSPECIES_CUTOFF;
        }
        if (dg_irxn < -200.) {
            dg_irxn = -200.;
        }
#ifdef DEBUG_MODE
        sprintf(ANOTE,"minor species alternative calc");
#endif
        if (dg_irxn >= 23.0) {
            molNum_kspec_new = w_kspec * 1.0e-10;
            if (w_kspec < VCS_DELETE_MINORSPECIES_CUTOFF) {
                goto L_ZERO_SPECIES;
            }
            dx = molNum_kspec_new - w_kspec;
            return dx;
        } else {
            if (fabs(dg_irxn) <= m_tolmin2) {
                molNum_kspec_new = w_kspec;
                return 0.0;
            }
        }

        /*
         * get the diagonal of the activity coefficient jacobian
         */
        s = m_dLnActCoeffdMolNum[kspec][kspec];
        // s *= (m_tPhaseMoles_old[iph]);
        /*
         *   We fit it to a power law approximation of the activity coefficient
         *
         *      gamma = gamma_0 * ( x / x0)**a
         *
         *   where a is forced to be a little bit greater than -1.
         *   We do this so that the resulting expression is always nonnegative
         *
         *   We then solve the resulting calculation:
         *
         *      gamma * x  = gamma_0 * x0 exp (-deltaG/RT);
         *
         *
         */
        a = w_kspec * s;
        if (a < (-1.0 + 1.0E-8)) {
            a = -1.0 + 1.0E-8;
        } else  if (a > 100.0) {
            a = 100.0;
        }
        tmp = -dg_irxn / (1.0 + a);
        if (tmp < -200.) {
            tmp = -200.;
        } else if (tmp > 200.) {
            tmp = 200.;
        }
        wTrial =  w_kspec * exp(tmp);
        // wTrial = w_kspec * exp(-dg_irxn);

        molNum_kspec_new = wTrial;

        if (wTrial > 100. * w_kspec) {
            double molNumMax = 0.0001 * m_tPhaseMoles_old[iph];
            if (molNumMax < 100. * w_kspec) {
                molNumMax =  100. * w_kspec;
            }
            if (wTrial > molNumMax) {
                molNum_kspec_new = molNumMax;
            } else {
                molNum_kspec_new = wTrial;
            }

        } else if (1.0E10 * wTrial < w_kspec) {
            molNum_kspec_new= 1.0E-10 * w_kspec;
        } else {
            molNum_kspec_new = wTrial;
        }


        if ((molNum_kspec_new) < VCS_DELETE_MINORSPECIES_CUTOFF) {
            goto L_ZERO_SPECIES;
        }
        dx = molNum_kspec_new - w_kspec;
        return dx;
        /*
         *
         *  Alternate return based for cases where we need to delete the species
         *  from the current list of active species, because its concentration
         *  has gotten too small.
         */
L_ZERO_SPECIES:
        ;
        *do_delete = true;
        dx = - w_kspec;
        return dx;
    } else {
        /*
         * Voltage calculation
         *   Need to check the sign -> This is good for electrons
         */
        dx = m_deltaGRxn_old[irxn]/ m_Faraday_dim;
#ifdef DEBUG_MODE
        sprintf(ANOTE,"voltage species alternative calc");
#endif
    }
    return dx;
}
/*****************************************************************************/

//  Change the concentration of a species by delta moles.
/*
 *  Make sure to conserve elements and keep track of the total kmoles in all phases.
 *
 *
 *  @param kspec The species index
 *  @param delta_ptr   pointer to the delta for the species. This may change during
 *                     the calculation
 *
 *  @return
 *      1: succeeded without change of dx
 *      0: Had to adjust dx, perhaps to zero, in order to do the delta.
 */
int VCS_SOLVE::delta_species(const size_t kspec, double* const delta_ptr)
{
    size_t irxn = kspec - m_numComponents;
    int retn = 1;
    double tmp;
    double delta = *delta_ptr;
#ifdef DEBUG_MODE
    if (kspec < m_numComponents) {
        plogf("  --- delete_species() ERROR: called for a component %d", kspec);
        plogendl();
        exit(EXIT_FAILURE);
    }
#endif
    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
        /*
         * Attempt the given dx. If it doesn't work, try to see if a smaller
         * one would work,
         */
        double dx = delta;
        double* sc_irxn = m_stoichCoeffRxnMatrix[irxn];
        for (size_t j = 0; j < m_numComponents; ++j) {
            if (m_molNumSpecies_old[j] > 0.0) {
                tmp = sc_irxn[j] * dx;
                if (-tmp > m_molNumSpecies_old[j]) {
                    retn = 0;
                    dx = std::min(dx, - m_molNumSpecies_old[j] / sc_irxn[j]);
                }
            }
            /*
             * If the component has a zero concentration and is a reactant
             * in the formation reaction, then dx == 0.0, and we just return.
             */
            if (m_molNumSpecies_old[j] <= 0.0) {
                if (sc_irxn[j] < 0.0) {
                    *delta_ptr = 0.0;
                    return 0;
                }
            }
        }
        /*
         * ok, we found a positive dx. implement it.
         */
        *delta_ptr = dx;
        m_molNumSpecies_old[kspec] += dx;
        size_t iph = m_phaseID[kspec];
        m_tPhaseMoles_old[iph] += dx;
        vcs_setFlagsVolPhase(iph, false, VCS_STATECALC_OLD);

        for (size_t j = 0; j < m_numComponents; ++j) {
            tmp = sc_irxn[j] * dx;
            if (tmp != 0.0) {
                iph = m_phaseID[j];
                m_molNumSpecies_old[j] += tmp;
                m_tPhaseMoles_old[iph] += tmp;
                vcs_setFlagsVolPhase(iph, false, VCS_STATECALC_OLD);
                if (m_molNumSpecies_old[j] < 0.0) {
                    m_molNumSpecies_old[j] = 0.0;
                }
            }
        }
    }
    return retn;
}
/*****************************************************************************/

//  Zero out the concentration of a species.
/*
 *     Zero out the concentration of a species. Make sure to conserve
 *  elements and keep track of the total moles in all phases.
 *       w[]
 *       m_tPhaseMoles_old[]
 *
 *  @param kspec  Species index
 *
 *  @return:
 *      1: succeeded
 *      0: failed.
 */
int VCS_SOLVE::vcs_zero_species(const size_t kspec)
{
    int retn = 1;
    /*
     * Calculate a delta that will eliminate the species.
     */
    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
        double dx = -(m_molNumSpecies_old[kspec]);
        if (dx != 0.0) {
            retn = delta_species(kspec, &dx);
#ifdef DEBUG_MODE
            if (!retn) {
                if (m_debug_print_lvl >= 1) {
                    plogf("vcs_zero_species: Couldn't zero the species %d, "
                          "did delta of %g. orig conc of %g",
                          kspec, dx, m_molNumSpecies_old[kspec] + dx);
                    plogendl();
                }
            }
#endif
        }
    }
    return retn;
}
/**************************************************************************/

// Change a single species from active to inactive status
/*
 *   Rearrange data when species is added or removed. The kspec species is
 *   moved to the back of the active species vector. The back of the species
 *   vector is indicated by the value of  m_numSpeciesRdc, the current
 *   number of active species in the mechanism.
 *
 * @param kspec   Species Index
 * @return
 *     Returns 0 unless.
 *     The return is 1 when the current number of
 *     noncomponent species is equal to zero. A recheck of deleted species
 *     is carried out in the main code.
 */
int VCS_SOLVE::vcs_delete_species(const size_t kspec)
{
    const size_t klast = m_numSpeciesRdc - 1;
    const size_t iph = m_phaseID[kspec];
    vcs_VolPhase* const Vphase = m_VolPhaseList[iph];
    const size_t irxn = kspec - m_numComponents;
    /*
     * Zero the concentration of the species.
     *     -> This zeroes w[kspec] and modifies m_tPhaseMoles_old[]
     */
    const int retn = vcs_zero_species(kspec);
    if (DEBUG_MODE_ENABLED && !retn) {
        plogf("Failed to delete a species!");
        plogendl();
        exit(EXIT_FAILURE);
    }
    /*
     *    Decrement the minor species counter if the current species is
     *    a minor species
     */
    if (m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) {
        --(m_numRxnMinorZeroed);
    }
    m_speciesStatus[kspec] = VCS_SPECIES_DELETED;
    m_deltaGRxn_new[irxn] = 0.0;
    m_deltaGRxn_old[irxn] = 0.0;
    m_feSpecies_new[kspec] = 0.0;
    m_feSpecies_old[kspec] = 0.0;
    m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
    /*
     *    Rearrange the data if the current species isn't the last active
     *    species.
     */
    if (kspec != klast) {
        vcs_switch_pos(true, klast, kspec);
    }
    /*
     *       Adjust the total moles in a phase downwards.
     */
    Vphase->setMolesFromVCSCheck(VCS_STATECALC_OLD,
                                 VCS_DATA_PTR(m_molNumSpecies_old),
                                 VCS_DATA_PTR(m_tPhaseMoles_old));

    /*
     *    Adjust the current number of active species and reactions counters
     */
    --(m_numRxnRdc);
    --(m_numSpeciesRdc);

    /*
     *    Check to see whether we have just annihilated a multispecies phase.
     *    If it is extinct, call the delete_multiphase() function.
     */
    if (! m_SSPhase[klast]) {
        if (Vphase->exists() != VCS_PHASE_EXIST_ALWAYS) {
            bool stillExists = false;
            for (size_t k = 0; k < m_numSpeciesRdc; k++) {
                if (m_speciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                    if (m_phaseID[k] == iph) {
                        if (m_molNumSpecies_old[k] > 0.0) {
                            stillExists = true;
                            break;
                        }
                    }
                }
            }
            if (!stillExists) {
                vcs_delete_multiphase(iph);
            }
        }
    }
    /*
     *    When the total number of noncomponent species is zero, we
     *    have to signal the calling code
     */
    return (m_numRxnRdc == 0);
}
/***************************************************************************/

/*
 *
 *  reinsert_deleted():
 *
 * irxn = id of the noncomponent species formation reaction for the
 *        species to be added in.
 *
 * We make decisions on the initial mole number, and major-minor status
 * here. We also fix up the total moles in a phase.
 *
 * The algorithm proceeds to implement these decisions in the previous
 * position of the species. Then, vcs_switch_pos is called to move the
 * species into the last active species slot, incrementing the number
 * of active species at the same time.
 *
 * This routine is responsible for the global data manipulation only.
 */
void VCS_SOLVE::vcs_reinsert_deleted(size_t kspec)
{
    size_t k;
    // int irxn = kspec - m_numComponents;
    size_t iph = m_phaseID[kspec];
    double dx;
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Add back a deleted species: %-12s\n", m_speciesName[kspec].c_str());
    }
#endif
    /*
     * Set the species back to minor species status
     *  this adjusts m_molNumSpecies_old[] and m_tPhaseMoles_old[]
     * HKM -> make this a relative mole number!
     */
    dx = m_tPhaseMoles_old[iph] * VCS_RELDELETE_SPECIES_CUTOFF * 10.;
    delta_species(kspec, &dx);
    m_speciesStatus[kspec] = VCS_SPECIES_MINOR;

    if (m_SSPhase[kspec]) {
        m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
        --(m_numRxnMinorZeroed);
    }

    vcs_VolPhase* Vphase = m_VolPhaseList[iph];
    Vphase->setMolesFromVCSCheck(VCS_STATECALC_OLD,
                                 VCS_DATA_PTR(m_molNumSpecies_old),
                                 VCS_DATA_PTR(m_tPhaseMoles_old));
    /*
     *   We may have popped a multispecies phase back
     *   into existence. If we did, we have to check
     *   the other species in that phase.
     *   Take care of the m_speciesStatus[] flag.
     *   The value of m_speciesStatus[] must change from
     *   VCS_SPECIES_ZEROEDPHASE to VCS_SPECIES_ZEROEDMS
     *   for those other species.
     */
    if (! m_SSPhase[kspec]) {
        if (Vphase->exists() == VCS_PHASE_EXIST_NO) {
            Vphase->setExistence(VCS_PHASE_EXIST_YES);
            for (k = 0; k < m_numSpeciesTot; k++) {
                if (m_phaseID[k] == iph) {
                    if (m_speciesStatus[k] != VCS_SPECIES_DELETED) {
                        m_speciesStatus[k] = VCS_SPECIES_MINOR;
                    }
                }
            }
        }
    } else {
        Vphase->setExistence(VCS_PHASE_EXIST_YES);
    }

    ++(m_numRxnRdc);
    ++(m_numSpeciesRdc);
    ++(m_numRxnMinorZeroed);

    if (kspec != (m_numSpeciesRdc - 1)) {
        /*
         *  Rearrange both the species and the non-component global data
         */
        vcs_switch_pos(true, (m_numSpeciesRdc - 1), kspec);
    }
}
/****************************************************************************/

// This routine handles the bookkeepking involved with the
//  deletion of multiphase phases from the problem.
/*
 *   When they are deleted, all of their species become active
 *   species, even though their mole numbers are set to zero.
 *   This routine does not make the decision to eliminate multiphases.
 *
 *   Note, species in phases with zero mole numbers are still
 *   considered active. Whether the phase pops back into
 *   existence or not is checked as part of the main iteration
 *   loop.
 *
 * @param iph Phase to be deleted
 */
bool VCS_SOLVE::vcs_delete_multiphase(const size_t iph)
{
    size_t kspec, irxn;
    double dx;
    vcs_VolPhase* Vphase = m_VolPhaseList[iph];
    bool successful = true;
    /*
     * set the phase existence flag to dead
     */
    Vphase->setTotalMoles(0.0);
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- delete_multiphase %d, %s\n", iph, Vphase->PhaseName.c_str());
    }
#endif

    /*
     * Loop over all of the species in the phase.
     */
    for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) {
        if (m_phaseID[kspec] == iph) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                /*
                 * calculate an extent of rxn, dx, that zeroes out the species.
                 */
                dx = - (m_molNumSpecies_old[kspec]);
                double dxTent = dx;

                int retn = delta_species(kspec, &dxTent);
                if (retn != 1) {
                    successful = false;
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 2) {
                        plogf("   --- delete_multiphase %d, %s ERROR problems deleting species %s\n",
                              iph, Vphase->PhaseName.c_str(), m_speciesName[kspec].c_str());
                        plogf("   ---     delta  attempted: %g  achieved: %g   "
                              "  Zeroing it manually\n", dx, dxTent);
                    }
#endif
                    m_molNumSpecies_old[kspec]  = 0.0;
                    m_molNumSpecies_new[kspec]  = 0.0;
                    m_deltaMolNumSpecies[kspec] = 0.0;
                    // recover the total phase moles.
                    vcs_tmoles();
                } else {
                    /*
                     * Set the mole number of that species to zero.
                     */
                    m_molNumSpecies_old[kspec]  = 0.0;
                    m_molNumSpecies_new[kspec]  = 0.0;
                    m_deltaMolNumSpecies[kspec] = 0.0;
                }
                /*
                 * Change the status flag of the species to that of an
                 * zeroed phase
                 */
                m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDMS;
            }
        }
    }

    double dj, dxWant, dxPerm = 0.0, dxPerm2 = 0.0;
    for (size_t kcomp = 0; kcomp < m_numComponents; ++kcomp) {
        if (m_phaseID[kcomp] == iph) {
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   --- delete_multiphase   One of the species is a component %d - %s with mole number %g\n",
                      kcomp, m_speciesName[kcomp].c_str(),   m_molNumSpecies_old[kcomp]);
            }
#endif
            if (m_molNumSpecies_old[kcomp] != 0.0) {
                for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) {
                    irxn = kspec - m_numComponents;
                    if (m_phaseID[kspec] != iph) {
                        if (m_stoichCoeffRxnMatrix[irxn][kcomp] != 0.0) {
                            dxWant = -m_molNumSpecies_old[kcomp] / m_stoichCoeffRxnMatrix[irxn][kcomp];
                            if (dxWant + m_molNumSpecies_old[kspec]  < 0.0) {
                                dxPerm = -m_molNumSpecies_old[kspec];
                            }
                            for (size_t jcomp = 0;  kcomp < m_numComponents; ++kcomp) {
                                if (jcomp != kcomp) {
                                    if (m_phaseID[jcomp] == iph) {
                                        dxPerm = 0.0;
                                    } else {
                                        dj = dxWant * m_stoichCoeffRxnMatrix[irxn][jcomp];
                                        if (dj + m_molNumSpecies_old[kcomp]  < 0.0) {
                                            dxPerm2 = -m_molNumSpecies_old[kcomp] / m_stoichCoeffRxnMatrix[irxn][jcomp];
                                        }
                                        if (fabs(dxPerm2) < fabs(dxPerm)) {
                                            dxPerm = dxPerm2;
                                        }
                                    }
                                }
                            }
                        }
                        if (dxPerm != 0.0) {
                            delta_species(kspec, &dxPerm);
                        }
                    }
                }

            }
            if (m_molNumSpecies_old[kcomp] != 0.0) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    plogf("   --- delete_multiphase   One of the species is a component %d - %s still with mole number %g\n",
                          kcomp, m_speciesName[kcomp].c_str(),   m_molNumSpecies_old[kcomp]);
                    plogf("   ---                     zeroing it \n");
                }
#endif
                m_molNumSpecies_old[kcomp] = 0.0;
            }
            m_speciesStatus[kcomp] = VCS_SPECIES_ZEROEDMS;
        }
    }


    /*
     *   Loop over all of the inactive species in the phase:
     *   Right now we reinstate all species in a deleted multiphase.
     *   We may only want to reinstate the "major ones" in the future.
     *   Note, species in phases with zero mole numbers are still
     *   considered active. Whether the phase pops back into
     *   existence or not is checked as part of the main iteration
     *   loop.
     */
    for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) {
        if (m_phaseID[kspec] == iph) {
            irxn = kspec - m_numComponents;
            m_molNumSpecies_old[kspec]  = 0.0;
            m_molNumSpecies_new[kspec] = 0.0;
            m_deltaMolNumSpecies[kspec] = 0.0;
            m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDMS;

            ++(m_numRxnRdc);
            ++(m_numSpeciesRdc);
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   ---    Make %s", m_speciesName[kspec].c_str());
                plogf(" an active but zeroed species because its phase "
                      "was zeroed\n");
            }
#endif
            if (kspec != (m_numSpeciesRdc - 1)) {
                /*
                 *  Rearrange both the species and the non-component global data
                 */
                vcs_switch_pos(true, (m_numSpeciesRdc - 1), kspec);
            }
        }
    }

    /*
     * Zero out the total moles counters for the phase
     */
    m_tPhaseMoles_old[iph] = 0.0;
    m_tPhaseMoles_new[iph] = 0.0;
    m_deltaPhaseMoles[iph] = 0.0;
    /*
     * Upload the state to the VP object
     */
    Vphase->setTotalMoles(0.0);

    return successful;
}
/**********************************************************************************/

//    Recheck deleted species in multispecies phases.
/*
 *   We are checking the equation:
 *
 *         sum_u = sum_j_comp [ sigma_i_j * u_j ]
 *               = u_i_O + log((AC_i * W_i)/m_tPhaseMoles_old)
 *
 *   by first evaluating:
 *
 *          DG_i_O = u_i_O - sum_u.
 *
 *   Then, if TL is zero, the phase pops into existence if DG_i_O < 0.
 *   Also, if the phase exists, then we check to see if the species
 *   can have a mole number larger than  VCS_DELETE_SPECIES_CUTOFF
 *   (default value = 1.0E-32).
 *
 */
int VCS_SOLVE::vcs_recheck_deleted()
{
    int npb;
    size_t iph, kspec, irxn;
    double* xtcutoff = VCS_DATA_PTR(m_TmpPhase);
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Start rechecking deleted species in multispec phases\n");
    }
#endif
    if (m_numSpeciesRdc == m_numSpeciesTot) {
        return 0;
    }
    /*
     * Use the standard chemical potentials for the chemical potentials
     * of deleted species. Then, calculate Delta G for
     * for formation reactions.
     * Note: fe[] here includes everything except for the ln(x[i]) term
     */
    for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) {
        iph = m_phaseID[kspec];
        m_feSpecies_new[kspec] = (m_SSfeSpecies[kspec] + log(m_actCoeffSpecies_old[kspec])
                                  - m_lnMnaughtSpecies[kspec]
                                  + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]);
    }

    /*
     *      Recalculate the DeltaG's of the formation reactions for the
     *      deleted species in the mechanism
     */
    vcs_deltag(0, true, VCS_STATECALC_NEW);

    for (iph = 0; iph < m_numPhases; iph++) {
        if (m_tPhaseMoles_old[iph] > 0.0) {
            xtcutoff[iph] = log(1.0 / VCS_RELDELETE_SPECIES_CUTOFF);
        } else {
            xtcutoff[iph] = 0.0;
        }
    }

    /*
     *
     *   We are checking the equation:
     *
     *         sum_u = sum_j_comp [ sigma_i_j * u_j ]
     *               = u_i_O + log((AC_i * W_i)/m_tPhaseMoles_old)
     *
     *   by first evaluating:
     *
     *          DG_i_O = u_i_O - sum_u.
     *
     *   Then, if TL is zero, the phase pops into existence if DG_i_O < 0.
     *   Also, if the phase exists, then we check to see if the species
     *   can have a mole number larger than  VCS_DELETE_SPECIES_CUTOFF
     *   (default value = 1.0E-32).
     *
     *   HKM:
     *       This seems to be an inconsistency in the algorithm here that needs
     *   correcting. The requirement above may bypass some multiphases which
     *   should exist. The real requirement for the phase to exist is:
     *
     *           sum_i_in_phase [ exp(-DG_i_O) ] >= 1.0
     *
     *   Thus, we need to amend the code. Also nonideal solutions will tend to
     *   complicate matters severely also.
     */
    npb = 0;
    for (irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) {
        kspec = m_indexRxnToSpecies[irxn];
        iph = m_phaseID[kspec];
        if (m_tPhaseMoles_old[iph] == 0.0) {
            if (m_deltaGRxn_new[irxn] < 0.0) {
                vcs_reinsert_deleted(kspec);
                npb++;
            } else {
                m_molNumSpecies_old[kspec] = 0.0;
            }
        } else if (m_tPhaseMoles_old[iph] > 0.0) {
            if (m_deltaGRxn_new[irxn] < xtcutoff[iph]) {
                vcs_reinsert_deleted(kspec);
                npb++;
            }
        }
    }
    return npb;
}
/***********************************************************************************/

// Recheck deletion condition for multispecies phases.
/*
 *   We assume here that DG_i_0 has been calculated for deleted species correctly
 *
 *
 *   m_feSpecies(I) = m_SSfeSpecies(I)
 *                  + ln(ActCoeff[I])
 *                  - ln(Mnaught * m_units)
 *                  + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *         sum_u = sum_j_comp [ sigma_i_j * u_j ]
 *               = u_i_O + log((AC_i * W_i)/m_tPhaseMoles_old)
 *
 *   DG_i_0 =  m_feSpecies(I) - sum_m{ a_i_m  DG_m }
 *
 *
 *   by first evaluating:
 *
 *          DG_i_O = u_i_O - sum_u.
 *
 *   Then, the phase pops into existence iff
 *
 *      phaseDG = 1.0 - sum_i{exp(-DG_i_O)}  < 0.0
 *
 *  This formula works for both single species phases and for multispecies
 *  phases. It's an overkill for single species phases.
 *
 *  @param iphase Phase index number
 *
 * @return   Returns true if the phase is currently deleted
 *           but should be reinstated. Returns false otherwise.
 *
 *  NOTE: this routine is currently not used in the code, and
 *       contains some basic changes that are incompatible.
 *
 * assumptions:
 *       1) Vphase Existence is up to date
 *       2) Vphase->IndSpecies is up to date
 *       3) m_deltaGRxn_old[irxn] is up to date
 */
bool VCS_SOLVE::recheck_deleted_phase(const int iphase)
{

    // Check first to see if the phase is in fact deleted
    const vcs_VolPhase* Vphase = m_VolPhaseList[iphase];
    if (Vphase->exists() != VCS_PHASE_EXIST_NO) {
        return false;
    }
    if (Vphase->exists() == VCS_PHASE_EXIST_ZEROEDPHASE) {
        return false;
    }
    size_t irxn, kspec;
    if (Vphase->m_singleSpecies) {
        kspec = Vphase->spGlobalIndexVCS(0);
        irxn = kspec + m_numComponents;
        if (m_deltaGRxn_old[irxn] < 0.0) {
            return true;
        }
        return false;
    }

    double phaseDG = 1.0;
    for (size_t kk = 0; kk <  Vphase->nSpecies(); kk++) {
        kspec = Vphase->spGlobalIndexVCS(kk);
        irxn = kspec + m_numComponents;
        if (m_deltaGRxn_old[irxn] >  50.0) {
            m_deltaGRxn_old[irxn] =  50.0;
        }
        if (m_deltaGRxn_old[irxn] < -50.0) {
            m_deltaGRxn_old[irxn] = -50.0;
        }
        phaseDG -= exp(-m_deltaGRxn_old[irxn]);
    }

    if (phaseDG < 0.0) {
        return true;
    }
    return false;
}
//====================================================================================================================
//  Provide an estimate for the deleted species in phases that are not zeroed out
/*
 *  Try to add back in all deleted species. An estimate of the kmol numbers
 *  are obtained and the species is added back into the equation system,
 *  into the old state vector.
 */
size_t VCS_SOLVE::vcs_add_all_deleted()
{
    size_t iph, kspec, retn;
    if (m_numSpeciesRdc == m_numSpeciesTot) {
        return 0;
    }
    /*
     * Use the standard chemical potentials for the chemical potentials of deleted species. Then, calculate Delta G for
     * for formation reactions.
     *     We are relying here on a old saved value of m_actCoeffSpecies_old[kspec]
     *  being sufficiently good. Note, we will recalculate everything at the end of the routine.
     */
    vcs_dcopy(VCS_DATA_PTR(m_molNumSpecies_new), VCS_DATA_PTR(m_molNumSpecies_old), m_numSpeciesTot);

    for (int cits = 0; cits < 3; cits++) {
        for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) {
            iph = m_phaseID[kspec];
            vcs_VolPhase* Vphase = m_VolPhaseList[iph];
            if (m_molNumSpecies_new[kspec] == 0.0) {
                m_molNumSpecies_new[kspec] = VCS_DELETE_MINORSPECIES_CUTOFF * 1.0E-10;
            }
            if (!Vphase->m_singleSpecies) {
                Vphase->sendToVCS_ActCoeff(VCS_STATECALC_NEW, VCS_DATA_PTR(m_actCoeffSpecies_new));
            }
            m_feSpecies_new[kspec] = (m_SSfeSpecies[kspec] + log(m_actCoeffSpecies_new[kspec]) - m_lnMnaughtSpecies[kspec]
                                      + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iph]);
        }
        /*
         * Recalculate the DeltaG's of the formation reactions for the deleted species in the mechanism
         */
        vcs_deltag(0, true, VCS_STATECALC_NEW);
        for (size_t irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) {
            kspec = m_indexRxnToSpecies[irxn];
            iph = m_phaseID[kspec];
            if (m_tPhaseMoles_old[iph] > 0.0) {
                double maxDG = std::min(m_deltaGRxn_new[irxn], 690.0);
                double dx = m_tPhaseMoles_old[iph] * exp(- maxDG);
                m_molNumSpecies_new[kspec] = dx;
                if (m_molNumSpecies_new[kspec] > 2 *VCS_DELETE_MINORSPECIES_CUTOFF) {
                    m_molNumSpecies_new[kspec] = 2 * VCS_DELETE_MINORSPECIES_CUTOFF;
                }
            }
        }
    }
    for (size_t irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) {
        kspec = m_indexRxnToSpecies[irxn];
        iph = m_phaseID[kspec];
        if (m_tPhaseMoles_old[iph] > 0.0) {
            double dx =  m_molNumSpecies_new[kspec];
            retn = delta_species(kspec, &dx);
            if (retn == 0) {
#ifdef DEBUG_MODE
                if (m_debug_print_lvl) {
                    plogf("  --- add_deleted(): delta_species() failed for species %s (%d) with mol number %g\n",
                          m_speciesName[kspec].c_str(), kspec, dx);
                }
#endif
                if (dx > 1.0E-50) {
                    dx = 1.0E-50;
                    retn = delta_species(kspec, &dx);
#ifdef DEBUG_MODE
                    if (retn == 0) {
                        if (m_debug_print_lvl) {
                            plogf("  --- add_deleted(): delta_species() failed for species %s (%d) with mol number %g\n",
                                  m_speciesName[kspec].c_str(), kspec, dx);
                        }
                    }
#endif
                }
            }
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                if (retn != 0) {
                    plogf("  --- add_deleted():  species %s added back in with mol number %g",
                          m_speciesName[kspec].c_str(), dx);
                    plogendl();
                } else {
                    plogf("  --- add_deleted():  species %s failed to be added  back in");
                    plogendl();
                }
            }
#endif
        }
    }
    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesTot);
    vcs_deltag(0, true, VCS_STATECALC_OLD);

    retn = 0;
    for (size_t irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) {
        kspec = m_indexRxnToSpecies[irxn];
        iph = m_phaseID[kspec];
        if (m_tPhaseMoles_old[iph] > 0.0) {
            if (fabs(m_deltaGRxn_old[irxn]) > m_tolmin) {
                if (((m_molNumSpecies_old[kspec] * exp(-m_deltaGRxn_old[irxn])) >
                        VCS_DELETE_MINORSPECIES_CUTOFF) ||
                        (m_molNumSpecies_old[kspec] > VCS_DELETE_MINORSPECIES_CUTOFF)) {
                    retn++;
#ifdef DEBUG_MODE
                    if (m_debug_print_lvl >= 2) {
                        plogf("  --- add_deleted():  species %s with mol number %g not converged: DG = %g",
                              m_speciesName[kspec].c_str(), m_molNumSpecies_old[kspec],
                              m_deltaGRxn_old[irxn]);
                        plogendl();
                    }
#endif
                }
            }
        }
    }
    return retn;
}
/***********************************************************************************/

//  This routine optimizes the minimization of the total gibbs free
//  energy by making sure the slope of the Gibbs free energy stays negative
/*
 *  The slope of the following functional is equivalent to the slope of the total
 *  Gibbs free energy of the system:
 *
 *                 d_Gibbs/ds = sum_k( m_deltaGRxn * m_deltaMolNumSpecies[k] )
 *
 *  along the current direction m_deltaMolNumSpecies[], by choosing a value, al: (0<al<1)
 *  such that the a parabola approximation to Gibbs(al) fit to the
 *  end points al = 0 and al = 1 is minimizied.
 *      s1 = slope of Gibbs function at al = 0, which is the previous
 *           solution = d(Gibbs)/d(al).
 *      s2 = slope of Gibbs function at al = 1, which is the current
 *           solution = d(Gibbs)/d(al).
 *  Only if there has been an inflection point (i.e., s1 < 0 and s2 > 0),
 *  does this code section kick in. It finds the point on the parabola
 *  where the slope is equal to zero.
 *
 */
bool VCS_SOLVE::vcs_globStepDamp()
{
    double s1, s2, al;
    size_t irxn, kspec, iph;
    double* dptr = VCS_DATA_PTR(m_deltaGRxn_new);

    /* *************************************************** */
    /* **** CALCULATE SLOPE AT END OF THE STEP  ********** */
    /* *************************************************** */
    s2 = 0.0;
    for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
        kspec = irxn + m_numComponents;
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            s2 += dptr[irxn] * m_deltaMolNumSpecies[kspec];
        }
    }


    /* *************************************************** */
    /* **** CALCULATE ORIGINAL SLOPE ********************* */
    /* ************************************************** */
    s1 = 0.0;
    dptr = VCS_DATA_PTR(m_deltaGRxn_old);
    for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
        kspec = irxn + m_numComponents;
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            s1 += dptr[irxn] * m_deltaMolNumSpecies[kspec];
        }
    }

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- subroutine FORCE: Beginning Slope = %g\n", s1);
        plogf("   --- subroutine FORCE: End Slope       = %g\n", s2);
    }
#endif

    if (s1 > 0.0) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- subroutine FORCE produced no adjustments,");
            if (s1 < 1.0E-40) {
                plogf(" s1 positive but really small");
            } else {
                plogf(" failed s1 test");
            }
            plogendl();
        }
#endif
        return false;
    }

    if (s2 <= 0.0) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- subroutine FORCE produced no adjustments, s2 < 0");
            plogendl();
        }
#endif
        return false;
    }

    /* *************************************************** */
    /* **** FIT PCJ2822ARABOLA ********************************* */
    /* *************************************************** */
    al = 1.0;
    if (fabs(s1 -s2) > 1.0E-200) {
        al = s1 / (s1 - s2);
    }
    if (al >= 0.95 || al < 0.0) {
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 2) {
            plogf("   --- subroutine FORCE produced no adjustments (al = %g)\n", al);
        }
#endif
        return false;
    }
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- subroutine FORCE produced a damping factor = %g\n", al);
    }
#endif

    /* *************************************************** */
    /* **** ADJUST MOLE NUMBERS, CHEM. POT *************** */
    /* *************************************************** */
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        vcs_dcopy(VCS_DATA_PTR(m_deltaGRxn_tmp), VCS_DATA_PTR(m_deltaGRxn_new),
                  m_numRxnRdc);
    }
#endif

    dptr = VCS_DATA_PTR(m_molNumSpecies_new);
    for (kspec = 0; kspec < m_numSpeciesRdc; ++kspec) {
        m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] +
                                     al * m_deltaMolNumSpecies[kspec];
    }
    for (iph = 0; iph < m_numPhases; iph++) {
        m_tPhaseMoles_new[iph] = m_tPhaseMoles_old[iph] + al * m_deltaPhaseMoles[iph];
    }
    vcs_updateVP(VCS_STATECALC_NEW);

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- subroutine FORCE adjusted the mole "
              "numbers, AL = %10.3f\n", al);
    }
#endif
    /*
     *           Because we changed the mole numbers, we need to
     *           calculate the chemical potentials again. If a major-
     *           only step is being carried out, then we don't need to
     *           update the minor noncomponents.
     */
    vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
    vcs_dfe(VCS_STATECALC_NEW, 0, 0, m_numSpeciesRdc);

    /*
     *           Evaluate DeltaG for all components if ITI=0, and for
     *           major components only if ITI NE 0
     */
    vcs_deltag(0, false, VCS_STATECALC_NEW);

    dptr = VCS_DATA_PTR(m_deltaGRxn_new);
    s2 = 0.0;
    for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
        kspec = irxn + m_numComponents;
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            s2 += dptr[irxn] * m_deltaMolNumSpecies[kspec];
        }
    }


#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- subroutine FORCE: Adj End Slope   = %g", s2);
        plogendl();
    }
#endif
    return true;
}
/****************************************************************************************/


//  Choose the optimum species basis for the calculations
/*
 * Choose the optimum component species basis for the calculations.
 *  This is done by choosing the species with the largest mole fraction
 * not currently a linear combination of the previous components.
 * Then, calculate the stoichiometric coefficient matrix for that
 * basis.
 *
 * Rearranges the solution data to put the component data at the
 * front of the species list.
 *
 * Then, calculates M_STOICHCOEFFRXNMATRIX(J,I) the formation reactions
 * for all noncomponent species in the mechanism.
 * Also calculates DNG(I) and DNL(I), the net mole change for each
 * formation reaction.
 * Also, initializes IR(I) to the default state.
 *
 * Input
 * ---------
 * @param doJustCompoents   If true, the m_stoichCoeffRxnMatrix[][] and
 *                          m_deltaMolNumPhase[]  are not calculated.
 *
 * @param aw         Vector of mole fractions which will be used to construct an
 *                   optimal basis from.
 *
 * @param  sa        Gramm-Schmidt orthog work space (nc in length) sa[j]
 * @param  ss        Gramm-Schmidt orthog work space (nc in length) ss[j]
 * @param  sm        QR matrix work space (nc*ne in length)         sm[i+j*ne]
 * @param test       This is a small negative number dependent upon whether
 *                   an estimate is supplied or not.
 *
 * Output
 * ---------
 * @param usedZeroedSpecies = If true, then a species with a zero concentration
 *                            was used as a component. The problem may be
 *                            converged. Or, the problem may have a range space
 *                            error and may not have a proper solution.
 *
 *  Internal Variables calculated by this routine:
 *  -----------------------------------------------
 *
 *      m_numComponents
 *                 Number of component species
 *
 *      component species
 *                 This routine calculates the m_numComponent species. It switches
 *                 their positions in the species vector so that they occupy
 *                 the first m_numComponent spots in the species vector.
 *
 *      m_stoichCoeffRxnMatrix[irxn][jcomp]
 *                 Stoichiometric coefficient matrix for the reaction mechanism
 *                 expressed in Reduced Canonical Form.
 *                 j refers to the component number, and irxn
 *                 refers to the irxn_th non-component species.
 *
 *      m_deltaMolNumPhase[irxn]
 *                Change in the number of total number of moles of species in all phases
 *                due to the noncomponent formation reaction, irxn.
 *
 *      m_deltaMolNumPhase[irxn][iphase]
 *                Change in the number of moles in phase, iphase, due to the
 *                noncomponent formation reaction, irxn.
 *
 *      m_phaseParticipation[irxn]
 *                This is 1 if the phase, iphase,  participates in the
 *                formation reaction, irxn, and zero otherwise.
 *
 * @return        Returns VCS_SUCCESS if everything went ok. Returns
 *                VCS_FAILED_CONVERGENCE if there is a problem.
 */
int VCS_SOLVE::vcs_basopt(const bool doJustComponents, double aw[], double sa[], double sm[],
                          double ss[], double test, bool* const usedZeroedSpecies)
{
    size_t  j, k, l, i, jl, ml, jr, irxn, kspec;
    bool lindep;
    size_t ncTrial;
    size_t juse = npos;
    size_t jlose = npos;
    double* dptr, *scrxn_ptr;
    Cantera::clockWC tickTock;
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   ");
        for (i=0; i<77; i++) {
            plogf("-");
        }
        plogf("\n");
        plogf("   --- Subroutine BASOPT called to ");
        if (doJustComponents) {
            plogf("calculate the number of components\n");
        } else {
            plogf("reevaluate the components\n");
        }
        if (m_debug_print_lvl >= 2) {
            plogf("\n");
            plogf("   ---       Formula Matrix used in BASOPT calculation\n");
            plogf("   ---      Active |   ");
            for (j = 0; j < m_numElemConstraints; j++) {
                plogf("  %1d  ", m_elementActive[j]);
            }
            plogf("\n");
            plogf("   ---     Species | ");
            for (j = 0; j < m_numElemConstraints; j++) {
                plogf(" ");
                vcs_print_stringTrunc(m_elementName[j].c_str(), 8, 1);
            }
            plogf("\n");
            for (k = 0; k < m_numSpeciesTot; k++) {
                plogf("   --- ");
                vcs_print_stringTrunc(m_speciesName[k].c_str(), 11, 1);
                plogf(" | ");
                for (j = 0; j < m_numElemConstraints; j++) {
                    plogf(" %8.2g", m_formulaMatrix[j][k]);
                }
                plogf("\n");
            }
            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.
     */
    ncTrial = std::min(m_numElemConstraints, m_numSpeciesTot);
    m_numComponents = ncTrial;
    *usedZeroedSpecies = false;

    /*
     *     Use a temporary work array for the mole numbers, aw[]
     */
    vcs_dcopy(aw, VCS_DATA_PTR(m_molNumSpecies_old), m_numSpeciesTot);
    /*
     * Take out the Voltage unknowns from consideration
     */
    for (k = 0; k < m_numSpeciesTot; k++) {
        if (m_speciesUnknownType[k] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            aw[k] = test;
        }
    }

    jr = npos;
    /*
     *   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 fraction 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 = vcs_basisOptMax(aw, jr, m_numSpeciesTot);

            /*
             * The fun really starts when you have run out of species that have a significant
             * concentration. It becomes extremely important to make a good choice of which
             * species you want to pick to fill out the basis. Basically, you don't want to
             * use species with elements abundances which aren't pegged to zero. This means
             * that those modes will never be allowed to grow. You want to have the
             * best chance that the component will grow positively.
             *
             * Suppose  you start with CH4, N2, as the only species with nonzero compositions.
             * You have the following abundances:
             *
             *  Abundances:
             * ----------------
             *     C 2.0
             *     N 2.0
             *     H 4.0
             *     O 0.0
             *
             * For example, Make the following choice:
             *
             *   CH4   N2  O choose ->  OH
             * or
             *   CH4   N2  O choose ->  H2
             *
             *  OH and H2 both fill out the basis. They will pass the algorithm. However,
             *  choosing OH as the next species will create a situation where H2 can not
             *  grow in concentration. This happened in practice, btw. The reason is that
             *  the formation reaction for H2 will cause one of the component species
             *  to go negative.
             *
             *  The basic idea here is to pick a simple species whose mole number
             *  can grow according to the element compositions. Candidates are still
             *  filtered according to their linear independence.
             *
             *   Note, if there is electronic charge and the electron species,
             *   you should probably pick the electron as a component, if it
             *   linearly independent. The algorithm below will do this automagically.
             *
             */
            if ((aw[k] != test) && aw[k] < VCS_DELETE_MINORSPECIES_CUTOFF) {
                *usedZeroedSpecies = true;

                double maxConcPossKspec = 0.0;
                double maxConcPoss = 0.0;
                size_t kfound = npos;
                int minNonZeroes = 100000;
                int nonZeroesKspec = 0;
                for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) {
                    if (aw[kspec] >= 0.0) {
                        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                            maxConcPossKspec = 1.0E10;
                            nonZeroesKspec = 0;
                            for (size_t j = 0; j < m_numElemConstraints; ++j) {
                                if (m_elementActive[j]) {
                                    if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) {
                                        double nu = m_formulaMatrix[j][kspec];
                                        if (nu != 0.0) {
                                            nonZeroesKspec++;
                                            maxConcPossKspec = std::min(m_elemAbundancesGoal[j] / nu, maxConcPossKspec);
                                        }
                                    }
                                }
                            }
                            if ((maxConcPossKspec >= maxConcPoss) || (maxConcPossKspec > 1.0E-5)) {
                                if (nonZeroesKspec <= minNonZeroes) {
                                    if (kfound == npos || nonZeroesKspec < minNonZeroes) {
                                        kfound = kspec;
                                    } else {
                                        // ok we are sitting pretty equal here decide on the raw ss Gibbs energy
                                        if (m_SSfeSpecies[kspec] <= m_SSfeSpecies[kfound]) {
                                            kfound = kspec;
                                        }
                                    }
                                }
                                if (nonZeroesKspec < minNonZeroes) {
                                    minNonZeroes = nonZeroesKspec;
                                }
                                if (maxConcPossKspec > maxConcPoss) {
                                    maxConcPoss = maxConcPossKspec;
                                }
                            }
                        }
                    }
                }
                if (kfound == npos) {
                    double gmin = 0.0;
                    kfound = k;
                    for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) {
                        if (aw[kspec] >= 0.0) {
                            irxn = kspec - ncTrial;
                            if (m_deltaGRxn_new[irxn] < gmin) {
                                gmin = m_deltaGRxn_new[irxn];
                                kfound = kspec;
                            }
                        }
                    }
                }
                k = kfound;
            }


            if (aw[k] == test) {
                m_numComponents = jr;
                ncTrial = m_numComponents;
                size_t numPreDeleted = m_numRxnTot - m_numRxnRdc;
                if (numPreDeleted != (m_numSpeciesTot - m_numSpeciesRdc)) {
                    plogf("vcs_basopt:: we shouldn't be here\n");
                    exit(EXIT_FAILURE);
                }
                m_numRxnTot = m_numSpeciesTot - ncTrial;
                m_numRxnRdc = m_numRxnTot - numPreDeleted;
                m_numSpeciesRdc = m_numSpeciesTot - numPreDeleted;
                for (i = 0; i < m_numSpeciesTot; ++i) {
                    m_indexRxnToSpecies[i] = ncTrial + i;
                }
#ifdef DEBUG_MODE
                if (m_debug_print_lvl >= 2) {
                    plogf("   ---   Total number of components found = %3d (ne = %d)\n ",
                          ncTrial, m_numElemConstraints);
                }
#endif
                goto L_END_LOOP;
            }
            /*
             *  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 < m_numElemConstraints; ++j) {
                sm[j + jr*m_numElemConstraints] = m_formulaMatrix[j][k];
            }
            if (jl > 0) {
                /*
                 *         Compute the coefficients of JA column of the
                 *         the upper triangular R matrix, SS(J) = R_J_JR
                 *         (this is slightly different than Dalquist)
                 *         R_JA_JA = 1
                 */
                for (j = 0; j < jl; ++j) {
                    ss[j] = 0.0;
                    for (i = 0; i < m_numElemConstraints; ++i) {
                        ss[j] += sm[i + jr*m_numElemConstraints] * sm[i + j*m_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 < m_numElemConstraints; ++l) {
                        sm[l + jr*m_numElemConstraints] -= ss[j] * sm[l + j*m_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 < m_numElemConstraints; ++ml) {
                sa[jr] += SQUARE(sm[ml + jr*m_numElemConstraints]);
            }
            /* **************************************************** */
            /* **** IF NORM OF NEW ROW  .LT. 1E-3 REJECT ********** */
            /* **************************************************** */
            lindep = (sa[jr] < 1.0e-6);
        } while (lindep);
        /* ****************************************** */
        /* **** REARRANGE THE DATA ****************** */
        /* ****************************************** */
        if (jr != k) {
#ifdef DEBUG_MODE
            if (m_debug_print_lvl >= 2) {
                plogf("   ---   %-12.12s", (m_speciesName[k]).c_str());
                plogf("(%9.2g) replaces %-12.12s", m_molNumSpecies_old[k],
                      m_speciesName[jr].c_str());
                plogf("(%9.2g) as component %3d\n", m_molNumSpecies_old[jr], jr);
            }
#endif
            vcs_switch_pos(false, jr, k);
            std::swap(aw[jr], aw[k]);
        }
#ifdef DEBUG_MODE
        else {
            if (m_debug_print_lvl >= 2) {
                plogf("   ---   %-12.12s", m_speciesName[k].c_str());
                plogf("(%9.2g) remains            ", m_molNumSpecies_old[k]);
                plogf("              as component %3d\n", jr);
            }
        }
#endif
        /* - entry point from up above */
L_END_LOOP:
        ;
        /*
         *      If we haven't found enough components, go back
         *      and find some more. (nc -1 is used below, because
         *      jr is counted from 0, via the C convention.
         */
    } while (jr < (ncTrial-1));

    if (doJustComponents) {
        goto L_CLEANUP;
    }
    /* ****************************************************** */
    /* **** EVALUATE THE STOICHIOMETRY ********************** */
    /* ****************************************************** */
    /*
     *  Formulate the matrix problem for the stoichiometric
     *  coefficients. CX + B = 0
     *      C will be an nc x nc matrix made up of the formula
     * vectors for the components.
     *      n rhs's will be solved for. Thus, B is an nc x n
     * matrix.
     *
     * BIG PROBLEM 1/21/99:
     *
     *    This algorithm makes the assumption that the
     * first nc rows of the formula matrix aren't rank deficient.
     * However, this might not be the case. For example, assume
     * that the first element in m_formulaMatrix[] is argon. Assume that
     * no species in the matrix problem actually includes argon.
     * Then, the first row in sm[], below will be indentically
     * zero. bleh.
     *    What needs to be done is to perform a rearrangement
     * of the ELEMENTS -> i.e. rearrange, m_formulaMatrix, sp,
     * and m_elemAbundancesGoal, such
     * that the first nc elements form in combination with the
     * nc components create an invertible sm[]. not a small
     * project, but very doable.
     *    An alternative would be to turn the matrix problem
     * below into an ne x nc problem, and do QR elimination instead
     * of Gauss-Jordon elimination.
     *    Note the rearrangement of elements need only be done once
     * in the problem. It's actually very similar to the top of
     * this program with ne being the species and nc being the
     * elements!!
     */
    for (j = 0; j < ncTrial; ++j) {
        for (i = 0; i < ncTrial; ++i) {
            sm[i + j*m_numElemConstraints] = m_formulaMatrix[i][j];
        }
    }
    for (i = 0; i < m_numRxnTot; ++i) {
        k = m_indexRxnToSpecies[i];
        for (j = 0; j < ncTrial; ++j) {
            m_stoichCoeffRxnMatrix[i][j] = m_formulaMatrix[j][k];
        }
    }
    /*
     *     Use Gauss-Jordon block elimination to calculate
     *     the reaction matrix, m_stoichCoeffRxnMatrix[][].
     */

    j = vcsUtil_gaussj(sm, m_numElemConstraints, ncTrial, m_stoichCoeffRxnMatrix[0], m_numRxnTot);
    // j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, m_stoichCoeffRxnMatrix[0], m_numRxnTot);


    if (j == 1) {
        plogf("vcs_solve_TP ERROR: mlequ returned an error condition\n");
        return  VCS_FAILED_CONVERGENCE;
    }

    /*
     * NOW, if we have interfacial voltage unknowns, what we did
     * was just wrong -> hopefully it didn't blow up. Redo the problem.
     * Search for inactive E
     */
    juse  = npos;
    jlose = npos;
    for (j = 0; j < m_numElemConstraints; j++) {
        if (!(m_elementActive[j])) {
            if (!strcmp((m_elementName[j]).c_str(), "E")) {
                juse = j;
            }
        }
    }
    for (j = 0; j < m_numElemConstraints; j++) {
        if (m_elementActive[j]) {
            if (!strncmp((m_elementName[j]).c_str(), "cn_", 3)) {
                jlose = j;
            }
        }
    }
    for (k = 0; k < m_numSpeciesTot; k++) {
        if (m_speciesUnknownType[k] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {

            for (j = 0; j < ncTrial; ++j) {
                for (i = 0; i < ncTrial; ++i) {
                    if (i == jlose) {
                        sm[i + j*m_numElemConstraints] = m_formulaMatrix[juse][j];
                    } else {
                        sm[i + j*m_numElemConstraints] = m_formulaMatrix[i][j];
                    }
                }
            }
            for (i = 0; i < m_numRxnTot; ++i) {
                k = m_indexRxnToSpecies[i];
                for (j = 0; j < ncTrial; ++j) {
                    if (j == jlose) {
                        aw[j] = m_formulaMatrix[juse][k];
                    } else {
                        aw[j] = m_formulaMatrix[j][k];
                    }
                }
            }

            j = vcsUtil_gaussj(sm, m_numElemConstraints, ncTrial, aw, 1);
            // j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, aw, 1);
            if (j == 1) {
                plogf("vcs_solve_TP ERROR: mlequ returned an error condition\n");
                return  VCS_FAILED_CONVERGENCE;
            }
            i = k - ncTrial;
            for (j = 0; j < ncTrial; j++) {
                m_stoichCoeffRxnMatrix[i][j] = aw[j];
            }
        }
    }


    /*
     * Calculate the szTmp array for each formation reaction
     */
    for (i = 0; i < m_numRxnTot; i++) {
        double szTmp = 0.0;
        for (j = 0; j < ncTrial; j++) {
            szTmp += fabs(m_stoichCoeffRxnMatrix[i][j]);
        }
        m_scSize[i] = szTmp;
    }


#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   ---                Components:");
        for (j = 0; j < ncTrial; j++) {
            plogf("        %3d", j);
        }
        plogf("\n   ---          Components Moles:");
        for (j = 0; j < ncTrial; j++) {
            plogf(" % -10.3E", m_molNumSpecies_old[j]);
        }
        plogf("\n   ---   NonComponent|   Moles  |");
        for (j = 0; j < ncTrial; j++) {
            plogf(" %10.10s", m_speciesName[j].c_str());
        }
        //plogf("|    m_scSize");
        plogf("\n");
        for (i = 0; i < m_numRxnTot; i++) {
            plogf("   --- %3d ", m_indexRxnToSpecies[i]);
            plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[i]].c_str());
            plogf("|% -10.3E|", m_molNumSpecies_old[m_indexRxnToSpecies[i]]);
            for (j = 0; j < ncTrial; j++) {
                plogf("    %+7.3f", m_stoichCoeffRxnMatrix[i][j]);
            }
            //plogf(" |  %6.2f", m_scSize[i]);
            plogf("\n");
        }


        /*
         *  Manual check on the satisfaction of the reaction matrix's ability
         *  to conserve elements
         */
        double sum;
        double sumMax = -1.0;
        int iMax = -1;
        int jMax = -1;
        int n;
        for (i = 0; i < m_numRxnTot; ++i) {
            k = m_indexRxnToSpecies[i];
            for (j = 0; j < ncTrial; ++j) {
                if (j == jlose) {
                    sum = m_formulaMatrix[juse][k];
                    for (n = 0; n < ncTrial; n++) {
                        double numElements = m_formulaMatrix[juse][n];
                        double coeff =  m_stoichCoeffRxnMatrix[i][n];
                        sum += coeff * numElements;
                    }
                } else {
                    sum = m_formulaMatrix[j][k];
                    for (n = 0; n < ncTrial; n++) {
                        double numElements = m_formulaMatrix[j][n];
                        double coeff =  m_stoichCoeffRxnMatrix[i][n];
                        sum += coeff * numElements;
                    }
                }
                if (fabs(sum) > sumMax) {
                    sumMax = fabs(sum);
                    iMax = i;
                    jMax = j;
                    if (j == jlose) {
                        jMax = juse;
                    }
                }
                if (fabs(sum) > 1.0E-6) {
                    printf("we have a prob\n");
                    exit(-1);
                }
            }
        }
        plogf("   ---               largest error in Stoich coeff = %g at rxn = %d ", sumMax, iMax);
        plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[iMax]].c_str());
        plogf(" element = %d ", jMax);
        plogf("%-5.5s", m_elementName[jMax].c_str());
        plogf("\n");
        plogf("   ");
        for (i=0; i<77; i++) {
            plogf("-");
        }
        plogf("\n");
    }
#endif
    /* **************************************************** */
    /* **** EVALUATE DELTA N VALUES *********************** */
    /* **************************************************** */
    /*
     *       Evaluate the change in gas and liquid total moles
     *       due to reaction vectors, DNG and DNL.
     */

    /*
     *  Zero out the change of Phase Moles array
     */
    vcs_dzero(m_deltaMolNumPhase[0], (NSPECIES0)*(NPHASE0));
    vcs_izero(m_phaseParticipation[0], (NSPECIES0)*(NPHASE0));
    /*
     *  Loop over each reaction, creating the change in Phase Moles
     *  array, m_deltaMolNumPhase[irxn][iphase],
     *  and the phase participation array, PhaseParticipation[irxn][iphase]
     */
    for (irxn = 0; irxn < m_numRxnTot; ++irxn) {
        scrxn_ptr = m_stoichCoeffRxnMatrix[irxn];
        dptr = m_deltaMolNumPhase[irxn];
        kspec = m_indexRxnToSpecies[irxn];
        size_t iph = m_phaseID[kspec];
        int* pp_ptr = m_phaseParticipation[irxn];
        dptr[iph] = 1.0;
        pp_ptr[iph]++;
        for (j = 0; j < ncTrial; ++j) {
            iph = m_phaseID[j];
            if (fabs(scrxn_ptr[j]) <= 1.0e-6) {
                scrxn_ptr[j] = 0.0;
            } else {
                dptr[iph] += scrxn_ptr[j];
                pp_ptr[iph]++;
            }
        }
    }

L_CLEANUP:
    ;
    double tsecond = tickTock.secondsWC();
    m_VCount->Time_basopt += tsecond;
    (m_VCount->Basis_Opts)++;
    return VCS_SUCCESS;
}
/***************************************************************************************/

//  Choose a species to test for the next component
/*
 *  We make the choice based on testing (molNum[i] * spSize[i]) for its maximum value.
 *  Preference for single species phases is also made.
 *
 *  The factors of 1.01 and 1.001 are placed in this routine for a purpose.
 *  The purpose is to ensure that roundoff errors don't influence major decisions.
 *  This means that the optimized and non-optimized versions of the code remain
 *  close to each other.
 *
 *  ( we try to avoid the logic:   a = b
 *                                 if (a > b) { do this }
 *                                 else       { do something else }
 *    because roundoff error makes a difference in the inequality evaluation)
 *
 *  Mole numbers are frequently equal to each other in equilibrium problems
 *  due to constraints. Swaps are only done if there are a 1% difference in the
 *  mole numbers. Of course this logic isn't fullproof.
 *
 * @param molNum  Mole number vector
 * @param j       index into molNum[] that indicates where the search will start from
 *                Previous successful components are swapped into the fronto of
 *                molNum[].
 * @param n       Length of molNum[]
 */
size_t VCS_SOLVE::vcs_basisOptMax(const double* const molNum, const size_t j,
                                  const size_t n)
{
    size_t largest = j;
    double big = molNum[j] * m_spSize[j] * 1.01;
    AssertThrowVCS(m_spSize[j] > 0.0, "spsize is nonpos");
    for (size_t i = j + 1; i < n; ++i) {
        AssertThrowVCS(m_spSize[i] > 0.0, "spsize is nonpos");
        bool doSwap = false;
        if (m_SSPhase[j]) {
            doSwap = (molNum[i] * m_spSize[i]) > (big);
            if (!m_SSPhase[i]) {
                if (doSwap) {
                    doSwap = (molNum[i]) > (molNum[largest] * 1.001);
                }
            }
        } else {
            if (m_SSPhase[i]) {
                doSwap = (molNum[i] * m_spSize[i]) > (big);
                if (!doSwap) {
                    doSwap = (molNum[i]) > (molNum[largest] * 1.001);
                }
            } else {
                doSwap = (molNum[i] * m_spSize[i]) > (big);
            }
        }
        if (doSwap) {
            largest = i;
            big = molNum[i] * m_spSize[i] * 1.01;
        }
    }
    return largest;
}
/**********************************************************************************/

// Evaluate the species category for the indicated species
/*
 *  All evaluations are done using the "old" version of the solution.
 *
 *  @param kspec   Species to be evaluated
 *
 *  @return Returns the calculated species type
 */
int VCS_SOLVE::vcs_species_type(const size_t kspec) const
{

    // ---------- Treat special cases first ---------------------


    if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
        return  VCS_SPECIES_INTERFACIALVOLTAGE;
    }

    size_t iph = m_phaseID[kspec];
    int irxn = int(kspec) - int(m_numComponents);
    vcs_VolPhase* VPhase = m_VolPhaseList[iph];
    int phaseExist = VPhase->exists();

    // ---------- Treat zeroed out species first ----------------

    if (m_molNumSpecies_old[kspec] <= 0.0) {

        if (m_tPhaseMoles_old[iph] <= 0.0) {
            if (!m_SSPhase[kspec]) {
                return VCS_SPECIES_ZEROEDMS;
            }
        }

        /*
         *    see if the species has an element
         *     which is so low that species will always be zero
         *
         */
        for (size_t j = 0; j < m_numElemConstraints; ++j) {
            int elType = m_elType[j];
            if (elType == VCS_ELEM_TYPE_ABSPOS) {
                double atomComp = m_formulaMatrix[j][kspec];
                if (atomComp > 0.0) {
                    double maxPermissible = m_elemAbundancesGoal[j] / atomComp;
                    if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) {
#ifdef DEBUG_MODE
                        if (m_debug_print_lvl >= 2) {
                            plogf("   ---   %s can not be nonzero because"
                                  " needed element %s is zero\n",
                                  m_speciesName[kspec].c_str(), (m_elementName[j]).c_str());
                        }
#endif
                        if (m_SSPhase[kspec]) {
                            return VCS_SPECIES_ZEROEDSS;
                        } else {
                            return VCS_SPECIES_STOICHZERO;
                        }
                    }
                }
            }
        }

        /*
         *     The Gibbs free energy for this species is such that
         *     it will pop back into existence.
         */
        /*
         *     -> An exception to this is if a needed regular element
         *        is also zeroed out. Then, don't pop the phase or the species back into
         *        existence.
         */
        if (irxn >= 0) {
            for (size_t j = 0; j < m_numComponents; ++j) {
                double stoicC = m_stoichCoeffRxnMatrix[irxn][j];
                if (stoicC != 0.0) {
                    double negChangeComp = - stoicC;
                    if (negChangeComp > 0.0) {
                        if (m_molNumSpecies_old[j] < 1.0E-60) {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   ---   %s is prevented from popping into existence because"
                                      " a needed component to be consumed, %s, has a zero mole number\n",
                                      m_speciesName[kspec].c_str(),  m_speciesName[j].c_str());
                            }
#endif
                            if (m_SSPhase[kspec]) {
                                return VCS_SPECIES_ZEROEDSS;
                            } else {
                                return VCS_SPECIES_STOICHZERO;
                            }
                        }
                    } else if (negChangeComp < 0.0) {
                        size_t jph = m_phaseID[j];
                        vcs_VolPhase* jVPhase = m_VolPhaseList[jph];
                        if (jVPhase->exists() <= 0) {
#ifdef DEBUG_MODE
                            if (m_debug_print_lvl >= 2) {
                                plogf("   ---   %s is prevented from popping into existence because"
                                      " a needed component %s is in a zeroed-phase that would be "
                                      "popped into existence at the same time\n",
                                      m_speciesName[kspec].c_str(),  m_speciesName[j].c_str());
                            }
#endif
                            if (m_SSPhase[kspec]) {
                                return VCS_SPECIES_ZEROEDSS;
                            } else {
                                return VCS_SPECIES_STOICHZERO;
                            }
                        }
                    }
                }
            }
        }

        if (irxn >= 0) {
            if (m_deltaGRxn_old[irxn] >= 0.0) {
                /*
                 *  We are here when the species is or should remain zeroed out
                 */
                if (m_SSPhase[kspec]) {
                    return VCS_SPECIES_ZEROEDSS;
                } else {
                    if (phaseExist >= VCS_PHASE_EXIST_YES) {
                        return VCS_SPECIES_ACTIVEBUTZERO;
                    } else if (phaseExist == VCS_PHASE_EXIST_ZEROEDPHASE) {
                        return VCS_SPECIES_ZEROEDPHASE;
                    } else {
                        return VCS_SPECIES_ZEROEDMS;
                    }
                }
            }
        }
        /*
         * If the current phase already exists,
         */
        if (m_tPhaseMoles_old[iph] > 0.0) {
            if (m_SSPhase[kspec]) {
                return VCS_SPECIES_MAJOR;
            } else {
                return VCS_SPECIES_ACTIVEBUTZERO;
            }
        }

        /*
         *     The Gibbs free energy for this species is such that
         *     it will pop back into existence.
         *
         *     -> Set it to a major species in anticipation.
         *      -> note, if we had an estimate for the emerging mole
         *         fraction of the species in the phase, we could do
         *         better here.
         */
        if (m_tPhaseMoles_old[iph] <= 0.0) {
            if (m_SSPhase[kspec]) {
                return VCS_SPECIES_MAJOR;
            } else {
                return VCS_SPECIES_ZEROEDMS;
            }
        }
    }

    // ---------- Treat species with non-zero mole numbers next  ------------

    /*
     *   Always treat species in single species phases as majors if the
     *   phase exists.
     */
    if (m_SSPhase[kspec]) {
        return VCS_SPECIES_MAJOR;
    }

    /*
     *   Check to see whether the current species is a major component
     *   of its phase. If it is, it is a major component. This is consistent
     *   with the above rule about single species phases. A major component
     *   (i.e., a species with a high mole fraction)
     *   in any phase is always treated as a major species
     */
    if (m_molNumSpecies_old[kspec] > (m_tPhaseMoles_old[iph] * 0.001)) {
        return VCS_SPECIES_MAJOR;
    }

    /*
     *   Main check in the loop:
     *      Check to see if there is a component with a mole number that is
     *      within a factor of 100 of the current species.
     *      If there is and that component is not part of a single species
     *      phase and shares a non-zero stoichiometric coefficient, then
     *      the current species is a major species.
     */
    if (irxn < 0) {
        return VCS_SPECIES_MAJOR;
    } else {
        double szAdj = m_scSize[irxn] * std::sqrt((double)m_numRxnTot);
        for (size_t k = 0; k < m_numComponents; ++k) {
            if (!(m_SSPhase[k])) {
                if (m_stoichCoeffRxnMatrix[irxn][k] != 0.0) {
                    if (m_molNumSpecies_old[kspec] * szAdj >= m_molNumSpecies_old[k] * 0.01) {
                        return VCS_SPECIES_MAJOR;
                    }
                }
            }
        }
    }
    return VCS_SPECIES_MINOR;
}
/*****************************************************************************/

//! We calculate the dimensionless chemical potentials of all species
//! in a single phase.
/*!
 *
 * We calculate the dimensionless chemical potentials of all species
 * in a single phase.
 *
 * Note, for multispecies phases which are currently zeroed out,
 * the chemical potential is filled out with the standard chemical
 * potential.
 *
 * For species in multispecies phases whose concentration is zero,
 * we need to set the mole fraction to a very low value.
 * Its chemical potential
 * is then calculated using the VCS_DELETE_MINORSPECIES_CUTOFF concentration
 * to keep numbers positive.
 *
 * Formula:
 * ---------------
 *
 *     Ideal Mixtures:
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I) + ln(z(I)) - ln(m_tPhaseMoles[iph])
 *                         + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *
 *              ( This is equivalent to the adding the log of the
 *                mole fraction onto the standard chemical
 *                potential. )
 *
 *     Non-Ideal Mixtures:
 *        ActivityConvention = 0:
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I)
 *                         + ln(ActCoeff[I] * z(I)) - ln(m_tPhaseMoles[iph])
 *                         + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *              ( This is equivalent to the adding the log of the
 *                mole fraction multiplied by the activity coefficient
 *                onto the standard chemical potential. )
 *
 *        ActivityConvention = 1: -> molality activity formulation
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I)
 *                           + ln(ActCoeff[I] * z(I)) - ln(m_tPhaseMoles[iph])
 *                           - ln(Mnaught * m_units)
 *                           + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *                  note:   m_SSfeSpecies(I) is the molality based standard state.
 *                          However, ActCoeff[I] is the molar based activity coefficient
 *                          We have used the formulas;
 *
 *                     ActCoeff_M[I] =  ActCoeff[I] / Xmol[N]
 *                              where Xmol[N] is the mole fraction of the solvent
 *                               ActCoeff_M[I] is the molality based act coeff.
 *
 *                  note:  This is equivalent to the "normal" molality formulation:
 *
 *                       m_feSpecies(I) = m_SSfeSpecies(I)
 *                                      + ln(ActCoeff_M[I] * m(I))
 *                                      + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase]
 *                                       where m[I] is the molality of the ith solute
 *
 *                                m[I] = Xmol[I] / ( Xmol[N] * Mnaught * m_units)
 *
 *
 *     note:   z(I)/tPhMoles_ptr[iph] = Xmol[i] is the mole fraction
 *                                     of i in the phase.
 *
 *  NOTE:
 *  As per the discussion in vcs_dfe(), for small species where the mole
 *  fraction is small:
 *
 *           z(i) < VCS_DELETE_MINORSPECIES_CUTOFF
 *
 *   The chemical potential is calculated as:
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I)
 *                         + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF))
 *
 * Input
 * --------
 *   @param iph        Phase to be calculated
 *   @param molNum     molNum[i] is the number of moles of species i
 *                            (VCS species order)
 *   @param do_deleted  Do species that are deleted (default = false)
 *
 * Output
 * -----------
 *   @param ac        Activity coefficients for species in phase
 *                     (VCS species order)
 *   @param mu_i      Dimensionless chemical potentials for phase species
 *                      (VCS species order)
 *
 */
void VCS_SOLVE::vcs_chemPotPhase(const int stateCalc,
                                 const size_t iph, const double* const molNum,
                                 double* const ac, double* const mu_i,
                                 const bool do_deleted)
{

    vcs_VolPhase* Vphase = m_VolPhaseList[iph];
    size_t nkk = Vphase->nSpecies();
    size_t k, kspec;

#ifdef DEBUG_MODE
    //if (m_debug_print_lvl >= 2) {
    // plogf("   --- Subroutine vcs_chemPotPhase called for phase %d\n",
    //     iph);
    //}
#endif
    double tMoles = TPhInertMoles[iph];
    for (k = 0; k < nkk; k++) {
        kspec = Vphase->spGlobalIndexVCS(k);
        tMoles += molNum[kspec];
    }
    double tlogMoles = 0.0;
    if (tMoles > 0.0) {
        tlogMoles = log(tMoles);
    }

    Vphase->setMolesFromVCS(stateCalc, molNum);
    Vphase->sendToVCS_ActCoeff(stateCalc, ac);

    double phi = Vphase->electricPotential();
    double Faraday_phi = m_Faraday_dim * phi;

    for (k = 0; k < nkk; k++) {
        kspec = Vphase->spGlobalIndexVCS(k);
        if (kspec >= m_numComponents) {
            if (!do_deleted &&
                    (m_speciesStatus[kspec] == VCS_SPECIES_DELETED)) {
                continue;
            }
        }
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
#ifdef DEBUG_MODE
            if (molNum[kspec] != phi) {
                plogf("We have an inconsistency!\n");
                exit(EXIT_FAILURE);
            }
            if (m_chargeSpecies[kspec] != -1.0) {
                plogf("We have an unexpected situation!\n");
                exit(EXIT_FAILURE);
            }
#endif
            mu_i[kspec] = m_SSfeSpecies[kspec] + m_chargeSpecies[kspec] * Faraday_phi;
        } else {
            if (m_SSPhase[kspec]) {
                mu_i[kspec] = m_SSfeSpecies[kspec] + m_chargeSpecies[kspec] * Faraday_phi;
            } else if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                mu_i[kspec] = m_SSfeSpecies[kspec] + log(ac[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF)
                              - tlogMoles - m_lnMnaughtSpecies[kspec] + m_chargeSpecies[kspec] * Faraday_phi;
            } else {
                mu_i[kspec] = m_SSfeSpecies[kspec] + log(ac[kspec] * molNum[kspec])
                              - tlogMoles - m_lnMnaughtSpecies[kspec] + m_chargeSpecies[kspec] * Faraday_phi;
            }
        }
    }
}
/*********************************************************************************/

// Calculate the dimensionless chemical potentials of all species or
// of certain groups of species, at a fixed temperature and pressure.
/*
 * We calculate the dimensionless chemical potentials of all species
 * or certain groups of species here, at a fixed temperature and pressure,
 * for the input mole vector z[] in the parameter list.
 * Nondimensionalization is achieved by division by RT.
 *
 * Note, for multispecies phases which are currently zeroed out,
 * the chemical potential is filled out with the standard chemical
 * potential.
 *
 * For species in multispecies phases whose concentration is zero,
 * we need to set the mole fraction to a very low value.
 * Its chemical potential
 * is then calculated using the VCS_DELETE_MINORSPECIES_CUTOFF concentration
 * to keep numbers positive.
 *
 *
 * Formula:
 * ---------------
 *
 *     Ideal Mixtures:
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I) + ln(z(I)) - ln(m_tPhaseMoles[iph])
 *                            + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *              ( This is equivalent to the adding the log of the
 *                mole fraction onto the standard chemical
 *                potential. )
 *
 *     Non-Ideal Mixtures:  -> molar activity formulation
 *        ActivityConvention = 0:
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I)
 *                           + ln(ActCoeff[I] * z(I)) - ln(m_tPhaseMoles[iph])
 *                            + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *              ( This is equivalent to the adding the log of the
 *                mole fraction multiplied by the activity coefficient
 *                onto the standard chemical potential. )
 *
 *                 note:   z(I)/tPhMoles_ptr[iph] = Xmol[i] is the mole fraction
 *                                                  of i in the phase.
 *
 *        ActivityConvention = 1: -> molality activity formulation
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I)
 *                           + ln(ActCoeff[I] * z(I)) - ln(m_tPhaseMoles[iph])
 *                           - ln(Mnaught * m_units)
 *                            + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase];
 *
 *                  note:   m_SSfeSpecies(I) is the molality based standard state.
 *                          However, ActCoeff[I] is the molar based activity coefficient
 *                          We have used the formulas;
 *
 *                                ActCoeff_M[I] =  ActCoeff[I] / Xmol[N]
 *                                      where Xmol[N] is the mole fraction of the solvent
 *                                            ActCoeff_M[I] is the molality based act coeff.
 *
 *                  note:   This is equivalent to the "normal" molality formulation below:
 *
 *                              m_feSpecies(I) = m_SSfeSpecies(I)
 *                                             + ln(ActCoeff_M[I] * m(I))
 *                                             + m_chargeSpecies[I] * Faraday_dim * m_phasePhi[iphase]
 *                                       where m[I] is the molality of the ith solute
 *
 *
 *                                m[I] = Xmol[I] / ( Xmol[N] * Mnaught * m_units)
 *
 *
 *  Handling of Small Species:
 * ------------------------------
 *  As per the discussion above, for small species where the mole
 *  fraction
 *
 *           z(i) < VCS_DELETE_MINORSPECIES_CUTOFF
 *
 *   The chemical potential is calculated as:
 *
 *         m_feSpecies(I) = m_SSfeSpecies(I) + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF))
 *
 *   Handling of "Species" Representing Interfacial Voltages
 *  ---------------------------------------------------------
 *
 *      These species have species types of  VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
 *      The chemical potentials for these "species" refer to electrons in
 *      metal electrodes. They have the following formula
 *
 *          m_feSpecies(I) = m_SSfeSpecies(I) - F z[I] / RT
 *
 *      F is Faraday's constant.
 *      R = gas constant
 *      T = temperature
 *      V = potential of the interface = phi_electrode - phi_solution
 *
 *      For these species, the solution vector unknown, z[I], is V, the phase voltage,
 *      in volts.
 *
 * Input
 * --------
 * @param ll     Determine which group of species gets updated
 *     ll =  0: Calculate for all species
 *        <  0: calculate for components and for major non-components
 *           1: calculate for components and for minor non-components
 *
 * @param lbot    Restricts the calculation of the chemical potential
 *                to the species between LBOT <= i < LTOP. Usually
 *                 LBOT and LTOP will be equal to 0 and MR, respectively.
 * @param ltop    Top value of the loops
 *
 * @param molNum   molNum[i]   : Number of moles of species i
 *                   -> This can either be the old solution vector
 *                      or the new solution vector depending upon the
 *                      stateCalc value
 *
 * @param stateCalc   Determines whether z is old or new or tmp:
 *            VCS_STATECALC_NEW: Use the tentative values for the total number of
 *                               moles in the phases, i.e., use TG1 instead of TG etc.
 *            VCS_STATECALC_OLD: Use the base values of the total number of
 *                               moles in each system.
 *
 *  Also needed:
 *    m_SSfeSpecies[kspec] : standard state chemical potentials. These are the
 *                           chemical potentials of the standard states at
 *                           the same T and P as the solution.
 *     tg     : Total Number of moles in the phase.
 */
void VCS_SOLVE::vcs_dfe(const int stateCalc,
                        const int ll, const size_t lbot, const size_t ltop)
{
    size_t l1, l2, iph, kspec, irxn;
    size_t iphase;
    double* tPhMoles_ptr;
    double* actCoeff_ptr;
    double* tlogMoles;
    vcs_VolPhase* Vphase;

    double* feSpecies;
    double* molNum;
    if (stateCalc == VCS_STATECALC_OLD) {
        feSpecies = VCS_DATA_PTR(m_feSpecies_old);
        tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_old);
        actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_old);
        molNum = VCS_DATA_PTR(m_molNumSpecies_old);
    } else { // stateCalc == VCS_STATECALC_NEW
        feSpecies = VCS_DATA_PTR(m_feSpecies_new);
        tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_new);
        actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_new);
        molNum = VCS_DATA_PTR(m_molNumSpecies_new);
    }
#ifdef DEBUG_MODE
    else {
        plogf("vcs_dfe: wrong stateCalc value");
        plogf("   --- Subroutine vcs_dfe called with bad stateCalc value: %d", stateCalc);
        plogendl();
        exit(EXIT_FAILURE);
    }
#endif

#ifdef DEBUG_MODE
    if (m_unitsState == VCS_DIMENSIONAL_G) {
        printf("vcs_dfe: called with wrong units state\n");
        exit(EXIT_FAILURE);
    }
#endif

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        if (ll == 0) {
            if (lbot != 0) {
                plogf("   --- Subroutine vcs_dfe called for one species: ");
                plogf("%-12.12s", m_speciesName[lbot].c_str());
            } else {
                plogf("   --- Subroutine vcs_dfe called for all species");
            }
        } else if (ll > 0) {
            plogf("   --- Subroutine vcs_dfe called for components and minors");
        } else {
            plogf("   --- Subroutine vcs_dfe called for components and majors");
        }
        if (stateCalc == VCS_STATECALC_NEW) {
            plogf(" using tentative solution");
        }
        plogendl();
    }
#endif

    tlogMoles = VCS_DATA_PTR(m_TmpPhase);
    /*
     * Might as well recalculate the phase mole vector
     * and compare to the stored one. They should be correct.
     */
    double* tPhInertMoles = VCS_DATA_PTR(TPhInertMoles);
    for (iph = 0; iph < m_numPhases; iph++) {
        tlogMoles[iph] = tPhInertMoles[iph];

    }
    for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            iph = m_phaseID[kspec];
            tlogMoles[iph] += molNum[kspec];
        }
    }
#ifdef DEBUG_MODE
    for (iph = 0; iph < m_numPhases; iph++) {
        if (! vcs_doubleEqual(tlogMoles[iph], tPhMoles_ptr[iph])) {
            plogf("phase Moles may be off, iph = %d, %20.14g %20.14g \n",
                  iph, tlogMoles[iph], tPhMoles_ptr[iph]);
            exit(EXIT_FAILURE);
        }
    }
#endif
    vcs_dzero(tlogMoles, m_numPhases);
    for (iph = 0; iph < m_numPhases; iph++) {
        if (tPhMoles_ptr[iph] > 0.0) {
            tlogMoles[iph] = log(tPhMoles_ptr[iph]);
        }
    }


    if (ll != 0) {
        l1 = lbot;
        l2 = m_numComponents;
    } else {
        l1 = lbot;
        l2 = ltop;
    }

    /*
     *  Calculate activity coefficients for all phases that are
     *  not current. Here we also trigger an update check for each
     *  VolPhase to see if its mole numbers are current with vcs
     */
    for (iphase = 0; iphase < m_numPhases; iphase++) {
        Vphase = m_VolPhaseList[iphase];
        Vphase->updateFromVCS_MoleNumbers(stateCalc);
        if (!Vphase->m_singleSpecies) {
            Vphase->sendToVCS_ActCoeff(stateCalc, VCS_DATA_PTR(actCoeff_ptr));
        }
        m_phasePhi[iphase] = Vphase->electricPotential();
    }
    /* ************************************************************** */
    /* **** ALL SPECIES, OR COMPONENTS ****************************** */
    /* ************************************************************** */
    /*
     *     Do all of the species when LL = 0. Then we are done for the routine
     *     When LL ne 0., just do the initial components. We will then
     *     finish up below with loops over either the major noncomponent
     *     species or the minor noncomponent species.
     */
    for (kspec = l1; kspec < l2; ++kspec) {
        iphase = m_phaseID[kspec];
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
#ifdef DEBUG_MODE
            if (molNum[kspec] != m_phasePhi[iphase]) {
                plogf("We have an inconsistency!\n");
                exit(EXIT_FAILURE);
            }
            if (m_chargeSpecies[kspec] != -1.0) {
                plogf("We have an unexpected situation!\n");
                exit(EXIT_FAILURE);
            }
#endif
            feSpecies[kspec] = m_SSfeSpecies[kspec]
                               + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
        } else {
            if (m_SSPhase[kspec]) {
                feSpecies[kspec] = m_SSfeSpecies[kspec]
                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
            } else if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) ||
                       (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE)) {
                feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec]
                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
            } else {
                if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                    iph = m_phaseID[kspec];
                    if (tPhMoles_ptr[iph] > 0.0) {
                        feSpecies[kspec] = m_SSfeSpecies[kspec]
                                           + log(actCoeff_ptr[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF)
                                           - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    } else {
                        feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    }
                } else {
                    feSpecies[kspec] = m_SSfeSpecies[kspec]
                                       + log(actCoeff_ptr[kspec] * molNum[kspec])
                                       - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                       + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                }
            }
        }
    }
    /* ************************************************ */
    /* **** MAJORS ONLY ******************************* */
    /* ************************************************ */
    if (ll < 0) {
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = m_indexRxnToSpecies[irxn];
            if (m_speciesStatus[kspec] != VCS_SPECIES_MINOR) {
                iphase = m_phaseID[kspec];
                if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
#ifdef DEBUG_MODE
                    if (molNum[kspec] != m_phasePhi[iphase]) {
                        plogf("We have an inconsistency!\n");
                        exit(EXIT_FAILURE);
                    }
                    if (m_chargeSpecies[kspec] != -1.0) {
                        plogf("We have an unexpected situation!\n");
                        exit(EXIT_FAILURE);
                    }
#endif
                    feSpecies[kspec] = m_SSfeSpecies[kspec]
                                       + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                } else {
                    if (m_SSPhase[kspec]) {
                        feSpecies[kspec] = m_SSfeSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    } else if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) ||
                               (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE)) {
                        feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    } else {
                        if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                            iph = m_phaseID[kspec];
                            if (tPhMoles_ptr[iph] > 0.0) {
                                feSpecies[kspec] = m_SSfeSpecies[kspec]
                                                   + log(actCoeff_ptr[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF)
                                                   - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                            } else {
                                feSpecies[kspec] = m_SSfeSpecies[kspec]  - m_lnMnaughtSpecies[kspec]
                                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                            }
                        } else {
                            feSpecies[kspec] = m_SSfeSpecies[kspec]
                                               + log(actCoeff_ptr[kspec] * molNum[kspec])
                                               - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                               + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                        }
                    }
                }
            }
        }
        /* ************************************************ */
        /* **** MINORS ONLY ******************************* */
        /* ************************************************ */
    } else if (ll > 0) {
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = m_indexRxnToSpecies[irxn];
            if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) {
                iphase = m_phaseID[kspec];
                if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
#ifdef DEBUG_MODE
                    if (molNum[kspec] != m_phasePhi[iphase]) {
                        plogf("We have an inconsistency!\n");
                        exit(EXIT_FAILURE);
                    }
                    if (m_chargeSpecies[kspec] != -1.0) {
                        plogf("We have an unexpected situation!\n");
                        exit(EXIT_FAILURE);
                    }
#endif
                    feSpecies[kspec] = m_SSfeSpecies[kspec]
                                       + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase]; ;
                } else {
                    if (m_SSPhase[kspec]) {
                        feSpecies[kspec] = m_SSfeSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    } else if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS) ||
                               (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE)) {
                        feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec]
                                           + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                    } else {
                        if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                            iph = m_phaseID[kspec];
                            if (tPhMoles_ptr[iph] > 0.0) {
                                feSpecies[kspec] = m_SSfeSpecies[kspec]
                                                   + log(actCoeff_ptr[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF)
                                                   - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                            } else {
                                feSpecies[kspec] = m_SSfeSpecies[kspec] - m_lnMnaughtSpecies[kspec]
                                                   + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                            }
                        } else {
                            feSpecies[kspec] = m_SSfeSpecies[kspec]
                                               + log(actCoeff_ptr[kspec] * molNum[kspec])
                                               - tlogMoles[m_phaseID[kspec]] - m_lnMnaughtSpecies[kspec]
                                               + m_chargeSpecies[kspec] * m_Faraday_dim * m_phasePhi[iphase];
                        }
                    }
                }
            }
        }
    }


}
//====================================================================================================================
// Print out a table of chemical potentials
/*
 *    @param vcsState Determines where to get the mole numbers from.
 *                -  VCS_STATECALC_OLD -> from m_molNumSpecies_old
 *                -  VCS_STATECALC_NEW -> from m_molNumSpecies_new
 */
void  VCS_SOLVE::vcs_printSpeciesChemPot(const int stateCalc) const
{
    double mfValue = 1.0;
    bool zeroedPhase = false;
    size_t kspec;

    const double* molNum = VCS_DATA_PTR(m_molNumSpecies_old);
    const double* actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_old);
    if (stateCalc == VCS_STATECALC_NEW) {
        actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_new);
        molNum = VCS_DATA_PTR(m_molNumSpecies_new);
    }

    double* tMoles = VCS_DATA_PTR(m_TmpPhase);
    const double* tPhInertMoles = VCS_DATA_PTR(TPhInertMoles);
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        tMoles[iph] = tPhInertMoles[iph];
    }
    for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            size_t iph = m_phaseID[kspec];
            tMoles[iph] += molNum[kspec];
        }
    }

    double RT = m_temperature * Cantera::GasConstant;
    printf("   ---  CHEMICAL POT TABLE (J/kmol) Name PhID     MolFR     ChemoSS   "
           "   logMF       Gamma       Elect       extra       ElectrChem\n");
    printf("   ");
    vcs_print_line("-", 132);

    for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
        mfValue = 1.0;
        size_t iphase = m_phaseID[kspec];
        const vcs_VolPhase* Vphase = m_VolPhaseList[iphase];
        if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS)    ||
                (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) ||
                (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDSS)) {
            zeroedPhase = true;
        } else {
            zeroedPhase = false;
        }
        if (tMoles[iphase] > 0.0) {
            if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                mfValue = VCS_DELETE_MINORSPECIES_CUTOFF / tMoles[iphase];
            } else {
                mfValue = molNum[kspec]/tMoles[iphase];
            }
        } else {
            size_t klocal = m_speciesLocalPhaseIndex[kspec];
            mfValue = Vphase->moleFraction(klocal);
        }
        double volts = Vphase->electricPotential();
        double elect = m_chargeSpecies[kspec] * m_Faraday_dim * volts;
        double comb = - m_lnMnaughtSpecies[kspec];
        double total = (m_SSfeSpecies[kspec] + log(mfValue) + elect + log(actCoeff_ptr[kspec]) + comb);

        if (zeroedPhase) {
            printf("   --- ** zp *** ");
        } else {
            printf("   ---           ");
        }
        printf("%-24.24s", m_speciesName[kspec].c_str());
        printf(" %-3s", Cantera::int2str(iphase).c_str());
        printf(" % -12.4e", mfValue);
        printf(" % -12.4e", m_SSfeSpecies[kspec] * RT);
        printf(" % -12.4e", log(mfValue) * RT);
        printf(" % -12.4e", log(actCoeff_ptr[kspec]) * RT);
        printf(" % -12.4e", elect * RT);
        printf(" % -12.4e", comb * RT);
        printf(" % -12.4e\n", total *RT);
    }
    printf("   ");
    vcs_print_line("-", 132);
}
/*****************************************************************************/

#ifdef DEBUG_MODE
//! Print out and check the elemental abundance vector
void VCS_SOLVE::prneav() const
{
    int j;
    bool kerr;
    std::vector<double> eav(m_numElemConstraints, 0.0);

    for (j = 0; j < m_numElemConstraints; ++j) {
        for (int i = 0; i < m_numSpeciesTot; ++i) {
            if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                eav[j] += m_formulaMatrix[j][i] * m_molNumSpecies_old[i];
            }
        }
    }
    kerr = false;
    plogf("--------------------------------------------------");
    plogf("ELEMENT ABUNDANCE VECTOR:\n");
    plogf(" Element   Now      Orignal      Deviation          Type\n");
    for (j = 0; j < m_numElemConstraints; ++j) {
        plogf("  ");
        plogf("%-2.2s", (m_elementName[j]).c_str());
        plogf(" = %15.6E     %15.6E     %15.6E  %3d\n",
              eav[j], m_elemAbundancesGoal[j], eav[j] - m_elemAbundancesGoal[j], m_elType[j]);
        if (m_elemAbundancesGoal[j] != 0.) {
            if (fabs(eav[j] - m_elemAbundancesGoal[j]) > m_elemAbundancesGoal[j] * 5.0e-9) {
                kerr = true;
            }
        } else {
            if (fabs(eav[j]) > 1.0e-10) {
                kerr = true;
            }
        }
    }
    if (kerr) {
        plogf("Element abundance check failure\n");
    }
    plogf("--------------------------------------------------");
    plogendl();
}
#endif
/*****************************************************************************/

// Calculate the norm of a deltaGibbs free energy vector
/*
 *   Positive DG for species which don't exist are ignored.
 *
 * @param dgLocal  Vector of local delta G's.
 */
double VCS_SOLVE::l2normdg(double dgLocal[]) const
{
    double tmp;
    size_t irxn;
    if (m_numRxnRdc <= 0) {
        return 0.0;
    }
    for (irxn = 0, tmp = 0.0; irxn < m_numRxnRdc; ++irxn) {
        size_t kspec = irxn + m_numComponents;
        if (m_speciesStatus[kspec] == VCS_SPECIES_MAJOR || m_speciesStatus[kspec] == VCS_SPECIES_MINOR ||
                dgLocal[irxn] < 0.0) {
            if (m_speciesStatus[kspec] != VCS_SPECIES_ZEROEDMS) {
                tmp += dgLocal[irxn] * dgLocal[irxn];
            }
        }
    }
    return (std::sqrt(tmp / m_numRxnRdc));
}
/*****************************************************************************/

//  Calculates the total number of moles of species in all phases.
/*
 *  Calculates the total number of moles in all phases.
 *  Reconciles Phase existence flags with total moles in each phase.
 */
double VCS_SOLVE::vcs_tmoles()
{
    double sum;
    vcs_VolPhase* Vphase;
    for (size_t i = 0; i < m_numPhases; i++) {
        m_tPhaseMoles_old[i] = TPhInertMoles[i];
    }
    for (size_t i = 0; i < m_numSpeciesTot; i++) {
        if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) {
            m_tPhaseMoles_old[m_phaseID[i]] += m_molNumSpecies_old[i];
        }
    }
    sum = 0.0;
    for (size_t i = 0; i < m_numPhases; i++) {
        sum += m_tPhaseMoles_old[i];
        Vphase = m_VolPhaseList[i];
        // Took out because we aren't updating mole fractions in Vphase
        // Vphase->TMoles = m_tPhaseMoles_old[i];
        if (m_tPhaseMoles_old[i] == 0.0) {
            Vphase->setTotalMoles(0.0);
        } else {
            Vphase->setTotalMoles(m_tPhaseMoles_old[i]);
        }
    }
    m_totalMolNum = sum;
    return m_totalMolNum;
}

#ifdef DEBUG_MODE
void VCS_SOLVE::check_tmoles() const
{
    int i;
    double sum = 0.0;
    for (i = 0; i < m_numPhases; i++) {
        double m_tPhaseMoles_old_a = TPhInertMoles[i];

        for (size_t k = 0; k < m_numSpeciesTot; k++) {
            if (m_speciesUnknownType[k] == VCS_SPECIES_TYPE_MOLNUM) {
                if (m_phaseID[k] == i) {
                    m_tPhaseMoles_old_a += m_molNumSpecies_old[k];
                }
            }
        }
        sum += m_tPhaseMoles_old_a;

        double denom = m_tPhaseMoles_old[i]+ m_tPhaseMoles_old_a + 1.0E-19;
        if (!vcs_doubleEqual(m_tPhaseMoles_old[i]/denom, m_tPhaseMoles_old_a/denom)) {
            plogf("check_tmoles: we have found a problem with phase  %d: %20.15g, %20.15g\n",
                  i, m_tPhaseMoles_old[i], m_tPhaseMoles_old_a);
        }
    }
}
#endif
/*****************************************************************************/

//  This routine uploads the state of the system into all of the
//  vcs_VolPhase objects in the current problem.
/*
 *  @param vcsState Determines where to get the mole numbers from.
 *                -  VCS_STATECALC_OLD -> from m_molNumSpecies_old
 *                -  VCS_STATECALC_NEW -> from m_molNumSpecies_new
 */
void VCS_SOLVE::vcs_updateVP(const int vcsState)
{
    vcs_VolPhase* Vphase;
    for (size_t i = 0; i < m_numPhases; i++) {
        Vphase = m_VolPhaseList[i];
        if (vcsState == VCS_STATECALC_OLD) {
            Vphase->setMolesFromVCSCheck(VCS_STATECALC_OLD,
                                         VCS_DATA_PTR(m_molNumSpecies_old),
                                         VCS_DATA_PTR(m_tPhaseMoles_old));
        } else if (vcsState == VCS_STATECALC_NEW) {
            Vphase->setMolesFromVCSCheck(VCS_STATECALC_NEW,
                                         VCS_DATA_PTR(m_molNumSpecies_new),
                                         VCS_DATA_PTR(m_tPhaseMoles_new));
        }
#ifdef DEBUG_MODE
        else {
            plogf("vcs_updateVP ERROR: wrong stateCalc value: %d", vcsState);
            plogendl();
            exit(EXIT_FAILURE);
        }
#endif
    }
}

//  This routine evaluates the species type for all species
/*
 *        kspec
 *                              1 -> Major species  VCS_SPECIES_MAJOR
 *                              0 -> Minor species  VCS_SPECIES_MINOR
 *                             -1 -> The species lies in a multicomponent phase
 *                                   that exists. Its concentration is currently
 *                                   very low, necessitating a different method
 *                                   of calculation.
 *                                   -  VCS_SPECIES_ZEROEDPHASE
 *                             -2 -> The species lies in a multicomponent phase
 *                                   which currently doesn't exist.
 *                                   Its concentration is currently zero.
 *                                   -  VCS_SPECIES_ZEROEDMS
 *                             -3 -> Species lies in a single-species phase which
 *                                   is currently zereod out.
 *                                   - VCS_SPECIES_ZEREODSS
 *                             -4 -> Species has such a small mole fraction it is
 *                                   deleted even though its phase may possibly exist.
 *                                   The species is believed to have such a small
 *                                   mole fraction that it best to throw the
 *                                   calculation of it out.  It will be added back in
 *                                   at the end of the calculation.
 *                                   - VCS_SPECIES_DELETED
 *                             -5 ->  Species refers to an electron in the metal
 *                                    The unknown is equal to the interfacial voltage
 *                                    drop across the interface on the SHE (standard
 *                                    hydroogen electrode) scale (volts).
 *                                     - VCS_SPECIES_INTERFACIALVOLTAGE
 *                             -6 ->  Species lies in a multicomponent phase that
 *                                    is zeroed atm  and will stay deleted due to a
 *                                    choice from a higher level.
 *                                    These species will formally always have zero
 *                                    mole numbers in the solution vector.
 *                                      - VCS_SPECIES_ZEROEDPHASE
 *                             -7 ->  The species lies in a multicomponent phase which
 *                                    currently does exist.  Its concentration is currently
 *                                    identically zero, though the phase exists. Note, this
 *                                    is a temporary condition that exists at the start
 *                                    of an equilibrium problem.
 *                                    The species is soon "birthed" or "deleted".
 *                                    - VCS_SPECIES_ACTIVEBUTZERO
 *                             -8 ->  The species lies in a multicomponent phase which
 *                                     currently does exist.  Its concentration is currently
 *                                    identically zero, though the phase exists. This is
 *                                    a permanent condition due to stoich constraints
 *                                    - VCS_SPECIES_STOICHZERO
 *
 */
bool VCS_SOLVE::vcs_evaluate_speciesType()
{
    bool allMinorZeroedSpecies;

    m_numRxnMinorZeroed = 0;
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("  --- Species Status decision is reevaluated: All species are minor except for:\n");
    } else if (m_debug_print_lvl >= 5) {
        plogf("  --- Species Status decision is reevaluated");
        plogendl();
    }
#endif
    for (size_t kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
        m_speciesStatus[kspec] = vcs_species_type(kspec);
#ifdef DEBUG_MODE
        if (m_debug_print_lvl >= 5) {
            plogf("  --- %-16s: ", m_speciesName[kspec].c_str());
            if (kspec < m_numComponents) {
                plogf("(COMP) ");
            } else {
                plogf("       ");
            }
            plogf(" %10.3g ", m_molNumSpecies_old[kspec]);
            const char* sString = vcs_speciesType_string(m_speciesStatus[kspec], 100);
            plogf("%s\n", sString);

        } else if (m_debug_print_lvl >= 2) {
            if (m_speciesStatus[kspec] != VCS_SPECIES_MINOR) {
                switch (m_speciesStatus[kspec]) {
                case VCS_SPECIES_COMPONENT:
                    break;
                case VCS_SPECIES_MAJOR:
                    plogf("  ---      Major Species          : %-s\n", m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_ZEROEDPHASE:
                    plogf("  ---      Purposely Zeroed-Phase Species (not in problem): %-s\n",
                          m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_ZEROEDMS:
                    plogf("  ---      Zeroed-MS Phase Species: %-s\n", m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_ZEROEDSS:
                    plogf("  ---      Zeroed-SS Phase Species: %-s\n", m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_DELETED:
                    plogf("  ---      Deleted-Small Species  : %-s\n", m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_ACTIVEBUTZERO:
                    plogf("  ---      Zeroed Species in an active MS phase (tmp): %-s\n",
                          m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_STOICHZERO:
                    plogf("  ---     Zeroed Species in an active MS phase (Stoich Constraint): %-s\n",
                          m_speciesName[kspec].c_str());
                    break;
                case VCS_SPECIES_INTERFACIALVOLTAGE:
                    plogf("  ---      InterfaceVoltage Species: %-s\n", m_speciesName[kspec].c_str());
                    break;
                default:
                    plogf("  --- Unknown type - ERROR %d\n", m_speciesStatus[kspec]);
                    plogendl();
                    exit(EXIT_FAILURE);
                }
            }
        }
#endif
        if (kspec >= m_numComponents) {
            if (m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) {
                ++m_numRxnMinorZeroed;
            }
        }
    }
#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("  ---");
        plogendl();
    }
#endif

    allMinorZeroedSpecies = (m_numRxnMinorZeroed >= m_numRxnRdc);

    return allMinorZeroedSpecies;
}
/*****************************************************************************/

//    Switch rows and columns of a sqare matrix
/*
 *  Switches the row and column of a matrix.
 *  So that after
 *
 *     J[k1][j] = J_old[k2][j]  and J[j][k1] = J_old[j][k2]
 *     J[k2][j] = J_old[k1][j]  and J[j][k2] = J_old[j][k1]
 *
 *  @param Jac         Double pointer to the jacobiam
 *  @param k1          first row/column value to be switched
 *  @param k2          second row/column value to be switched
 */
void VCS_SOLVE::vcs_switch2D(double* const* const Jac,
                             const size_t k1, const size_t k2) const
{
    size_t i;
    if (k1 == k2) {
        return;
    }
    for (i = 0; i < m_numSpeciesTot; i++) {
        std::swap(Jac[k1][i], Jac[k2][i]);
    }
    for (i = 0; i < m_numSpeciesTot; i++) {
        std::swap(Jac[i][k1], Jac[i][k2]);
    }
}
/*****************************************************************************/

static void print_space(size_t num)
{
    size_t j;
    for (j = 0; j < num; j++) {
        plogf(" ");
    }
}
/********************************************************************************/

// This subroutine calculates reaction free energy changes for
// all noncomponent formation reactions.
/*
 *  Formation reactions are
 *  reactions which create each noncomponent species from the component
 *  species. m_stoichCoeffRxnMatrix[irxn][jcomp]  are the stoichiometric
 *  coefficients for these  reactions. A stoichiometric coefficient of
 *  one is assumed for species irxn in this reaction.
 *
 *  INPUT
 *  @param l
 *    L < 0   :  Calculate reactions corresponding to
 *               major noncomponent and zeroed species only
 *    L = 0   :  Do all noncomponent reactions, i, between
 *               0 <= i < irxnl
 *    L > 0   :  Calculate reactions corresponding to
 *               minor noncomponent and zeroed species only
 *
 *    @param doDeleted   Do deleted species
 *    @param stateCalc   Calculate deltaG corresponding to either old or new
 *                       free energies
 *
 *    Note we special case one important issue.
 *    If the component has zero moles, then we do not
 *    allow deltaG < 0.0 for formation reactions which
 *    would lead to the loss of more of that same component.
 *    This dG < 0.0 condition feeds back into the algorithm in several
 *    places, and leads to a infinite loop in at least one case.
 */
void VCS_SOLVE::vcs_deltag(const int l, const bool doDeleted,
                           const int vcsState, const bool alterZeroedPhases)
{
    size_t iph;
    size_t irxn, kspec;
    bool lneed;
    double* dtmp_ptr;
    int icase = 0;
    size_t irxnl = m_numRxnRdc;
    if (doDeleted) {
        irxnl = m_numRxnTot;
    }

    double* deltaGRxn;
    double* feSpecies;
    double* molNumSpecies;
    double* actCoeffSpecies;
    if (vcsState == VCS_STATECALC_NEW) {
        deltaGRxn     = VCS_DATA_PTR(m_deltaGRxn_new);
        feSpecies     = VCS_DATA_PTR(m_feSpecies_new);
        molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_new);
        actCoeffSpecies = VCS_DATA_PTR(m_actCoeffSpecies_new);
    } else if (vcsState == VCS_STATECALC_OLD) {
        deltaGRxn     = VCS_DATA_PTR(m_deltaGRxn_old);
        feSpecies     = VCS_DATA_PTR(m_feSpecies_old);
        molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_old);
        actCoeffSpecies = VCS_DATA_PTR(m_actCoeffSpecies_old);
    } else {
        printf("Error\n");
        exit(EXIT_FAILURE);
    }

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Subroutine vcs_deltag called for ");
        if (l < 0) {
            plogf("major noncomponents\n");
        } else if (l == 0) {
            plogf("all noncomponents\n");
        } else {
            plogf("minor noncomponents\n");
        }
    }
#endif
    /* ************************************************* */
    /* **** MAJORS and ZEREOD SPECIES ONLY ************* */
    /* ************************************************* */
    if (l < 0) {
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = irxn + m_numComponents;
            if (m_speciesStatus[kspec] != VCS_SPECIES_MINOR) {
                icase = 0;
                deltaGRxn[irxn] = feSpecies[m_indexRxnToSpecies[irxn]];
                dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
                for (kspec = 0; kspec < m_numComponents; ++kspec) {
                    deltaGRxn[irxn] += dtmp_ptr[kspec] * feSpecies[kspec];
                    if (molNumSpecies[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) {
                        icase = 1;
                    }
                }
                if (icase) {
                    deltaGRxn[irxn] = std::max(0.0, deltaGRxn[irxn]);
                }
            }
        }
    } else if (l == 0) {
        /* ************************************************* */
        /* **** ALL REACTIONS ****************************** */
        /* ************************************************* */
        for (irxn = 0; irxn < irxnl; ++irxn) {
            icase = 0;
            deltaGRxn[irxn] = feSpecies[m_indexRxnToSpecies[irxn]];
            dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
            for (kspec = 0; kspec < m_numComponents; ++kspec) {
                deltaGRxn[irxn] += dtmp_ptr[kspec] * feSpecies[kspec];
                if (molNumSpecies[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF &&
                        dtmp_ptr[kspec] < 0.0) {
                    icase = 1;
                }
            }
            if (icase) {
                deltaGRxn[irxn] = std::max(0.0, deltaGRxn[irxn]);
            }
        }
    } else {
        /* ************************************************* */
        /* **** MINORS AND ZEROED SPECIES ****************** */
        /* ************************************************* */
        for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
            kspec = irxn + m_numComponents;
            if (m_speciesStatus[kspec] <= VCS_SPECIES_MINOR) {
                icase = 0;
                deltaGRxn[irxn] = feSpecies[m_indexRxnToSpecies[irxn]];
                dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
                for (kspec = 0; kspec < m_numComponents; ++kspec) {
                    deltaGRxn[irxn] += dtmp_ptr[kspec] * feSpecies[kspec];
                    if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF &&
                            dtmp_ptr[kspec] < 0.0) {
                        icase = 1;
                    }
                }
                if (icase) {
                    deltaGRxn[irxn] = std::max(0.0, deltaGRxn[irxn]);
                }
            }
        }
    }
    /* ************************************************* */
    /* **** MULTISPECIES PHASES WITH ZERO MOLES ******** */
    /* ************************************************* */
    /*
     *    Massage the free energies for species with zero mole fractions
     *  in multispecies phases.  This section implements the
     *  Equation 3.8-5 in Smith and Missen, p.59.
     *  A multispecies phase will exist iff
     *           1 < sum_i(exp(-dg_i)/AC_i)
     *  If DG is negative then that species wants to be reintroduced into
     *  the calculation.
     *  For small dg_i, the expression below becomes:
     *      1 - sum_i(exp(-dg_i)/AC_i) ~ sum_i((dg_i-1)/AC_i)  + 1
     *
     *  So, what we are doing here is equalizing all DG's in a multispecies
     *  phase whose total mole number has already been zeroed out.
     *  It must have to do with the case where a complete multispecies
     *  phase is currently zeroed out. In that case, when one species
     *  in that phase has a negative DG, then the phase should kick in.
     *  This code section will cause that to happen, because a negative
     *  DG will dominate the calculation of SDEL. Then, DG(I) for all
     *  species in that phase will be forced to be equal and negative.
     *  Thus, all species in that phase will come into being at the
     *  same time.
     *
     *  HKM -> The ratio of mole fractions at the reinstatement
     *         time should be equal to the normalized weighting
     *         of exp(-dg_i) / AC_i. This should be implemented.
     *
     *  HKM -> There is circular logic here. ActCoeff depends on the
     *         mole fractions of a phase that does not exist. In actuality
     *         the proto-mole fractions should be selected from the
     *         solution of a nonlinear problem with NsPhase unknowns
     *
     *              X_i = exp(-dg[irxn]) / ActCoeff_i / denom
     *
     *              where
     *               denom = sum_i[  exp(-dg[irxn]) / ActCoeff_i  ]
     *
     *         This can probably be solved by successive iteration.
     *         This should be implemented.
     */
    //alterZeroedPhases = false;
    if (alterZeroedPhases  && false) {
        for (iph = 0; iph < m_numPhases; iph++) {
            lneed = false;
            vcs_VolPhase* Vphase = m_VolPhaseList[iph];
            if (! Vphase->m_singleSpecies) {
                double sum = 0.0;
                for (size_t k = 0; k < Vphase->nSpecies(); k++) {
                    kspec = Vphase->spGlobalIndexVCS(k);
                    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                        sum += molNumSpecies[kspec];
                    }
                    if (sum > 0.0) {
                        break;
                    }
                }
                if (sum == 0.0) {
                    lneed = true;
                }
            }

            if (lneed) {
                double poly = 0.0;
                for (size_t k = 0; k < Vphase->nSpecies(); k++) {
                    kspec = Vphase->spGlobalIndexVCS(k);
                    // We may need to look at deltaGRxn for components!
                    if (kspec >= m_numComponents) {
                        irxn = kspec - m_numComponents;
                        if (deltaGRxn[irxn] >  50.0) {
                            deltaGRxn[irxn] =  50.0;
                        }
                        if (deltaGRxn[irxn] < -50.0) {
                            deltaGRxn[irxn] = -50.0;
                        }
                        poly += exp(-deltaGRxn[irxn])/actCoeffSpecies[kspec];
                    }
                }
                /*
                 *      Calculate deltaGRxn[] for each species in a zeroed multispecies phase.
                 *      All of the m_deltaGRxn_new[]'s will be equal. If deltaGRxn[] is
                 *      negative, then the phase will come back into existence.
                 */
                for (size_t k = 0; k < Vphase->nSpecies(); k++) {
                    kspec = Vphase->spGlobalIndexVCS(k);
                    if (kspec >= m_numComponents) {
                        irxn = kspec - m_numComponents;
                        deltaGRxn[irxn] = 1.0 - poly;
                    }
                }

            }
        }
    }


#ifdef DEBUG_NOT
    for (irxn = 0; irxn < m_numRxnRdc; ++irxn) {
        checkFinite(deltaGRxn[irxn]);
    }
#endif
}
//====================================================================================================================
void  VCS_SOLVE::vcs_printDeltaG(const int stateCalc)
{
    size_t j;
    double* deltaGRxn = VCS_DATA_PTR(m_deltaGRxn_old);
    double* feSpecies = VCS_DATA_PTR(m_feSpecies_old);
    double* molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_old);
    const double* tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_old);
    const double* actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_old);
    if (stateCalc == VCS_STATECALC_NEW) {
        deltaGRxn     = VCS_DATA_PTR(m_deltaGRxn_new);
        feSpecies     = VCS_DATA_PTR(m_feSpecies_new);
        molNumSpecies = VCS_DATA_PTR(m_molNumSpecies_new);
        actCoeff_ptr = VCS_DATA_PTR(m_actCoeffSpecies_new);
        tPhMoles_ptr = VCS_DATA_PTR(m_tPhaseMoles_new);
    }
    double RT = m_temperature * Cantera::GasConstant;
    bool zeroedPhase = false;
    if (m_debug_print_lvl >= 2) {
        plogf("   --- DELTA_G TABLE  Components:");
        for (j = 0; j < m_numComponents; j++) {
            plogf("     %3d  ", j);
        }
        plogf("\n   ---          Components Moles:");
        for (j = 0; j < m_numComponents; j++) {
            plogf("%10.3g", m_molNumSpecies_old[j]);
        }
        plogf("\n   ---   NonComponent|   Moles  |       ");
        for (j = 0; j < m_numComponents; j++) {
            plogf("%-10.10s", m_speciesName[j].c_str());
        }
        //plogf("|    m_scSize");
        plogf("\n");
        for (size_t i = 0; i < m_numRxnTot; i++) {
            plogf("   --- %3d ", m_indexRxnToSpecies[i]);
            plogf("%-10.10s", m_speciesName[m_indexRxnToSpecies[i]].c_str());
            plogf("|%10.3g|", m_molNumSpecies_old[m_indexRxnToSpecies[i]]);
            for (j = 0; j < m_numComponents; j++) {
                plogf("     %6.2f", m_stoichCoeffRxnMatrix[i][j]);
            }
            //plogf(" |  %6.2f", m_scSize[i]);
            plogf("\n");
        }
        plogf("   ");
        for (int i=0; i<77; i++) {
            plogf("-");
        }
        plogf("\n");
    }

    printf("   --- DeltaG Table (J/kmol) Name       PhID   MoleNum      MolFR  "
           "  ElectrChemStar ElectrChem    DeltaGStar   DeltaG(Pred)  Stability\n");
    printf("   ");
    vcs_print_line("-", 132);

    for (size_t kspec = 0; kspec < m_numSpeciesTot; kspec++) {

        size_t irxn = kspec -  m_numComponents;

        double mfValue = 1.0;
        size_t iphase = m_phaseID[kspec];
        const vcs_VolPhase* Vphase = m_VolPhaseList[iphase];
        if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS)    ||
                (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE) ||
                (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDSS)) {
            zeroedPhase = true;
        } else {
            zeroedPhase = false;
        }
        if (tPhMoles_ptr[iphase] > 0.0) {
            if (molNumSpecies[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) {
                mfValue = VCS_DELETE_MINORSPECIES_CUTOFF / tPhMoles_ptr[iphase];
            } else {
                mfValue = molNumSpecies[kspec] / tPhMoles_ptr[iphase];
            }
        } else {
            size_t klocal = m_speciesLocalPhaseIndex[kspec];
            mfValue = Vphase->moleFraction(klocal);
        }
        if (zeroedPhase) {
            printf("   --- ** zp *** ");
        } else {
            printf("   ---           ");
        }
        double feFull =  feSpecies[kspec];
        if ((m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDMS)    ||
                (m_speciesStatus[kspec] == VCS_SPECIES_ZEROEDPHASE)) {
            feFull += log(actCoeff_ptr[kspec]) + log(mfValue);
        }
        printf("%-24.24s", m_speciesName[kspec].c_str());
        printf(" %-3s", Cantera::int2str(iphase).c_str());
        printf(" % -12.4e", molNumSpecies[kspec]);
        printf(" % -12.4e", mfValue);
        printf(" % -12.4e", feSpecies[kspec] * RT);
        printf(" % -12.4e", feFull * RT);
        if (irxn != npos) {
            printf(" % -12.4e", deltaGRxn[irxn] * RT);
            printf(" % -12.4e", (deltaGRxn[irxn] + feFull - feSpecies[kspec]) * RT);

            if (deltaGRxn[irxn] < 0.0) {
                if (molNumSpecies[kspec] > 0.0) {
                    printf("   growing");
                } else {
                    printf("    stable");
                }
            } else if (deltaGRxn[irxn] > 0.0) {
                if (molNumSpecies[kspec] > 0.0) {
                    printf(" shrinking");
                } else {
                    printf("  unstable");
                }
            } else {
                printf(" balanced");
            }
        }

        printf(" \n");
    }

    printf("   ");
    vcs_print_line("-", 132);

}
//====================================================================================================================
//    Calculate deltag of formation for all species in a single phase.
/*
 *     Calculate deltag of formation for all species in a single
 *     phase. It is assumed that the fe[] is up to date for all species.
 *     Howevever, if the phase is currently zereoed out, a subproblem
 *     is calculated to solve for AC[i] and pseudo-X[i] for that
 *     phase.
 *
 *   @param iphase       phase index of the phase to be calculated
 *   @param doDeleted    boolean indicating whether to do deleted species or not
 *   @param stateCalc    integer describing which set of free energies
 *                       to use and where to stick the results.
 *
 *    NOTE: this is currently not used used anywhere. It may be in the future?
 */
void VCS_SOLVE::vcs_deltag_Phase(const size_t iphase, const bool doDeleted,
                                 const int stateCalc, const bool alterZeroedPhases)
{
    size_t iph;
    size_t  irxn, kspec, kcomp;
    double* dtmp_ptr;

    double* feSpecies;
    double* deltaGRxn;
    double* actCoeffSpecies;
    if (stateCalc == VCS_STATECALC_NEW) {
        feSpecies = VCS_DATA_PTR(m_feSpecies_new);
        deltaGRxn = VCS_DATA_PTR(m_deltaGRxn_new);
        actCoeffSpecies = VCS_DATA_PTR(m_actCoeffSpecies_new);
    } else { // stateCalc == VCS_STATECALC_OLD
        feSpecies = VCS_DATA_PTR(m_feSpecies_old);
        deltaGRxn = VCS_DATA_PTR(m_deltaGRxn_old);
        actCoeffSpecies = VCS_DATA_PTR(m_actCoeffSpecies_old);
    }
#ifdef DEBUG_MODE
    else {
        plogf("vcs_deltag_Phase: we shouldn't be here\n");
        plogendl();
        exit(EXIT_FAILURE);
    }
#endif

    size_t irxnl = m_numRxnRdc;
    if (doDeleted) {
        irxnl = m_numRxnTot;
    }
    vcs_VolPhase* vPhase = m_VolPhaseList[iphase];

#ifdef DEBUG_MODE
    if (m_debug_print_lvl >= 2) {
        plogf("   --- Subroutine vcs_deltag_Phase called for phase %d\n",
              iphase);
    }
#endif

    /*
     * Single species Phase
     */
    if (vPhase->m_singleSpecies) {
        kspec = vPhase->spGlobalIndexVCS(0);
#ifdef DEBUG_MODE
        if (iphase != m_phaseID[kspec]) {
            plogf("vcs_deltag_Phase index error\n");
            exit(EXIT_FAILURE);
        }
#endif
        if (kspec >= m_numComponents) {
            irxn = kspec - m_numComponents;
            deltaGRxn[irxn] = feSpecies[kspec];
            dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
            for (kcomp = 0; kcomp < m_numComponents; ++kcomp) {
                deltaGRxn[irxn] += dtmp_ptr[kcomp] * feSpecies[kcomp];
            }
        }
    }
    /*
     * Multispecies Phase
     */
    else {
        bool zeroedPhase = true;

        for (irxn = 0; irxn < irxnl; ++irxn) {
            kspec = m_indexRxnToSpecies[irxn];
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                iph = m_phaseID[kspec];
                if (iph == iphase) {
                    if (m_molNumSpecies_old[kspec] > 0.0) {
                        zeroedPhase = false;
                    }
                    deltaGRxn[irxn] = feSpecies[kspec];
                    dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
                    for (kcomp = 0; kcomp < m_numComponents; ++kcomp) {
                        deltaGRxn[irxn] += dtmp_ptr[kcomp] * feSpecies[kcomp];
                    }
                }
            }
        }

        /*
         * special section for zeroed phases
         */
        /* ************************************************* */
        /* **** MULTISPECIES PHASES WITH ZERO MOLES************ */
        /* ************************************************* */
        /*
         *    Massage the free energies for species with zero mole fractions
         *  in multispecies phases.  This section implements the
         *  Equation 3.8-5 in Smith and Missen, p.59.
         *  A multispecies phase will exist iff
         *           1 < sum_i(exp(-dg_i)/AC_i)
         *  If DG is negative then that species wants to be reintroduced into
         *  the calculation.
         *  For small dg_i, the expression below becomes:
         *      1 - sum_i(exp(-dg_i)/AC_i) ~ sum_i((dg_i-1)/AC_i)  + 1
         *
         *
         *  HKM -> The ratio of mole fractions at the reinstatement
         *         time should be equal to the normalized weighting
         *         of exp(-dg_i) / AC_i. This should be implemented.
         *
         *  HKM -> There is circular logic here. ActCoeff depends on the
         *         mole fractions of a phase that does not exist. In actuality
         *         the proto-mole fractions should be selected from the
         *         solution of a nonlinear problem with NsPhase unknowns
         *
         *              X_i = exp(-dg[irxn]) / ActCoeff_i / denom
         *
         *              where
         *               denom = sum_i[  exp(-dg[irxn]) / ActCoeff_i  ]
         *
         *         This can probably be solved by successive iteration.
         *         This should be implemented.
         */
        /*
         *      Calculate dg[] for each species in a zeroed multispecies phase.
         *      All of the dg[]'s will be equal. If dg[] is negative, then
         *      the phase will come back into existence.
         */
        if (alterZeroedPhases) {
            if (zeroedPhase) {
                double phaseDG = 1.0;
                for (irxn = 0; irxn < irxnl; ++irxn) {
                    kspec = m_indexRxnToSpecies[irxn];
                    iph = m_phaseID[kspec];
                    if (iph == iphase) {
                        if (deltaGRxn[irxn] >  50.0) {
                            deltaGRxn[irxn] =  50.0;
                        }
                        if (deltaGRxn[irxn] < -50.0) {
                            deltaGRxn[irxn] = -50.0;
                        }
                        phaseDG -= exp(-deltaGRxn[irxn])/actCoeffSpecies[kspec];
                    }
                }
                /*
                 * Overwrite the individual dg's with the phase DG.
                 */
                for (irxn = 0; irxn < irxnl; ++irxn) {
                    kspec = m_indexRxnToSpecies[irxn];
                    iph = m_phaseID[kspec];
                    if (iph == iphase) {
                        deltaGRxn[irxn] = 1.0 - phaseDG;
                    }
                }
            }
        }
    }
}
/****************************************************************************/

//  Swaps the indices for all of the global data for two species, k1
//  and k2.
/*
 *  @param  ifunc:  If true, switch the species data and the noncomponent reaction
 *                  data. This must be called for a non-component species only.
 *                  If false, switch the species data only. Typically, we use this
 *                  option when determining the component species and at the
 *                  end of the calculation, when we want to return unscrambled
 *                  results. All rxn data will be out-of-date.
 *
 *  @param k1        First species index
 *
 *  @param k2        Second species index
 */
void VCS_SOLVE::vcs_switch_pos(const bool ifunc, const size_t k1, const size_t k2)
{
    size_t i1, i2, iph, kp1, kp2;
    vcs_VolPhase* pv1, *pv2;
    if (k1 == k2) {
        return;
    }
#ifdef DEBUG_MODE
    if (k1 > (m_numSpeciesTot - 1) ||
            k2 > (m_numSpeciesTot - 1)) {
        plogf("vcs_switch_pos: ifunc = 0: inappropriate args: %d %d\n",
              k1, k2);
    }
#endif
    /*
     *     Handle the index pointer in the phase structures first
     */
    pv1 = m_VolPhaseList[m_phaseID[k1]];
    pv2 = m_VolPhaseList[m_phaseID[k2]];

    kp1 = m_speciesLocalPhaseIndex[k1];
    kp2 = m_speciesLocalPhaseIndex[k2];
#ifdef DEBUG_MODE
    if (pv1->spGlobalIndexVCS(kp1) != k1) {
        plogf("Indexing error in program\n");
        exit(EXIT_FAILURE);
    }
    if (pv2->spGlobalIndexVCS(kp2) != k2) {
        plogf("Indexing error in program\n");
        exit(EXIT_FAILURE);
    }
#endif
    pv1->setSpGlobalIndexVCS(kp1, k2);
    pv2->setSpGlobalIndexVCS(kp2, k1);
    //pv1->IndSpecies[kp1] = k2;
    //pv2->IndSpecies[kp2] = k1;
    std::swap(m_speciesName[k1], m_speciesName[k2]);
    std::swap(m_molNumSpecies_old[k1], m_molNumSpecies_old[k2]);
    std::swap(m_speciesUnknownType[k1], m_speciesUnknownType[k2]);
    std::swap(m_molNumSpecies_new[k1], m_molNumSpecies_new[k2]);
    std::swap(m_SSfeSpecies[k1], m_SSfeSpecies[k2]);
    std::swap(m_spSize[k1], m_spSize[k2]);
    std::swap(m_deltaMolNumSpecies[k1], m_deltaMolNumSpecies[k2]);
    std::swap(m_feSpecies_old[k1], m_feSpecies_old[k2]);
    std::swap(m_feSpecies_new[k1], m_feSpecies_new[k2]);
    std::swap(m_SSPhase[k1], m_SSPhase[k2]);
    std::swap(m_phaseID[k1], m_phaseID[k2]);
    std::swap(m_speciesMapIndex[k1], m_speciesMapIndex[k2]);
    std::swap(m_speciesLocalPhaseIndex[k1], m_speciesLocalPhaseIndex[k2]);
    std::swap(m_actConventionSpecies[k1], m_actConventionSpecies[k2]);
    std::swap(m_lnMnaughtSpecies[k1], m_lnMnaughtSpecies[k2]);
    std::swap(m_actCoeffSpecies_new[k1], m_actCoeffSpecies_new[k2]);
    std::swap(m_actCoeffSpecies_old[k1], m_actCoeffSpecies_old[k2]);
    std::swap(m_wtSpecies[k1], m_wtSpecies[k2]);
    std::swap(m_chargeSpecies[k1], m_chargeSpecies[k2]);
    std::swap(m_speciesThermoList[k1], m_speciesThermoList[k2]);
    std::swap(m_PMVolumeSpecies[k1], m_PMVolumeSpecies[k2]);

    for (size_t j = 0; j < m_numElemConstraints; ++j) {
        std::swap(m_formulaMatrix[j][k1], m_formulaMatrix[j][k2]);
    }
    if (m_useActCoeffJac) {
        vcs_switch2D(m_dLnActCoeffdMolNum.baseDataAddr(), k1, k2);
    }
    std::swap(m_speciesStatus[k1], m_speciesStatus[k2]);
    /*
     *     Handle the index pointer in the phase structures
     */


    if (ifunc) {
        /*
         * Find the Rxn indices corresponding to the two species
         */
        i1 = k1 - m_numComponents;
        i2 = k2 - m_numComponents;
#ifdef DEBUG_MODE
        if (i1 > (m_numRxnTot - 1) ||
                i2 > (m_numRxnTot - 1)) {
            plogf("switch_pos: ifunc = 1: inappropriate noncomp values: %d %d\n",
                  i1 , i2);
        }
#endif
        for (size_t j = 0; j < m_numComponents; ++j) {
            std::swap(m_stoichCoeffRxnMatrix[i1][j], m_stoichCoeffRxnMatrix[i2][j]);
        }
        std::swap(m_scSize[i1], m_scSize[i2]);
        for (iph = 0; iph < m_numPhases; iph++) {
            std::swap(m_deltaMolNumPhase[i1][iph], m_deltaMolNumPhase[i2][iph]);
            std::swap(m_phaseParticipation[i1][iph],
                      m_phaseParticipation[i2][iph]);
        }
        std::swap(m_deltaGRxn_new[i1],  m_deltaGRxn_new[i2]);
        std::swap(m_deltaGRxn_old[i1], m_deltaGRxn_old[i2]);
        std::swap(m_deltaGRxn_tmp[i1], m_deltaGRxn_tmp[i2]);

        /*
         *   We don't want to swap ir[], because the values of ir should
         *   stay the same after the swap
         *
         * vcs_isw(ir, i1, i2);
         */
    }
}
/*******************************************************************************/


//     Birth guess returns the number of moles of a species
//     that is coming back to life.
/*
 *     Birth guess returns the number of moles of a species
 *     that is coming back to life.
 *     Note, this routine is not applicable if the whole phase is coming
 *     back to life, not just one species in that phase.
 *
 *  Do a minor alt calculation. But, cap the mole numbers at
 *  1.0E-15.
 *  For SS phases use VCS_DELETE_SPECIES_CUTOFF * 100.
 *
 *  The routine makes sure the guess doesn't reduce the concentration
 *  of a component by more than 1/3. Note this may mean that
 *  the vlaue coming back from this routine is zero or a
 *  very small number.
 *
 *
 * @param kspec   Species number that is coming back to life
 *
 * @return      Returns the number of kmol that the species should
 *              have.
 */
double VCS_SOLVE::vcs_birthGuess(const int kspec)
{
    size_t irxn = kspec - m_numComponents;
    double dx = 0.0;
    if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
        return dx;
    }
    double w_kspec = VCS_DELETE_MINORSPECIES_CUTOFF;
#ifdef DEBUG_MODE
    // Check to make sure that species is zero in the solution vector
    // If it isn't, we don't know what's happening
    if (m_molNumSpecies_old[kspec] != 0.0) {
        w_kspec = 0.0;
        plogf("vcs_birthGuess:: we shouldn't be here\n");
        exit(EXIT_FAILURE);
    }
#endif
    int ss = m_SSPhase[kspec];
    if (!ss) {
        /*
         * Logic to handle species in multiple species phases
         *    we cap the moles here at 1.0E-15 kmol.
         */
        bool soldel_ret;
#ifdef DEBUG_MODE
        char ANOTE[32];
        double dxm = vcs_minor_alt_calc(kspec, irxn, &soldel_ret, ANOTE);
#else
        double dxm = vcs_minor_alt_calc(kspec, irxn, &soldel_ret);
#endif
        dx = w_kspec + dxm;
        if (dx > 1.0E-15) {
            dx = 1.0E-15;
        }
    } else {
        /*
         * Logic to handle single species phases
         *      There is no real way to estimate the moles. So
         *      we set it to a small number.
         */
        dx = 1.0E-30;
    }

    /*
     * Check to see if the current value of the components
     * allow the dx just estimated.
     * If we are in danger of zeroing a component,
     * only go 1/3 the way to zeroing the component with
     * this dx. Note, this may mean that dx= 0 coming
     * back from this routine. This evaluation should
     * be respected.
     */
    double* sc_irxn = m_stoichCoeffRxnMatrix[irxn];
    for (size_t j = 0; j < m_numComponents; ++j) {
        // Only loop over element constraints that involve positive def. constraints
        if (m_speciesUnknownType[j] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            if (m_molNumSpecies_old[j] > 0.0) {
                double tmp = sc_irxn[j] * dx;
                if (3.0*(-tmp) > m_molNumSpecies_old[j]) {
                    dx = std::min(dx, - 0.3333* m_molNumSpecies_old[j] / sc_irxn[j]);
                }
            }
            if (m_molNumSpecies_old[j] <= 0.0) {
                if (sc_irxn[j] < 0.0) {
                    dx = 0.0;
                }
            }
        }
    }
    return dx;
}
/*******************************************************************************/

void VCS_SOLVE::vcs_setFlagsVolPhases(const bool upToDate, const int stateCalc)
{
    vcs_VolPhase* Vphase;
    if (!upToDate) {
        for (size_t iph = 0; iph < m_numPhases; iph++) {
            Vphase = m_VolPhaseList[iph];
            Vphase->setMolesOutOfDate(stateCalc);
        }
    } else {
        for (size_t iph = 0; iph < m_numPhases; iph++) {
            Vphase = m_VolPhaseList[iph];
            Vphase->setMolesCurrent(stateCalc);
        }
    }
}
/*******************************************************************************/

void VCS_SOLVE::vcs_setFlagsVolPhase(const size_t iph, const bool upToDate,
                                     const int stateCalc)
{
    vcs_VolPhase* Vphase = m_VolPhaseList[iph];
    if (!upToDate) {
        Vphase->setMolesOutOfDate(stateCalc);
    } else {
        Vphase->setMolesCurrent(stateCalc);
    }
}
/*******************************************************************************/

// Update all underlying vcs_VolPhase objects
/*
 *  Update the mole numbers and the phase voltages of all phases in the
 *  vcs problem
 *
 *  @param stateCalc Location of the update (either VCS_STATECALC_NEW or
 *         VCS_STATECALC_OLD).
 */
void VCS_SOLVE::vcs_updateMolNumVolPhases(const int stateCalc)
{
    vcs_VolPhase* Vphase;
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        Vphase = m_VolPhaseList[iph];
        Vphase->updateFromVCS_MoleNumbers(stateCalc);
    }
}
/*******************************************************************************/

}
