From fa7e832b143695bf76159bc2e4b90423537bf594 Mon Sep 17 00:00:00 2001 From: Harry Moffat Date: Fri, 18 Jan 2008 17:04:07 +0000 Subject: [PATCH] doxygen update mostly. worked on moving #define to inline functions --- Cantera/src/equil/vcs_internal.h | 196 +- Cantera/src/equil/vcs_nondim.cpp | 56 +- Cantera/src/equil/vcs_solve_TP.cpp | 9189 ++++++++++++++-------------- Cantera/src/equil/vcs_util.cpp | 904 +-- 4 files changed, 5219 insertions(+), 5126 deletions(-) diff --git a/Cantera/src/equil/vcs_internal.h b/Cantera/src/equil/vcs_internal.h index 461fb7199..08ef0a6e0 100644 --- a/Cantera/src/equil/vcs_internal.h +++ b/Cantera/src/equil/vcs_internal.h @@ -2,7 +2,6 @@ * @file vcs_internal.h * Internal declarations for the VCSnonideal package */ - /* * $Id$ */ @@ -139,25 +138,106 @@ namespace VCSnonideal { double T_Time_vcs; }; - /*****************************************************************************/ - /**************** Prototypes *************************************************/ - /*****************************************************************************/ + //! This is the rootfinder function call for the function vcs_TV() + /*! + * The function is of type VCS_FUNC_PTR + * It's the function call for the vcs_TV(). + * Solves for the total volume of the system, by first calculating + * the equilibrium wrt T,P. + * Routine then returns + * + * \f[ + * f(x) = V(T,P) - Vtarget + * \f] + * + * @param xval Currently value of the independent variable + * @param Vtarget Target value of the volume + * @param varID If 0, xval is temperature, If 1, xval is pressure. + * @param fptrPassthrough Pointer to VCS_SOLVE object + * @param err Return 0 for success. Anything else is an error code. + * + */ + double vcs_funcVtot(double xval, double Vtarget, int varID, + void *fptrPassthrough, int *err); - /* Externals for vcs_funcVtot.c */ - extern double vcs_funcVtot(double, double, int, void *, int *); + //! Returns the value of the gas constant in the units specified by parameter + /*! + * @param mu_units Specifies the units. + * - VCS_UNITS_KCALMOL: kcal gmol-1 K-1 + * - VCS_UNITS_UNITLESS: 1.0 K-1 + * - VCS_UNITS_KJMOL: kJ gmol-1 K-1 + * - VCS_UNITS_KELVIN: 1.0 K-1 + * - VCS_UNITS_MKS: joules kmol-1 K-1 = kg m2 s-2 kmol-1 K-1 + */ + double vcsUtil_gasConstant(int mu_units); - /* Externals defined in vcs_nondim.c */ + //! Invert an n x n matrix and solve m rhs's + /*! + * Solve a square matrix with multiple right hand sides + * + * \f[ + * C X + B = 0; + * \f] + * + * This routine uses Gauss elimination and is optimized for the solution + * of lots of rhs's. A crude form of row pivoting is used here. + * The matrix C is destroyed during the solve. + * + * @return The solution x[] is returned in the matrix B. + * Routine returns an integer representing success: + * - 1 : Matrix is singluar + * - 0 : solution is OK + * + * + * @param c Matrix to be inverted. c is in fortran format, i.e., rows + * are the inner loop. Row numbers equal to idem. + * c[i+j*idem] = c_i_j = Matrix to be inverted: + * - i = row number + * - j = column number + * + * @param idem number of row dimensions in c + * @param n Number of rows and columns in c + * @param b Multiple RHS. Note, b is actually the negative of + * most formulations. Row numbers equal to idem. + * b[i+j*idem] = b_i_j = vectors of rhs's: + * - i = row number + * - j = column number + * (each column is a new rhs) + * @param m number of rhs's + */ + int vcsUtil_mlequ(double *c, int idem, int n, double *b, int m); - extern double vcsUtil_gasConstant(int); + //! Swap values in vector of doubles + /*! + * Switches the value of x[i1] with x[i2] + * + * @param x Vector of doubles + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_dsw(double x[], int i1, int i2); - /* Externals in vcs_solve_TP.c */ + //! Swap values in an integer array + /*! + * Switches the value of x[i1] with x[i2] + * + * @param x Vector of integers + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_isw(int x[], int i1, int i2); - extern int vcsUtil_mlequ(double *, int, int, double *, int); - extern void vcsUtil_dsw(double *, int ,int); - extern void vcsUtil_isw(int [], int, int); - extern void vcsUtil_ssw(char **, int, int); - extern void vcsUtil_stsw(std::vector & vecStrings, int, int); + //! Swap values in a std vector string + /*! + * Switches the value of vecStrings[i1] with vecStrings[i2] + * + * @param vecStrings Vector of integers + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_stsw(std::vector & vecStrings, + int i1, int i2); /* Externals for vcs_root1d.c */ @@ -262,8 +342,10 @@ namespace VCSnonideal { double thetaR = Pi/2.0; int printLvl = 4; - iconv = VCSnonideal::vcsUtil_root1d(thetamin, thetamax, maxit, funcZero, - (void *) 0, 0.0, 0, &thetaR, printLvl); + iconv = VCSnonideal::vcsUtil_root1d(thetamin, thetamax, maxit, + funcZero, + (void *) 0, 0.0, 0, + &thetaR, printLvl); printf("theta = %g\n", thetaR); double h2Final = calc_h2_farfield(thetaR); printf("h2Final = %g\n", h2Final); @@ -273,30 +355,74 @@ namespace VCSnonideal { */ int vcsUtil_root1d(double xmin, double xmax, int itmax, VCS_FUNC_PTR func, void *fptrPassthrough, - double FuncTargVal, int varID, double *xbest, int printLvl = 0); + double FuncTargVal, int varID, double *xbest, + int printLvl = 0); - /* Externals defined in vcs_timer_generic.c */ - - extern double vcs_second(void); - - - /* Externals defined in vcs_util.c */ + //! Returns the system wall clock time in seconds + /*! + * @return time in seconds. + */ + double vcs_second(); + //! This define turns on using memset and memcpy. I have not run into + //! any systems where this is a problem. It's the fastest way to do + //! low lvl operations where applicable. There are alternative routines + //! available if this ever fails. #define USE_MEMSET #ifdef USE_MEMSET #include -# define vcs_dzero(vector, length) (void) memset((void *) (vector), 0, \ - (length) * sizeof(double)) -# define vcs_izero(vector, length) (void) memset((void *) (vector), 0, \ - (length) * sizeof(int)) -# define vcs_dcopy(vec_to, vec_from, length) \ - (void) memcpy((void *) (vec_to), (const void *) (vec_from), \ - (length) * sizeof(double)) -# define vcs_icopy(vec_to, vec_from, length) \ - (void) memcpy((void *) (vec_to), (const void *) (vec_from), \ - (length) * sizeof(int)) -# define vcs_vdzero(vector, length) (void) memset(VCS_DATA_PTR(vector), 0, \ - (length) * sizeof(double)) + + //! Zero a double vector + /*! + * @param vec_to vector of doubles + * @param length length of the vector to zero. + */ + inline void vcs_dzero(double *vec_to, int length) { + (void) memset((void *) vec_to, 0, length * sizeof(double)); + } + + //! Zero an int vector + /*! + * @param vec_to vector of ints + * @param length length of the vector to zero. + */ + inline void vcs_izero(int *vec_to, int length) { + (void) memset((void *) vec_to, 0, length * sizeof(int)); + } + + //! Copy a double vector + /*! + * @param vec_to Vector to copy into. This vector must be dimensioned + * at least as large as the vec_from vector. + * @param vec_from Vector to copy from + * @param length Number of doubles to copy. + */ + inline void vcs_dcopy(double *vec_to, const double *vec_from, int length) { + (void) memcpy((void *) vec_to, (const void *) vec_from, + (length) * sizeof(double)); + } + + + //! Copy an int vector + /*! + * @param vec_to Vector to copy into. This vector must be dimensioned + * at least as large as the vec_from vector. + * @param vec_from Vector to copy from + * @param length Number of int to copy. + */ + inline void vcs_icopy(int *vec_to, const int *vec_from, int length) { + (void) memcpy((void *) vec_to, (const void *) vec_from, + (length) * sizeof(int)); + } + + //! Zero a std double vector + /*! + * @param vec_to vector of doubles + * @param length length of the vector to zero. + */ + inline void vcs_vdzero(std::vector &vec_to, int length) { + (void) memset(VCS_DATA_PTR(vec_to), 0, (length) * sizeof(double)); + } //! Zero a std int vector /*! diff --git a/Cantera/src/equil/vcs_nondim.cpp b/Cantera/src/equil/vcs_nondim.cpp index 89873c302..8863b7911 100644 --- a/Cantera/src/equil/vcs_nondim.cpp +++ b/Cantera/src/equil/vcs_nondim.cpp @@ -1,12 +1,15 @@ -/*======================================================================= -* -------------------------------------------------- -* | CVS Head Information on zuzax.pchem.sandia.gov | -* -------------------------------------------------- -* $RCSfile$ -* $Author$ -* $Date$ -* $Revision$ -*======================================================================= */ +/** + * @file vcs_nondim.cpp + * Nondimensionalization routines with VCSnonideal + */ +/* + * $Id$ + */ +/* + * Copywrite (2007) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ #include #include #include @@ -73,41 +76,6 @@ double VCS_SOLVE::vcs_nondimMult_TP(int mu_units, double TKelvin) return rt; } -/************************************************************************** - * - * vcs_gasConstant: - * - * Returns the value of the gas constant in the units specified by - * if__. - ***************************************************************************/ -double vcsUtil_gasConstant(int mu_units) -{ - double r; - switch (mu_units) { - case VCS_UNITS_KCALMOL: - r = 0.008314472/4.184; - break; - case VCS_UNITS_UNITLESS: - r = 1.0; - break; - case VCS_UNITS_KJMOL: - r = 0.008314472; - break; - case VCS_UNITS_KELVIN: - r = 1.0; - break; - case VCS_UNITS_MKS: - /* joules / kg-mol K = kg m2 / s2 kg-mol K */ - r = 8.314472E3; - break; - default: - plogf("vcs_gasConstant error: uknown units: %d\n", - mu_units); - exit(-1); - } - return r; -} - /************************************************************************** * * vcs_nondim_TP: diff --git a/Cantera/src/equil/vcs_solve_TP.cpp b/Cantera/src/equil/vcs_solve_TP.cpp index a5aee834f..ca97f17c3 100644 --- a/Cantera/src/equil/vcs_solve_TP.cpp +++ b/Cantera/src/equil/vcs_solve_TP.cpp @@ -27,1801 +27,1782 @@ namespace VCSnonideal { -/*****************************************************************************/ -/************ Prototypes for static functions ********************************/ + /***************************************************************************/ + /************ Prototypes for static functions ******************************/ -static void print_space(int num); + static void print_space(int num); #ifdef DEBUG_MODE -//static double minor_alt_calc(int, int, int *, char *); + //static double minor_alt_calc(int, int, int *, char *); #else -//static double minor_alt_calc(int, int, int *); + //static double minor_alt_calc(int, int, int *); #endif #ifdef DEBUG_MODE # ifdef DEBUG_NOT -static void prneav(void); -static int prnfm(void); + 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 dchange(NPhase, 0.0); - for (int k = 0; k < kspec; k++) { - if (SpeciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - int iph = PhaseID[k]; - dchange[iph] += dsLocal[k]; + void VCS_SOLVE::checkDelta1(double * const dsLocal, + double * const delTPhMoles, int kspec) { + std::vector dchange(NPhase, 0.0); + for (int k = 0; k < kspec; k++) { + if (SpeciesUnknownType[k] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + int iph = PhaseID[k]; + dchange[iph] += dsLocal[k]; + } + } + for (int iphase = 0; iphase < NPhase; iphase++) { + double denom = MAX(TMoles, 1.0E-4); + if (!vcs_doubleEqual(dchange[iphase]/denom, delTPhMoles[iphase]/denom)) { + plogf("checkDelta1: we have found a problem\n"); + exit(-1); + } } } - for (int iphase = 0; iphase < NPhase; iphase++) { - double denom = MAX(TMoles, 1.0E-4); - if (!vcs_doubleEqual(dchange[iphase]/denom, delTPhMoles[iphase]/denom)) { - plogf("checkDelta1: we have found a problem\n"); - exit(-1); - } - } -} #endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -int VCS_SOLVE::vcs_solve_TP(int print_lvl, int printDetails, int maxit) + int VCS_SOLVE::vcs_solve_TP(int print_lvl, int printDetails, int maxit) - /************************************************************************** - * - * NONIDEAL SYSTEM STOICHIOMETRIC EQUILBRIUM ALGORITHM USING VCS METHOD - * ---------------------------------------------------------------------- - * - * Any number of single-species phases and two multi-species phases - * can be handled by the present version (the latter is readily - * modified). Phase 1 is nominally a gas, since alog(P) is added to the - * standard chemical potential data. This can be overridden by - * setting p = 1. Phase 2 is nominally a liquid, or any phase for - * which the standard chemical potential data is independent of P. - * Multi-species phases is deemed to be absent if nt .lt. 1.0E-10. - * If multi-species phase is absent at equilibrium, dgRT value refers - * to 1 - sigma(x(I)), where x(I) are virtual mole fractions at the - * current equilibrium. - * A linear programming routine must be provided for the initial - * estimate of the equilibrium composition - * - * Input - * print_lvl = 1 -> Print results to standard output - * 0 -> don't report on anything - * printDetails = 1 -> Print intermediate results. - * MAXIT -> Maximum number of iterations for the algorithm - * - * Return Value - * - * solveFail = TRUE -> Failure to solve the current problem - * FALSE -> Normal successful return. - * - * Some definitions of variables - * - * NL = Number of species in multiphase non-gaseous phases - * M = Number of species - * NC = Number of components. - * NE = Number of elements - * - * E(J) = Char*2 name for the Jth element in the mechanism - * - * IT = Running count on the number of iterations of the algorithm. - * ITL = Controls whether the FORCER subroutine is called. TRUE means - * that FORCER is not called. - * MajorSpeciesHaveConverged = Indicates convergence amongst - * major species. - * -> Also controls whether a new reaction adjustment is requested. - * IM = IM is true if all noncomponent species are minor or nonexistent - * NRUNS = number of problems to run - * M = Number of species - * NE = Number of elements - * NS1 = number of single-species phases - * NL1 = Number of phase2 species - * IF = Type of chemical potential data: -1 kcal/mol - * 0 MU/RT - * 1 kJ/mol - * IEST = Initial estimate: 0 user estimate - * -1 machine estimate - * For each Species: - * SP = Species name - * BM = formula vector - * SI = Type of phase, 0 single-species - * 1 multi-species gas - * 2 multi-species liquid - * FF = Input standard chemical potential - * - * E(J) = Char*2 name for the Jth element in the mechanism - * - * Return Codes - * ------------------ - * 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 conv = FALSE, retn = VCS_SUCCESS; - double test, RT; - int j, k, l, solveFail, l1, kspec, irxn, im, forced, iph; - // double *ss, *sm, *sa, *aw, *wx, - double dx, xx, par, tsecond; - int liqphase = FALSE, numSpecliquid = 0; - int dofast, soldel, ll, it1; - int lec, npb, iti, i, lnospec; - int rangeErrorFound = 0; - bool giveUpOnElemAbund = false; - int finalElemAbundAttempts = 0; - bool MajorSpeciesHaveConverged = false; - int uptodate_minors = TRUE; - bool justDeletedMultiPhase = FALSE; - int usedZeroedSpecies; /* return flag from basopt indicating that - one of the components had a zero concentration */ + /************************************************************************** + * + * NONIDEAL SYSTEM STOICHIOMETRIC EQUILBRIUM ALGORITHM USING VCS METHOD + * ---------------------------------------------------------------------- + * + * Any number of single-species phases and two multi-species phases + * can be handled by the present version (the latter is readily + * modified). Phase 1 is nominally a gas, since alog(P) is added to the + * standard chemical potential data. This can be overridden by + * setting p = 1. Phase 2 is nominally a liquid, or any phase for + * which the standard chemical potential data is independent of P. + * Multi-species phases is deemed to be absent if nt .lt. 1.0E-10. + * If multi-species phase is absent at equilibrium, dgRT value refers + * to 1 - sigma(x(I)), where x(I) are virtual mole fractions at the + * current equilibrium. + * A linear programming routine must be provided for the initial + * estimate of the equilibrium composition + * + * Input + * print_lvl = 1 -> Print results to standard output + * 0 -> don't report on anything + * printDetails = 1 -> Print intermediate results. + * MAXIT -> Maximum number of iterations for the algorithm + * + * Return Value + * + * solveFail = TRUE -> Failure to solve the current problem + * FALSE -> Normal successful return. + * + * Some definitions of variables + * + * NL = Number of species in multiphase non-gaseous phases + * M = Number of species + * NC = Number of components. + * NE = Number of elements + * + * E(J) = Char*2 name for the Jth element in the mechanism + * + * IT = Running count on the number of iterations of the algorithm. + * ITL = Controls whether the FORCER subroutine is called. TRUE means + * that FORCER is not called. + * MajorSpeciesHaveConverged = Indicates convergence amongst + * major species. + * -> Also controls whether a new reaction adjustment is requested. + * IM = IM is true if all noncomponent species are minor or nonexistent + * NRUNS = number of problems to run + * M = Number of species + * NE = Number of elements + * NS1 = number of single-species phases + * NL1 = Number of phase2 species + * IF = Type of chemical potential data: -1 kcal/mol + * 0 MU/RT + * 1 kJ/mol + * IEST = Initial estimate: 0 user estimate + * -1 machine estimate + * For each Species: + * SP = Species name + * BM = formula vector + * SI = Type of phase, 0 single-species + * 1 multi-species gas + * 2 multi-species liquid + * FF = Input standard chemical potential + * + * E(J) = Char*2 name for the Jth element in the mechanism + * + * Return Codes + * ------------------ + * 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 conv = FALSE, retn = VCS_SUCCESS; + double test, RT; + int j, k, l, solveFail, l1, kspec, irxn, im, forced, iph; + // double *ss, *sm, *sa, *aw, *wx, + double dx, xx, par, tsecond; + int liqphase = FALSE, numSpecliquid = 0; + int dofast, soldel, ll, it1; + int lec, npb, iti, i, lnospec; + int rangeErrorFound = 0; + bool giveUpOnElemAbund = false; + int finalElemAbundAttempts = 0; + bool MajorSpeciesHaveConverged = false; + int uptodate_minors = TRUE; + bool justDeletedMultiPhase = FALSE; + int usedZeroedSpecies; /* return flag from basopt indicating that + one of the components had a zero concentration */ - vcs_VolPhase *Vphase; - double *sc_irxn = NULL; /* Stoichiometric coefficients for cur rxn */ - double *dnPhase_irxn; + vcs_VolPhase *Vphase; + double *sc_irxn = NULL; /* Stoichiometric coefficients for cur rxn */ + double *dnPhase_irxn; #ifdef DEBUG_MODE - char ANOTE[128]; - /* - * Set the debug print lvl to the same as the print lvl. - */ - vcs_debug_print_lvl = printDetails; -#endif - if (printDetails > 0 && print_lvl == 0) { - print_lvl = 1; - } - /* - * Initialize and set up all counters - */ - vcs_counters_init(0); - tsecond = vcs_second(); - - /* - * 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 sm(m_numElemConstraints*m_numElemConstraints, 0.0); - std::vector ss(m_numElemConstraints, 0.0); - std::vector sa(m_numElemConstraints, 0.0); - - std::vector aw(m_numSpeciesTot, 0.0); - std::vector wx(m_numElemConstraints, 0.0); - - solveFail = FALSE; - im = FALSE; - - /* ****************************************************** */ - /* **** Evaluate the elemental composition ****** */ - /* ****************************************************** */ - vcs_elab(); - - /* ******************************************************* */ - /* **** Printout the initial conditions for problem ****** */ - /* ******************************************************* */ - if (NPhase > 1) { - if (! VPhaseList[1]->SingleSpecies) { - liqphase = TRUE; - numSpecliquid = VPhaseList[1]->NVolSpecies; - } - } - if (print_lvl != 0) { - plogf("VCS CALCULATION METHOD\n\n "); - plogf("%s\n", Title.c_str()); - plogf("\n\n%5d SPECIES%8d ELEMENTS", m_numSpeciesTot, m_numElemConstraints); - plogf("%16d COMPONENTS\n%5d PHASE1 SPECIES", m_numComponents, - ((VPhaseList[0])->NVolSpecies)); - plogf("%10d PHASE2 SPECIES%8d SINGLE SPECIES PHASES\n\n", - numSpecliquid, - m_numSpeciesTot - (VPhaseList[0])->NVolSpecies - numSpecliquid); - plogf(" PRESSURE%22.3f ATM\n TEMPERATURE%19.3f K\n", - Pres, T); - Vphase = VPhaseList[0]; - if (Vphase->NVolSpecies > 0) { - plogf(" PHASE1 INERTS%17.3f\n", TPhInertMoles[0]); - } - if (liqphase) { - 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", (ElName[i]).c_str()); - plogf("%20.12E%20.12E %3d\n", gai[i], ga[i], m_elType[i]); - } - if (iest < 0) { - plogf("\n MODIFIED LINEAR PROGRAMMING ESTIMATE OF EQUILIBRIUM\n"); - } - if (iest >= 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(29); - plogf(" STAN_CHEM_POT EQUILIBRIUM_EST. Species_Type\n\n"); - print_space(14); - for (i = 0; i < m_numElemConstraints; ++i) plogf(" %-2.2s", ElName[i].c_str()); - plogf(" SI(I)\n"); - RT = vcs_nondimMult_TP(m_VCS_UnitsFormat, T); - for (i = 0; i < m_numSpeciesTot; ++i) { - plogf(" %-12s", SpName[i].c_str()); - for (j = 0; j < m_numElemConstraints; ++j) { - plogf("%3g", FormulaMatrix[j][i]); - } - if (PhaseID[i] == 0) { - plogf(" 1"); - } else if (PhaseID[i] == 1) { - if (liqphase) plogf(" 2"); - else plogf(" 0"); - } else { - plogf(" 0"); - } - print_space(47-m_numElemConstraints*3); - plogf("%12.5E %12.5E", RT * ff[i], soln[i]); - if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { - plogf(" Mol_Num"); - } else if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - plogf(" Voltage"); - } else { - plogf(" Unknown"); - } - plogf(" \n"); - } - } - - for (i = 0; i < m_numSpeciesTot; ++i) { - if (soln[i] < 0.0) { - plogf("On Input species %-12s has a " - "negative MF, setting it small\n", - SpName[i].c_str()); - soln[i] = VCS_DELETE_SPECIES_CUTOFF; - } - } - - /* *********************************************** */ - /* **** EVALUATE TOTAL MOLES, GAS AND LIQUID ***** */ - /* *********************************************** */ - /* - Evaluate the total moles of gas and liquid */ - /* - These quantities are storred in the global variables */ - vcs_tmoles(); - /* ******************************************* */ - /* **** EVALUATE ALL CHEMICAL POTENTIALS ***** */ - /* ******************************************* */ - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); - /* - * HKM -> If there was a machine estimate, we used to branch - * to the code segment which determined whether we needed a - * new component basis. If we did, we would go to L429. - * If we didn't, we would go to a point below basopt() below. - * I have taken this section out of the code for simplicity's - * sake. It's not need for speed, since in any recursive - * call to this subroutine we would have an initial estimate - * of the solution. And, we don't need to optimize the - * startup of nonrecursive calls to this subroutine. - */ - /* *********************************************************** */ - /* **** 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; - - if (conv) { - goto L_RETURN_BLOCK; - } - it1 = 1; - MajorSpeciesHaveConverged = false; - /*************************************************************************/ - /************** EVALUATE INITIAL MAJOR-MINOR VECTOR **********************/ - /*************************************************************************/ - m_numRxnMinorZeroed = 0; - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - kspec = ir[irxn]; - spStatus[irxn] = vcs_species_type(kspec); - if (spStatus[irxn] == VCS_SPECIES_MINOR) { - spStatus[irxn] = VCS_SPECIES_MAJOR; -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Minor species changed to major: "); - plogf("%-12s\n", SpName[kspec].c_str()); - } -#endif - } - if (spStatus[irxn] != VCS_SPECIES_MAJOR) { - ++m_numRxnMinorZeroed; - } - } - im = (m_numRxnMinorZeroed == m_numRxnRdc); - lec = FALSE; - if (! vcs_elabcheck(0)) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Element Abundance check failed\n"); - } -#endif - vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); - } -#ifdef DEBUG_MODE - else { - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Element Abundance check passed\n"); - } - } -#endif - // Update the phase objects with the contents of the soln vector - vcs_updateVP(0); - vcs_deltag(0, false); - 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 == FALSE) { - vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); - vcs_deltag(1, false); - } - 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"); - } - } - - vcs_dcopy(VCS_DATA_PTR(fel), VCS_DATA_PTR(m_gibbsSpecies), m_numSpeciesRdc); - vcs_dcopy(VCS_DATA_PTR(feTrial), VCS_DATA_PTR(m_gibbsSpecies), m_numSpeciesRdc); - vcs_dcopy(VCS_DATA_PTR(ActCoeff0), VCS_DATA_PTR(ActCoeff), m_numSpeciesRdc); - vcs_dcopy(VCS_DATA_PTR(dgl), VCS_DATA_PTR(dg), m_numRxnRdc); - - /* Go find a new reaction adjustment -> - * i.e., change in extent of reaction for each reaction. - * - * 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(ds), m_numSpeciesTot); - /* - * Figure out whether we will calculate new reaction step sizes - * for the major species. - * -> We won't if all species are minors (im), OR - * all major species have already converged - */ - if (!(MajorSpeciesHaveConverged) && ! im) { - soldel = vcs_RxnStepSizes(); - /* - If SOLDEL is true then we encountered a reaction between */ - /* - single-species-phase species, only, and have adjusted */ - /* - the mole number vector, W(), directly. In this case, */ - /* - we should immediately go back and recompute a new */ - /* - component basis, if the species that was zeroed was */ - /* - a component. SOLDEL is true when this is so. */ - if (soldel > 0) { - /* - We have changed the base mole number amongst single- */ - /* - species-phase species. However, we don't need to */ - /* - recaculate their chemical potentials because they */ - /* - are constant, anyway! */ - if (soldel == 2) { - goto L_COMPONENT_CALC; - } - /* - We have not changed the actual DG values for */ - /* - any species, even the one we deleted. Thus, */ - /* - we don't need to start over. */ - } - } else { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (im) { - plogf(" --- vcs_RxnStepSizes not called because all" - "species are minors\n"); - } else { - plogf(" --- vcs_RxnStepSizes not called because " - "all majors have converged\n"); - } - } -#endif - } - - lec = FALSE; - /* - * Zero out the net change in moles of multispecies phases - */ - vcs_dzero(VCS_DATA_PTR(DelTPhMoles), NPhase); - /* **************************************************************** */ - /* ***************** MAIN LOOP IN CALCULATION ******************** */ - /* **************************************************************** */ - /* - * 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 wt[kspec] for all species consistent with an extent - * of reaction, ds[kspec] for all noncomponent species formation - * reactions. We will have also ensured that all predicted - * non-component mole numbers are greater than zero. - */ - if (m_VCount->Its > maxit) { - solveFail = -1; + char ANOTE[128]; /* - * Clean up and exit code even though we haven't - * converged. -> we have run out of iterations! + * Set the debug print lvl to the same as the print lvl. */ - goto L_RETURN_BLOCK; - } -#ifdef DEBUG_MODE - if (vcs_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(" Moles Tent_Moles Rxn_Adj | Comment \n"); - } + vcs_debug_print_lvl = printDetails; #endif - - for (irxn = 0; irxn < m_numRxnRdc; irxn++) { - kspec = ir[irxn]; - sc_irxn = sc[irxn]; - iph = PhaseID[kspec]; - Vphase = VPhaseList[iph]; -#ifdef DEBUG_MODE - ANOTE[0] = '\0'; -#endif - /********************************************************************/ - /********************** VOLTAGE SPECIES **************************/ - /********************************************************************/ - if (spStatus[irxn] == VCS_SPECIES_INTERFACIALVOLTAGE) { -#ifdef DEBUG_MODE - dx = minor_alt_calc(kspec, irxn, &soldel, ANOTE); -#else - dx = minor_alt_calc(kspec, irxn, &soldel); -#endif - ds[kspec] = dx; + if (printDetails > 0 && print_lvl == 0) { + print_lvl = 1; } - else if (spStatus[irxn] < VCS_SPECIES_MINOR) { - - /********************************************************************/ - /********************** ZEROED OUT SPECIES **************************/ - /********************************************************************/ - bool resurrect = true; -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 3) { - plogf(" --- %s currently zeroed (SpStatus=%-2d):", - SpName[kspec].c_str(), spStatus[irxn]); - plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n", - irxn, dg[irxn], wt[kspec], soln[kspec], ds[kspec]); + /* + * Initialize and set up all counters + */ + vcs_counters_init(0); + tsecond = vcs_second(); + + /* + * 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 sm(m_numElemConstraints*m_numElemConstraints, 0.0); + std::vector ss(m_numElemConstraints, 0.0); + std::vector sa(m_numElemConstraints, 0.0); + + std::vector aw(m_numSpeciesTot, 0.0); + std::vector wx(m_numElemConstraints, 0.0); + + solveFail = FALSE; + im = FALSE; + + /* ****************************************************** */ + /* **** Evaluate the elemental composition ****** */ + /* ****************************************************** */ + vcs_elab(); + + /* ******************************************************* */ + /* **** Printout the initial conditions for problem ****** */ + /* ******************************************************* */ + if (NPhase > 1) { + if (! VPhaseList[1]->SingleSpecies) { + liqphase = TRUE; + numSpecliquid = VPhaseList[1]->NVolSpecies; } -#endif - // HKM Alternative is to not allow ds[] = 0.0 phases - // to pop back into existence. For esthetics, I'm allowing this. - // so that dg < 0.0 phases with zero mole numbers become components. - // This is also better, because that component will be the first - // one to pop into existence if there is a minute quantity of the element. - // This could change in the future. - //if (dg[irxn] >= 0.0 || ds[kspec] <= 0.0) { - if (dg[irxn] >= 0.0 ) { - wt[kspec] = soln[kspec]; - ds[kspec] = 0.0; - resurrect = false; -#ifdef DEBUG_MODE - sprintf(ANOTE, "Species stays zeroed: DG = %11.4E", - dg[irxn]); - if (dg[irxn] < 0.0) { - sprintf(ANOTE, "Species stays zeroed even though dg neg:DG = %11.4E, ds zeroed ", - dg[irxn]); - } - //if (vcs_debug_print_lvl >= 2) { - //plogf(" --- "); plogf("%-12s", SpName[kspec]); - //plogf("%3d%11.4E%11.4E%11.4E | %s\n", - // spStatus[irxn], w[kspec], wt[kspec], - // ds[kspec], ANOTE); - //} -#endif - } else { - for (int j = 0; j < m_numElemConstraints; ++j) { - int elType = m_elType[j]; - if (elType == VCS_ELEM_TYPE_ABSPOS) { - double atomComp = FormulaMatrix[j][kspec]; - if (atomComp > 0.0) { - double maxPermissible = gai[j] / atomComp; - if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { -#ifdef DEBUG_MODE - sprintf(ANOTE, "Species stays zeroed even though dG neg, because of %s elemAbund", - ElName[j].c_str()); -#endif - resurrect = false; - break; - } - } - } - } + } + if (print_lvl != 0) { + plogf("VCS CALCULATION METHOD\n\n "); + plogf("%s\n", Title.c_str()); + plogf("\n\n%5d SPECIES%8d ELEMENTS", m_numSpeciesTot, m_numElemConstraints); + plogf("%16d COMPONENTS\n%5d PHASE1 SPECIES", m_numComponents, + ((VPhaseList[0])->NVolSpecies)); + plogf("%10d PHASE2 SPECIES%8d SINGLE SPECIES PHASES\n\n", + numSpecliquid, + m_numSpeciesTot - (VPhaseList[0])->NVolSpecies - numSpecliquid); + plogf(" PRESSURE%22.3f ATM\n TEMPERATURE%19.3f K\n", + Pres, T); + Vphase = VPhaseList[0]; + if (Vphase->NVolSpecies > 0) { + plogf(" PHASE1 INERTS%17.3f\n", TPhInertMoles[0]); } - /* - * Resurrect the species - */ - if (resurrect) { - if (Vphase->Existence == 0) Vphase->Existence = 1; - --m_numRxnMinorZeroed; + if (liqphase) { + 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", (ElName[i]).c_str()); + plogf("%20.12E%20.12E %3d\n", gai[i], ga[i], m_elType[i]); + } + if (iest < 0) { + plogf("\n MODIFIED LINEAR PROGRAMMING ESTIMATE OF EQUILIBRIUM\n"); + } + if (iest >= 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(29); + plogf(" STAN_CHEM_POT EQUILIBRIUM_EST. Species_Type\n\n"); + print_space(14); + for (i = 0; i < m_numElemConstraints; ++i) plogf(" %-2.2s", ElName[i].c_str()); + plogf(" SI(I)\n"); + RT = vcs_nondimMult_TP(m_VCS_UnitsFormat, T); + for (i = 0; i < m_numSpeciesTot; ++i) { + plogf(" %-12s", SpName[i].c_str()); + for (j = 0; j < m_numElemConstraints; ++j) { + plogf("%3g", FormulaMatrix[j][i]); + } + if (PhaseID[i] == 0) { + plogf(" 1"); + } else if (PhaseID[i] == 1) { + if (liqphase) plogf(" 2"); + else plogf(" 0"); + } else { + plogf(" 0"); + } + print_space(47-m_numElemConstraints*3); + plogf("%12.5E %12.5E", RT * ff[i], soln[i]); + if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { + plogf(" Mol_Num"); + } else if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + plogf(" Voltage"); + } else { + plogf(" Unknown"); + } + plogf(" \n"); + } + } + + for (i = 0; i < m_numSpeciesTot; ++i) { + if (soln[i] < 0.0) { + plogf("On Input species %-12s has a " + "negative MF, setting it small\n", + SpName[i].c_str()); + soln[i] = VCS_DELETE_SPECIES_CUTOFF; + } + } + + /* *********************************************** */ + /* **** EVALUATE TOTAL MOLES, GAS AND LIQUID ***** */ + /* *********************************************** */ + /* - Evaluate the total moles of gas and liquid */ + /* - These quantities are storred in the global variables */ + vcs_tmoles(); + /* ******************************************* */ + /* **** EVALUATE ALL CHEMICAL POTENTIALS ***** */ + /* ******************************************* */ + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); + /* + * HKM -> If there was a machine estimate, we used to branch + * to the code segment which determined whether we needed a + * new component basis. If we did, we would go to L429. + * If we didn't, we would go to a point below basopt() below. + * I have taken this section out of the code for simplicity's + * sake. It's not need for speed, since in any recursive + * call to this subroutine we would have an initial estimate + * of the solution. And, we don't need to optimize the + * startup of nonrecursive calls to this subroutine. + */ + /* *********************************************************** */ + /* **** 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; + + if (conv) { + goto L_RETURN_BLOCK; + } + it1 = 1; + MajorSpeciesHaveConverged = false; + /*************************************************************************/ + /************** EVALUATE INITIAL MAJOR-MINOR VECTOR **********************/ + /*************************************************************************/ + m_numRxnMinorZeroed = 0; + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + kspec = ir[irxn]; + spStatus[irxn] = vcs_species_type(kspec); + if (spStatus[irxn] == VCS_SPECIES_MINOR) { + spStatus[irxn] = VCS_SPECIES_MAJOR; #ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 2) { - plogf(" --- Zeroed species changed to major: "); + plogf(" --- Minor species changed to major: "); plogf("%-12s\n", SpName[kspec].c_str()); } #endif - spStatus[irxn] = VCS_SPECIES_MAJOR; - im = FALSE; - MajorSpeciesHaveConverged = false; - if (ds[kspec] > 0.0) { - dx = ds[kspec] * 0.01; - - wt[kspec] = soln[kspec] + dx; - } else { - wt[kspec] = TMoles * VCS_DELETE_PHASE_CUTOFF * 10.; - dx = wt[kspec] - soln[kspec]; - } - ds[kspec] = dx; -#ifdef DEBUG_MODE - sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", dg[irxn]); -#endif - } else { - wt[kspec] = soln[kspec]; - ds[kspec] = 0.0; - dx = 0.0; } - } else if (spStatus[irxn] == VCS_SPECIES_MINOR) { - /********************************************************************/ - /***************************** MINOR SPECIES ************************/ - /********************************************************************/ + if (spStatus[irxn] != VCS_SPECIES_MAJOR) { + ++m_numRxnMinorZeroed; + } + } + im = (m_numRxnMinorZeroed == m_numRxnRdc); + lec = FALSE; + if (! vcs_elabcheck(0)) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Element Abundance check failed\n"); + } +#endif + vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); + } +#ifdef DEBUG_MODE + else { + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Element Abundance check passed\n"); + } + } +#endif + // Update the phase objects with the contents of the soln vector + vcs_updateVP(0); + vcs_deltag(0, false); + 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) { /* - * Unless ITI isn't equal to zero we zero out changes - * to minor species. + * Evaluate the minor non-componenent species chemical + * potentials and delta G for their formation reactions + * We have already evaluated the major non-components */ - if (iti != 0) { - wt[kspec] = soln[kspec]; - ds[kspec] = 0.0; - dx = 0.0; -#ifdef DEBUG_MODE - sprintf(ANOTE,"minor species not considered"); - if (vcs_debug_print_lvl >= 2) { - plogf(" --- "); plogf("%-12s", SpName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s\n", - spStatus[irxn], soln[kspec], wt[kspec], - ds[kspec], ANOTE); - } -#endif - continue; + if (uptodate_minors == FALSE) { + vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); + vcs_deltag(1, false); } - /* - * 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. - */ -#ifdef DEBUG_MODE - dx = minor_alt_calc(kspec, irxn, &soldel, ANOTE); -#else - dx = minor_alt_calc(kspec, irxn, &soldel); -#endif - ds[kspec] = dx; - if (soldel) { - /*******************************************************************/ - /***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */ - /***** MOLE NUMBER */ - /*******************************************************************/ -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Delete minor species in multispec phase: %-12s\n", - SpName[kspec].c_str()); + 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"); + } + } + + vcs_dcopy(VCS_DATA_PTR(fel), VCS_DATA_PTR(m_gibbsSpecies), m_numSpeciesRdc); + vcs_dcopy(VCS_DATA_PTR(feTrial), VCS_DATA_PTR(m_gibbsSpecies), m_numSpeciesRdc); + vcs_dcopy(VCS_DATA_PTR(ActCoeff0), VCS_DATA_PTR(ActCoeff), m_numSpeciesRdc); + vcs_dcopy(VCS_DATA_PTR(dgl), VCS_DATA_PTR(dg), m_numRxnRdc); + + /* Go find a new reaction adjustment -> + * i.e., change in extent of reaction for each reaction. + * + * 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(ds), m_numSpeciesTot); + /* + * Figure out whether we will calculate new reaction step sizes + * for the major species. + * -> We won't if all species are minors (im), OR + * all major species have already converged + */ + if (!(MajorSpeciesHaveConverged) && ! im) { + soldel = vcs_RxnStepSizes(); + /* - If SOLDEL is true then we encountered a reaction between */ + /* - single-species-phase species, only, and have adjusted */ + /* - the mole number vector, W(), directly. In this case, */ + /* - we should immediately go back and recompute a new */ + /* - component basis, if the species that was zeroed was */ + /* - a component. SOLDEL is true when this is so. */ + if (soldel > 0) { + /* - We have changed the base mole number amongst single- */ + /* - species-phase species. However, we don't need to */ + /* - recaculate their chemical potentials because they */ + /* - are constant, anyway! */ + if (soldel == 2) { + goto L_COMPONENT_CALC; } -#endif - ds[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 = 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 + /* - We have not changed the actual DG values for */ + /* - any species, even the one we deleted. Thus, */ + /* - we don't need to start over. */ } } else { - /********************************************************************/ - /*********************** MAJOR SPECIES ******************************/ - /********************************************************************/ #ifdef DEBUG_MODE - sprintf(ANOTE, "Normal Major Calc"); + if (vcs_debug_print_lvl >= 2) { + if (im) { + plogf(" --- vcs_RxnStepSizes not called because all" + "species are minors\n"); + } else { + plogf(" --- vcs_RxnStepSizes not called because " + "all majors have converged\n"); + } + } #endif + } + + lec = FALSE; + /* + * Zero out the net change in moles of multispecies phases + */ + vcs_dzero(VCS_DATA_PTR(DelTPhMoles), NPhase); + /* **************************************************************** */ + /* ***************** MAIN LOOP IN CALCULATION ******************** */ + /* **************************************************************** */ + /* + * 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 wt[kspec] for all species consistent with an extent + * of reaction, ds[kspec] for all noncomponent species formation + * reactions. We will have also ensured that all predicted + * non-component mole numbers are greater than zero. + */ + if (m_VCount->Its > maxit) { + solveFail = -1; /* - * 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. + * Clean up and exit code even though we haven't + * converged. -> we have run out of iterations! */ - if (fabs(dg[irxn]) <= tolmaj2) { - wt[kspec] = soln[kspec]; - ds[kspec] = 0.0; - dx = 0.0; + goto L_RETURN_BLOCK; + } #ifdef DEBUG_MODE - sprintf(ANOTE, "major species is converged"); - if (vcs_debug_print_lvl >= 2) { - plogf(" --- "); plogf("%-12s", SpName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s\n", - spStatus[irxn], soln[kspec], wt[kspec], - ds[kspec], ANOTE); + if (vcs_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(" Moles Tent_Moles Rxn_Adj | Comment \n"); + } +#endif + + for (irxn = 0; irxn < m_numRxnRdc; irxn++) { + kspec = ir[irxn]; + sc_irxn = sc[irxn]; + iph = PhaseID[kspec]; + Vphase = VPhaseList[iph]; +#ifdef DEBUG_MODE + ANOTE[0] = '\0'; +#endif + /********************************************************************/ + /********************** VOLTAGE SPECIES **************************/ + /********************************************************************/ + if (spStatus[irxn] == VCS_SPECIES_INTERFACIALVOLTAGE) { +#ifdef DEBUG_MODE + dx = minor_alt_calc(kspec, irxn, &soldel, ANOTE); +#else + dx = minor_alt_calc(kspec, irxn, &soldel); +#endif + ds[kspec] = dx; + } + else if (spStatus[irxn] < VCS_SPECIES_MINOR) { + + /********************************************************************/ + /********************** ZEROED OUT SPECIES **************************/ + /********************************************************************/ + bool resurrect = true; +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 3) { + plogf(" --- %s currently zeroed (SpStatus=%-2d):", + SpName[kspec].c_str(), spStatus[irxn]); + plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n", + irxn, dg[irxn], wt[kspec], soln[kspec], ds[kspec]); } #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 ((dg[irxn] * ds[kspec]) <= 0.0) { - dx = ds[kspec]; - } else { - dx = 0.0; - ds[kspec] = 0.0; + // HKM Alternative is to not allow ds[] = 0.0 phases + // to pop back into existence. For esthetics, I'm allowing this. + // so that dg < 0.0 phases with zero mole numbers become components. + // This is also better, because that component will be the first + // one to pop into existence if there is a minute quantity of the element. + // This could change in the future. + //if (dg[irxn] >= 0.0 || ds[kspec] <= 0.0) { + if (dg[irxn] >= 0.0 ) { + wt[kspec] = soln[kspec]; + ds[kspec] = 0.0; + resurrect = false; #ifdef DEBUG_MODE - sprintf(ANOTE, "dx set to 0, DG flipped sign due to " - "changed initial point"); + sprintf(ANOTE, "Species stays zeroed: DG = %11.4E", + dg[irxn]); + if (dg[irxn] < 0.0) { + sprintf(ANOTE, "Species stays zeroed even though dg neg:DG = %11.4E, ds zeroed ", + dg[irxn]); + } + //if (vcs_debug_print_lvl >= 2) { + //plogf(" --- "); plogf("%-12s", SpName[kspec]); + //plogf("%3d%11.4E%11.4E%11.4E | %s\n", + // spStatus[irxn], w[kspec], wt[kspec], + // ds[kspec], ANOTE); + //} #endif - } - /* - * Form a tentative value of the new species moles - */ - wt[kspec] = soln[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 (wt[kspec] <= 0.0) { + } else { + for (int j = 0; j < m_numElemConstraints; ++j) { + int elType = m_elType[j]; + if (elType == VCS_ELEM_TYPE_ABSPOS) { + double atomComp = FormulaMatrix[j][kspec]; + if (atomComp > 0.0) { + double maxPermissible = gai[j] / atomComp; + if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { #ifdef DEBUG_MODE - sprintf(ANOTE, "initial nonpos moles= %11.3E", - wt[kspec]); + sprintf(ANOTE, "Species stays zeroed even though dG neg, because of %s elemAbund", + ElName[j].c_str()); #endif - /* ************************************************* */ - /* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */ - /* ************************************************* */ + resurrect = false; + break; + } + } + } + } + } /* - * We are here when a tentative value of a mole fraction - * created by a tentative value of DS(*) is negative. - * We branch from here depending upon whether this - * species is in a single species phase or in - * a multispecies phase. - */ - if (! (SSPhase[kspec])) { - /* - * Section for multispecies phases: - * - Cut reaction adjustment for positive moles of - * major species in multispecies phases. - * Decrease its concentration by a factor of 10. - */ - dx = -0.9 * soln[kspec]; + * Resurrect the species + */ + if (resurrect) { + if (Vphase->Existence == 0) Vphase->Existence = 1; + --m_numRxnMinorZeroed; +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Zeroed species changed to major: "); + plogf("%-12s\n", SpName[kspec].c_str()); + } +#endif + spStatus[irxn] = VCS_SPECIES_MAJOR; + im = FALSE; + MajorSpeciesHaveConverged = false; + if (ds[kspec] > 0.0) { + dx = ds[kspec] * 0.01; + + wt[kspec] = soln[kspec] + dx; + } else { + wt[kspec] = TMoles * VCS_DELETE_PHASE_CUTOFF * 10.; + dx = wt[kspec] - soln[kspec]; + } ds[kspec] = dx; - wt[kspec] = soln[kspec] + dx; +#ifdef DEBUG_MODE + sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", dg[irxn]); +#endif + } else { + wt[kspec] = soln[kspec]; + ds[kspec] = 0.0; + dx = 0.0; + } + } else if (spStatus[irxn] == VCS_SPECIES_MINOR) { + /********************************************************************/ + /***************************** MINOR SPECIES ************************/ + /********************************************************************/ + /* + * Unless ITI isn't equal to zero we zero out changes + * to minor species. + */ + if (iti != 0) { + wt[kspec] = soln[kspec]; + ds[kspec] = 0.0; + dx = 0.0; +#ifdef DEBUG_MODE + sprintf(ANOTE,"minor species not considered"); + if (vcs_debug_print_lvl >= 2) { + plogf(" --- "); plogf("%-12s", SpName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s\n", + spStatus[irxn], soln[kspec], wt[kspec], + ds[kspec], ANOTE); + } +#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. + */ +#ifdef DEBUG_MODE + dx = minor_alt_calc(kspec, irxn, &soldel, ANOTE); +#else + dx = minor_alt_calc(kspec, irxn, &soldel); +#endif + ds[kspec] = dx; + if (soldel) { + /*******************************************************************/ + /***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */ + /***** MOLE NUMBER */ + /*******************************************************************/ +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Delete minor species in multispec phase: %-12s\n", + SpName[kspec].c_str()); + } +#endif + ds[kspec] = 0.0; /* - * Change major to minor if the current species - * has a mole number that is less than 1/100 of the - * total moles in the problem. - * However, it also has to be a small species within its - * own phase as well. - * we can't call vcs_species_type() because the phase moles - * would be wrong. + * 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. */ - if (wt[kspec] < 0.005 * TMoles) { - iph = PhaseID[kspec]; - if (wt[kspec] < (TPhMoles[iph] * 0.01)) { + lnospec = 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(dg[irxn]) <= tolmaj2) { + wt[kspec] = soln[kspec]; + ds[kspec] = 0.0; + dx = 0.0; +#ifdef DEBUG_MODE + sprintf(ANOTE, "major species is converged"); + if (vcs_debug_print_lvl >= 2) { + plogf(" --- "); plogf("%-12s", SpName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s\n", + spStatus[irxn], soln[kspec], wt[kspec], + ds[kspec], ANOTE); + } +#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 ((dg[irxn] * ds[kspec]) <= 0.0) { + dx = ds[kspec]; + } else { + dx = 0.0; + ds[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 + */ + wt[kspec] = soln[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 (wt[kspec] <= 0.0) { +#ifdef DEBUG_MODE + sprintf(ANOTE, "initial nonpos moles= %11.3E", + wt[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 DS(*) is negative. + * We branch from here depending upon whether this + * species is in a single species phase or in + * a multispecies phase. + */ + if (! (SSPhase[kspec])) { + /* + * Section for multispecies phases: + * - Cut reaction adjustment for positive moles of + * major species in multispecies phases. + * Decrease its concentration by a factor of 10. + */ + dx = -0.9 * soln[kspec]; + ds[kspec] = dx; + wt[kspec] = soln[kspec] + dx; + /* + * Change major to minor if the current species + * has a mole number that is less than 1/100 of the + * total moles in the problem. + * However, it also has to be a small species within its + * own phase as well. + * we can't call vcs_species_type() because the phase moles + * would be wrong. + */ + if (wt[kspec] < 0.005 * TMoles) { + iph = PhaseID[kspec]; + if (wt[kspec] < (TPhMoles[iph] * 0.01)) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Major species changed to minor: "); + plogf("%-12s\n", SpName[kspec].c_str()); + } +#endif + spStatus[irxn] = VCS_SPECIES_MINOR; + ++m_numRxnMinorZeroed; + im = (m_numRxnMinorZeroed == m_numRxnRdc); + } + } + } else { + /* + * Section for single species phases: + * Calculate a dx that will wipe out the + * moles in the phase. + */ + dx = -soln[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] = soln[j] + sc_irxn[j] * dx; + if (wx[j] <= soln[j] * 0.01 - 1.0E-150) { + dx = MAX(dx, soln[j] * -0.99 / sc_irxn[j]); + } + } else { + wx[j] = soln[j]; + } + } + wt[kspec] = soln[kspec] + dx; + if (wt[kspec] > 0.0) { + ds[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 = PhaseID[kspec]; + Vphase = VPhaseList[iph]; + Vphase->Existence = 0; +#ifdef DEBUG_MODE + sprintf(ANOTE, "zero SS phase: moles went neg"); +#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. + */ + soln[kspec] = 0.0; + for (j = 0; j < m_numComponents; ++j) { + soln[j] = wx[j]; + } + /* + * Change the total number of moles in all phases due to + * the reaction that wil be zeroing out the pure species + * phase. Make sure the moles in the current ss phase is + * identically zero. + */ + dnPhase_irxn = DnPhase[irxn]; + for (int iphase = 0; iphase < NPhase; iphase++) { + TPhMoles[iphase] += dnPhase_irxn[iphase] * dx; + } + TPhMoles[iph] = 0.0; + vcs_updateVP(0); + /* + * Recalcuate the chemical potentials, FE(), and the + * reaction free energy changes, DG(), for the current + * set of reactions being considered. The set of reactions + * is determined by the value of iti. + */ + vcs_dfe(VCS_DATA_PTR(soln), 0, iti, 0, m_numSpeciesRdc); + vcs_deltag(iti, false); + /* + * Redefine the starting conditions for noncomponents + * which have yet to be processed in the main loop + */ + for (ll = kspec+1; ll < m_numSpeciesRdc; ++ll) { + fel[ll] = m_gibbsSpecies[ll]; + } + for (ll = irxn+1; ll < m_numRxnRdc; ++ll) { + dgl[ll] = dg[ll]; + } #ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 2) { - plogf(" --- Major species changed to minor: "); - plogf("%-12s\n", SpName[kspec].c_str()); + if (spStatus[irxn] >= 0) { + plogf(" --- SS species changed to zeroedss: "); + plogf("%-12s\n", SpName[kspec].c_str()); + } } #endif - spStatus[irxn] = VCS_SPECIES_MINOR; + spStatus[irxn] = VCS_SPECIES_ZEROEDSS; ++m_numRxnMinorZeroed; im = (m_numRxnMinorZeroed == m_numRxnRdc); - } - } - } else { - /* - * Section for single species phases: - * Calculate a dx that will wipe out the - * moles in the phase. - */ - dx = -soln[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] = soln[j] + sc_irxn[j] * dx; - if (wx[j] <= soln[j] * 0.01 - 1.0E-150) { - dx = MAX(dx, soln[j] * -0.99 / sc_irxn[j]); + if (im && iti != 0) { + goto L_EQUILIB_CHECK; } - } else { - wx[j] = soln[j]; + wt[kspec] = soln[kspec]; + ds[kspec] = 0.0; + dx = 0.0; } } - wt[kspec] = soln[kspec] + dx; - if (wt[kspec] > 0.0) { - ds[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 = PhaseID[kspec]; - Vphase = VPhaseList[iph]; - Vphase->Existence = 0; -#ifdef DEBUG_MODE - sprintf(ANOTE, "zero SS phase: moles went neg"); -#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. - */ - soln[kspec] = 0.0; - for (j = 0; j < m_numComponents; ++j) { - soln[j] = wx[j]; - } - /* - * Change the total number of moles in all phases due to - * the reaction that wil be zeroing out the pure species - * phase. Make sure the moles in the current ss phase is - * identically zero. - */ - dnPhase_irxn = DnPhase[irxn]; - for (int iphase = 0; iphase < NPhase; iphase++) { - TPhMoles[iphase] += dnPhase_irxn[iphase] * dx; - } - TPhMoles[iph] = 0.0; - vcs_updateVP(0); - /* - * Recalcuate the chemical potentials, FE(), and the - * reaction free energy changes, DG(), for the current - * set of reactions being considered. The set of reactions - * is determined by the value of iti. - */ - vcs_dfe(VCS_DATA_PTR(soln), 0, iti, 0, m_numSpeciesRdc); - vcs_deltag(iti, false); - /* - * Redefine the starting conditions for noncomponents - * which have yet to be processed in the main loop - */ - for (ll = kspec+1; ll < m_numSpeciesRdc; ++ll) { - fel[ll] = m_gibbsSpecies[ll]; - } - for (ll = irxn+1; ll < m_numRxnRdc; ++ll) { - dgl[ll] = dg[ll]; - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (spStatus[irxn] >= 0) { - plogf(" --- SS species changed to zeroedss: "); - plogf("%-12s\n", SpName[kspec].c_str()); - } - } -#endif - spStatus[irxn] = VCS_SPECIES_ZEROEDSS; - ++m_numRxnMinorZeroed; - im = (m_numRxnMinorZeroed == m_numRxnRdc); - if (im && iti != 0) { - goto L_EQUILIB_CHECK; - } - wt[kspec] = soln[kspec]; - ds[kspec] = 0.0; - dx = 0.0; - } } - } - /*********************************************************************/ - /*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/ - /*********************************************************************/ - /* - * Skip the line search if we are birthing a species - */ - if (dx != 0.0 && (soln[kspec] > 0.0) && - (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { - double dx_old = dx; + /*********************************************************************/ + /*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/ + /*********************************************************************/ + /* + * Skip the line search if we are birthing a species + */ + if (dx != 0.0 && (soln[kspec] > 0.0) && + (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { + double dx_old = dx; #ifdef DEBUG_MODE - dx = vcs_line_search(irxn, dx_old, ANOTE); + dx = vcs_line_search(irxn, dx_old, ANOTE); #else - dx = vcs_line_search(irxn, dx_old); + dx = vcs_line_search(irxn, dx_old); #endif - } - ds[kspec] = dx; + } + ds[kspec] = dx; - } /* End of Loop on ic[irxn] -> the type of species */ + } /* End of Loop on ic[irxn] -> the type of species */ /***********************************************************************/ /****** CALCULATE MOLE NUMBER CHANGE FOR THE COMPONENT BASIS ***********/ /***********************************************************************/ - if (dx != 0.0 && (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. - */ + if (dx != 0.0 && (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 (ds[kspec] != dx) { - plogf("we have a problem!\n"); + if (ds[kspec] != dx) { + plogf("we have a problem!\n"); + exit(-1); + } +#endif + for (k = 0; k < m_numComponents; ++k) { + ds[k] += sc_irxn[k] * dx; + } + /* + * Calculate the tentative change in the total number of + * moles in all of the phases + */ + + dnPhase_irxn = DnPhase[irxn]; + for (iph = 0; iph < NPhase; iph++) { + DelTPhMoles[iph] += dx * dnPhase_irxn[iph]; + } + } +#ifdef DEBUG_MODE + checkDelta1(VCS_DATA_PTR(ds), VCS_DATA_PTR(DelTPhMoles), kspec+1); +#endif + /* + * Branch point for returning - + */ +#ifndef DEBUG_MODE + L_MAIN_LOOP_END: ; +#endif +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + wt[kspec] = soln[kspec] + ds[kspec]; + plogf(" --- "); plogf("%-12.12s", SpName[kspec].c_str()); + plogf("%3d%11.4E%11.4E%11.4E | %s\n", + spStatus[irxn], soln[kspec], wt[kspec], + ds[kspec], ANOTE); + } + L_MAIN_LOOP_END_NO_PRINT: ; +#endif + /**************** END OF MAIN LOOP OVER FORMATION REACTIONS ************/ + } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + for (k = 0; k < m_numComponents; k++) { + plogf(" --- "); plogf("%-12.12s", SpName[k].c_str()); + plogf(" c%11.4E%11.4E%11.4E |\n", + soln[k], soln[k]+ds[k], ds[k]); + } + plogf(" "); vcs_print_line("-", 80); + plogf(" --- Finished Main Loop\n"); + } +#endif + /*************************************************************************/ + /*********** LIMIT REDUCTION OF BASIS SPECIES TO 99% *********************/ + /*************************************************************************/ + /* + * We have a tentative DS(L=1,MR). Now apply other criteria + * to limit it's magnitude. + */ + par = 0.5; + for (k = 0; k < m_numComponents; ++k) { + if (soln[k] > 0.0) { + xx = -ds[k] / soln[k]; + if (par < xx) { + par = xx; +#ifdef DEBUG_MODE + ll = k; +#endif + } + } else { + if (ds[k] < 0.0) { + /* + * If we are here, we then do a step which violates element + * conservation. + */ + iph = PhaseID[k]; + DelTPhMoles[iph] -= ds[k]; + ds[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 (vcs_debug_print_lvl >= 2) { + plogf(" --- Reduction in step size due to component "); + plogf("%s", SpName[ll].c_str()); + plogf(" going negative = %11.3E\n", par); + } +#endif + for (i = 0; i < m_numSpeciesTot; ++i) { + ds[i] *= par; + } + for (iph = 0; iph < NPhase; iph++) { + DelTPhMoles[iph] *= par; + } + } else { + par = 1.0; + } +#ifdef DEBUG_MODE + checkDelta1(VCS_DATA_PTR(ds), VCS_DATA_PTR(DelTPhMoles), m_numSpeciesTot); +#endif + + /* + * Now adjust the wt[kspec]'s so that the reflect the decrease in + * the overall length of ds[kspec] just calculated. At the end + * of this section wt[], ds[], tPhMoles, and tPhMoles1 should all be + * consistent with a new estimate of the state of the system. + */ + for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { + wt[kspec] = soln[kspec] + ds[kspec]; + if (wt[kspec] < 0.0 && (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { + plogf("vcs_solve_TP: ERROR on step change wt[%d:%s]: %g < 0.0\n", + kspec, SpName[kspec].c_str(), wt[kspec]); exit(-1); } -#endif - for (k = 0; k < m_numComponents; ++k) { - ds[k] += sc_irxn[k] * dx; - } - /* - * Calculate the tentative change in the total number of - * moles in all of the phases - */ - - dnPhase_irxn = DnPhase[irxn]; - for (iph = 0; iph < NPhase; iph++) { - DelTPhMoles[iph] += dx * dnPhase_irxn[iph]; - } } -#ifdef DEBUG_MODE - checkDelta1(VCS_DATA_PTR(ds), VCS_DATA_PTR(DelTPhMoles), kspec+1); -#endif + /* - * Branch point for returning - + * Calculate the tentative total mole numbers for each phase */ -#ifndef DEBUG_MODE - L_MAIN_LOOP_END: ; -#endif -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - wt[kspec] = soln[kspec] + ds[kspec]; - plogf(" --- "); plogf("%-12.12s", SpName[kspec].c_str()); - plogf("%3d%11.4E%11.4E%11.4E | %s\n", - spStatus[irxn], soln[kspec], wt[kspec], - ds[kspec], ANOTE); - } - L_MAIN_LOOP_END_NO_PRINT: ; -#endif - /**************** END OF MAIN LOOP OVER FORMATION REACTIONS ************/ - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - for (k = 0; k < m_numComponents; k++) { - plogf(" --- "); plogf("%-12.12s", SpName[k].c_str()); - plogf(" c%11.4E%11.4E%11.4E |\n", - soln[k], soln[k]+ds[k], ds[k]); - } - plogf(" "); vcs_print_line("-", 80); - plogf(" --- Finished Main Loop\n"); - } -#endif - /*************************************************************************/ - /*********** LIMIT REDUCTION OF BASIS SPECIES TO 99% *********************/ - /*************************************************************************/ - /* - * We have a tentative DS(L=1,MR). Now apply other criteria - * to limit it's magnitude. - */ - par = 0.5; - for (k = 0; k < m_numComponents; ++k) { - if (soln[k] > 0.0) { - xx = -ds[k] / soln[k]; - if (par < xx) { - par = xx; -#ifdef DEBUG_MODE - ll = k; -#endif - } - } else { - if (ds[k] < 0.0) { - /* - * If we are here, we then do a step which violates element - * conservation. - */ - iph = PhaseID[k]; - DelTPhMoles[iph] -= ds[k]; - ds[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 (vcs_debug_print_lvl >= 2) { - plogf(" --- Reduction in step size due to component "); - plogf("%s", SpName[ll].c_str()); - plogf(" going negative = %11.3E\n", par); - } -#endif - for (i = 0; i < m_numSpeciesTot; ++i) { - ds[i] *= par; - } for (iph = 0; iph < NPhase; iph++) { - DelTPhMoles[iph] *= par; + TPhMoles1[iph] = TPhMoles[iph] + DelTPhMoles[iph]; } - } else { - par = 1.0; - } + /* + * 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_updateVP(1); + vcs_dfe(VCS_DATA_PTR(wt), 1, iti, 0, m_numSpeciesTot); + /* + * Evaluate DeltaG for all components if ITI=0, and for + * major components only if ITI NE 0 + */ + if (iti == 0) vcs_deltag(0, false); + else vcs_deltag(-1, false); + + /* + * Print Intermediate results + */ + // HKM Actually always need to calculate this + // or else nonprintouts get different results and sometimes + // fail in the line search algorithm -> Why is this? + vcs_dfe(VCS_DATA_PTR(wt), 1, 1, 0, m_numSpeciesRdc); + if (printDetails) { + if (iti != 0) { #ifdef DEBUG_MODE - checkDelta1(VCS_DATA_PTR(ds), VCS_DATA_PTR(DelTPhMoles), m_numSpeciesTot); + if (vcs_debug_print_lvl >= 2) { + plogf(" *** vcs_dfe for printout only:"); + } #endif - - /* - * Now adjust the wt[kspec]'s so that the reflect the decrease in - * the overall length of ds[kspec] just calculated. At the end - * of this section wt[], ds[], tPhMoles, and tPhMoles1 should all be - * consistent with a new estimate of the state of the system. - */ - for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { - wt[kspec] = soln[kspec] + ds[kspec]; - if (wt[kspec] < 0.0 && (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) { - plogf("vcs_solve_TP: ERROR on step change wt[%d:%s]: %g < 0.0\n", - kspec, SpName[kspec].c_str(), wt[kspec]); - exit(-1); - } - } - - /* - * Calculate the tentative total mole numbers for each phase - */ - for (iph = 0; iph < NPhase; iph++) { - TPhMoles1[iph] = TPhMoles[iph] + DelTPhMoles[iph]; - } - /* - * 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_updateVP(1); - vcs_dfe(VCS_DATA_PTR(wt), 1, iti, 0, m_numSpeciesTot); - /* - * Evaluate DeltaG for all components if ITI=0, and for - * major components only if ITI NE 0 - */ - if (iti == 0) vcs_deltag(0, false); - else vcs_deltag(-1, false); - - /* - * Print Intermediate results - */ - // HKM Actually always need to calculate this - // or else nonprintouts get different results and sometimes - // fail in the line search algorithm -> Why is this? - vcs_dfe(VCS_DATA_PTR(wt), 1, 1, 0, m_numSpeciesRdc); - if (printDetails) { - if (iti != 0) { + vcs_dfe(VCS_DATA_PTR(wt), 1, 1, 0, m_numSpeciesRdc); #ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" *** vcs_dfe for printout only:"); + if (vcs_debug_print_lvl >= 2) { + plogf(" *** vcs_deltag for printout only:"); + } +#endif + vcs_deltag(1, false); } -#endif - vcs_dfe(VCS_DATA_PTR(wt), 1, 1, 0, m_numSpeciesRdc); -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" *** vcs_deltag for printout only:"); - } -#endif - vcs_deltag(1, false); - } - plogf(" "); vcs_print_line("-", 103); - plogf(" --- Summary of the Update "); - if (iti == 0) { - plogf(" (all species):\n"); - } else { - plogf(" (only major species):\n"); - } - plogf(" --- Species Status Initial_Moles Final_Moles Initial_Mu/RT"); - plogf(" Mu/RT Init_Del_G/RT Delta_G/RT\n"); - for (i = 0; i < m_numComponents; ++i) { - plogf(" --- %-12.12s", SpName[i].c_str()); plogf(" "); - plogf("%14.6E%14.6E%14.6E%14.6E\n", soln[i], - wt[i], fel[i], m_gibbsSpecies[i]); - } - for (i = m_numComponents; i < m_numSpeciesRdc; ++i) { - l1 = i - m_numComponents; - plogf(" --- %-12.12s", SpName[i].c_str()); - plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", - spStatus[l1], soln[i], - wt[i], fel[i], m_gibbsSpecies[i], - dgl[l1], dg[l1]); - } - for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { - l1 = kspec - m_numComponents; - plogf(" --- %-12.12s", SpName[kspec].c_str()); - plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", - spStatus[l1], soln[kspec], - wt[kspec], fel[kspec], m_gibbsSpecies[kspec], - dgl[l1], dg[l1]); - } - plogf(" ---"); print_space(56); - plogf("Norms of Delta G():%14.6E%14.6E\n", - l2normdg(VCS_DATA_PTR(dgl)), - l2normdg(VCS_DATA_PTR(dg))); + plogf(" "); vcs_print_line("-", 103); + plogf(" --- Summary of the Update "); + if (iti == 0) { + plogf(" (all species):\n"); + } else { + plogf(" (only major species):\n"); + } + plogf(" --- Species Status Initial_Moles Final_Moles Initial_Mu/RT"); + plogf(" Mu/RT Init_Del_G/RT Delta_G/RT\n"); + for (i = 0; i < m_numComponents; ++i) { + plogf(" --- %-12.12s", SpName[i].c_str()); plogf(" "); + plogf("%14.6E%14.6E%14.6E%14.6E\n", soln[i], + wt[i], fel[i], m_gibbsSpecies[i]); + } + for (i = m_numComponents; i < m_numSpeciesRdc; ++i) { + l1 = i - m_numComponents; + plogf(" --- %-12.12s", SpName[i].c_str()); + plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", + spStatus[l1], soln[i], + wt[i], fel[i], m_gibbsSpecies[i], + dgl[l1], dg[l1]); + } + for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { + l1 = kspec - m_numComponents; + plogf(" --- %-12.12s", SpName[kspec].c_str()); + plogf(" %2d %14.6E%14.6E%14.6E%14.6E%14.6E%14.6E\n", + spStatus[l1], soln[kspec], + wt[kspec], fel[kspec], m_gibbsSpecies[kspec], + dgl[l1], dg[l1]); + } + plogf(" ---"); print_space(56); + plogf("Norms of Delta G():%14.6E%14.6E\n", + l2normdg(VCS_DATA_PTR(dgl)), + l2normdg(VCS_DATA_PTR(dg))); - plogf(" --- Phase_Name Moles(after update)\n"); - plogf(" --- "); vcs_print_line("-", 50); - for (iph = 0; iph < NPhase; iph++) { - Vphase = VPhaseList[iph]; - plogf(" --- %18s = %15.7E\n", Vphase->PhaseName.c_str(), TPhMoles1[iph]); - } - plogf(" "); vcs_print_line("-", 103); - plogf(" --- Total Dimensionless Gibbs Free Energy = %15.7E\n", - vcs_Total_Gibbs(VCS_DATA_PTR(wt), VCS_DATA_PTR(m_gibbsSpecies), - VCS_DATA_PTR(TPhMoles1))); - if (m_VCount->Its > 150) { - plogf(" --- Troublesome solve\n"); - } + plogf(" --- Phase_Name Moles(after update)\n"); + plogf(" --- "); vcs_print_line("-", 50); + for (iph = 0; iph < NPhase; iph++) { + Vphase = VPhaseList[iph]; + plogf(" --- %18s = %15.7E\n", Vphase->PhaseName.c_str(), TPhMoles1[iph]); + } + plogf(" "); vcs_print_line("-", 103); + plogf(" --- Total Dimensionless Gibbs Free Energy = %15.7E\n", + vcs_Total_Gibbs(VCS_DATA_PTR(wt), VCS_DATA_PTR(m_gibbsSpecies), + VCS_DATA_PTR(TPhMoles1))); + if (m_VCount->Its > 150) { + plogf(" --- Troublesome solve\n"); + } #ifdef DEBUG_MODE #ifdef DEBUG_NOT - if (vcs_debug_print_lvl >= 3) { - prneav(); - } -#endif -#endif - } - /* *************************************************************** */ - /* **** CONVERGENCE FORCER SECTION ******************************* */ - /* *************************************************************** */ - /* - * Save the previous delta G in the old vector for - * printout purposes - */ - if (printDetails) { - vcs_dcopy(VCS_DATA_PTR(dgl), VCS_DATA_PTR(dg), m_numRxnRdc); - } - forced = FALSE; - // if (! im && ! MajorSpeciesHaveConverged) { - forced = force(iti); - //} - /* - * Print out the changes to the solution that FORCER produced - */ - if (printDetails && forced) { - - if (iti != 0) { -#ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 3) { - plogf(" *** vcs_dfe for printout only:"); - } -#endif - vcs_updateVP(0); - vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 3) { - plogf(" *** vcs_deltag call for printouts only;"); + prneav(); } #endif - vcs_deltag(1, false); - } - plogf(" -----------------------------------------------------\n"); - plogf(" --- FORCER SUBROUTINE changed the solution:\n"); - plogf(" --- SPECIES Status TENT MOLES"); - plogf(" FINAL MOLES TENT_DEL_G/RT FINAL_DELTA_G/RT\n"); - for (i = 0; i < m_numComponents; ++i) { - plogf(" --- %-12.12s", SpName[i].c_str()); - plogf(" %14.6E%14.6E\n", wt[i], soln[i]); - } - for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) { - irxn = kspec - m_numComponents; - plogf(" --- %-12.12s", SpName[kspec].c_str()); - plogf(" %2d %14.6E%14.6E%14.6E%14.6E\n", spStatus[irxn], - wt[kspec], soln[kspec], dgl[irxn], dg[irxn]); - } - print_space(26); - plogf("Norms of Delta G():%14.6E%14.6E\n", - l2normdg(VCS_DATA_PTR(dgl)), - l2normdg(VCS_DATA_PTR(dg))); - plogf(" Total moles of gas = %15.7E\n", TPhMoles[0]); - if ((NPhase > 1) && (! (VPhaseList[1])->SingleSpecies)) { - plogf(" Total moles of liquid = %15.7E\n", TPhMoles[1]); - } else { - plogf(" Total moles of liquid = %15.7E\n", 0.0); - } - plogf(" Total Dimensionless Gibbs Free Energy = %15.7E\n", - vcs_Total_Gibbs(VCS_DATA_PTR(soln), VCS_DATA_PTR(m_gibbsSpecies), - VCS_DATA_PTR(TPhMoles))); - plogf(" -----------------------------------------------------\n"); - } - /*************************************************************************/ - /******************* 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. - */ - if (! forced) { - vcs_dcopy(VCS_DATA_PTR(TPhMoles), VCS_DATA_PTR(TPhMoles1), NPhase); - vcs_dcopy(VCS_DATA_PTR(soln), VCS_DATA_PTR(wt), m_numSpeciesRdc); - } - vcs_updateVP(0); - /* - * Increment the iteration counters - */ - ++(m_VCount->Its); - ++it1; -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Increment counter increased, step is accepted: %4d\n", - m_VCount->Its); - } #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 < NPhase; iph++) { - Vphase = VPhaseList[iph]; - if (!(Vphase->SingleSpecies)) { - if (TPhMoles[iph] != 0.0 && - TPhMoles[iph]/TMoles <= VCS_DELETE_PHASE_CUTOFF) { - soldel = 1; - for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - if (PhaseID[kspec] == iph && soln[kspec] > 0.0) { - irxn = kspec - m_numComponents; - if (kspec < m_numComponents) { - if (soln[kspec] > VCS_DELETE_SPECIES_CUTOFF) { - soldel = 0; - break; - } - } else { - for (k = 0; k < m_numComponents; k++) { - if (sc[irxn][k] != 0.0) { - if (soln[kspec]/soln[k] > VCS_DELETE_PHASE_CUTOFF) { - soldel = 0; - break; + } + /* *************************************************************** */ + /* **** CONVERGENCE FORCER SECTION ******************************* */ + /* *************************************************************** */ + /* + * Save the previous delta G in the old vector for + * printout purposes + */ + if (printDetails) { + vcs_dcopy(VCS_DATA_PTR(dgl), VCS_DATA_PTR(dg), m_numRxnRdc); + } + forced = FALSE; + // if (! im && ! MajorSpeciesHaveConverged) { + forced = force(iti); + //} + /* + * Print out the changes to the solution that FORCER produced + */ + if (printDetails && forced) { + + if (iti != 0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 3) { + plogf(" *** vcs_dfe for printout only:"); + } +#endif + vcs_updateVP(0); + vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 3) { + plogf(" *** vcs_deltag call for printouts only;"); + } +#endif + vcs_deltag(1, false); + } + plogf(" -----------------------------------------------------\n"); + plogf(" --- FORCER SUBROUTINE changed the solution:\n"); + plogf(" --- SPECIES Status TENT MOLES"); + plogf(" FINAL MOLES TENT_DEL_G/RT FINAL_DELTA_G/RT\n"); + for (i = 0; i < m_numComponents; ++i) { + plogf(" --- %-12.12s", SpName[i].c_str()); + plogf(" %14.6E%14.6E\n", wt[i], soln[i]); + } + for (kspec = m_numComponents; kspec < m_numSpeciesRdc; ++kspec) { + irxn = kspec - m_numComponents; + plogf(" --- %-12.12s", SpName[kspec].c_str()); + plogf(" %2d %14.6E%14.6E%14.6E%14.6E\n", spStatus[irxn], + wt[kspec], soln[kspec], dgl[irxn], dg[irxn]); + } + print_space(26); + plogf("Norms of Delta G():%14.6E%14.6E\n", + l2normdg(VCS_DATA_PTR(dgl)), + l2normdg(VCS_DATA_PTR(dg))); + plogf(" Total moles of gas = %15.7E\n", TPhMoles[0]); + if ((NPhase > 1) && (! (VPhaseList[1])->SingleSpecies)) { + plogf(" Total moles of liquid = %15.7E\n", TPhMoles[1]); + } else { + plogf(" Total moles of liquid = %15.7E\n", 0.0); + } + plogf(" Total Dimensionless Gibbs Free Energy = %15.7E\n", + vcs_Total_Gibbs(VCS_DATA_PTR(soln), VCS_DATA_PTR(m_gibbsSpecies), + VCS_DATA_PTR(TPhMoles))); + plogf(" -----------------------------------------------------\n"); + } + /*************************************************************************/ + /******************* 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. + */ + if (! forced) { + vcs_dcopy(VCS_DATA_PTR(TPhMoles), VCS_DATA_PTR(TPhMoles1), NPhase); + vcs_dcopy(VCS_DATA_PTR(soln), VCS_DATA_PTR(wt), m_numSpeciesRdc); + } + vcs_updateVP(0); + /* + * Increment the iteration counters + */ + ++(m_VCount->Its); + ++it1; +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Increment counter increased, step is accepted: %4d\n", + m_VCount->Its); + } +#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 < NPhase; iph++) { + Vphase = VPhaseList[iph]; + if (!(Vphase->SingleSpecies)) { + if (TPhMoles[iph] != 0.0 && + TPhMoles[iph]/TMoles <= VCS_DELETE_PHASE_CUTOFF) { + soldel = 1; + for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + if (PhaseID[kspec] == iph && soln[kspec] > 0.0) { + irxn = kspec - m_numComponents; + if (kspec < m_numComponents) { + if (soln[kspec] > VCS_DELETE_SPECIES_CUTOFF) { + soldel = 0; + break; + } + } else { + for (k = 0; k < m_numComponents; k++) { + if (sc[irxn][k] != 0.0) { + if (soln[kspec]/soln[k] > VCS_DELETE_PHASE_CUTOFF) { + soldel = 0; + break; + } } } } } } - } - if (soldel) { + if (soldel) { #ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 1) { - plogf(" --- Setting microscopic phase %d to zero\n", iph); - } -#endif - justDeletedMultiPhase = TRUE; - 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) return retn; - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); - vcs_deltag(0, true); - uptodate_minors = TRUE; - if (conv) { - /* - * HKM -> I don't understand why the code would just give - * up here in some cases. - * This should probably be taken out - */ - plogf(" DELETION OF MULTISPECIES PHASE. "); - plogf("Convergence to number of positive n(i) less than C.\n"); - plogf("Check results to follow carefully. \n\n"); - goto L_RETURN_BLOCK; - } - } - /*************************************************************************/ - /***************** CHECK FOR ELEMENT ABUNDANCE****************************/ - /*************************************************************************/ -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Normal element abundance check"); - } -#endif - vcs_elab(); - if (! vcs_elabcheck(0)) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" - failed -> redoing element abundances.\n"); - } -#endif - vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); - vcs_deltag(0, true); - uptodate_minors = TRUE; - } -#ifdef DEBUG_MODE - else { - if (vcs_debug_print_lvl >= 2) { - plogf(" - passed\n"); - } - } -#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 (soln[i - 1] < soln[i]) { - dofast = FALSE; - break; - } - } - dofast = false; - if (dofast) { - for (i = 0; i < m_numRxnRdc; ++i) { - l = ir[i]; - for (j = m_numComponents - 1; j >= 0; j--) { - if (soln[l] > soln[j]) { - if (sc[i][j] != 0.0) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Get a new basis because %s", SpName[l].c_str()); - plogf(" is larger than comp %s", SpName[j].c_str()); - plogf(" and share nonzero stoic: %-9.1f\n", - sc[i][j]); + if (vcs_debug_print_lvl >= 1) { + plogf(" --- Setting microscopic phase %d to zero\n", iph); } -#endif - goto L_COMPONENT_CALC; - } - } else { - break; - } -#ifdef DEBUG_NOT - if (spStatus[i] == VCS_SPECIES_ZEROEDMS) { - if (soln[j] == 0.0) { - if (sc[i][j] != 0.0) { - if (dg[i] < 0.0) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Get a new basis because %s", SpName[l].c_str()); - plogf(" has dg < 0.0 and comp %s has zero mole num", SpName[j].c_str()); - plogf(" and share nonzero stoic: %-9.1f\n", - sc[i][j]); - } -#endif - goto L_COMPONENT_CALC; - } - } - } - } #endif + justDeletedMultiPhase = TRUE; + delete_multiphase(iph); + } + } } } - } else { - for (i = 0; i < m_numRxnRdc; ++i) { - l = ir[i]; - for (j = 0; j < m_numComponents; ++j) { - if (soln[l] > soln[j]) { - if (sc[i][j] != 0.0) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Get a new basis because "); - plogf("%s", SpName[l].c_str()); - plogf(" is larger than comp "); - plogf("%s", SpName[j].c_str()); - plogf(" and share nonzero stoic: %-9.1f\n", - sc[i][j]); - } -#endif - goto L_COMPONENT_CALC; - } - } -#ifdef DEBUG_NOT - if (spStatus[i] == VCS_SPECIES_ZEROEDMS) { - if (soln[j] == 0.0) { - if (sc[i][j] != 0.0) { - if (dg[i] < 0.0) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Get a new basis because %s", SpName[l].c_str()); - plogf(" has dg < 0.0 and comp %s has zero mole num", SpName[j].c_str()); - plogf(" and share nonzero stoic: %-9.1f\n", - sc[i][j]); - } -#endif - goto L_COMPONENT_CALC; - } - } - } - } -#endif - } - } - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Check for an optimum basis passed\n"); - } -#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 (vcs_debug_print_lvl >= 2) { - plogf(" --- Reevaluate major-minor status of noncomponents:\n"); - } -#endif - m_numRxnMinorZeroed = 0; - for (irxn = 0; irxn < m_numRxnRdc; irxn++) { - kspec = ir[irxn]; - - int speciesType = vcs_species_type(kspec); - if (speciesType < VCS_SPECIES_MINOR) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (spStatus[irxn] >= VCS_SPECIES_MINOR) { - plogf(" --- major/minor species is now zeroed out: %s\n", - SpName[kspec].c_str()); - } - } -#endif - ++m_numRxnMinorZeroed; - } else if (speciesType == VCS_SPECIES_MINOR) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (spStatus[irxn] != VCS_SPECIES_MINOR) { - if (spStatus[irxn] == VCS_SPECIES_MAJOR) { - plogf(" --- Noncomponent turned from major to minor: "); - } else if (spStatus[irxn] == VCS_SPECIES_COMPONENT) { - plogf(" --- Component turned into a minor species: "); - } else { - plogf(" --- Zeroed Species turned into a " - "minor species: "); - } - plogf("%s\n", SpName[kspec].c_str()); - } - } -#endif - ++m_numRxnMinorZeroed; - } else if (speciesType == VCS_SPECIES_MAJOR) { - if (spStatus[irxn] != VCS_SPECIES_MAJOR) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (spStatus[irxn] == VCS_SPECIES_MINOR) { - plogf(" --- Noncomponent turned from minor to major: "); - } else if (spStatus[irxn] == VCS_SPECIES_COMPONENT) { - plogf(" --- Component turned into a major: "); - } else { - plogf(" --- Noncomponent turned from zeroed to major: "); - } - plogf("%s\n", SpName[kspec].c_str()); - } -#endif - spStatus[irxn] = VCS_SPECIES_MAJOR; - /* - * For this special case, we must reevaluate thermo functions - */ - if (iti != 0) { - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, kspec, kspec+1); - vcs_deltag(0, false); - } - } - } - spStatus[irxn] = speciesType; - } /* - * This logical variable indicates whether all current - * non-component species are minor or nonexistent + * 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. */ - im = (m_numRxnMinorZeroed == m_numRxnRdc); - } - /*************************************************************************/ - /***************** EQUILIBRIUM CHECK FOR MAJOR SPECIES *******************/ - /*************************************************************************/ - L_EQUILIB_CHECK: ; - if (! im) { + 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) return retn; + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); + vcs_deltag(0, true); + uptodate_minors = TRUE; + if (conv) { + /* + * HKM -> I don't understand why the code would just give + * up here in some cases. + * This should probably be taken out + */ + plogf(" DELETION OF MULTISPECIES PHASE. "); + plogf("Convergence to number of positive n(i) less than C.\n"); + plogf("Check results to follow carefully. \n\n"); + goto L_RETURN_BLOCK; + } + } + /*************************************************************************/ + /***************** CHECK FOR ELEMENT ABUNDANCE****************************/ + /*************************************************************************/ #ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 2) { - plogf(" --- Equilibrium check for major species: "); + plogf(" --- Normal element abundance check"); } #endif - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] == VCS_SPECIES_MAJOR && (fabs(dg[irxn]) > 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 { + vcs_elab(); + if (! vcs_elabcheck(0)) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" - failed -> redoing element abundances.\n"); + } +#endif + vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); + vcs_deltag(0, true); + uptodate_minors = TRUE; + } +#ifdef DEBUG_MODE + else { + if (vcs_debug_print_lvl >= 2) { + plogf(" - passed\n"); + } + } +#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 (soln[i - 1] < soln[i]) { + dofast = FALSE; + break; + } + } + dofast = false; + if (dofast) { + for (i = 0; i < m_numRxnRdc; ++i) { + l = ir[i]; + for (j = m_numComponents - 1; j >= 0; j--) { + if (soln[l] > soln[j]) { + if (sc[i][j] != 0.0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Get a new basis because %s", SpName[l].c_str()); + plogf(" is larger than comp %s", SpName[j].c_str()); + plogf(" and share nonzero stoic: %-9.1f\n", + sc[i][j]); + } +#endif + goto L_COMPONENT_CALC; + } + } else { + break; + } +#ifdef DEBUG_NOT + if (spStatus[i] == VCS_SPECIES_ZEROEDMS) { + if (soln[j] == 0.0) { + if (sc[i][j] != 0.0) { + if (dg[i] < 0.0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Get a new basis because %s", SpName[l].c_str()); + plogf(" has dg < 0.0 and comp %s has zero mole num", SpName[j].c_str()); + plogf(" and share nonzero stoic: %-9.1f\n", + sc[i][j]); + } +#endif + goto L_COMPONENT_CALC; + } + } + } + } +#endif + } + } + } else { + for (i = 0; i < m_numRxnRdc; ++i) { + l = ir[i]; + for (j = 0; j < m_numComponents; ++j) { + if (soln[l] > soln[j]) { + if (sc[i][j] != 0.0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Get a new basis because "); + plogf("%s", SpName[l].c_str()); + plogf(" is larger than comp "); + plogf("%s", SpName[j].c_str()); + plogf(" and share nonzero stoic: %-9.1f\n", + sc[i][j]); + } +#endif + goto L_COMPONENT_CALC; + } + } +#ifdef DEBUG_NOT + if (spStatus[i] == VCS_SPECIES_ZEROEDMS) { + if (soln[j] == 0.0) { + if (sc[i][j] != 0.0) { + if (dg[i] < 0.0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Get a new basis because %s", SpName[l].c_str()); + plogf(" has dg < 0.0 and comp %s has zero mole num", SpName[j].c_str()); + plogf(" and share nonzero stoic: %-9.1f\n", + sc[i][j]); + } +#endif + goto L_COMPONENT_CALC; + } + } + } + } +#endif + } + } + } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Check for an optimum basis passed\n"); + } +#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 (vcs_debug_print_lvl >= 2) { + plogf(" --- Reevaluate major-minor status of noncomponents:\n"); + } +#endif + m_numRxnMinorZeroed = 0; + for (irxn = 0; irxn < m_numRxnRdc; irxn++) { + kspec = ir[irxn]; + + int speciesType = vcs_species_type(kspec); + if (speciesType < VCS_SPECIES_MINOR) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + if (spStatus[irxn] >= VCS_SPECIES_MINOR) { + plogf(" --- major/minor species is now zeroed out: %s\n", + SpName[kspec].c_str()); + } + } +#endif + ++m_numRxnMinorZeroed; + } else if (speciesType == VCS_SPECIES_MINOR) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + if (spStatus[irxn] != VCS_SPECIES_MINOR) { + if (spStatus[irxn] == VCS_SPECIES_MAJOR) { + plogf(" --- Noncomponent turned from major to minor: "); + } else if (spStatus[irxn] == VCS_SPECIES_COMPONENT) { + plogf(" --- Component turned into a minor species: "); + } else { + plogf(" --- Zeroed Species turned into a " + "minor species: "); + } + plogf("%s\n", SpName[kspec].c_str()); + } + } +#endif + ++m_numRxnMinorZeroed; + } else if (speciesType == VCS_SPECIES_MAJOR) { + if (spStatus[irxn] != VCS_SPECIES_MAJOR) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + if (spStatus[irxn] == VCS_SPECIES_MINOR) { + plogf(" --- Noncomponent turned from minor to major: "); + } else if (spStatus[irxn] == VCS_SPECIES_COMPONENT) { + plogf(" --- Component turned into a major: "); + } else { + plogf(" --- Noncomponent turned from zeroed to major: "); + } + plogf("%s\n", SpName[kspec].c_str()); + } +#endif + spStatus[irxn] = VCS_SPECIES_MAJOR; + /* + * For this special case, we must reevaluate thermo functions + */ + if (iti != 0) { + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, kspec, kspec+1); + vcs_deltag(0, false); + } + } + } + spStatus[irxn] = speciesType; + } + /* + * This logical variable indicates whether all current + * non-component species are minor or nonexistent + */ + im = (m_numRxnMinorZeroed == m_numRxnRdc); + } + /*************************************************************************/ + /***************** EQUILIBRIUM CHECK FOR MAJOR SPECIES *******************/ + /*************************************************************************/ + L_EQUILIB_CHECK: ; + if (! im) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Equilibrium check for major species: "); + } +#endif + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] == VCS_SPECIES_MAJOR && (fabs(dg[irxn]) > 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 (vcs_debug_print_lvl >= 2) { + plogf("%s failed\n", SpName[ir[irxn]].c_str()); + } +#endif + /* + * Set MajorSpeciesHaveConverged to false to indicate that + * convergence amongst + * major species has not been achieved + */ + MajorSpeciesHaveConverged = false; + /* + * Go back and do another iteration with variable ITI + */ + goto L_MAINLOOP_MM4_SPECIES; + } + } + } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" MAJOR SPECIES CONVERGENCE achieved\n"); + } +#endif + } +#ifdef DEBUG_MODE + else { + if (vcs_debug_print_lvl >= 2) { + plogf(" MAJOR SPECIES CONVERGENCE achieved " + "(because there are no major species)\n"); + } + } +#endif + /* + * Set MajorSpeciesHaveConverged to true to indicate + * that convergence amongst major species has been achieved + */ + MajorSpeciesHaveConverged = true; + /*************************************************************************/ + /*************** 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_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); + vcs_deltag(1, false); + uptodate_minors = TRUE; + } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Equilibrium check for minor species: "); + } +#endif + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] == VCS_SPECIES_MINOR && (fabs(dg[irxn]) > 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 (vcs_debug_print_lvl >= 2) { plogf("%s failed\n", SpName[ir[irxn]].c_str()); } #endif /* - * Set MajorSpeciesHaveConverged to false to indicate that - * convergence amongst - * major species has not been achieved + * Set iti to zero to force a full calculation, and go back + * to the main loop to do another iteration. */ - MajorSpeciesHaveConverged = false; - /* - * Go back and do another iteration with variable ITI - */ - goto L_MAINLOOP_MM4_SPECIES; - } - } - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" MAJOR SPECIES CONVERGENCE achieved\n"); - } -#endif - } -#ifdef DEBUG_MODE - else { - if (vcs_debug_print_lvl >= 2) { - plogf(" MAJOR SPECIES CONVERGENCE achieved " - "(because there are no major species)\n"); - } - } -#endif - /* - * Set MajorSpeciesHaveConverged to true to indicate - * that convergence amongst major species has been achieved - */ - MajorSpeciesHaveConverged = true; - /*************************************************************************/ - /*************** 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_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); - vcs_deltag(1, false); - uptodate_minors = TRUE; - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Equilibrium check for minor species: "); - } -#endif - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] == VCS_SPECIES_MINOR && (fabs(dg[irxn]) > 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 (vcs_debug_print_lvl >= 2) { - plogf("%s failed\n", SpName[ir[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; - goto L_MAINLOOP_ALL_SPECIES; - } - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" CONVERGENCE achieved\n"); - } -#endif - } - /*************************************************************************/ - /*********************** FINAL ELEMENTAL ABUNDANCE CHECK *****************/ - /*************************************************************************/ - /* - * Recalculate the element abundance vector again - */ - vcs_updateVP(0); - vcs_elab(); - - /* LEC is only true when we are near the end game */ - if (lec) { - if (!giveUpOnElemAbund) { -#ifdef DEBUG_MODE - if (vcs_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 (vcs_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 (vcs_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)) { - int ncBefore = vcs_elabcheck(0); - vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); - int ncAfter = vcs_elabcheck(0); - int neAfter = vcs_elabcheck(1); - /* - * Go back to evaluate the total moles of gas and liquid. - */ - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); - vcs_deltag(0, false); - /* - * - */ - 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 (vcs_debug_print_lvl >= 2) { + plogf(" CONVERGENCE achieved\n"); + } +#endif + } + /*************************************************************************/ + /*********************** FINAL ELEMENTAL ABUNDANCE CHECK *****************/ + /*************************************************************************/ + /* + * Recalculate the element abundance vector again + */ + vcs_updateVP(0); + vcs_elab(); + + /* LEC is only true when we are near the end game */ + if (lec) { + if (!giveUpOnElemAbund) { +#ifdef DEBUG_MODE + if (vcs_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 (vcs_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 \n"); + if (! vcs_elabcheck(0)) { + plogf(" failed\n"); + } else { + plogf(" passed for NC but failed for NE: RANGE ERROR\n"); + } } #endif - rangeErrorFound = 1; - giveUpOnElemAbund = true; - goto L_EQUILIB_CHECK; + // delete? + goto L_ELEM_ABUND_CHECK; } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" passed\n"); + } +#endif } - } - } - // Calculate delta g's - vcs_deltag(0, false); - // Go back to equilibrium check as a prep to eventually checking out - goto L_EQUILIB_CHECK; + /* + * 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)) { + int ncBefore = vcs_elabcheck(0); + vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); + int ncAfter = vcs_elabcheck(0); + int neAfter = vcs_elabcheck(1); + /* + * Go back to evaluate the total moles of gas and liquid. + */ + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesRdc); + vcs_deltag(0, false); + /* + * + */ + 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 (vcs_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 \n"); + } +#endif + rangeErrorFound = 1; + giveUpOnElemAbund = true; + goto L_EQUILIB_CHECK; + } + } + } + } + // Calculate delta g's + vcs_deltag(0, false); + // 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 = 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 - */ - MajorSpeciesHaveConverged = true; - vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); - vcs_deltag(0, false); - iti = 0; - goto L_MAINLOOP_ALL_SPECIES; - /*************************************************************************/ - /******************** CLEANUP AND RETURN BLOCK ***************************/ - /*************************************************************************/ - L_RETURN_BLOCK: ; - - npb = recheck_deleted(); - /* - * If we haven't found any species that needed adding we are done. - */ - if (npb > 0) { + /* *************************************************** */ + /* **** 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 = 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 @@ -1831,3021 +1812,1328 @@ int VCS_SOLVE::vcs_solve_TP(int print_lvl, int printDetails, int maxit) vcs_deltag(0, false); iti = 0; goto L_MAINLOOP_ALL_SPECIES; - } + /*************************************************************************/ + /******************** CLEANUP AND RETURN BLOCK ***************************/ + /*************************************************************************/ + L_RETURN_BLOCK: ; + + npb = 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 + */ + MajorSpeciesHaveConverged = true; + vcs_dfe(VCS_DATA_PTR(soln), 0, 1, 0, m_numSpeciesRdc); + vcs_deltag(0, false); + iti = 0; + goto L_MAINLOOP_ALL_SPECIES; + } - L_RETURN_BLOCK_B: ; + L_RETURN_BLOCK_B: ; - /* - * Add back deleted species in non-zeroed phases. Estimate their - * mole numbers. - */ - add_deleted(); - /* - * 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(0); - /* - * 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; - dg[kspec] = dg[i]; - } - vcs_dzero(VCS_DATA_PTR(dg), m_numComponents); - /* - * Evaluate the final mole fractions - * storring them in wt[] - */ - vcs_vdzero(wt, m_numSpeciesTot); - for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { - if (SSPhase[kspec]) { - wt[kspec] = 1.0; - } else { - iph = PhaseID[kspec]; - if (TPhMoles[iph] != 0.0) { - wt[kspec] = soln[kspec] / TPhMoles[iph]; + /* + * Add back deleted species in non-zeroed phases. Estimate their + * mole numbers. + */ + add_deleted(); + /* + * 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(0); + /* + * 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; + dg[kspec] = dg[i]; + } + vcs_dzero(VCS_DATA_PTR(dg), m_numComponents); + /* + * Evaluate the final mole fractions + * storring them in wt[] + */ + vcs_vdzero(wt, m_numSpeciesTot); + for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) { + if (SSPhase[kspec]) { + wt[kspec] = 1.0; } 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 = indPhSp[kspec]; - Vphase = VPhaseList[iph]; - wt[kspec] = Vphase->molefraction(i); + iph = PhaseID[kspec]; + if (TPhMoles[iph] != 0.0) { + wt[kspec] = soln[kspec] / TPhMoles[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 = indPhSp[kspec]; + Vphase = VPhaseList[iph]; + wt[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 - */ - tsecond = vcs_second() - tsecond; - 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; -} /* vcs_solve_TP() **********************************************************/ + // 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 + */ + tsecond = vcs_second() - tsecond; + 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; + } /* vcs_solve_TP() **********************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -double VCS_SOLVE::minor_alt_calc(int kspec, int irxn, int *do_delete + double VCS_SOLVE::minor_alt_calc(int kspec, int irxn, int *do_delete #ifdef DEBUG_MODE - , char *ANOTE + , char *ANOTE #endif - ) + ) - /************************************************************************** - * - * minor_alt_calc: - * - * 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 phase: - * 0 = DG(I) + log(WT(I)/W(I)) - * - * W(i) = Old mole number of species i in the phase - * WT(i) = Trial new mole number of species i in the pahse - * - * (DG contains the contribution from - * FF(I) + log(ActCoeff[i] * W(I)/Total_Moles) ) - * Thus, - * WT(I) = W(I) EXP(-DG(I)) - * - * Most of this section is mainly restricting the update to reasonable - * values. - * - * - * Note: This routine was generalized to incorporate - * nonideal phases. - * - * Input: - * ------ - * kspec, irxn = the current species and corresponding formation - * reaction number. - * Output: - * --------- - * return value: dx = the change in mole number - * 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. - *************************************************************************/ -{ - double dx; - double w_kspec = soln[kspec]; - double *wt_kspec = VCS_DATA_PTR(wt) + kspec; - double wTrial; - double *ds_kspec = VCS_DATA_PTR(ds) + kspec; - double dg_irxn = dg[irxn]; - int iphase = PhaseID[kspec]; - vcs_VolPhase *Vphase = VPhaseList[iphase]; - *do_delete = FALSE; - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - if (w_kspec <= 0.0) { - w_kspec = VCS_DELETE_MINORSPECIES_CUTOFF; - } - if (dg_irxn < -20.) { - dg_irxn = -20.; - } + /************************************************************************** + * + * minor_alt_calc: + * + * 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 phase: + * 0 = DG(I) + log(WT(I)/W(I)) + * + * W(i) = Old mole number of species i in the phase + * WT(i) = Trial new mole number of species i in the pahse + * + * (DG contains the contribution from + * FF(I) + log(ActCoeff[i] * W(I)/Total_Moles) ) + * Thus, + * WT(I) = W(I) EXP(-DG(I)) + * + * Most of this section is mainly restricting the update to reasonable + * values. + * + * + * Note: This routine was generalized to incorporate + * nonideal phases. + * + * Input: + * ------ + * kspec, irxn = the current species and corresponding formation + * reaction number. + * Output: + * --------- + * return value: dx = the change in mole number + * 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. + *************************************************************************/ + { + double dx; + double w_kspec = soln[kspec]; + double *wt_kspec = VCS_DATA_PTR(wt) + kspec; + double wTrial; + double *ds_kspec = VCS_DATA_PTR(ds) + kspec; + double dg_irxn = dg[irxn]; + int iphase = PhaseID[kspec]; + vcs_VolPhase *Vphase = VPhaseList[iphase]; + *do_delete = FALSE; + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + if (w_kspec <= 0.0) { + w_kspec = VCS_DELETE_MINORSPECIES_CUTOFF; + } + if (dg_irxn < -20.) { + dg_irxn = -20.; + } #ifdef DEBUG_MODE - sprintf(ANOTE,"minor species alternative calc"); + sprintf(ANOTE,"minor species alternative calc"); #endif - if (dg_irxn >= 82.0) { - (*wt_kspec) = w_kspec * 1.0e-6; - if (w_kspec < VCS_DELETE_MINORSPECIES_CUTOFF) { - goto L_ZERO_SPECIES; - } - } else { - if (fabs(dg_irxn) <= tolmin2) { - (*wt_kspec) = w_kspec; - (*ds_kspec) = 0.0; - return 0.0; - } - // c = log(ActCoeff[kspec] * w_kspec) - dg_irxn; + if (dg_irxn >= 82.0) { + (*wt_kspec) = w_kspec * 1.0e-6; + if (w_kspec < VCS_DELETE_MINORSPECIES_CUTOFF) { + goto L_ZERO_SPECIES; + } + } else { + if (fabs(dg_irxn) <= tolmin2) { + (*wt_kspec) = w_kspec; + (*ds_kspec) = 0.0; + return 0.0; + } + // c = log(ActCoeff[kspec] * w_kspec) - dg_irxn; - } + } - if (dg_irxn > 10.0) { - (*wt_kspec) = w_kspec * 1.0e-5; - if (w_kspec < VCS_DELETE_MINORSPECIES_CUTOFF) { + if (dg_irxn > 10.0) { + (*wt_kspec) = w_kspec * 1.0e-5; + if (w_kspec < VCS_DELETE_MINORSPECIES_CUTOFF) { + goto L_ZERO_SPECIES; + } + } else { + double ac0 = ActCoeff[kspec]; + double ac = ac0; + double w0 = w_kspec; + double dd = exp(-dg_irxn); + + wTrial = w0 * ac0 / ac * dd; + *wt_kspec = wTrial; + Vphase->setMolesFromVCS(VCS_DATA_PTR(wt)); + Vphase->sendToVCSActCoeff(VCS_DATA_PTR(ActCoeff)); + double ac1 = ActCoeff[kspec]; + double acprime = 0.0; + if (fabs(wTrial - w0) > 1.0E-8 * w0) { + acprime = (ac1 - ac0) / (wTrial - w0); + } + double jac = acprime * wTrial + ac1; + double fTrial = ac1 * wTrial - ac0*w0*dd; + double w2 = wTrial - fTrial / jac; + if (w2 > 100.*w0) { + *wt_kspec = 100.0 * w0; + } else if (100. * w2 < w0) { + *wt_kspec = 0.01 * w0; + } else { + *wt_kspec = w2; + } + } + + if ((*wt_kspec) < VCS_DELETE_MINORSPECIES_CUTOFF) { goto L_ZERO_SPECIES; } - } else { - double ac0 = ActCoeff[kspec]; - double ac = ac0; - double w0 = w_kspec; - double dd = exp(-dg_irxn); - - wTrial = w0 * ac0 / ac * dd; - *wt_kspec = wTrial; - Vphase->setMolesFromVCS(VCS_DATA_PTR(wt)); - Vphase->sendToVCSActCoeff(VCS_DATA_PTR(ActCoeff)); - double ac1 = ActCoeff[kspec]; - double acprime = 0.0; - if (fabs(wTrial - w0) > 1.0E-8 * w0) { - acprime = (ac1 - ac0) / (wTrial - w0); - } - double jac = acprime * wTrial + ac1; - double fTrial = ac1 * wTrial - ac0*w0*dd; - double w2 = wTrial - fTrial / jac; - if (w2 > 100.*w0) { - *wt_kspec = 100.0 * w0; - } else if (100. * w2 < w0) { - *wt_kspec = 0.01 * w0; - } else { - *wt_kspec = w2; - } - } - - if ((*wt_kspec) < VCS_DELETE_MINORSPECIES_CUTOFF) { - goto L_ZERO_SPECIES; - } - dx = (*wt_kspec) - w_kspec; - (*ds_kspec) = dx; - 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; - (*ds_kspec) = dx; - return dx; - } - else { - /* - * Voltage calculation - * HKM -> Need to check the sign - */ - dx = dg[irxn]/ Faraday_dim; + dx = (*wt_kspec) - w_kspec; + (*ds_kspec) = dx; + 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; + (*ds_kspec) = dx; + return dx; + } + else { + /* + * Voltage calculation + * HKM -> Need to check the sign + */ + dx = dg[irxn]/ Faraday_dim; #ifdef DEBUG_MODE - sprintf(ANOTE,"voltage species alternative calc"); + sprintf(ANOTE,"voltage species alternative calc"); #endif + } + return dx; } - return dx; -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -int VCS_SOLVE::delta_species(int kspec, double *delta_ptr) + int VCS_SOLVE::delta_species(int kspec, double *delta_ptr) - /************************************************************************ - * - * delta_species(): - * - * Change the concentration of a species by delta moles. - * Make sure to conserve - * elements and keep track of the total moles in all phases. - * - * return: - * 1: succeeded - * 0: failed. - ************************************************************************/ -{ - int irxn = kspec - m_numComponents; - int retn = 1; - int j; - double tmp; - double delta = *delta_ptr; - if (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 = sc[irxn]; - for (j = 0; j < m_numComponents; ++j) { - if (soln[j] > 0.0) { - tmp = sc_irxn[j] * dx; - if (-tmp > soln[j]) { - retn = 0; - dx = MIN(dx, - soln[j] / sc_irxn[j]); + /************************************************************************ + * + * delta_species(): + * + * Change the concentration of a species by delta moles. + * Make sure to conserve + * elements and keep track of the total moles in all phases. + * + * return: + * 1: succeeded + * 0: failed. + ************************************************************************/ + { + int irxn = kspec - m_numComponents; + int retn = 1; + int j; + double tmp; + double delta = *delta_ptr; + if (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 = sc[irxn]; + for (j = 0; j < m_numComponents; ++j) { + if (soln[j] > 0.0) { + tmp = sc_irxn[j] * dx; + if (-tmp > soln[j]) { + retn = 0; + dx = MIN(dx, - soln[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 (soln[j] <= 0.0) { + if (sc_irxn[j] < 0.0) { + *delta_ptr = 0.0; + return 0; + } } } /* - * If the component has a zero concentration and is a reactant - * in the formation reaction, then dx == 0.0, and we just return. + * ok, we found a positive dx. implement it. */ - if (soln[j] <= 0.0) { - if (sc_irxn[j] < 0.0) { - *delta_ptr = 0.0; - return 0; + *delta_ptr = dx; + soln[kspec] += dx; + int iph = PhaseID[kspec]; + TPhMoles[iph] += dx; + for (j = 0; j < m_numComponents; ++j) { + iph = PhaseID[j]; + tmp = sc_irxn[j] * dx; + soln[j] += tmp; + TPhMoles[iph] += tmp; + if (soln[j] < 0.0) { + soln[j] = 0.0; } } } + return retn; + } + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int VCS_SOLVE::zero_species(int kspec) + + /************************************************************************ + * + * zero_species: + * + * Zero out the concentration of a species. Make sure to conserve + * elements and keep track of the total moles in all phases. + * w[] + * TPhMoles[] + * + * return: + * 1: succeeded + * 0: failed. + ************************************************************************/ + { + int retn = 1; /* - * ok, we found a positive dx. implement it. + * Calculate a delta that will eliminate the species. */ - *delta_ptr = dx; - soln[kspec] += dx; + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + double dx = -(soln[kspec]); + if (dx != 0.0) { + retn = delta_species(kspec, &dx); + if (!retn) { + plogf("zero_species: Couldn't zero the species %d, " + "did delta of %g. orig conc of %g\n", + kspec, dx, soln[kspec] + dx); + } + } + } + return retn; + } + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int VCS_SOLVE::delete_species(int kspec) + + /************************************************************************ + * + * delete_species: + * + * Rearrange data when species is added or removed. The Lth species is + * moved to the back of the species vector. The back of the species + * vector is indicated by the value of MR, the current number of + * active species in the mechanism. + * + * Input + * kspec = species number + * Return value + * The return is true when the current number of + * noncomponent species is equal to zero. A recheck of deleted species + * is carried out in the main code. + *************************************************************************/ + { + int klast = m_numSpeciesRdc - 1; int iph = PhaseID[kspec]; - TPhMoles[iph] += dx; - for (j = 0; j < m_numComponents; ++j) { - iph = PhaseID[j]; - tmp = sc_irxn[j] * dx; - soln[j] += tmp; - TPhMoles[iph] += tmp; - if (soln[j] < 0.0) { - soln[j] = 0.0; - } + vcs_VolPhase *Vphase = VPhaseList[iph]; + int irxn = kspec - m_numComponents; /* This is the noncomponent rxn index */ + /* + * Zero the concentration of the species. + * -> This zeroes w[kspec] and modifies TPhMoles[] + */ + int retn = zero_species(kspec); + if (! retn) { + plogf("Failed to delete a species!\n"); + exit(-1); } - } - return retn; -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int VCS_SOLVE::zero_species(int kspec) - - /************************************************************************ - * - * zero_species: - * - * Zero out the concentration of a species. Make sure to conserve - * elements and keep track of the total moles in all phases. - * w[] - * TPhMoles[] - * - * return: - * 1: succeeded - * 0: failed. - ************************************************************************/ -{ - int retn = 1; - /* - * Calculate a delta that will eliminate the species. - */ - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - double dx = -(soln[kspec]); - if (dx != 0.0) { - retn = delta_species(kspec, &dx); - if (!retn) { - plogf("zero_species: Couldn't zero the species %d, " - "did delta of %g. orig conc of %g\n", - kspec, dx, soln[kspec] + dx); - } + /* + * Decrement the minor species counter if the current species is + * a minor species + */ + if (spStatus[irxn] != VCS_SPECIES_MAJOR) --(m_numRxnMinorZeroed); + spStatus[irxn] = VCS_SPECIES_DELETED; + dg[irxn] = 0.0; + dgl[irxn] = 0.0; + m_gibbsSpecies[kspec] = 0.0; + fel[kspec] = 0.0; + wt[kspec] = 0.0; + /* + * Rearrange the data if the current species isn't the last active + * species. + */ + if (kspec != klast) { + vcs_switch_pos(TRUE, klast, kspec); } - } - return retn; -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int VCS_SOLVE::delete_species(int kspec) - - /************************************************************************ - * - * delete_species: - * - * Rearrange data when species is added or removed. The Lth species is - * moved to the back of the species vector. The back of the species - * vector is indicated by the value of MR, the current number of - * active species in the mechanism. - * - * Input - * kspec = species number - * Return value - * The return is true when the current number of - * noncomponent species is equal to zero. A recheck of deleted species - * is carried out in the main code. - *************************************************************************/ -{ - int klast = m_numSpeciesRdc - 1; - int iph = PhaseID[kspec]; - vcs_VolPhase *Vphase = VPhaseList[iph]; - int irxn = kspec - m_numComponents; /* This is the noncomponent rxn index */ - /* - * Zero the concentration of the species. - * -> This zeroes w[kspec] and modifies TPhMoles[] - */ - int retn = zero_species(kspec); - if (! retn) { - plogf("Failed to delete a species!\n"); - exit(-1); - } - /* - * Decrement the minor species counter if the current species is - * a minor species - */ - if (spStatus[irxn] != VCS_SPECIES_MAJOR) --(m_numRxnMinorZeroed); - spStatus[irxn] = VCS_SPECIES_DELETED; - dg[irxn] = 0.0; - dgl[irxn] = 0.0; - m_gibbsSpecies[kspec] = 0.0; - fel[kspec] = 0.0; - wt[kspec] = 0.0; - /* - * 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_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles)); + /* + * Adjust the total moles in a phase downwards. + */ + Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles)); - /* - * Adjust the current number of active species and reactions counters - */ - --(m_numRxnRdc); - --(m_numSpeciesRdc); + /* + * 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 (! SSPhase[klast]) { - if (Vphase->Existence != 2) { - Vphase->Existence = 0; - for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - if (PhaseID[kspec] == iph) { - if (soln[kspec] > 0.0) { - Vphase->Existence = 1; - break; + /* + * Check to see whether we have just annihilated a multispecies phase. + * If it is extinct, call the delete_multiphase() function. + */ + if (! SSPhase[klast]) { + if (Vphase->Existence != 2) { + Vphase->Existence = 0; + for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + if (PhaseID[kspec] == iph) { + if (soln[kspec] > 0.0) { + Vphase->Existence = 1; + break; + } } } } - } - if (Vphase->Existence == 0) { - delete_multiphase(iph); - } - } - } - /* - * When the total number of noncomponent species is zero, we - * have to signal the calling code - */ - return (m_numRxnRdc == 0); -} /* delete_species() ********************************************************/ - -/**************************************************************************** - * - * 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(int kspec) { - int i, k, irxn = kspec - m_numComponents; - int *phaseID = VCS_DATA_PTR(PhaseID); - double dx; -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Add back a deleted species: %-12s\n", SpName[kspec].c_str()); - } -#endif - /* - * Set the species back to minor species status - * this adjusts soln[] and TPhMoles[] - * HKM -> make this a relative mole number! - */ - dx = VCS_DELETE_SPECIES_CUTOFF * 10.; - delta_species(kspec, &dx); - spStatus[irxn] = VCS_SPECIES_MINOR; - - if (SSPhase[kspec]) { - spStatus[irxn] = VCS_SPECIES_MAJOR; - --(m_numRxnMinorZeroed); - } - int iph = PhaseID[kspec]; - vcs_VolPhase *Vphase = VPhaseList[iph]; - Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles)); - /* - * 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 spStatus[] flag. - * The value of spStatus[] must change from - * VCS_SPECIES_ZEROEDPHASE to VCS_SPECIES_ZEROEDMS - * for those other species. - */ - if (! SSPhase[kspec]) { - if (Vphase->Existence == 0) { - Vphase->Existence = 1; - for (k = 0; k < m_numSpeciesTot; k++) { - if (phaseID[k] == iph) { - i = k - m_numComponents; - if (spStatus[i] == VCS_SPECIES_ZEROEDPHASE) - spStatus[i] = VCS_SPECIES_ZEROEDMS; + if (Vphase->Existence == 0) { + delete_multiphase(iph); } } } - } else { - Vphase->Existence = 1; - } - - ++(m_numRxnRdc); - ++(m_numSpeciesRdc); - ++(m_numRxnMinorZeroed); - - if (kspec != (m_numSpeciesRdc - 1)) { - /* - * Rearrange both the species and the non-component global data + /* + * When the total number of noncomponent species is zero, we + * have to signal the calling code */ - vcs_switch_pos(TRUE, (m_numSpeciesRdc - 1), kspec); - } -} /* vcs_reinsert_deleted() */ + return (m_numRxnRdc == 0); + } /* delete_species() ********************************************************/ -/**************************************************************************** - * - * delete_multiphase(): - * - * 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. - * The 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. - */ -void VCS_SOLVE::delete_multiphase(int iph) { - int kspec, j, irxn; - double dx; - vcs_VolPhase *Vphase = VPhaseList[iph]; - /* - * set the phase existence flag to dead + /**************************************************************************** + * + * 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. */ - Vphase->Existence = 0; + void VCS_SOLVE::vcs_reinsert_deleted(int kspec) { + int i, k, irxn = kspec - m_numComponents; + int *phaseID = VCS_DATA_PTR(PhaseID); + double dx; #ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- delete_multiphase %d, %s\n", iph, Vphase->PhaseName.c_str()); - } + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Add back a deleted species: %-12s\n", SpName[kspec].c_str()); + } #endif - /* - * Zero out the total moles counters for the phase - */ - TPhMoles[iph] = 0.0; - TPhMoles1[iph] = 0.0; - DelTPhMoles[iph] = 0.0; - - /* - * Loop over all of the active species in the phase. - */ - for (kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { - if (PhaseID[kspec] == iph) { - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - irxn = kspec - m_numComponents; - /* - * calculate an extent of rxn, dx, that zeroes out the species. - */ - dx = - (soln[kspec]); - /* - * Set the mole numbers of that species to zero. - */ - soln[kspec] = 0.0; - wt[kspec] = 0.0; - ds[kspec] = 0.0; - /* - * Change the status flag of the species to that of an - * zeroed phase - */ - spStatus[irxn] = VCS_SPECIES_ZEROEDPHASE; - /* - * changed the component mole numbers to account for the - * final extent of reaction. Make sure to keep component - * mole numbers constant. - * HKM -> note, this will cause a loss of moles! - */ - for (j = 0; j < m_numComponents; ++j) { - soln[j] += sc[irxn][j] * dx; - if (soln[j] < 0.0) { - soln[j] = 0.0; + /* + * Set the species back to minor species status + * this adjusts soln[] and TPhMoles[] + * HKM -> make this a relative mole number! + */ + dx = VCS_DELETE_SPECIES_CUTOFF * 10.; + delta_species(kspec, &dx); + spStatus[irxn] = VCS_SPECIES_MINOR; + + if (SSPhase[kspec]) { + spStatus[irxn] = VCS_SPECIES_MAJOR; + --(m_numRxnMinorZeroed); + } + int iph = PhaseID[kspec]; + vcs_VolPhase *Vphase = VPhaseList[iph]; + Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles)); + /* + * 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 spStatus[] flag. + * The value of spStatus[] must change from + * VCS_SPECIES_ZEROEDPHASE to VCS_SPECIES_ZEROEDMS + * for those other species. + */ + if (! SSPhase[kspec]) { + if (Vphase->Existence == 0) { + Vphase->Existence = 1; + for (k = 0; k < m_numSpeciesTot; k++) { + if (phaseID[k] == iph) { + i = k - m_numComponents; + if (spStatus[i] == VCS_SPECIES_ZEROEDPHASE) + spStatus[i] = VCS_SPECIES_ZEROEDMS; } } } + } else { + Vphase->Existence = 1; } - } - /* - * 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. + + ++(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); + } + } /* vcs_reinsert_deleted() */ + + /**************************************************************************** + * + * delete_multiphase(): + * + * 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. + * The 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. */ - for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { - if (PhaseID[kspec] == iph) { - irxn = kspec - m_numComponents; - soln[kspec] = 0.0; - wt[kspec] = 0.0; - ds[kspec] = 0.0; - spStatus[irxn] = VCS_SPECIES_ZEROEDPHASE; - - ++(m_numRxnRdc); - ++(m_numSpeciesRdc); -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Make %s", SpName[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); - } - } - } - /* - * Upload the state to the VP object - */ - Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles), iph); - -} /* delete_multiphase() *****************************************************/ - -/***************************************************************************** - * - * recheck_deleted: - * - * Recheck deleted species in multispecies phases. - * - * HKM -> This algorithm needs to be updated for activity coefficients - */ -int VCS_SOLVE::recheck_deleted(void) -{ - int iph, kspec, irxn, npb; - double *xtcutoff = VCS_DATA_PTR(TmpPhase); -#ifdef DEBUG_MODE - if (vcs_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 - */ - for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { - m_gibbsSpecies[kspec] = ff[kspec]; - } - /* - * Recalculate the DeltaG's of the formation reactions for the - * deleted species in the mechanism - */ - vcs_deltag(0, true); - - for (iph = 0; iph < NPhase; iph++) { - if (TPhMoles[iph] > 0.0) - xtcutoff[iph] = log (TPhMoles[iph] / VCS_DELETE_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)/TPhMoles) - * - * 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 th code. Also nonideal solutions will tend to - * complicate matters severely also. - */ - npb = 0; - for (irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { - kspec = ir[irxn]; - iph = PhaseID[kspec]; - if (TPhMoles[iph] == 0.0) { - if (dg[irxn] < 0.0) { - vcs_reinsert_deleted(kspec); - npb++; - } else { - soln[kspec] = 0.0; - } - } else if (TPhMoles[iph] > 0.0) { - if (dg[irxn] < xtcutoff[iph]) { - vcs_reinsert_deleted(kspec); - npb++; - } - } - } - return npb; -} /* recheck_deleted() *******************************************************/ - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::add_deleted(void) - - /************************************************************************* - * - * Provide an estimate for the deleted species in phases that - * are not zeroed out - * - *************************************************************************/ -{ - int iph, kspec, retn; - if (m_numSpeciesRdc == m_numSpeciesTot) return; - /* - * Use the standard chemical potentials for the chemical potentials - * of deleted species. Then, calculate Delta G for - * for formation reactions - * - * HKM Note: We need to update this step for nonunity activity - * coefficients. - * The formula will be fe = ff + RT * ln(actCoeff) - * where the activity coefficient is evaluated at - * ~ infinite dilution. - */ - for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { - m_gibbsSpecies[kspec] = ff[kspec]; - } - /* - * Recalculate the DeltaG's of the formation reactions for the - * deleted species in the mechanism - */ - vcs_deltag(0, true); - - - for (int irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { - kspec = ir[irxn]; - iph = PhaseID[kspec]; - if (TPhMoles[iph] > 0.0) { - double maxDG = MIN(dg[irxn], 300); - double dx = TPhMoles[iph] * exp(- maxDG); - retn = delta_species(kspec, &dx); - } - } - - vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesTot); - vcs_deltag(0, true); -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int VCS_SOLVE::force(int iti) - - /************************************************************************** - * - * force: - * - * Convergence Forcer: - * - * This routine optimizes the minimization of the total gibbs free - * energy: - * Gibbs = sum_k( fe_k * w_k ) - * along the current direction ds[], by choosing a value, al: (0 0), - * does this code section kick in. It finds the point on the parabola - * where the slope is equal to zero. - * - * NOTE: The algorithm used to find the slope is not quite accurate. - * The term, sum_k( (fe_k_n - fe_k_n-1) * w_k_n-1 ) - * is dropped from s1, and, the term, - * sum_k( (fe_k_n - fe_k_n-1) * w_k_n ), is dropped from s2 - *************************************************************************/ -{ - double s1, s2, al; - int i, iph; - double *dptr = VCS_DATA_PTR(m_gibbsSpecies); - //int numSpeciesRdc = m_numSpeciesRdc; - - /* *************************************************** */ - /* **** CALCULATE SLOPE AT END OF THE STEP ********** */ - /* *************************************************** */ - s2 = 0.0; - for (i = 0; i < m_numSpeciesRdc; ++i) { - s2 += dptr[i] * ds[i]; - } -#ifdef DEBUG_NOT - if (s2 <= 0.0) { -#ifdef DEBUG_NOT - if (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE produced no adjustments,"); - plogf(" failed s2 test\n"); - } -#endif - return FALSE; - } -#endif -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE: End Slope = %g\n", s2); - } -#endif - /* *************************************************** */ - /* **** CALCULATE ORIGINAL SLOPE ********************* */ - /* ************************************************** */ - s1 = 0.0; - dptr = VCS_DATA_PTR(fel); - for (i = 0; i < m_numSpeciesRdc; ++i) { - s1 += dptr[i] * ds[i]; - } -#ifdef DEBUG_NOT - if (s1 >= 0.0) { + void VCS_SOLVE::delete_multiphase(int iph) { + int kspec, j, irxn; + double dx; + vcs_VolPhase *Vphase = VPhaseList[iph]; + /* + * set the phase existence flag to dead + */ + Vphase->Existence = 0; #ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE produced no adjustments,"); - plogf(" failed s1 test -PROBLEM!!\n"); + plogf(" --- delete_multiphase %d, %s\n", iph, Vphase->PhaseName.c_str()); } #endif - return FALSE; - } -#endif -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE: Beginning Slope = %g\n", s1); - } -#endif - /* *************************************************** */ - /* **** FIT PARABOLA ********************************* */ - /* *************************************************** */ - 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 (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE produced no adjustments (al = %g)\n", al); - } -#endif - return FALSE; - } -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- subroutine FORCE produced a damping factor = %g\n", al); - } -#endif - /* *************************************************** */ - /* **** ADJUST MOLE NUMBERS, CHEM. POT *************** */ - /* *************************************************** */ - dptr = VCS_DATA_PTR(soln); - for (i = 0; i < m_numSpeciesRdc; ++i) { - dptr[i] += al * ds[i]; - } - for (iph = 0; iph < NPhase; iph++) { - TPhMoles[iph] += al * DelTPhMoles[iph]; - } - vcs_updateVP(0); + /* + * Zero out the total moles counters for the phase + */ + TPhMoles[iph] = 0.0; + TPhMoles1[iph] = 0.0; + DelTPhMoles[iph] = 0.0; -#ifdef DEBUG_MODE - if (vcs_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_dfe(dptr, 0, iti, 0, m_numSpeciesRdc); - /* - * Evaluate DeltaG for all components if ITI=0, and for - * major components only if ITI NE 0 - */ - vcs_deltag(iti, false); - return TRUE; -} /* force() *****************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/* - * vcs_RxnStepSizes(): - * - * Calculates formation reaction step sizes. - * This is equation 6.4-16, p. 143 in Smith and Missen. - * - * Output - * ------- - * ds(I) : reaction adjustments, where I refers to the Ith species - * formation reaction. This is adjustment is for species - * i + M, where M is the number of components. - * Special branching occurs sometimes. This causes the component basis - * to be reevaluated - * return = 0 : normal return - * 1 : A single species phase species has been zeroed out - * in this routine. The species is a noncomponent - * 2 : Same as one but, the zeroed species is a component. - */ -int VCS_SOLVE::vcs_RxnStepSizes() { - int j, k, irxn, kspec, soldel = 0, iph; - double s, xx, dss; - vcs_VolPhase *Vphase = 0; - double *dnPhase_irxn; -#ifdef DEBUG_MODE - char ANOTE[128]; - if (vcs_debug_print_lvl >= 2) { - plogf(" "); for (j = 0; j < 82; j++) plogf("-"); plogf("\n"); - plogf(" --- Subroutine vcs_RxnStepSizes called - Details:\n"); - plogf(" "); for (j = 0; j < 82; j++) plogf("-"); plogf("\n"); - plogf(" --- Species Moles Rxn_Adjustment DeltaG" - " | Comment\n"); - } -#endif - /* - * We update the matrix dlnActCoeffdmolNumber[][] at the - * top of the loop, when necessary - */ - if (UseActCoeffJac) { - vcs_CalcLnActCoeffJac(VCS_DATA_PTR(soln)); - } - /************************************************************************ - ******** LOOP OVER THE FORMATION REACTIONS ***************************** - ************************************************************************/ - - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { -#ifdef DEBUG_MODE - sprintf(ANOTE,"Normal Calc"); -#endif - - kspec = ir[irxn]; - - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - - dnPhase_irxn = DnPhase[irxn]; - - if (soln[kspec] == 0.0 && (! SSPhase[kspec])) { - /********************************************************************/ - /******* MULTISPECIES PHASE WITH total moles equal to zero *********/ - /*******************************************************************/ - /* - * If dg[irxn] is negative, then the multispecies phase should - * come alive again. Add a small positive step size to - * make it come alive. - */ - if (dg[irxn] < -1.0e-4) { + /* + * Loop over all of the active species in the phase. + */ + for (kspec = 0; kspec < m_numSpeciesRdc; ++kspec) { + if (PhaseID[kspec] == iph) { + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + irxn = kspec - m_numComponents; /* - * First decide if this species is part of a multiphase that - * is nontrivial in size. + * calculate an extent of rxn, dx, that zeroes out the species. */ - iph = PhaseID[kspec]; - double tphmoles = TPhMoles[iph]; - double trphmoles = tphmoles / TMoles; - if (trphmoles > VCS_DELETE_PHASE_CUTOFF) { - ds[kspec] = TMoles * VCS_SMALL_MULTIPHASE_SPECIES; -#ifdef DEBUG_MODE - sprintf(ANOTE, - "MultSpec: small species born again DG = %11.3E", - dg[irxn]); -#endif - } else { -#ifdef DEBUG_MODE - sprintf(ANOTE, "MultSpec: phase come alive DG = %11.3E", dg[irxn]); -#endif - Vphase = VPhaseList[iph]; - int numSpPhase = Vphase->NVolSpecies; - ds[kspec] = TMoles * 10.0 * VCS_DELETE_PHASE_CUTOFF / numSpPhase; - } - --(m_numRxnMinorZeroed); - } else { -#ifdef DEBUG_MODE - sprintf(ANOTE, "MultSpec: still dead DG = %11.3E", dg[irxn]); -#endif + dx = - (soln[kspec]); + /* + * Set the mole numbers of that species to zero. + */ + soln[kspec] = 0.0; + wt[kspec] = 0.0; ds[kspec] = 0.0; - } - } else { - /********************************************************************/ - /************************* REGULAR PROCESSING ************/ - /********************************************************************/ - /* - * First take care of cases where we want to bail out - * - * - * Don't bother if superconvergence has already been achieved - * in this mode. - */ - if (fabs(dg[irxn]) <= tolmaj2) { -#ifdef DEBUG_MODE - sprintf(ANOTE,"Skipped: superconverged DG = %11.3E", dg[irxn]); - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", SpName[kspec].c_str()); - plogf(" %12.4E %12.4E %12.4E | %s\n", - soln[kspec], ds[kspec], dg[irxn], ANOTE); - } -#endif - continue; - } - /* - * Don't calculate for minor or nonexistent species if - * their values are to be decreasing anyway. - */ - if ((spStatus[irxn] != VCS_SPECIES_MAJOR) && (dg[irxn] >= 0.0)) { -#ifdef DEBUG_MODE - sprintf(ANOTE,"Skipped: IC = %3d and DG >0: %11.3E", - spStatus[irxn], dg[irxn]); - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", SpName[kspec].c_str()); - plogf(" %12.4E %12.4E %12.4E | %s\n", - soln[kspec], ds[kspec], dg[irxn], ANOTE); - } -#endif - continue; - } - /* - * Start of the regular processing - */ - if (SSPhase[kspec]) { - s = 0.0; - } else { - s = 1.0 / soln[kspec] ; - } - for (j = 0; j < m_numComponents; ++j) { - if (!SSPhase[j]) { - if (soln[j] > 0.0) { - s += SQUARE(sc[irxn][j]) / soln[j]; - } - } - } - for (j = 0; j < NPhase; j++) { - Vphase = VPhaseList[j]; - if (! Vphase->SingleSpecies) { - if (TPhMoles[j] > 0.0) - s -= SQUARE(dnPhase_irxn[j]) / TPhMoles[j]; - } - } - if (s != 0.0) { /* - * Take into account of the - * derivatives of the activity coefficients with respect to the - * mole numbers, even in our diagonal approximation. + * Change the status flag of the species to that of an + * zeroed phase */ - if (UseActCoeffJac) { - double s_old = s; - s = vcs_Hessian_diag_adj(irxn, s_old); -#ifdef DEBUG_MODE - if (s_old != s) { - sprintf(ANOTE, "Normal calc: diag adjusted from %g " - "to %g due to act coeff", s_old, s); - } -#endif - } - - ds[kspec] = -dg[irxn] / s; - // New section to do damping of the ds[] + spStatus[irxn] = VCS_SPECIES_ZEROEDPHASE; /* - * + * changed the component mole numbers to account for the + * final extent of reaction. Make sure to keep component + * mole numbers constant. + * HKM -> note, this will cause a loss of moles! */ for (j = 0; j < m_numComponents; ++j) { - double stoicC = sc[irxn][j]; - if (stoicC != 0.0) { - double negChangeComp = - stoicC * ds[kspec]; - if (negChangeComp > soln[j]) { - if (soln[j] > 0.0) { -#ifdef DEBUG_MODE - sprintf(ANOTE, "Delta damped from %g " - "to %g due to component %d (%10s) going neg", ds[kspec], - -soln[j]/stoicC, j, SpName[j].c_str()); -#endif - ds[kspec] = - soln[j] / stoicC; - } else { -#ifdef DEBUG_MODE - sprintf(ANOTE, "Delta damped from %g " - "to %g due to component %d (%10s) zero", ds[kspec], - -soln[j]/stoicC, j, SpName[j].c_str()); -#endif - ds[kspec] = 0.0; - } - } + soln[j] += sc[irxn][j] * dx; + if (soln[j] < 0.0) { + soln[j] = 0.0; } } - // Implement a damping term that limits ds to the size of the mole number - if (-ds[kspec] > soln[kspec]) { -#ifdef DEBUG_MODE - sprintf(ANOTE, "Delta damped from %g " - "to %g due to %s going negative", ds[kspec], - -soln[kspec], SpName[kspec].c_str()); -#endif - ds[kspec] = -soln[kspec]; - } - - } else { - /* ************************************************************ */ - /* **** REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES **** */ - /* **** DELETE ONE OF THE PHASES AND RECOMPUTE BASIS ********* */ - /* ************************************************************ */ - /* - * Either the species L will disappear or one of the - * component single species phases will disappear. The sign - * of DG(I) will indicate which way the reaction will go. - * Then, we need to follow the reaction to see which species - * will zero out first. - * -> The species to be zeroed out will be "k". - */ - if (dg[irxn] > 0.0) { - dss = soln[kspec]; - k = kspec; - for (j = 0; j < m_numComponents; ++j) { - if (sc[irxn][j] > 0.0) { - xx = soln[j] / sc[irxn][j]; - if (xx < dss) { - dss = xx; - k = j; - } - } - } - dss = -dss; - } else { - dss = 1.0e10; - for (j = 0; j < m_numComponents; ++j) { - if (sc[irxn][j] < 0.0) { - xx = -soln[j] / sc[irxn][j]; - if (xx < dss) { - dss = xx; - k = j; - } - } - } - } - /* - * Here we adjust the mole fractions - * according to DSS and the stoichiometric array - * to take into account that we are eliminating - * the kth species. DSS contains the amount - * of moles of the kth species that needs to be - * added back into the component species. - */ - if (dss != 0.0) { - soln[kspec] += dss; - TPhMoles[PhaseID[kspec]] += dss; - for (j = 0; j < m_numComponents; ++j) { - soln[j] += dss * sc[irxn][j]; - TPhMoles[PhaseID[j]] += dss * sc[irxn][j]; - } - soln[k] = 0.0; - iph = PhaseID[k]; - Vphase = VPhaseList[iph]; - Vphase->Existence = 0; - TPhMoles[iph] = 0.0; -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- vcs_RxnStepSizes Special section to delete %s\n", - SpName[k].c_str()); - plogf(" --- Immediate return - Restart iteration\n"); - } -#endif - /* - * We need to immediately recompute the - * component basis, because we just zeroed - * it out. - */ - if (k != kspec) soldel = 2; - else soldel = 1; - return soldel; - } - } - } /* End of regular processing */ -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", SpName[kspec].c_str()); - plogf(" %12.4E %12.4E %12.4E | %s\n", - soln[kspec], ds[kspec], dg[irxn], ANOTE); - } -#endif - } /* End of loop over SpeciesUnknownType */ - } /* End of loop over non-component stoichiometric formation reactions */ -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" "); vcs_print_line("-", 82); - } -#endif - return soldel; -} -/*****************************************************************************/ - -/************************************************************************** - * - * vcs_deltag: - * - * 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. SC(J,I) are the stoichiometric coefficients for these - * reactions. A stoichiometric coefficient of one is assumed for - * species I in this reaction. - * - * INPUT - * 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 - * irxnl : used with L = 0 to indicate upper limit. - * - * 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 the component. - * This dG < 0.0 feeds back into the algorithm in several - * places, and leads to a infinite loop in at least one case. - */ -void VCS_SOLVE::vcs_deltag(int l, bool doDeleted) { - int iph; - int lneed, irxn, kspec; - double *dtmp_ptr; - int icase = 0; - int irxnl = m_numRxnRdc; - if (doDeleted) { - irxnl = m_numRxnTot; - } - -#ifdef DEBUG_MODE - if (vcs_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) { - if (spStatus[irxn] != VCS_SPECIES_MINOR) { - icase = 0; - dg[irxn] = m_gibbsSpecies[ir[irxn]]; - dtmp_ptr = sc[irxn]; - for (kspec = 0; kspec < m_numComponents; ++kspec) { - dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; - if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { - icase = 1; - } - } - if (icase) { - dg[irxn] = MAX(0.0, dg[irxn]); } } } - } else if (l == 0) { - /* ************************************************* */ - /* **** ALL REACTIONS ****************************** */ - /* ************************************************* */ - for (irxn = 0; irxn < irxnl; ++irxn) { - icase = 0; - dg[irxn] = m_gibbsSpecies[ir[irxn]]; - dtmp_ptr = sc[irxn]; - for (kspec = 0; kspec < m_numComponents; ++kspec) { - dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; - if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { - icase = 1; - } - } - if (icase) { - dg[irxn] = MAX(0.0, dg[irxn]); - } - } - } else { - /* ************************************************* */ - /* **** MINORS AND ZEROED SPECIES ****************** */ - /* ************************************************* */ - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] <= VCS_SPECIES_MINOR) { - icase = 0; - dg[irxn] = m_gibbsSpecies[ir[irxn]]; - dtmp_ptr = sc[irxn]; - for (kspec = 0; kspec < m_numComponents; ++kspec) { - dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; - if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { - icase = 1; - } - } - if (icase) { - dg[irxn] = MAX(0.0, dg[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. - */ - int k; - for (iph = 0; iph < NPhase; iph++) { - lneed = FALSE; - vcs_VolPhase *Vphase = VPhaseList[iph]; - if (! Vphase->SingleSpecies) { - double sum = 0.0; - for (k = 0; k < Vphase->NVolSpecies; k++) { - kspec = Vphase->IndSpecies[k]; - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - sum += soln[kspec]; - } - if (sum > 0.0) break; - } - if (sum == 0.0) { - lneed = TRUE; - } - } - - if (lneed) { - double poly = 0.0; - for (k = 0; k < Vphase->NVolSpecies; k++) { - kspec = Vphase->IndSpecies[k]; + /* + * 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 (PhaseID[kspec] == iph) { irxn = kspec - m_numComponents; - if (dg[irxn] > 50.0) dg[irxn] = 50.0; - if (dg[irxn] < -50.0) dg[irxn] = -50.0; - poly += exp(-dg[irxn])/ActCoeff[kspec]; - } - /* - * 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. - */ - for (k = 0; k < Vphase->NVolSpecies; k++) { - kspec = Vphase->IndSpecies[k]; - irxn = kspec - m_numComponents; - dg[irxn] = 1.0 - poly; - } - - } - } - - -#ifdef DEBUG_NOT - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - checkFinite(dg[irxn]); - } -#endif -} /* vcs_deltag() ************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int VCS_SOLVE::vcs_basopt(int ifirst, double aw[], double sa[], double sm[], - double ss[], double test, int *usedZeroedSpecies) - - /************************************************************************** - * Choose the optimum 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. - * - * Calculates the identity of the component species in the mechanism. - * Rearranges the solution data to put the component data at the - * front of the species list. - * - * Then, calculates SC(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 - * --------- - * IFIRST = If true, the SC, DNG, and DNL are not calculated. - * TEST = This is a small negative number dependent upon whether - * an estimate is supplied or not. - * W(I) = Mole fractions which will be used to construct an - * optimal basis from. - * - * Output - * --------- - * usedZeroedSpecies = If true, then a species with a zero concentration - * was used as a component. The problem may be - * converged. - * - * Other Variables - * aw[i] = Mole fraction work space (# species in length) - * sa[j] = Gramm-Schmidt orthog work space (nc in length) - * ss[j] = Gramm-Schmidt orthog work space (nc in length) - * sm[i+j*ne] = QR matrix work space (nc*ne in length) - * - *************************************************************************/ -{ - int j, k, l, i, jl, ml, jr, lindep, irxn, kspec; - int ncTrial; - int juse = -1; - int jlose = -1; - double *dptr, *scrxn_ptr; - double tsecond = vcs_second(); -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n"); - plogf(" --- Subroutine BASOPT called to "); - if (ifirst) plogf("calculate the number of components\n"); - else plogf("reevaluate the components\n"); - if (vcs_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 ", ElActive[j]); - } - plogf("\n"); - plogf(" --- Species | "); - for (j = 0; j < m_numElemConstraints; j++) { - plogf(" "); - vcs_print_stringTrunc(ElName[j].c_str(), 4, 1); - } - plogf("\n"); - for (k = 0; k < m_numSpeciesTot; k++) { - plogf(" --- "); - vcs_print_stringTrunc(SpName[k].c_str(), 11, 1); - plogf(" | "); - for (j = 0; j < m_numElemConstraints; j++) { - plogf("%5.1g", FormulaMatrix[j][k]); - } - plogf("\n"); - } - plogf("\n"); - } - } -#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 = 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(soln), m_numSpeciesTot); - /* - * Take out the Voltage unknowns from consideration - */ - for (k = 0; k < m_numSpeciesTot; k++) { - if (SpeciesUnknownType[k] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - aw[k] = test; - } - } - - jr = -1; - /* - * Top of a loop of some sort based on the index JR. JR is the - * current number of component species found. - */ - do { - ++jr; - /* - Top of another loop point based on finding a linearly */ - /* - independent species */ - do { - /* - * Search the remaining part of the mole 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_amax(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; - int kfound = -1; - int minNonZeroes = 100000; - int nonZeroesKspec = 0; - for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) { - if (aw[kspec] >= 0.0) { - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - maxConcPossKspec = 1.0E10; - nonZeroesKspec = 0; - for (int j = 0; j < m_numElemConstraints; ++j) { - if (ElActive[j]) { - if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { - double nu = FormulaMatrix[j][kspec]; - if (nu != 0.0) { - nonZeroesKspec++; - maxConcPossKspec = MIN(gai[j] / nu, maxConcPossKspec); - } - } - } - } - if ((maxConcPossKspec >= maxConcPoss) || (maxConcPossKspec > 1.0E-5)) { - if (nonZeroesKspec <= minNonZeroes) { - if (kfound < 0 || nonZeroesKspec < minNonZeroes) { - kfound = kspec; - } else { - // ok we are sitting pretty equal here decide on the raw ss Gibbs energy - if (ff[kspec] <= ff[kfound]) { - kfound = kspec; - } - } - } - if (nonZeroesKspec < minNonZeroes) { - minNonZeroes = nonZeroesKspec; - } - if (maxConcPossKspec > maxConcPoss) { - maxConcPoss = maxConcPossKspec; - } - } - } - } - } - if (kfound == -1) { - double gmin = 0.0; - kfound = k; - for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) { - if (aw[kspec] >= 0.0) { - irxn = kspec - ncTrial; - if (dg[irxn] < gmin) { - gmin = dg[irxn]; - kfound = kspec; - } - } - } - } - k = kfound; - } - - - if (aw[k] == test) { - m_numComponents = jr; - ncTrial = m_numComponents; - int numPreDeleted = m_numRxnTot - m_numRxnRdc; - if (numPreDeleted != (m_numSpeciesTot - m_numSpeciesRdc)) { - plogf("we shouldn't be here\n"); - exit(-1); - } - m_numRxnTot = m_numSpeciesTot - ncTrial; - m_numRxnRdc = m_numRxnTot - numPreDeleted; - m_numSpeciesRdc = m_numSpeciesTot - numPreDeleted; - for (i = 0; i < m_numSpeciesTot; ++i) { - ir[i] = ncTrial + i; - } + soln[kspec] = 0.0; + wt[kspec] = 0.0; + ds[kspec] = 0.0; + spStatus[irxn] = VCS_SPECIES_ZEROEDPHASE; + + ++(m_numRxnRdc); + ++(m_numSpeciesRdc); #ifdef DEBUG_MODE if (vcs_debug_print_lvl >= 2) { - plogf(" --- Total number of components found = %3d (ne = %d)\n ", - ncTrial, m_numElemConstraints); + plogf(" --- Make %s", SpName[kspec].c_str()); + plogf(" an active but zeroed species because its phase " + "was zeroed\n"); } #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] = 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]; + if (kspec != (m_numSpeciesRdc - 1)) { + /* + * Rearrange both the species and the non-component global data + */ + vcs_switch_pos(TRUE, (m_numSpeciesRdc - 1), kspec); } - /* - * 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 ********** */ - /* **************************************************** */ - if (sa[jr] < 1.0e-6) lindep = TRUE; - else lindep = FALSE; - } while(lindep); - /* ****************************************** */ - /* **** REARRANGE THE DATA ****************** */ - /* ****************************************** */ - if (jr != k) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", (SpName[k]).c_str()); - plogf("(%9.2g) replaces %-12.12s", soln[k], SpName[jr].c_str()); - plogf("(%9.2g) as component %3d\n", soln[jr], jr); - } -#endif - vcs_switch_pos(FALSE, jr, k); - vcsUtil_dsw(aw, jr, k); - } -#ifdef DEBUG_MODE - else { - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %-12.12s", SpName[k].c_str()); - plogf("(%9.2g) remains ", soln[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 (ifirst) 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 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, FormulaMatrix, sp, and gai, 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] = FormulaMatrix[i][j]; - } - } - for (i = 0; i < m_numRxnTot; ++i) { - k = ir[i]; - for (j = 0; j < ncTrial; ++j) { - sc[i][j] = FormulaMatrix[j][k]; - } - } - /* - * Use Gauss-Jordon block elimination to calculate - * the reaction matrix, sc[][]. - */ - j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, sc[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 = -1; - jlose = -1; - for (j = 0; j < m_numElemConstraints; j++) { - if (! (ElActive[j])) { - if (!strcmp((ElName[j]).c_str(), "E")) { - juse = j; - } - } - } - for (j = 0; j < m_numElemConstraints; j++) { - if (ElActive[j]) { - if (!strncmp((ElName[j]).c_str(), "cn_", 3)) { - jlose = j; - } - } - } - for (k = 0; k < m_numSpeciesTot; k++) { - if (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] = FormulaMatrix[juse][j]; - } else { - sm[i + j*m_numElemConstraints] = FormulaMatrix[i][j]; - } - } - } - for (i = 0; i < m_numRxnTot; ++i) { - k = ir[i]; - for (j = 0; j < ncTrial; ++j) { - if (j == jlose) { - aw[j] = FormulaMatrix[juse][k]; - } else { - aw[j] = FormulaMatrix[j][k]; - } - } - } - 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++) { - sc[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(sc[i][j]); - } - scSize[i] = szTmp; - } - - -#ifdef DEBUG_MODE - if (vcs_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.3g", soln[j]); - } - plogf("\n --- NonComponent| Moles | "); - for (j = 0; j < ncTrial; j++) { - plogf("%-10.10s", SpName[j].c_str()); - } - //plogf("| scSize"); - plogf("\n"); - for (i = 0; i < m_numRxnTot; i++) { - plogf(" --- %3d ", ir[i]); - plogf("%-10.10s", SpName[ir[i]].c_str()); - plogf("|%10.3g|", soln[ir[i]]); - for (j = 0; j < ncTrial; j++) { - plogf(" %6.2f", sc[i][j]); - } - //plogf(" | %6.2f", scSize[i]); - 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(DnPhase[0], (NSPECIES0)*(NPHASE0)); - vcs_izero(PhaseParticipation[0], (NSPECIES0)*(NPHASE0)); - /* - * Loop over each reaction, creating the change in Phase Moles - * array, DnPhase[irxn][iphase], - * and the phase participation array, PhaseParticipation[irxn][iphase] - */ - for (irxn = 0; irxn < m_numRxnTot; ++irxn) { - scrxn_ptr = sc[irxn]; - dptr = DnPhase[irxn]; - kspec = ir[irxn]; - int iph = PhaseID[kspec]; - int *pp_ptr = PhaseParticipation[irxn]; - dptr[iph] = 1.0; - pp_ptr[iph]++; - for (j = 0; j < ncTrial; ++j) { - iph = 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: ; - tsecond = vcs_second() - tsecond; - m_VCount->Time_basopt += tsecond; - (m_VCount->Basis_Opts)++; - return VCS_SUCCESS; -} /* vcs_basopt() ************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int VCS_SOLVE::vcs_species_type(int kspec) - - /************************************************************************* - * - * vcs_species_type: - * - * Evaluate the species category for the input species - * return the type in the return variable - *************************************************************************/ -{ - int irxn = kspec - m_numComponents; - int iph, k; - - if (kspec < m_numComponents) return VCS_SPECIES_COMPONENT; - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - return VCS_SPECIES_INTERFACIALVOLTAGE; - } - iph = PhaseID[kspec]; - if (soln[kspec] <= 0.0) { - if (dg[irxn] >= 0.0) { - /* - * We are here when the species is or should be zeroed out - */ - if (SSPhase[kspec]) { - return VCS_SPECIES_ZEROEDSS; - } else { - if (TPhMoles[iph] == 0.0) return VCS_SPECIES_ZEROEDPHASE; - else return VCS_SPECIES_ZEROEDMS; } } /* - * The Gibbs free energy for this species is such that - * it will pop back into existence. - * -> Set it to a major species in anticipation. - * -> One exception to this is if a needed component - * is also zeroed out. Then, don't pop the phase back into - * existence. - * -> Another 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. + * Upload the state to the VP object */ - for (int j = 0; j < m_numComponents; ++j) { - double stoicC = sc[irxn][j]; - if (stoicC != 0.0) { - double negChangeComp = - stoicC; - if (negChangeComp > 0.0) { - if (soln[j] < 1.0E-60) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %s would have popped back into existance but" - " needed component %s is zero\n", - SpName[kspec].c_str(), SpName[j].c_str()); - } -#endif - if (SSPhase[kspec]) { - return VCS_SPECIES_ZEROEDSS; - } else { - return VCS_SPECIES_ZEROEDMS; - } - } - } - } - } + Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), VCS_DATA_PTR(TPhMoles), iph); - for (int j = 0; j < m_numElemConstraints; ++j) { - int elType = m_elType[j]; - if (elType == VCS_ELEM_TYPE_ABSPOS) { - double atomComp = FormulaMatrix[j][kspec]; - if (atomComp > 0.0) { - double maxPermissible = gai[j] / atomComp; - if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- %s would have popped back into existance but" - " needed element %s is zero\n", - SpName[kspec].c_str(), (ElName[j]).c_str()); - } -#endif - if (SSPhase[kspec]) { - return VCS_SPECIES_ZEROEDSS; - } else { - return VCS_SPECIES_ZEROEDMS; - } - } - } - } - } - - return VCS_SPECIES_MAJOR; - } - /* - * Always treat species in single species phases as majors + } /* delete_multiphase() *****************************************************/ + + /***************************************************************************** + * + * recheck_deleted: + * + * Recheck deleted species in multispecies phases. + * + * HKM -> This algorithm needs to be updated for activity coefficients */ - if (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 - */ - if (soln[kspec] > (TPhMoles[iph] * 0.1)) 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. - */ - double szAdj = scSize[irxn] * std::sqrt((double)m_numRxnTot); - for (k = 0; k < m_numComponents; ++k) { - if (!(SSPhase[k])) { - if (sc[irxn][k] != 0.0) { - if (soln[kspec] * szAdj >= soln[k] * 0.01) { - return VCS_SPECIES_MAJOR; - } - } - } - } - return VCS_SPECIES_MINOR; -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_chemPotPhase(int iph, const double *const molNum, - double * const ac, double * const mu_i, - bool do_deleted) - - /************************************************************************** - * - * vcs_chemPotPhase: - * - * We calculate the dimensionless chemical potentials of all species - * in a single phase. - * - * Formula: - * --------------- - * - * Ideal Mixtures: - * - * fe(I) = ff(I) + ln(z(I)) - ln(tPhMoles_ptr[iph]) - * - * ( This is equivalent to the adding the log of the - * mole fraction onto the standard chemical - * potential. ) - * - * Non-Ideal Mixtures: - * ActivityConvention = 0: - * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) - * - * ( 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 - * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) - * - ln(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 - * z(i) < VCS_DELETE_MINORSPECIES_CUTOFF - * The chemical potential is calculated as: - * fe(I) = ff(I) + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF)) - * - * Input - * -------- - * iph : Phase to be calculated - * molNum(i) : Number of moles of species i - * (VCS species order) - * ff : standard state chemical potentials. These are the - * chemical potentials of the standard states at - * the same T and P as the solution. - * (VCS species order) - * Output - * ------- - * ac[] : Activity coefficients for species in phase - * (VCS species order) - * mu_i[] : Dimensionless chemical potentials for phase species - * (VCS species order) - * - *************************************************************************/ -{ - vcs_VolPhase *Vphase = VPhaseList[iph]; - int nkk = Vphase->NVolSpecies; - int k, kspec; - + int VCS_SOLVE::recheck_deleted(void) + { + int iph, kspec, irxn, npb; + double *xtcutoff = VCS_DATA_PTR(TmpPhase); #ifdef DEBUG_MODE - //if (vcs_debug_print_lvl >= 2) { - // plogf(" --- Subroutine vcs_chemPotPhase called for phase %d\n", - // iph); - //} + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Start rechecking deleted species in multispec phases\n"); + } #endif - double tMoles = TPhInertMoles[iph]; - for (k = 0; k < nkk; k++) { - kspec = Vphase->IndSpecies[k]; - tMoles += molNum[kspec]; - } - double tlogMoles = 0.0; - if (tMoles > 0.0) { - tlogMoles = log(tMoles); - } - - Vphase->setMolesFromVCS(molNum); - Vphase->sendToVCSActCoeff(ac); - - double phi = Vphase->electricPotential(); - double Faraday_phi = Faraday_dim * phi; - - for (k = 0; k < nkk; k++) { - kspec = Vphase->IndSpecies[k]; - if (kspec >= m_numComponents) { - int irxn = kspec - m_numComponents; - if (!do_deleted && - (spStatus[irxn] == VCS_SPECIES_DELETED)) { - continue; - } - } - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { -#ifdef DEBUG_MODE - if (molNum[kspec] != phi) { - plogf("We have an inconsistency!\n"); - exit(-1); - } - if (Charge[kspec] != -1.0) { - plogf("We have an unexpected situation!\n"); - exit(-1); - } -#endif - mu_i[kspec] = ff[kspec] + Charge[kspec] * Faraday_phi; - } else { - if (SSPhase[kspec]) { - mu_i[kspec] = ff[kspec] + Charge[kspec] * Faraday_phi; - } else if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { - mu_i[kspec] = ff[kspec] + log(ac[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) - - tlogMoles - SpecLnMnaught[kspec] + Charge[kspec] * Faraday_phi; - } else { - mu_i[kspec] = ff[kspec] + log(ac[kspec] * molNum[kspec]) - - tlogMoles - SpecLnMnaught[kspec] + Charge[kspec] * Faraday_phi; - } - } - } -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_dfe(double *z, int kk, int ll, int lbot, int ltop) - - /************************************************************************** - * - * vcs_dfe: - * - * 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. - * It's chemical potential - * is then calculated using the VCS_DELETE_MINORSPECIES_CUTOFF concentration - * to keep numbers positive. - * - * - * Formula: - * --------------- - * - * Ideal Mixtures: - * - * fe(I) = ff(I) + ln(z(I)) - ln(tPhMoles_ptr[iph]) - * - * ( This is equivalent to the adding the log of the - * mole fraction onto the standard chemical - * potential. ) - * - * Non-Ideal Mixtures: - * ActivityConvention = 0: - * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) - * - * ( 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 - * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) - * - ln(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 above, for small species where the mole - * fraction - * z(i) < VCS_DELETE_MINORSPECIES_CUTOFF - * The chemical potential is calculated as: - * fe(I) = ff(I) + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF)) - * - * VCS_SPECIES_TYPE_INTERFACIALVOLTAGE - * - * These chemical potentials refer to electrons in - * metal electrodes. They have the following formula - * - * fe(I) = ff(I) - F V / 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 is V in volts. - * - * Input - * -------- - * ll = 0: Calculate for all species - * -1: calculate for components and for major non-components - * 1: calculate for components and for minor non-components - * lbot : restricts the calculation of the chemical potential - * ltop to the species between LBOT <= i < LTOP. Usually - * LBOT and LTOP will be equal to 0 and MR, respectively. - * z(i) : Number of moles of species i - * -> This can either be the current solution vector WT() - * or the actual solution vector W() - * kk 1: Use the tentative values for the total number of - * moles in the phases, i.e., use TG1 instead of TG etc. - * 0: Use the base values of the total number of - * moles in each system. - * ff : 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. - * - * - *************************************************************************/ -{ - int l1, l2, iph, kspec, irxn; - int iphase; - double *tPhMoles_ptr; - double *tlogMoles; - vcs_VolPhase *Vphase; - VCS_SPECIES_THERMO *st_ptr; - -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - if (ll == 0) { - if (lbot != 0) { - plogf(" --- Subroutine vcs_dfe called for one species: "); - plogf("%-12.12s", SpName[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 (kk == 1) plogf(" using tentative solution\n"); - else plogf("\n"); - } -#endif - if (kk <= 0) { - tPhMoles_ptr = VCS_DATA_PTR(TPhMoles); - } else { - tPhMoles_ptr = VCS_DATA_PTR(TPhMoles1); - } - tlogMoles = VCS_DATA_PTR(TmpPhase); - /* - * Might as well recalculate the phase mole vector - * and compare to the storred one. They should be correct. - */ - double *tPhInertMoles = VCS_DATA_PTR(TPhInertMoles); - for (iph = 0; iph < NPhase; iph++) { - tlogMoles[iph] = tPhInertMoles[iph]; - - } - for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { - if(SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - iph = PhaseID[kspec]; - tlogMoles[iph] += z[kspec]; - } - } -#ifdef DEBUG_MODE - for (iph = 0; iph < NPhase; 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(0); - } - } -#endif - vcs_dzero(tlogMoles, NPhase); - for (iph = 0; iph < NPhase; iph++) { - if (tPhMoles_ptr[iph] > 0.0) { - tlogMoles[iph] = log(tPhMoles_ptr[iph]); - } - } - /* - * Zero the indicator that that tells us the activity coefficients - * are current - */ - vcs_izero(VCS_DATA_PTR(CurrPhAC), NPhase); - - if (ll != 0) { - l1 = lbot; - l2 = m_numComponents; - } else { - l1 = lbot; - l2 = ltop; - } - - /* - * Calculate activity coefficients for all phases that are - * not current - */ - for (iphase = 0; iphase < NPhase; iphase++) { - if (!CurrPhAC[iphase]) { - Vphase = VPhaseList[iphase]; - if (!Vphase->SingleSpecies) { - Vphase->setMolesFromVCS(z); - Vphase->sendToVCSActCoeff(VCS_DATA_PTR(ActCoeff)); - } - phasePhi[iphase] = Vphase->electricPotential(); - CurrPhAC[iphase] = 1; - } - } - /* ************************************************************** */ - /* **** 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 = PhaseID[kspec]; - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { -#ifdef DEBUG_MODE - if (z[kspec] != phasePhi[iphase]) { - plogf("We have an inconsistency!\n"); - exit(-1); - } - if (Charge[kspec] != -1.0) { - plogf("We have an unexpected situation!\n"); - exit(-1); - } -#endif - m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; - } else { - if (SSPhase[kspec]) { - m_gibbsSpecies[kspec] = ff[kspec]; - } else { - if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { - iph = PhaseID[kspec]; - if (tPhMoles_ptr[iph] > 0.0) { - m_gibbsSpecies[kspec] = ff[kspec] - + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] - + Charge[kspec] * Faraday_dim * phasePhi[iphase]; - } else { - m_gibbsSpecies[kspec] = ff[kspec]; - } - } else { - m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] - + Charge[kspec] * Faraday_dim * phasePhi[iphase]; - } - } - } - } - /* ************************************************ */ - /* **** MAJORS ONLY ******************************* */ - /* ************************************************ */ - if (ll < 0) { - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] != VCS_SPECIES_MINOR) { - kspec = ir[irxn]; - iphase = PhaseID[kspec]; - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { -#ifdef DEBUG_MODE - if (z[kspec] != phasePhi[iphase]) { - plogf("We have an inconsistency!\n"); - exit(-1); - } - if (Charge[kspec] != -1.0) { - plogf("We have an unexpected situation!\n"); - exit(-1); - } -#endif - m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; - } else { - if (SSPhase[kspec]) { - m_gibbsSpecies[kspec] = ff[kspec]; - } else { - if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { - iph = PhaseID[kspec]; - if (tPhMoles_ptr[iph] > 0.0) { - m_gibbsSpecies[kspec] = ff[kspec] - + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] - + Charge[kspec] * Faraday_dim * phasePhi[iphase]; ; - } else { - m_gibbsSpecies[kspec] = ff[kspec]; - } - } else { - m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] - + Charge[kspec] * Faraday_dim * phasePhi[iphase]; - } - } - } - } - } - /* ************************************************ */ - /* **** MINORS ONLY ******************************* */ - /* ************************************************ */ - } else if (ll > 0) { - for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] == VCS_SPECIES_MINOR) { - kspec = ir[irxn]; - iphase = PhaseID[kspec]; - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { -#ifdef DEBUG_MODE - if (z[kspec] != phasePhi[iphase]) { - plogf("We have an inconsistency!\n"); - exit(-1); - } - if (Charge[kspec] != -1.0) { - plogf("We have an unexpected situation!\n"); - exit(-1); - } -#endif - m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; ; - } else { - if (SSPhase[kspec]) { - m_gibbsSpecies[kspec] = ff[kspec]; - } else { - if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { - iph = PhaseID[kspec]; - if (tPhMoles_ptr[iph] > 0.0) { - m_gibbsSpecies[kspec] = ff[kspec] - + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec]; - } else { - m_gibbsSpecies[kspec] = ff[kspec]; - } - } else { - st_ptr = SpeciesThermo[kspec]; - m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) - - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec]; - } - } - } - } - } - } -#ifdef DEBUG_NOT - for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { - checkFinite(fe[kspec]); - } -#endif -} /* vcs_dfe() ***************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int vcsUtil_mlequ(double *c, int idem, int n, double *b, int m) - - /************************************************************************* - * - * vcs_mlequ: - * - * Invert an nxn matrix and solve m rhs's - * - * Solve C X + B = 0; - * - * This routine uses Gauss elimination and is optimized for the solution - * of lots of rhs's. - * A crude form of row pivoting is used here. - * - * - * c[i+j*idem] = c_i_j = Matrix to be inverted: i = row number - * j = column number - * b[i+j*idem] = b_i_j = vectors of rhs's: i = row number - * j = column number - * (each column is a new rhs) - * n = number of rows and columns in the matrix - * m = number of rhs to be solved for - * idem = first dimension in the fortran calling routine - * idem >= n must be true - * - * Return Value - * 1 : Matrix is singluar - * 0 : solution is OK - * - * The solution is returned in the matrix b. - *************************************************************************/ -{ - int i, j, k, l; - double R; - - /* - * Loop over the rows - * -> At the end of each loop, the only nonzero entry in the column - * will be on the diagonal. We can therfore just invert the - * diagonal at the end of the program to solve the equation system. - */ - for (i = 0; i < n; ++i) { - if (c[i + i * idem] == 0.0) { - /* - * Do a simple form of row pivoting to find a non-zero pivot - */ - for (k = i + 1; k < n; ++k) { - if (c[k + i * idem] != 0.0) goto FOUND_PIVOT; - } - plogf("vcs_mlequ ERROR: Encountered a zero column: %d\n", i); - return 1; - FOUND_PIVOT: ; - for (j = 0; j < n; ++j) c[i + j * idem] += c[k + j * idem]; - for (j = 0; j < m; ++j) b[i + j * idem] += b[k + j * idem]; - } - - for (l = 0; l < n; ++l) { - if (l != i && c[l + i * idem] != 0.0) { - R = c[l + i * idem] / c[i + i * idem]; - c[l + i * idem] = 0.0; - for (j = i+1; j < n; ++j) c[l + j * idem] -= c[i + j * idem] * R; - for (j = 0; j < m; ++j) b[l + j * idem] -= b[i + j * idem] * R; - } - } - } - /* - * The negative in the last expression is due to the form of B upon - * input - */ - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) - b[i + j * idem] = -b[i + j * idem] / c[i + i*idem]; - } - return VCS_SUCCESS; -} /* vcs_mlequ() *************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void vcsUtil_isw(int x[], int i1, int i2) - - /************************************************************************** - * - * vcs_isw: - * - * Switches the value of X(i1) with X(i2) - *************************************************************************/ -{ - int t; - t = x[i1]; - x[i1] = x[i2]; - x[i2] = t; -} /* vcs_isw() ***************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void vcsUtil_dsw(double *x, int i1, int i2) - - /************************************************************************** - * - * vcs_dsw: - * - * Switches the value of X(i1) with X(i2) - *************************************************************************/ -{ - double t; - t = x[i1]; - x[i1] = x[i2]; - x[i2] = t; -} /* vcs_dsw() ***************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void vcsUtil_ssw(char **vstr, int i1, int i2) - - /************************************************************************** - * - * vcs_ssw: - * - * Switches the place of two strings in an array of strings. - * (Limited to strings of length less than 24 characters). - *************************************************************************/ -{ - char tmp[24]; - (void) strncpy(tmp, vstr[i2], (size_t) 24); - (void) strncpy(vstr[i2], vstr[i1], (size_t) 24); - (void) strncpy(vstr[i1], tmp, (size_t) 24); -} - -/* - * - * vcs_stsw: - * - * Switches the place of two strings in a vector of strings. - */ -void vcsUtil_stsw(std::vector & vstr, int i1, int i2) -{ - std::string tmp(vstr[i2]); - vstr[i2] = vstr[i1]; - vstr[i1] = tmp; -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -#ifdef DEBUG_MODE - -void VCS_SOLVE::prneav(void) - - /************************************************************************* - * - * Print out and check the elemental abundance vector - * - *************************************************************************/ -{ - int kerr, i, j; - std::vector eav(m_numElemConstraints, 0.0); - - for (j = 0; j < m_numElemConstraints; ++j) { - for (i = 0; i < m_numSpeciesTot; ++i) { - if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - eav[j] += FormulaMatrix[j][i] * soln[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", (ElName[j]).c_str()); - plogf(" = %15.6E %15.6E %15.6E %3d\n", - eav[j], gai[j], eav[j] - gai[j], m_elType[j]); - if (gai[j] != 0.) { - if (fabs(eav[j] - gai[j]) > gai[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("--------------------------------------------------\n"); -} -#endif - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -double VCS_SOLVE::l2normdg(double dgLocal[]) - - /************************************************************************* - * - * l2normdg: - * - * Calculate the norm of the DG vector. - * Positive DG for species which don't exist are ignored. - ************************************************************************/ -{ - double tmp; - int irxn; - if (m_numRxnRdc <= 0) return 0.0; - for (irxn = 0, tmp = 0.0; irxn < m_numRxnRdc; ++irxn) { - if (spStatus[irxn] == VCS_SPECIES_MAJOR || spStatus[irxn] == VCS_SPECIES_MINOR || - dgLocal[irxn] < 0.0) { - if (spStatus[irxn] != VCS_SPECIES_ZEROEDMS) { - tmp += dgLocal[irxn] * dgLocal[irxn]; - } - } - } - return (sqrt(tmp / m_numRxnRdc)); -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_tmoles(void) - - /************************************************************************** - * - * vcs_tmoles: - * - * 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. - *************************************************************************/ -{ - int i; - double sum; - vcs_VolPhase *Vphase; - for (i = 0; i < NPhase; i++) { - TPhMoles[i] = TPhInertMoles[i]; - } - for (i = 0; i < m_numSpeciesTot; i++) { - if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { - TPhMoles[PhaseID[i]] += soln[i]; - } - } - sum = 0.0; - for (i = 0; i < NPhase; i++) { - sum += TPhMoles[i]; - Vphase = VPhaseList[i]; - // Took out because we aren't updating mole fractions in Vphase - // Vphase->TMoles = TPhMoles[i]; - if (TPhMoles[i] == 0.0) { - Vphase->Existence = 0; - } else { - if (TPhInertMoles[i] > 0.0) { - Vphase->Existence = 2; - } else { - Vphase->Existence = 1; - } - } - } - TMoles = sum; -} /* vcs_tmoles() ************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_updateVP (int place) - - /************************************************************************* - * vcs_updateVP() - * - * This routine uploads the state of the system into all of the - * VolumePhase objects in the current problem. - * place - * 0 -> from soln - * 1 -> from wt - *************************************************************************/ -{ - vcs_VolPhase *Vphase; - for (int i = 0; i < NPhase; i++) { - Vphase = VPhaseList[i]; - if (place == 0) { - Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), - VCS_DATA_PTR(TPhMoles), i); - } else if (place == 1) { - Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(wt), - VCS_DATA_PTR(TPhMoles1), i); - } else { - plogf("we shouldn't be here\n"); - exit(-1); - } - } -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_switch2D(double * const * const Jac, int k1, int k2) - - /************************************************************************** - * vcs_switch2D: - * - * Switch rows and columns of a square matrix - *************************************************************************/ -{ - int i; - register double dtmp; - for (i = 0; i < m_numSpeciesTot; i++) { - SWAP(Jac[k1][i], Jac[k2][i], dtmp); - } - for (i = 0; i < m_numSpeciesTot; i++) { - SWAP(Jac[i][k1], Jac[i][k2], dtmp); - } -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void VCS_SOLVE::vcs_switch_pos(int ifunc, int k1, int k2) - - /************************************************************************** - * - * vcs_switch_pos: - * - * Swaps the indecises for all of the global data for two species, k1 - * and k2. - * - * 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. - *************************************************************************/ -{ - register int j; - register double t1 = 0.0; - int i1, i2, iph, kp1, kp2; - vcs_VolPhase *pv1, *pv2; - VCS_SPECIES_THERMO *st_tmp; - if (k1 == k2) return; -#ifdef DEBUG_MODE - if (k1 < 0 || k1 > (m_numSpeciesTot - 1) || - k2 < 0 || 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 = VPhaseList[PhaseID[k1]]; - pv2 = VPhaseList[PhaseID[k2]]; - - kp1 = indPhSp[k1]; - kp2 = indPhSp[k2]; -#ifdef DEBUG_MODE - if (pv1->IndSpecies[kp1] != k1) { - plogf("Indexing error in program\n"); - exit(-1); - } - if (pv2->IndSpecies[kp2] != k2) { - plogf("Indexing error in program\n"); - exit(-1); - } -#endif - pv1->IndSpecies[kp1] = k2; - pv2->IndSpecies[kp2] = k1; - - vcsUtil_stsw(SpName, k1, k2); - SWAP(soln[k1], soln[k2], t1); - SWAP(SpeciesUnknownType[k1], SpeciesUnknownType[k2], j); - SWAP(wt[k1], wt[k2], t1); - SWAP(ff[k1], ff[k2], t1); - SWAP(m_gibbsSpecies[k1], m_gibbsSpecies[k2], t1); - SWAP(ds[k1], ds[k2], t1); - SWAP(fel[k1], fel[k2], t1); - SWAP(feTrial[k1], feTrial[k2], t1); - SWAP(SSPhase[k1], SSPhase[k2], j); - SWAP(PhaseID[k1], PhaseID[k2], j); - SWAP(ind[k1], ind[k2], j); - SWAP(indPhSp[k1], indPhSp[k2], j); - SWAP(SpecActConvention[k1], SpecActConvention[k2], j); - SWAP(SpecLnMnaught[k1], SpecLnMnaught[k2], t1); - SWAP(ActCoeff[k1], ActCoeff[k2], t1); - SWAP(ActCoeff0[k1], ActCoeff0[k2], t1); - SWAP(WtSpecies[k1], WtSpecies[k2], t1); - SWAP(Charge[k1], Charge[k2], t1); - SWAP(SpeciesThermo[k1], SpeciesThermo[k2], st_tmp); - SWAP(VolPM[k1], VolPM[k2], t1); - - for (j = 0; j < m_numElemConstraints; ++j) { - SWAP(FormulaMatrix[j][k1], FormulaMatrix[j][k2], t1); - } - if (UseActCoeffJac) { - vcs_switch2D(dLnActCoeffdMolNum.baseDataAddr(), k1, k2); - } - - /* - * Handle the index pointer in the phase structures - */ - - - if (ifunc) { + if (m_numSpeciesRdc == m_numSpeciesTot) return 0; /* - * Find the noncomponent indecises for the two species + * Use the standard chemical potentials for the chemical potentials + * of deleted species. Then, calculate Delta G for + * for formation reactions */ - i1 = k1 - m_numComponents; - i2 = k2 - m_numComponents; -#ifdef DEBUG_MODE - if (i1 < 0 || i1 > (m_numRxnTot - 1) || - i2 < 0 || i2 > (m_numRxnTot - 1) ) { - plogf("switch_pos: ifunc = 1: inappropriate noncomp values: %d %d\n", - i1 , i2); + for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { + m_gibbsSpecies[kspec] = ff[kspec]; } -#endif - for (j = 0; j < m_numComponents; ++j) { - SWAP(sc[i1][j], sc[i2][j], t1); - } - SWAP(scSize[i1], scSize[i2], t1); + /* + * Recalculate the DeltaG's of the formation reactions for the + * deleted species in the mechanism + */ + vcs_deltag(0, true); + for (iph = 0; iph < NPhase; iph++) { - SWAP(DnPhase[i1][iph], DnPhase[i2][iph], t1); - SWAP(PhaseParticipation[i1][iph], - PhaseParticipation[i2][iph], j); + if (TPhMoles[iph] > 0.0) + xtcutoff[iph] = log (TPhMoles[iph] / VCS_DELETE_SPECIES_CUTOFF); + else + xtcutoff[iph] = 0.0; } - SWAP(dg[i1], dg[i2], t1); - SWAP(dgl[i1], dgl[i2], t1); - SWAP(spStatus[i1], spStatus[i2], j); - /* - * We don't want to swap ir[], because the values of ir should - * stay the same after the swap + * + * We are checking the equation: * - * vcs_isw(ir, i1, i2); + * sum_u = sum_j_comp [ sigma_i_j * u_j ] + * = u_i_O + log((AC_i * W_i)/TPhMoles) + * + * 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 th code. Also nonideal solutions will tend to + * complicate matters severely also. */ - } -} /* vcs_switch_pos() ********************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -static void print_space(int num) -{ - int j; - for (j = 0; j < num; j++) plogf(" "); -} - -/**************************************************************************** - * - * vcs_deltag_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. - */ -void VCS_SOLVE::vcs_deltag_Phase(int iphase, bool doDeleted) { - int iph; - int irxn, kspec, kcomp; - double *dtmp_ptr; - int irxnl = m_numRxnRdc; - if (doDeleted) irxnl = m_numRxnTot; - vcs_VolPhase *vPhase = VPhaseList[iphase]; - -#ifdef DEBUG_MODE - if (vcs_debug_print_lvl >= 2) { - plogf(" --- Subroutine vcs_deltag_Phase called for phase %d\n", - iphase); - } -#endif - - /* - * Single species Phase - */ - if (vPhase->SingleSpecies) { - kspec = vPhase->IndSpecies[0]; -#ifdef DEBUG_MODE - if (iphase != PhaseID[kspec]) { - plogf("vcs_deltag_Phase index error\n"); - exit(-1); - } -#endif - if (kspec >= m_numComponents) { - irxn = kspec - m_numComponents; - dg[irxn] = m_gibbsSpecies[kspec]; - dtmp_ptr = sc[irxn]; - for (kcomp = 0; kcomp < m_numComponents; ++kcomp) { - dg[irxn] += dtmp_ptr[kcomp] * m_gibbsSpecies[kcomp]; + npb = 0; + for (irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { + kspec = ir[irxn]; + iph = PhaseID[kspec]; + if (TPhMoles[iph] == 0.0) { + if (dg[irxn] < 0.0) { + vcs_reinsert_deleted(kspec); + npb++; + } else { + soln[kspec] = 0.0; + } + } else if (TPhMoles[iph] > 0.0) { + if (dg[irxn] < xtcutoff[iph]) { + vcs_reinsert_deleted(kspec); + npb++; + } } } - } - /* - * Multispecies Phase - */ - else { - bool zeroedPhase = TRUE; + return npb; + } /* recheck_deleted() *******************************************************/ - for (irxn = 0; irxn < irxnl; ++irxn) { + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::add_deleted(void) + + /************************************************************************* + * + * Provide an estimate for the deleted species in phases that + * are not zeroed out + * + *************************************************************************/ + { + int iph, kspec, retn; + if (m_numSpeciesRdc == m_numSpeciesTot) return; + /* + * Use the standard chemical potentials for the chemical potentials + * of deleted species. Then, calculate Delta G for + * for formation reactions + * + * HKM Note: We need to update this step for nonunity activity + * coefficients. + * The formula will be fe = ff + RT * ln(actCoeff) + * where the activity coefficient is evaluated at + * ~ infinite dilution. + */ + for (kspec = m_numSpeciesRdc; kspec < m_numSpeciesTot; ++kspec) { + m_gibbsSpecies[kspec] = ff[kspec]; + } + /* + * Recalculate the DeltaG's of the formation reactions for the + * deleted species in the mechanism + */ + vcs_deltag(0, true); + + + for (int irxn = m_numRxnRdc; irxn < m_numRxnTot; ++irxn) { kspec = ir[irxn]; - if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - iph = PhaseID[kspec]; - if (iph == iphase ) { - if (soln[kspec] > 0.0) zeroedPhase = FALSE; - dg[irxn] = m_gibbsSpecies[kspec]; + iph = PhaseID[kspec]; + if (TPhMoles[iph] > 0.0) { + double maxDG = MIN(dg[irxn], 300); + double dx = TPhMoles[iph] * exp(- maxDG); + retn = delta_species(kspec, &dx); + } + } + + vcs_dfe(VCS_DATA_PTR(soln), 0, 0, 0, m_numSpeciesTot); + vcs_deltag(0, true); + } + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int VCS_SOLVE::force(int iti) + + /************************************************************************** + * + * force: + * + * Convergence Forcer: + * + * This routine optimizes the minimization of the total gibbs free + * energy: + * Gibbs = sum_k( fe_k * w_k ) + * along the current direction ds[], by choosing a value, al: (0 0), + * does this code section kick in. It finds the point on the parabola + * where the slope is equal to zero. + * + * NOTE: The algorithm used to find the slope is not quite accurate. + * The term, sum_k( (fe_k_n - fe_k_n-1) * w_k_n-1 ) + * is dropped from s1, and, the term, + * sum_k( (fe_k_n - fe_k_n-1) * w_k_n ), is dropped from s2 + *************************************************************************/ + { + double s1, s2, al; + int i, iph; + double *dptr = VCS_DATA_PTR(m_gibbsSpecies); + //int numSpeciesRdc = m_numSpeciesRdc; + + /* *************************************************** */ + /* **** CALCULATE SLOPE AT END OF THE STEP ********** */ + /* *************************************************** */ + s2 = 0.0; + for (i = 0; i < m_numSpeciesRdc; ++i) { + s2 += dptr[i] * ds[i]; + } +#ifdef DEBUG_NOT + if (s2 <= 0.0) { +#ifdef DEBUG_NOT + if (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE produced no adjustments,"); + plogf(" failed s2 test\n"); + } +#endif + return FALSE; + } +#endif +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE: End Slope = %g\n", s2); + } +#endif + /* *************************************************** */ + /* **** CALCULATE ORIGINAL SLOPE ********************* */ + /* ************************************************** */ + s1 = 0.0; + dptr = VCS_DATA_PTR(fel); + for (i = 0; i < m_numSpeciesRdc; ++i) { + s1 += dptr[i] * ds[i]; + } +#ifdef DEBUG_NOT + if (s1 >= 0.0) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE produced no adjustments,"); + plogf(" failed s1 test -PROBLEM!!\n"); + } +#endif + return FALSE; + } +#endif +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE: Beginning Slope = %g\n", s1); + } +#endif + /* *************************************************** */ + /* **** FIT PARABOLA ********************************* */ + /* *************************************************** */ + 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 (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE produced no adjustments (al = %g)\n", al); + } +#endif + return FALSE; + } +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- subroutine FORCE produced a damping factor = %g\n", al); + } +#endif + /* *************************************************** */ + /* **** ADJUST MOLE NUMBERS, CHEM. POT *************** */ + /* *************************************************** */ + dptr = VCS_DATA_PTR(soln); + for (i = 0; i < m_numSpeciesRdc; ++i) { + dptr[i] += al * ds[i]; + } + for (iph = 0; iph < NPhase; iph++) { + TPhMoles[iph] += al * DelTPhMoles[iph]; + } + vcs_updateVP(0); + +#ifdef DEBUG_MODE + if (vcs_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_dfe(dptr, 0, iti, 0, m_numSpeciesRdc); + /* + * Evaluate DeltaG for all components if ITI=0, and for + * major components only if ITI NE 0 + */ + vcs_deltag(iti, false); + return TRUE; + } /* force() *****************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /* + * vcs_RxnStepSizes(): + * + * Calculates formation reaction step sizes. + * This is equation 6.4-16, p. 143 in Smith and Missen. + * + * Output + * ------- + * ds(I) : reaction adjustments, where I refers to the Ith species + * formation reaction. This is adjustment is for species + * i + M, where M is the number of components. + * Special branching occurs sometimes. This causes the component basis + * to be reevaluated + * return = 0 : normal return + * 1 : A single species phase species has been zeroed out + * in this routine. The species is a noncomponent + * 2 : Same as one but, the zeroed species is a component. + */ + int VCS_SOLVE::vcs_RxnStepSizes() { + int j, k, irxn, kspec, soldel = 0, iph; + double s, xx, dss; + vcs_VolPhase *Vphase = 0; + double *dnPhase_irxn; +#ifdef DEBUG_MODE + char ANOTE[128]; + if (vcs_debug_print_lvl >= 2) { + plogf(" "); for (j = 0; j < 82; j++) plogf("-"); plogf("\n"); + plogf(" --- Subroutine vcs_RxnStepSizes called - Details:\n"); + plogf(" "); for (j = 0; j < 82; j++) plogf("-"); plogf("\n"); + plogf(" --- Species Moles Rxn_Adjustment DeltaG" + " | Comment\n"); + } +#endif + /* + * We update the matrix dlnActCoeffdmolNumber[][] at the + * top of the loop, when necessary + */ + if (UseActCoeffJac) { + vcs_CalcLnActCoeffJac(VCS_DATA_PTR(soln)); + } + /************************************************************************ + ******** LOOP OVER THE FORMATION REACTIONS ***************************** + ************************************************************************/ + + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { +#ifdef DEBUG_MODE + sprintf(ANOTE,"Normal Calc"); +#endif + + kspec = ir[irxn]; + + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + + dnPhase_irxn = DnPhase[irxn]; + + if (soln[kspec] == 0.0 && (! SSPhase[kspec])) { + /********************************************************************/ + /******* MULTISPECIES PHASE WITH total moles equal to zero *********/ + /*******************************************************************/ + /* + * If dg[irxn] is negative, then the multispecies phase should + * come alive again. Add a small positive step size to + * make it come alive. + */ + if (dg[irxn] < -1.0e-4) { + /* + * First decide if this species is part of a multiphase that + * is nontrivial in size. + */ + iph = PhaseID[kspec]; + double tphmoles = TPhMoles[iph]; + double trphmoles = tphmoles / TMoles; + if (trphmoles > VCS_DELETE_PHASE_CUTOFF) { + ds[kspec] = TMoles * VCS_SMALL_MULTIPHASE_SPECIES; +#ifdef DEBUG_MODE + sprintf(ANOTE, + "MultSpec: small species born again DG = %11.3E", + dg[irxn]); +#endif + } else { +#ifdef DEBUG_MODE + sprintf(ANOTE, "MultSpec: phase come alive DG = %11.3E", dg[irxn]); +#endif + Vphase = VPhaseList[iph]; + int numSpPhase = Vphase->NVolSpecies; + ds[kspec] = TMoles * 10.0 * VCS_DELETE_PHASE_CUTOFF / numSpPhase; + } + --(m_numRxnMinorZeroed); + } else { +#ifdef DEBUG_MODE + sprintf(ANOTE, "MultSpec: still dead DG = %11.3E", dg[irxn]); +#endif + ds[kspec] = 0.0; + } + } else { + /********************************************************************/ + /************************* REGULAR PROCESSING ************/ + /********************************************************************/ + /* + * First take care of cases where we want to bail out + * + * + * Don't bother if superconvergence has already been achieved + * in this mode. + */ + if (fabs(dg[irxn]) <= tolmaj2) { +#ifdef DEBUG_MODE + sprintf(ANOTE,"Skipped: superconverged DG = %11.3E", dg[irxn]); + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", SpName[kspec].c_str()); + plogf(" %12.4E %12.4E %12.4E | %s\n", + soln[kspec], ds[kspec], dg[irxn], ANOTE); + } +#endif + continue; + } + /* + * Don't calculate for minor or nonexistent species if + * their values are to be decreasing anyway. + */ + if ((spStatus[irxn] != VCS_SPECIES_MAJOR) && (dg[irxn] >= 0.0)) { +#ifdef DEBUG_MODE + sprintf(ANOTE,"Skipped: IC = %3d and DG >0: %11.3E", + spStatus[irxn], dg[irxn]); + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", SpName[kspec].c_str()); + plogf(" %12.4E %12.4E %12.4E | %s\n", + soln[kspec], ds[kspec], dg[irxn], ANOTE); + } +#endif + continue; + } + /* + * Start of the regular processing + */ + if (SSPhase[kspec]) { + s = 0.0; + } else { + s = 1.0 / soln[kspec] ; + } + for (j = 0; j < m_numComponents; ++j) { + if (!SSPhase[j]) { + if (soln[j] > 0.0) { + s += SQUARE(sc[irxn][j]) / soln[j]; + } + } + } + for (j = 0; j < NPhase; j++) { + Vphase = VPhaseList[j]; + if (! Vphase->SingleSpecies) { + if (TPhMoles[j] > 0.0) + s -= SQUARE(dnPhase_irxn[j]) / TPhMoles[j]; + } + } + if (s != 0.0) { + /* + * Take into account of the + * derivatives of the activity coefficients with respect to the + * mole numbers, even in our diagonal approximation. + */ + if (UseActCoeffJac) { + double s_old = s; + s = vcs_Hessian_diag_adj(irxn, s_old); +#ifdef DEBUG_MODE + if (s_old != s) { + sprintf(ANOTE, "Normal calc: diag adjusted from %g " + "to %g due to act coeff", s_old, s); + } +#endif + } + + ds[kspec] = -dg[irxn] / s; + // New section to do damping of the ds[] + /* + * + */ + for (j = 0; j < m_numComponents; ++j) { + double stoicC = sc[irxn][j]; + if (stoicC != 0.0) { + double negChangeComp = - stoicC * ds[kspec]; + if (negChangeComp > soln[j]) { + if (soln[j] > 0.0) { +#ifdef DEBUG_MODE + sprintf(ANOTE, "Delta damped from %g " + "to %g due to component %d (%10s) going neg", ds[kspec], + -soln[j]/stoicC, j, SpName[j].c_str()); +#endif + ds[kspec] = - soln[j] / stoicC; + } else { +#ifdef DEBUG_MODE + sprintf(ANOTE, "Delta damped from %g " + "to %g due to component %d (%10s) zero", ds[kspec], + -soln[j]/stoicC, j, SpName[j].c_str()); +#endif + ds[kspec] = 0.0; + } + } + } + } + // Implement a damping term that limits ds to the size of the mole number + if (-ds[kspec] > soln[kspec]) { +#ifdef DEBUG_MODE + sprintf(ANOTE, "Delta damped from %g " + "to %g due to %s going negative", ds[kspec], + -soln[kspec], SpName[kspec].c_str()); +#endif + ds[kspec] = -soln[kspec]; + } + + } else { + /* ************************************************************ */ + /* **** REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES **** */ + /* **** DELETE ONE OF THE PHASES AND RECOMPUTE BASIS ********* */ + /* ************************************************************ */ + /* + * Either the species L will disappear or one of the + * component single species phases will disappear. The sign + * of DG(I) will indicate which way the reaction will go. + * Then, we need to follow the reaction to see which species + * will zero out first. + * -> The species to be zeroed out will be "k". + */ + if (dg[irxn] > 0.0) { + dss = soln[kspec]; + k = kspec; + for (j = 0; j < m_numComponents; ++j) { + if (sc[irxn][j] > 0.0) { + xx = soln[j] / sc[irxn][j]; + if (xx < dss) { + dss = xx; + k = j; + } + } + } + dss = -dss; + } else { + dss = 1.0e10; + for (j = 0; j < m_numComponents; ++j) { + if (sc[irxn][j] < 0.0) { + xx = -soln[j] / sc[irxn][j]; + if (xx < dss) { + dss = xx; + k = j; + } + } + } + } + /* + * Here we adjust the mole fractions + * according to DSS and the stoichiometric array + * to take into account that we are eliminating + * the kth species. DSS contains the amount + * of moles of the kth species that needs to be + * added back into the component species. + */ + if (dss != 0.0) { + soln[kspec] += dss; + TPhMoles[PhaseID[kspec]] += dss; + for (j = 0; j < m_numComponents; ++j) { + soln[j] += dss * sc[irxn][j]; + TPhMoles[PhaseID[j]] += dss * sc[irxn][j]; + } + soln[k] = 0.0; + iph = PhaseID[k]; + Vphase = VPhaseList[iph]; + Vphase->Existence = 0; + TPhMoles[iph] = 0.0; +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- vcs_RxnStepSizes Special section to delete %s\n", + SpName[k].c_str()); + plogf(" --- Immediate return - Restart iteration\n"); + } +#endif + /* + * We need to immediately recompute the + * component basis, because we just zeroed + * it out. + */ + if (k != kspec) soldel = 2; + else soldel = 1; + return soldel; + } + } + } /* End of regular processing */ +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", SpName[kspec].c_str()); + plogf(" %12.4E %12.4E %12.4E | %s\n", + soln[kspec], ds[kspec], dg[irxn], ANOTE); + } +#endif + } /* End of loop over SpeciesUnknownType */ + } /* End of loop over non-component stoichiometric formation reactions */ +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" "); vcs_print_line("-", 82); + } +#endif + return soldel; + } + /*****************************************************************************/ + + /************************************************************************** + * + * vcs_deltag: + * + * 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. SC(J,I) are the stoichiometric coefficients for these + * reactions. A stoichiometric coefficient of one is assumed for + * species I in this reaction. + * + * INPUT + * 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 + * irxnl : used with L = 0 to indicate upper limit. + * + * 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 the component. + * This dG < 0.0 feeds back into the algorithm in several + * places, and leads to a infinite loop in at least one case. + */ + void VCS_SOLVE::vcs_deltag(int l, bool doDeleted) { + int iph; + int lneed, irxn, kspec; + double *dtmp_ptr; + int icase = 0; + int irxnl = m_numRxnRdc; + if (doDeleted) { + irxnl = m_numRxnTot; + } + +#ifdef DEBUG_MODE + if (vcs_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) { + if (spStatus[irxn] != VCS_SPECIES_MINOR) { + icase = 0; + dg[irxn] = m_gibbsSpecies[ir[irxn]]; dtmp_ptr = sc[irxn]; - for (kcomp = 0; kcomp < m_numComponents; ++kcomp) { - dg[irxn] += dtmp_ptr[kcomp] * m_gibbsSpecies[kcomp]; + for (kspec = 0; kspec < m_numComponents; ++kspec) { + dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; + if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { + icase = 1; + } + } + if (icase) { + dg[irxn] = MAX(0.0, dg[irxn]); + } + } + } + } else if (l == 0) { + /* ************************************************* */ + /* **** ALL REACTIONS ****************************** */ + /* ************************************************* */ + for (irxn = 0; irxn < irxnl; ++irxn) { + icase = 0; + dg[irxn] = m_gibbsSpecies[ir[irxn]]; + dtmp_ptr = sc[irxn]; + for (kspec = 0; kspec < m_numComponents; ++kspec) { + dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; + if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { + icase = 1; + } + } + if (icase) { + dg[irxn] = MAX(0.0, dg[irxn]); + } + } + } else { + /* ************************************************* */ + /* **** MINORS AND ZEROED SPECIES ****************** */ + /* ************************************************* */ + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] <= VCS_SPECIES_MINOR) { + icase = 0; + dg[irxn] = m_gibbsSpecies[ir[irxn]]; + dtmp_ptr = sc[irxn]; + for (kspec = 0; kspec < m_numComponents; ++kspec) { + dg[irxn] += dtmp_ptr[kspec] * m_gibbsSpecies[kspec]; + if (soln[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF && dtmp_ptr[kspec] < 0.0) { + icase = 1; + } + } + if (icase) { + dg[irxn] = MAX(0.0, dg[irxn]); } } } } - - /* - * special section for zeroed phases - */ /* ************************************************* */ /* **** MULTISPECIES PHASES WITH ZERO MOLES************ */ /* ************************************************* */ @@ -4860,6 +3148,16 @@ void VCS_SOLVE::vcs_deltag_Phase(int iphase, bool doDeleted) { * 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 @@ -4878,111 +3176,1662 @@ void VCS_SOLVE::vcs_deltag_Phase(int iphase, bool doDeleted) { * 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 (zeroedPhase) { - double phaseDG = 1.0; - for (irxn = 0; irxn < irxnl; ++irxn) { - kspec = ir[irxn]; - iph = PhaseID[kspec]; - if (iph == iphase) { + int k; + for (iph = 0; iph < NPhase; iph++) { + lneed = FALSE; + vcs_VolPhase *Vphase = VPhaseList[iph]; + if (! Vphase->SingleSpecies) { + double sum = 0.0; + for (k = 0; k < Vphase->NVolSpecies; k++) { + kspec = Vphase->IndSpecies[k]; + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + sum += soln[kspec]; + } + if (sum > 0.0) break; + } + if (sum == 0.0) { + lneed = TRUE; + } + } + + if (lneed) { + double poly = 0.0; + for (k = 0; k < Vphase->NVolSpecies; k++) { + kspec = Vphase->IndSpecies[k]; + irxn = kspec - m_numComponents; if (dg[irxn] > 50.0) dg[irxn] = 50.0; if (dg[irxn] < -50.0) dg[irxn] = -50.0; - phaseDG -= exp(-dg[irxn])/ActCoeff[kspec]; + poly += exp(-dg[irxn])/ActCoeff[kspec]; + } + /* + * 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. + */ + for (k = 0; k < Vphase->NVolSpecies; k++) { + kspec = Vphase->IndSpecies[k]; + irxn = kspec - m_numComponents; + dg[irxn] = 1.0 - poly; + } + + } + } + + +#ifdef DEBUG_NOT + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + checkFinite(dg[irxn]); + } +#endif + } /* vcs_deltag() ************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int VCS_SOLVE::vcs_basopt(int ifirst, double aw[], double sa[], double sm[], + double ss[], double test, int *usedZeroedSpecies) + + /************************************************************************** + * Choose the optimum 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. + * + * Calculates the identity of the component species in the mechanism. + * Rearranges the solution data to put the component data at the + * front of the species list. + * + * Then, calculates SC(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 + * --------- + * IFIRST = If true, the SC, DNG, and DNL are not calculated. + * TEST = This is a small negative number dependent upon whether + * an estimate is supplied or not. + * W(I) = Mole fractions which will be used to construct an + * optimal basis from. + * + * Output + * --------- + * usedZeroedSpecies = If true, then a species with a zero concentration + * was used as a component. The problem may be + * converged. + * + * Other Variables + * aw[i] = Mole fraction work space (# species in length) + * sa[j] = Gramm-Schmidt orthog work space (nc in length) + * ss[j] = Gramm-Schmidt orthog work space (nc in length) + * sm[i+j*ne] = QR matrix work space (nc*ne in length) + * + *************************************************************************/ + { + int j, k, l, i, jl, ml, jr, lindep, irxn, kspec; + int ncTrial; + int juse = -1; + int jlose = -1; + double *dptr, *scrxn_ptr; + double tsecond = vcs_second(); +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n"); + plogf(" --- Subroutine BASOPT called to "); + if (ifirst) plogf("calculate the number of components\n"); + else plogf("reevaluate the components\n"); + if (vcs_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 ", ElActive[j]); + } + plogf("\n"); + plogf(" --- Species | "); + for (j = 0; j < m_numElemConstraints; j++) { + plogf(" "); + vcs_print_stringTrunc(ElName[j].c_str(), 4, 1); + } + plogf("\n"); + for (k = 0; k < m_numSpeciesTot; k++) { + plogf(" --- "); + vcs_print_stringTrunc(SpName[k].c_str(), 11, 1); + plogf(" | "); + for (j = 0; j < m_numElemConstraints; j++) { + plogf("%5.1g", FormulaMatrix[j][k]); + } + plogf("\n"); + } + plogf("\n"); + } + } +#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 = 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(soln), m_numSpeciesTot); + /* + * Take out the Voltage unknowns from consideration + */ + for (k = 0; k < m_numSpeciesTot; k++) { + if (SpeciesUnknownType[k] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + aw[k] = test; + } + } + + jr = -1; + /* + * Top of a loop of some sort based on the index JR. JR is the + * current number of component species found. + */ + do { + ++jr; + /* - Top of another loop point based on finding a linearly */ + /* - independent species */ + do { + /* + * Search the remaining part of the mole 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_amax(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; + int kfound = -1; + int minNonZeroes = 100000; + int nonZeroesKspec = 0; + for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) { + if (aw[kspec] >= 0.0) { + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + maxConcPossKspec = 1.0E10; + nonZeroesKspec = 0; + for (int j = 0; j < m_numElemConstraints; ++j) { + if (ElActive[j]) { + if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) { + double nu = FormulaMatrix[j][kspec]; + if (nu != 0.0) { + nonZeroesKspec++; + maxConcPossKspec = MIN(gai[j] / nu, maxConcPossKspec); + } + } + } + } + if ((maxConcPossKspec >= maxConcPoss) || (maxConcPossKspec > 1.0E-5)) { + if (nonZeroesKspec <= minNonZeroes) { + if (kfound < 0 || nonZeroesKspec < minNonZeroes) { + kfound = kspec; + } else { + // ok we are sitting pretty equal here decide on the raw ss Gibbs energy + if (ff[kspec] <= ff[kfound]) { + kfound = kspec; + } + } + } + if (nonZeroesKspec < minNonZeroes) { + minNonZeroes = nonZeroesKspec; + } + if (maxConcPossKspec > maxConcPoss) { + maxConcPoss = maxConcPossKspec; + } + } + } + } + } + if (kfound == -1) { + double gmin = 0.0; + kfound = k; + for (kspec = ncTrial; kspec < m_numSpeciesTot; kspec++) { + if (aw[kspec] >= 0.0) { + irxn = kspec - ncTrial; + if (dg[irxn] < gmin) { + gmin = dg[irxn]; + kfound = kspec; + } + } + } + } + k = kfound; + } + + + if (aw[k] == test) { + m_numComponents = jr; + ncTrial = m_numComponents; + int numPreDeleted = m_numRxnTot - m_numRxnRdc; + if (numPreDeleted != (m_numSpeciesTot - m_numSpeciesRdc)) { + plogf("we shouldn't be here\n"); + exit(-1); + } + m_numRxnTot = m_numSpeciesTot - ncTrial; + m_numRxnRdc = m_numRxnTot - numPreDeleted; + m_numSpeciesRdc = m_numSpeciesTot - numPreDeleted; + for (i = 0; i < m_numSpeciesTot; ++i) { + ir[i] = ncTrial + i; + } +#ifdef DEBUG_MODE + if (vcs_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] = 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 ********** */ + /* **************************************************** */ + if (sa[jr] < 1.0e-6) lindep = TRUE; + else lindep = FALSE; + } while(lindep); + /* ****************************************** */ + /* **** REARRANGE THE DATA ****************** */ + /* ****************************************** */ + if (jr != k) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", (SpName[k]).c_str()); + plogf("(%9.2g) replaces %-12.12s", soln[k], SpName[jr].c_str()); + plogf("(%9.2g) as component %3d\n", soln[jr], jr); + } +#endif + vcs_switch_pos(FALSE, jr, k); + vcsUtil_dsw(aw, jr, k); + } +#ifdef DEBUG_MODE + else { + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %-12.12s", SpName[k].c_str()); + plogf("(%9.2g) remains ", soln[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 (ifirst) 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 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, FormulaMatrix, sp, and gai, 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] = FormulaMatrix[i][j]; + } + } + for (i = 0; i < m_numRxnTot; ++i) { + k = ir[i]; + for (j = 0; j < ncTrial; ++j) { + sc[i][j] = FormulaMatrix[j][k]; + } + } + /* + * Use Gauss-Jordon block elimination to calculate + * the reaction matrix, sc[][]. + */ + j = vcsUtil_mlequ(sm, m_numElemConstraints, ncTrial, sc[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 = -1; + jlose = -1; + for (j = 0; j < m_numElemConstraints; j++) { + if (! (ElActive[j])) { + if (!strcmp((ElName[j]).c_str(), "E")) { + juse = j; + } + } + } + for (j = 0; j < m_numElemConstraints; j++) { + if (ElActive[j]) { + if (!strncmp((ElName[j]).c_str(), "cn_", 3)) { + jlose = j; + } + } + } + for (k = 0; k < m_numSpeciesTot; k++) { + if (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] = FormulaMatrix[juse][j]; + } else { + sm[i + j*m_numElemConstraints] = FormulaMatrix[i][j]; + } + } + } + for (i = 0; i < m_numRxnTot; ++i) { + k = ir[i]; + for (j = 0; j < ncTrial; ++j) { + if (j == jlose) { + aw[j] = FormulaMatrix[juse][k]; + } else { + aw[j] = FormulaMatrix[j][k]; + } + } + } + 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++) { + sc[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(sc[i][j]); + } + scSize[i] = szTmp; + } + + +#ifdef DEBUG_MODE + if (vcs_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.3g", soln[j]); + } + plogf("\n --- NonComponent| Moles | "); + for (j = 0; j < ncTrial; j++) { + plogf("%-10.10s", SpName[j].c_str()); + } + //plogf("| scSize"); + plogf("\n"); + for (i = 0; i < m_numRxnTot; i++) { + plogf(" --- %3d ", ir[i]); + plogf("%-10.10s", SpName[ir[i]].c_str()); + plogf("|%10.3g|", soln[ir[i]]); + for (j = 0; j < ncTrial; j++) { + plogf(" %6.2f", sc[i][j]); + } + //plogf(" | %6.2f", scSize[i]); + 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(DnPhase[0], (NSPECIES0)*(NPHASE0)); + vcs_izero(PhaseParticipation[0], (NSPECIES0)*(NPHASE0)); + /* + * Loop over each reaction, creating the change in Phase Moles + * array, DnPhase[irxn][iphase], + * and the phase participation array, PhaseParticipation[irxn][iphase] + */ + for (irxn = 0; irxn < m_numRxnTot; ++irxn) { + scrxn_ptr = sc[irxn]; + dptr = DnPhase[irxn]; + kspec = ir[irxn]; + int iph = PhaseID[kspec]; + int *pp_ptr = PhaseParticipation[irxn]; + dptr[iph] = 1.0; + pp_ptr[iph]++; + for (j = 0; j < ncTrial; ++j) { + iph = 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: ; + tsecond = vcs_second() - tsecond; + m_VCount->Time_basopt += tsecond; + (m_VCount->Basis_Opts)++; + return VCS_SUCCESS; + } /* vcs_basopt() ************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int VCS_SOLVE::vcs_species_type(int kspec) + + /************************************************************************* + * + * vcs_species_type: + * + * Evaluate the species category for the input species + * return the type in the return variable + *************************************************************************/ + { + int irxn = kspec - m_numComponents; + int iph, k; + + if (kspec < m_numComponents) return VCS_SPECIES_COMPONENT; + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + return VCS_SPECIES_INTERFACIALVOLTAGE; + } + iph = PhaseID[kspec]; + if (soln[kspec] <= 0.0) { + if (dg[irxn] >= 0.0) { + /* + * We are here when the species is or should be zeroed out + */ + if (SSPhase[kspec]) { + return VCS_SPECIES_ZEROEDSS; + } else { + if (TPhMoles[iph] == 0.0) return VCS_SPECIES_ZEROEDPHASE; + else return VCS_SPECIES_ZEROEDMS; } } /* - * Overwrite the individual dg's with the phase DG. + * The Gibbs free energy for this species is such that + * it will pop back into existence. + * -> Set it to a major species in anticipation. + * -> One exception to this is if a needed component + * is also zeroed out. Then, don't pop the phase back into + * existence. + * -> Another 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. */ + for (int j = 0; j < m_numComponents; ++j) { + double stoicC = sc[irxn][j]; + if (stoicC != 0.0) { + double negChangeComp = - stoicC; + if (negChangeComp > 0.0) { + if (soln[j] < 1.0E-60) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %s would have popped back into existance but" + " needed component %s is zero\n", + SpName[kspec].c_str(), SpName[j].c_str()); + } +#endif + if (SSPhase[kspec]) { + return VCS_SPECIES_ZEROEDSS; + } else { + return VCS_SPECIES_ZEROEDMS; + } + } + } + } + } + + for (int j = 0; j < m_numElemConstraints; ++j) { + int elType = m_elType[j]; + if (elType == VCS_ELEM_TYPE_ABSPOS) { + double atomComp = FormulaMatrix[j][kspec]; + if (atomComp > 0.0) { + double maxPermissible = gai[j] / atomComp; + if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) { +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- %s would have popped back into existance but" + " needed element %s is zero\n", + SpName[kspec].c_str(), (ElName[j]).c_str()); + } +#endif + if (SSPhase[kspec]) { + return VCS_SPECIES_ZEROEDSS; + } else { + return VCS_SPECIES_ZEROEDMS; + } + } + } + } + } + + return VCS_SPECIES_MAJOR; + } + /* + * Always treat species in single species phases as majors + */ + if (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 + */ + if (soln[kspec] > (TPhMoles[iph] * 0.1)) 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. + */ + double szAdj = scSize[irxn] * std::sqrt((double)m_numRxnTot); + for (k = 0; k < m_numComponents; ++k) { + if (!(SSPhase[k])) { + if (sc[irxn][k] != 0.0) { + if (soln[kspec] * szAdj >= soln[k] * 0.01) { + return VCS_SPECIES_MAJOR; + } + } + } + } + return VCS_SPECIES_MINOR; + } + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_chemPotPhase(int iph, const double *const molNum, + double * const ac, double * const mu_i, + bool do_deleted) + + /************************************************************************** + * + * vcs_chemPotPhase: + * + * We calculate the dimensionless chemical potentials of all species + * in a single phase. + * + * Formula: + * --------------- + * + * Ideal Mixtures: + * + * fe(I) = ff(I) + ln(z(I)) - ln(tPhMoles_ptr[iph]) + * + * ( This is equivalent to the adding the log of the + * mole fraction onto the standard chemical + * potential. ) + * + * Non-Ideal Mixtures: + * ActivityConvention = 0: + * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) + * + * ( 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 + * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) + * - ln(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 + * z(i) < VCS_DELETE_MINORSPECIES_CUTOFF + * The chemical potential is calculated as: + * fe(I) = ff(I) + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF)) + * + * Input + * -------- + * iph : Phase to be calculated + * molNum(i) : Number of moles of species i + * (VCS species order) + * ff : standard state chemical potentials. These are the + * chemical potentials of the standard states at + * the same T and P as the solution. + * (VCS species order) + * Output + * ------- + * ac[] : Activity coefficients for species in phase + * (VCS species order) + * mu_i[] : Dimensionless chemical potentials for phase species + * (VCS species order) + * + *************************************************************************/ + { + vcs_VolPhase *Vphase = VPhaseList[iph]; + int nkk = Vphase->NVolSpecies; + int k, kspec; + +#ifdef DEBUG_MODE + //if (vcs_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->IndSpecies[k]; + tMoles += molNum[kspec]; + } + double tlogMoles = 0.0; + if (tMoles > 0.0) { + tlogMoles = log(tMoles); + } + + Vphase->setMolesFromVCS(molNum); + Vphase->sendToVCSActCoeff(ac); + + double phi = Vphase->electricPotential(); + double Faraday_phi = Faraday_dim * phi; + + for (k = 0; k < nkk; k++) { + kspec = Vphase->IndSpecies[k]; + if (kspec >= m_numComponents) { + int irxn = kspec - m_numComponents; + if (!do_deleted && + (spStatus[irxn] == VCS_SPECIES_DELETED)) { + continue; + } + } + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { +#ifdef DEBUG_MODE + if (molNum[kspec] != phi) { + plogf("We have an inconsistency!\n"); + exit(-1); + } + if (Charge[kspec] != -1.0) { + plogf("We have an unexpected situation!\n"); + exit(-1); + } +#endif + mu_i[kspec] = ff[kspec] + Charge[kspec] * Faraday_phi; + } else { + if (SSPhase[kspec]) { + mu_i[kspec] = ff[kspec] + Charge[kspec] * Faraday_phi; + } else if (molNum[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + mu_i[kspec] = ff[kspec] + log(ac[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) + - tlogMoles - SpecLnMnaught[kspec] + Charge[kspec] * Faraday_phi; + } else { + mu_i[kspec] = ff[kspec] + log(ac[kspec] * molNum[kspec]) + - tlogMoles - SpecLnMnaught[kspec] + Charge[kspec] * Faraday_phi; + } + } + } + } + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_dfe(double *z, int kk, int ll, int lbot, int ltop) + + /************************************************************************** + * + * vcs_dfe: + * + * 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. + * It's chemical potential + * is then calculated using the VCS_DELETE_MINORSPECIES_CUTOFF concentration + * to keep numbers positive. + * + * + * Formula: + * --------------- + * + * Ideal Mixtures: + * + * fe(I) = ff(I) + ln(z(I)) - ln(tPhMoles_ptr[iph]) + * + * ( This is equivalent to the adding the log of the + * mole fraction onto the standard chemical + * potential. ) + * + * Non-Ideal Mixtures: + * ActivityConvention = 0: + * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) + * + * ( 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 + * fe(I) = ff(I) + ln(ActCoeff[i]z(I)) - ln(tPhMoles_ptr[iph]) + * - ln(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 above, for small species where the mole + * fraction + * z(i) < VCS_DELETE_MINORSPECIES_CUTOFF + * The chemical potential is calculated as: + * fe(I) = ff(I) + ln(ActCoeff[i](VCS_DELETE_MINORSPECIES_CUTOFF)) + * + * VCS_SPECIES_TYPE_INTERFACIALVOLTAGE + * + * These chemical potentials refer to electrons in + * metal electrodes. They have the following formula + * + * fe(I) = ff(I) - F V / 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 is V in volts. + * + * Input + * -------- + * ll = 0: Calculate for all species + * -1: calculate for components and for major non-components + * 1: calculate for components and for minor non-components + * lbot : restricts the calculation of the chemical potential + * ltop to the species between LBOT <= i < LTOP. Usually + * LBOT and LTOP will be equal to 0 and MR, respectively. + * z(i) : Number of moles of species i + * -> This can either be the current solution vector WT() + * or the actual solution vector W() + * kk 1: Use the tentative values for the total number of + * moles in the phases, i.e., use TG1 instead of TG etc. + * 0: Use the base values of the total number of + * moles in each system. + * ff : 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. + * + * + *************************************************************************/ + { + int l1, l2, iph, kspec, irxn; + int iphase; + double *tPhMoles_ptr; + double *tlogMoles; + vcs_VolPhase *Vphase; + VCS_SPECIES_THERMO *st_ptr; + +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + if (ll == 0) { + if (lbot != 0) { + plogf(" --- Subroutine vcs_dfe called for one species: "); + plogf("%-12.12s", SpName[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 (kk == 1) plogf(" using tentative solution\n"); + else plogf("\n"); + } +#endif + if (kk <= 0) { + tPhMoles_ptr = VCS_DATA_PTR(TPhMoles); + } else { + tPhMoles_ptr = VCS_DATA_PTR(TPhMoles1); + } + tlogMoles = VCS_DATA_PTR(TmpPhase); + /* + * Might as well recalculate the phase mole vector + * and compare to the storred one. They should be correct. + */ + double *tPhInertMoles = VCS_DATA_PTR(TPhInertMoles); + for (iph = 0; iph < NPhase; iph++) { + tlogMoles[iph] = tPhInertMoles[iph]; + + } + for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { + if(SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + iph = PhaseID[kspec]; + tlogMoles[iph] += z[kspec]; + } + } +#ifdef DEBUG_MODE + for (iph = 0; iph < NPhase; 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(0); + } + } +#endif + vcs_dzero(tlogMoles, NPhase); + for (iph = 0; iph < NPhase; iph++) { + if (tPhMoles_ptr[iph] > 0.0) { + tlogMoles[iph] = log(tPhMoles_ptr[iph]); + } + } + /* + * Zero the indicator that that tells us the activity coefficients + * are current + */ + vcs_izero(VCS_DATA_PTR(CurrPhAC), NPhase); + + if (ll != 0) { + l1 = lbot; + l2 = m_numComponents; + } else { + l1 = lbot; + l2 = ltop; + } + + /* + * Calculate activity coefficients for all phases that are + * not current + */ + for (iphase = 0; iphase < NPhase; iphase++) { + if (!CurrPhAC[iphase]) { + Vphase = VPhaseList[iphase]; + if (!Vphase->SingleSpecies) { + Vphase->setMolesFromVCS(z); + Vphase->sendToVCSActCoeff(VCS_DATA_PTR(ActCoeff)); + } + phasePhi[iphase] = Vphase->electricPotential(); + CurrPhAC[iphase] = 1; + } + } + /* ************************************************************** */ + /* **** 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 = PhaseID[kspec]; + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { +#ifdef DEBUG_MODE + if (z[kspec] != phasePhi[iphase]) { + plogf("We have an inconsistency!\n"); + exit(-1); + } + if (Charge[kspec] != -1.0) { + plogf("We have an unexpected situation!\n"); + exit(-1); + } +#endif + m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; + } else { + if (SSPhase[kspec]) { + m_gibbsSpecies[kspec] = ff[kspec]; + } else { + if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + iph = PhaseID[kspec]; + if (tPhMoles_ptr[iph] > 0.0) { + m_gibbsSpecies[kspec] = ff[kspec] + + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] + + Charge[kspec] * Faraday_dim * phasePhi[iphase]; + } else { + m_gibbsSpecies[kspec] = ff[kspec]; + } + } else { + m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] + + Charge[kspec] * Faraday_dim * phasePhi[iphase]; + } + } + } + } + /* ************************************************ */ + /* **** MAJORS ONLY ******************************* */ + /* ************************************************ */ + if (ll < 0) { + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] != VCS_SPECIES_MINOR) { + kspec = ir[irxn]; + iphase = PhaseID[kspec]; + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { +#ifdef DEBUG_MODE + if (z[kspec] != phasePhi[iphase]) { + plogf("We have an inconsistency!\n"); + exit(-1); + } + if (Charge[kspec] != -1.0) { + plogf("We have an unexpected situation!\n"); + exit(-1); + } +#endif + m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; + } else { + if (SSPhase[kspec]) { + m_gibbsSpecies[kspec] = ff[kspec]; + } else { + if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + iph = PhaseID[kspec]; + if (tPhMoles_ptr[iph] > 0.0) { + m_gibbsSpecies[kspec] = ff[kspec] + + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] + + Charge[kspec] * Faraday_dim * phasePhi[iphase]; ; + } else { + m_gibbsSpecies[kspec] = ff[kspec]; + } + } else { + m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec] + + Charge[kspec] * Faraday_dim * phasePhi[iphase]; + } + } + } + } + } + /* ************************************************ */ + /* **** MINORS ONLY ******************************* */ + /* ************************************************ */ + } else if (ll > 0) { + for (irxn = 0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] == VCS_SPECIES_MINOR) { + kspec = ir[irxn]; + iphase = PhaseID[kspec]; + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { +#ifdef DEBUG_MODE + if (z[kspec] != phasePhi[iphase]) { + plogf("We have an inconsistency!\n"); + exit(-1); + } + if (Charge[kspec] != -1.0) { + plogf("We have an unexpected situation!\n"); + exit(-1); + } +#endif + m_gibbsSpecies[kspec] = ff[kspec] + Charge[kspec] * Faraday_dim * phasePhi[iphase]; ; + } else { + if (SSPhase[kspec]) { + m_gibbsSpecies[kspec] = ff[kspec]; + } else { + if (z[kspec] <= VCS_DELETE_MINORSPECIES_CUTOFF) { + iph = PhaseID[kspec]; + if (tPhMoles_ptr[iph] > 0.0) { + m_gibbsSpecies[kspec] = ff[kspec] + + log(ActCoeff[kspec] * VCS_DELETE_MINORSPECIES_CUTOFF) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec]; + } else { + m_gibbsSpecies[kspec] = ff[kspec]; + } + } else { + st_ptr = SpeciesThermo[kspec]; + m_gibbsSpecies[kspec] = ff[kspec] + log(ActCoeff[kspec] * z[kspec]) + - tlogMoles[PhaseID[kspec]] - SpecLnMnaught[kspec]; + } + } + } + } + } + } +#ifdef DEBUG_NOT + for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { + checkFinite(fe[kspec]); + } +#endif + } /* vcs_dfe() ***************************************************************/ + +#ifdef DEBUG_MODE + void VCS_SOLVE::prneav(void) + + /************************************************************************* + * + * Print out and check the elemental abundance vector + * + *************************************************************************/ + { + int kerr, i, j; + std::vector eav(m_numElemConstraints, 0.0); + + for (j = 0; j < m_numElemConstraints; ++j) { + for (i = 0; i < m_numSpeciesTot; ++i) { + if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + eav[j] += FormulaMatrix[j][i] * soln[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", (ElName[j]).c_str()); + plogf(" = %15.6E %15.6E %15.6E %3d\n", + eav[j], gai[j], eav[j] - gai[j], m_elType[j]); + if (gai[j] != 0.) { + if (fabs(eav[j] - gai[j]) > gai[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("--------------------------------------------------\n"); + } +#endif + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + double VCS_SOLVE::l2normdg(double dgLocal[]) + + /************************************************************************* + * + * l2normdg: + * + * Calculate the norm of the DG vector. + * Positive DG for species which don't exist are ignored. + ************************************************************************/ + { + double tmp; + int irxn; + if (m_numRxnRdc <= 0) return 0.0; + for (irxn = 0, tmp = 0.0; irxn < m_numRxnRdc; ++irxn) { + if (spStatus[irxn] == VCS_SPECIES_MAJOR || spStatus[irxn] == VCS_SPECIES_MINOR || + dgLocal[irxn] < 0.0) { + if (spStatus[irxn] != VCS_SPECIES_ZEROEDMS) { + tmp += dgLocal[irxn] * dgLocal[irxn]; + } + } + } + return (sqrt(tmp / m_numRxnRdc)); + } + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_tmoles(void) + + /************************************************************************** + * + * vcs_tmoles: + * + * 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. + *************************************************************************/ + { + int i; + double sum; + vcs_VolPhase *Vphase; + for (i = 0; i < NPhase; i++) { + TPhMoles[i] = TPhInertMoles[i]; + } + for (i = 0; i < m_numSpeciesTot; i++) { + if (SpeciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) { + TPhMoles[PhaseID[i]] += soln[i]; + } + } + sum = 0.0; + for (i = 0; i < NPhase; i++) { + sum += TPhMoles[i]; + Vphase = VPhaseList[i]; + // Took out because we aren't updating mole fractions in Vphase + // Vphase->TMoles = TPhMoles[i]; + if (TPhMoles[i] == 0.0) { + Vphase->Existence = 0; + } else { + if (TPhInertMoles[i] > 0.0) { + Vphase->Existence = 2; + } else { + Vphase->Existence = 1; + } + } + } + TMoles = sum; + } /* vcs_tmoles() ************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_updateVP (int place) + + /************************************************************************* + * vcs_updateVP() + * + * This routine uploads the state of the system into all of the + * VolumePhase objects in the current problem. + * place + * 0 -> from soln + * 1 -> from wt + *************************************************************************/ + { + vcs_VolPhase *Vphase; + for (int i = 0; i < NPhase; i++) { + Vphase = VPhaseList[i]; + if (place == 0) { + Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(soln), + VCS_DATA_PTR(TPhMoles), i); + } else if (place == 1) { + Vphase->setMolesFromVCSCheck(VCS_DATA_PTR(wt), + VCS_DATA_PTR(TPhMoles1), i); + } else { + plogf("we shouldn't be here\n"); + exit(-1); + } + } + } + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_switch2D(double * const * const Jac, int k1, int k2) + + /************************************************************************** + * vcs_switch2D: + * + * Switch rows and columns of a square matrix + *************************************************************************/ + { + int i; + register double dtmp; + for (i = 0; i < m_numSpeciesTot; i++) { + SWAP(Jac[k1][i], Jac[k2][i], dtmp); + } + for (i = 0; i < m_numSpeciesTot; i++) { + SWAP(Jac[i][k1], Jac[i][k2], dtmp); + } + } + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + void VCS_SOLVE::vcs_switch_pos(int ifunc, int k1, int k2) + + /************************************************************************** + * + * vcs_switch_pos: + * + * Swaps the indecises for all of the global data for two species, k1 + * and k2. + * + * 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. + *************************************************************************/ + { + register int j; + register double t1 = 0.0; + int i1, i2, iph, kp1, kp2; + vcs_VolPhase *pv1, *pv2; + VCS_SPECIES_THERMO *st_tmp; + if (k1 == k2) return; +#ifdef DEBUG_MODE + if (k1 < 0 || k1 > (m_numSpeciesTot - 1) || + k2 < 0 || 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 = VPhaseList[PhaseID[k1]]; + pv2 = VPhaseList[PhaseID[k2]]; + + kp1 = indPhSp[k1]; + kp2 = indPhSp[k2]; +#ifdef DEBUG_MODE + if (pv1->IndSpecies[kp1] != k1) { + plogf("Indexing error in program\n"); + exit(-1); + } + if (pv2->IndSpecies[kp2] != k2) { + plogf("Indexing error in program\n"); + exit(-1); + } +#endif + pv1->IndSpecies[kp1] = k2; + pv2->IndSpecies[kp2] = k1; + + vcsUtil_stsw(SpName, k1, k2); + SWAP(soln[k1], soln[k2], t1); + SWAP(SpeciesUnknownType[k1], SpeciesUnknownType[k2], j); + SWAP(wt[k1], wt[k2], t1); + SWAP(ff[k1], ff[k2], t1); + SWAP(m_gibbsSpecies[k1], m_gibbsSpecies[k2], t1); + SWAP(ds[k1], ds[k2], t1); + SWAP(fel[k1], fel[k2], t1); + SWAP(feTrial[k1], feTrial[k2], t1); + SWAP(SSPhase[k1], SSPhase[k2], j); + SWAP(PhaseID[k1], PhaseID[k2], j); + SWAP(ind[k1], ind[k2], j); + SWAP(indPhSp[k1], indPhSp[k2], j); + SWAP(SpecActConvention[k1], SpecActConvention[k2], j); + SWAP(SpecLnMnaught[k1], SpecLnMnaught[k2], t1); + SWAP(ActCoeff[k1], ActCoeff[k2], t1); + SWAP(ActCoeff0[k1], ActCoeff0[k2], t1); + SWAP(WtSpecies[k1], WtSpecies[k2], t1); + SWAP(Charge[k1], Charge[k2], t1); + SWAP(SpeciesThermo[k1], SpeciesThermo[k2], st_tmp); + SWAP(VolPM[k1], VolPM[k2], t1); + + for (j = 0; j < m_numElemConstraints; ++j) { + SWAP(FormulaMatrix[j][k1], FormulaMatrix[j][k2], t1); + } + if (UseActCoeffJac) { + vcs_switch2D(dLnActCoeffdMolNum.baseDataAddr(), k1, k2); + } + + /* + * Handle the index pointer in the phase structures + */ + + + if (ifunc) { + /* + * Find the noncomponent indecises for the two species + */ + i1 = k1 - m_numComponents; + i2 = k2 - m_numComponents; +#ifdef DEBUG_MODE + if (i1 < 0 || i1 > (m_numRxnTot - 1) || + i2 < 0 || i2 > (m_numRxnTot - 1) ) { + plogf("switch_pos: ifunc = 1: inappropriate noncomp values: %d %d\n", + i1 , i2); + } +#endif + for (j = 0; j < m_numComponents; ++j) { + SWAP(sc[i1][j], sc[i2][j], t1); + } + SWAP(scSize[i1], scSize[i2], t1); + for (iph = 0; iph < NPhase; iph++) { + SWAP(DnPhase[i1][iph], DnPhase[i2][iph], t1); + SWAP(PhaseParticipation[i1][iph], + PhaseParticipation[i2][iph], j); + } + SWAP(dg[i1], dg[i2], t1); + SWAP(dgl[i1], dgl[i2], t1); + SWAP(spStatus[i1], spStatus[i2], j); + + /* + * We don't want to swap ir[], because the values of ir should + * stay the same after the swap + * + * vcs_isw(ir, i1, i2); + */ + } + } /* vcs_switch_pos() ********************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + static void print_space(int num) + { + int j; + for (j = 0; j < num; j++) plogf(" "); + } + + /**************************************************************************** + * + * vcs_deltag_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. + */ + void VCS_SOLVE::vcs_deltag_Phase(int iphase, bool doDeleted) { + int iph; + int irxn, kspec, kcomp; + double *dtmp_ptr; + int irxnl = m_numRxnRdc; + if (doDeleted) irxnl = m_numRxnTot; + vcs_VolPhase *vPhase = VPhaseList[iphase]; + +#ifdef DEBUG_MODE + if (vcs_debug_print_lvl >= 2) { + plogf(" --- Subroutine vcs_deltag_Phase called for phase %d\n", + iphase); + } +#endif + + /* + * Single species Phase + */ + if (vPhase->SingleSpecies) { + kspec = vPhase->IndSpecies[0]; +#ifdef DEBUG_MODE + if (iphase != PhaseID[kspec]) { + plogf("vcs_deltag_Phase index error\n"); + exit(-1); + } +#endif + if (kspec >= m_numComponents) { + irxn = kspec - m_numComponents; + dg[irxn] = m_gibbsSpecies[kspec]; + dtmp_ptr = sc[irxn]; + for (kcomp = 0; kcomp < m_numComponents; ++kcomp) { + dg[irxn] += dtmp_ptr[kcomp] * m_gibbsSpecies[kcomp]; + } + } + } + /* + * Multispecies Phase + */ + else { + bool zeroedPhase = TRUE; + for (irxn = 0; irxn < irxnl; ++irxn) { kspec = ir[irxn]; - iph = PhaseID[kspec]; - if (iph == iphase) { - dg[irxn] = 1.0 - phaseDG; + if (SpeciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + iph = PhaseID[kspec]; + if (iph == iphase ) { + if (soln[kspec] > 0.0) zeroedPhase = FALSE; + dg[irxn] = m_gibbsSpecies[kspec]; + dtmp_ptr = sc[irxn]; + for (kcomp = 0; kcomp < m_numComponents; ++kcomp) { + dg[irxn] += dtmp_ptr[kcomp] * m_gibbsSpecies[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 (zeroedPhase) { + double phaseDG = 1.0; + for (irxn = 0; irxn < irxnl; ++irxn) { + kspec = ir[irxn]; + iph = PhaseID[kspec]; + if (iph == iphase) { + if (dg[irxn] > 50.0) dg[irxn] = 50.0; + if (dg[irxn] < -50.0) dg[irxn] = -50.0; + phaseDG -= exp(-dg[irxn])/ActCoeff[kspec]; + } + } + /* + * Overwrite the individual dg's with the phase DG. + */ + for (irxn = 0; irxn < irxnl; ++irxn) { + kspec = ir[irxn]; + iph = PhaseID[kspec]; + if (iph == iphase) { + dg[irxn] = 1.0 - phaseDG; + } } } } + } -} - -/**************************************************************************** - * - * vcs_birthGuess - * - * Birth guess returns the number of moles of a species - * that is coming back to life. or -> whose concentration has - * been forced to zero by a constraint for some reason, and needs - * to be reinitialized. - */ -double VCS_SOLVE::vcs_birthGuess(int kspec) { - int irxn = kspec - m_numComponents; - int soldel = false; - double dx = 0.0; - if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + /**************************************************************************** + * + * vcs_birthGuess + * + * Birth guess returns the number of moles of a species + * that is coming back to life. or -> whose concentration has + * been forced to zero by a constraint for some reason, and needs + * to be reinitialized. + */ + double VCS_SOLVE::vcs_birthGuess(int kspec) { + int irxn = kspec - m_numComponents; + int soldel = false; + double dx = 0.0; + if (SpeciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + return dx; + } + double w_kspec = VCS_DELETE_SPECIES_CUTOFF; + // Check to make sure that species is zero in the solution vector + // If it isn't, we don't know what's happening + if (soln[kspec] != 0.0) { + w_kspec = 0.0; + plogf("we shouldn't be here\n"); + exit(-1); + } + int ss = SSPhase[kspec]; + if (!ss) { + /* + * Logic to handle species in multiple species phases + */ +#ifdef DEBUG_MODE + char ANOTE[32]; + double dxm = minor_alt_calc(kspec, irxn, &soldel, ANOTE); +#else + double dxm = minor_alt_calc(kspec, irxn, &soldel); +#endif + dx = w_kspec + dxm; + if (dx > 1.0E-15) { + dx = 1.0E-15; + } + } else { + /* + * Logic to handle single species phases + */ + dx = VCS_DELETE_SPECIES_CUTOFF * 100.; + } + + /* + * Check to see if the current value of the components + * allow the dx. + * 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 = sc[irxn]; + for (int j = 0; j < m_numComponents; ++j) { + // Only loop over element contraints that involve positive def. constraints + if (SpeciesUnknownType[j] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { + if (soln[j] > 0.0) { + double tmp = sc_irxn[j] * dx; + if (3.0*(-tmp) > soln[j]) { + dx = MIN(dx, - 0.3333* soln[j] / sc_irxn[j]); + } + } + if (soln[j] <= 0.0) { + if (sc_irxn[j] < 0.0) { + dx = 0.0; + } + } + } + } return dx; } - double w_kspec = VCS_DELETE_SPECIES_CUTOFF; - // Check to make sure that species is zero in the solution vector - // If it isn't, we don't know what's happening - if (soln[kspec] != 0.0) { - w_kspec = 0.0; - plogf("we shouldn't be here\n"); - exit(-1); - } - int ss = SSPhase[kspec]; - if (!ss) { - /* - * Logic to handle species in multiple species phases - */ -#ifdef DEBUG_MODE - char ANOTE[32]; - double dxm = minor_alt_calc(kspec, irxn, &soldel, ANOTE); -#else - double dxm = minor_alt_calc(kspec, irxn, &soldel); -#endif - dx = w_kspec + dxm; - if (dx > 1.0E-15) { - dx = 1.0E-15; - } - } else { - /* - * Logic to handle single species phases - */ - dx = VCS_DELETE_SPECIES_CUTOFF * 100.; - } - - /* - * Check to see if the current value of the components - * allow the dx. - * 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 = sc[irxn]; - for (int j = 0; j < m_numComponents; ++j) { - // Only loop over element contraints that involve positive def. constraints - if (SpeciesUnknownType[j] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { - if (soln[j] > 0.0) { - double tmp = sc_irxn[j] * dx; - if (3.0*(-tmp) > soln[j]) { - dx = MIN(dx, - 0.3333* soln[j] / sc_irxn[j]); - } - } - if (soln[j] <= 0.0) { - if (sc_irxn[j] < 0.0) { - dx = 0.0; - } - } - } - } - return dx; -} -/*****************************************************************/ + /*****************************************************************/ } diff --git a/Cantera/src/equil/vcs_util.cpp b/Cantera/src/equil/vcs_util.cpp index 49b4d9a23..e29d43043 100644 --- a/Cantera/src/equil/vcs_util.cpp +++ b/Cantera/src/equil/vcs_util.cpp @@ -15,412 +15,566 @@ namespace VCSnonideal { -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ #ifndef USE_MEMSET -void vcs_dzero(double *vector, int length) + void vcs_dzero(double *vector, int length) - /************************************************************************** - * - * vcs_dzero: - * - * Zeroes a double vector - ***************************************************************************/ -{ - int i; - for (i = 0; i < length; i++) vector[i] = 0.0; -} /* vcs_dzero() *************************************************************/ + /************************************************************************** + * + * vcs_dzero: + * + * Zeroes a double vector + ***************************************************************************/ + { + int i; + for (i = 0; i < length; i++) vector[i] = 0.0; + } /* vcs_dzero() *************************************************************/ #endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ #ifndef USE_MEMSET -void vcs_izero(int *vector, int length) + void vcs_izero(int *vector, int length) - /************************************************************************** - * - * vcs_izero: - * - * Zeroes an int vector - ***************************************************************************/ -{ - int i; - for (i = 0; i < length; i++) vector[i] = 0; -} /* vcs_izero() *************************************************************/ + /************************************************************************** + * + * vcs_izero: + * + * Zeroes an int vector + ***************************************************************************/ + { + int i; + for (i = 0; i < length; i++) vector[i] = 0; + } /* vcs_izero() *************************************************************/ #endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ #ifndef USE_MEMSET -void vcs_dcopy(double *vec_to, double *vec_from, int length) + void vcs_dcopy(double *vec_to, double *vec_from, int length) - /************************************************************************** - * - * vcs_dcopy: - * - * Copies a double vector - ***************************************************************************/ -{ - int i; - for (i = 0; i < length; i++) vec_to[i] = vec_from[i]; -} /* vcs_dzero() *************************************************************/ + /************************************************************************** + * + * vcs_dcopy: + * + * Copies a double vector + ***************************************************************************/ + { + int i; + for (i = 0; i < length; i++) vec_to[i] = vec_from[i]; + } /* vcs_dzero() *************************************************************/ #endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ #ifndef USE_MEMSET -void vcs_icopy(int *vec_to, int *vec_from, int length) + void vcs_icopy(int *vec_to, int *vec_from, int length) - /************************************************************************** - * - * vcs_icopy: - * - * copies an int vector - ***************************************************************************/ -{ - int i; - for (i = 0; i < length; i++) vec_to[i] = vec_from[i]; -} /* vcs_dzero() *************************************************************/ + /************************************************************************** + * + * vcs_icopy: + * + * copies an int vector + ***************************************************************************/ + { + int i; + for (i = 0; i < length; i++) vec_to[i] = vec_from[i]; + } /* vcs_dzero() *************************************************************/ #endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ #ifndef USE_MEMSET -/* - * vcs_vdzero - * - * zeroes a double vector - */ -void vcs_vdzero(std::vector &vvv, int len) { - if (len < 0) { - std::fill(vvv.begin(), vvv.end(), 0.0); - } else { - std::fill_n(vvv.begin(), len, 0.0); - } -} -#endif - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -#ifndef USE_MEMSET -/* - * vcs_vizero - * - * zeroes a double vector - */ -void vcs_vizero(std::vector &vvv, int len) { - if (len < 0) { - std::fill(vvv.begin(), vvv.end(), 0.0); - } else { - std::fill_n(vvv.begin(), len, 0.0); - } -} -#endif - - - -#ifndef USE_MEMSET -/* - * vcs_vdcopy - * - * copies a vector of doubles to another vector of doubles - * - * @param vec_to Vector to be copied to - * @param vec_from Vector to be copied from - * @param length Length of the copy - */ -void vcs_vdcopy(std::vector &vec_to, - const std::vector & vec_from, int length) { - std::copy(vec_from.begin(), vec_from.begin() + length, vec_to.begin()); -} -#endif - - -#ifndef USE_MEMSET -/* - * vcs_vicopy - * - * copies a vector to another vector - * - * @param vec_to Vector to be copied to - * @param vec_from Vector to be copied from - * @param length Length of the copy - */ -void vcs_vicopy(std::vector &vec_to, - const std::vector & vec_from, int length) { - std::copy(vec_from.begin(), vec_from.begin() + length, vec_to.begin()); -} -#endif -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int vcs_amax(const double *x, int j, int n) - - /************************************************************************** + /* + * vcs_vdzero * - * vcs_amax: - * - * Finds the location of the maximum component in a double vector - * INPUT - * x(*) - Vector to search - * j <= i < n : i is the range of indecises to search in X(*) - * - * RETURN - * return index of the greatest value on X(*) searched - ***************************************************************************/ -{ - int i; - int largest = j; - double big = x[j]; - for (i = j + 1; i < n; ++i) { - if (x[i] > big) { - largest = i; - big = x[i]; - } - } - return largest; -} /* vcs_amax() **************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int vcs_max_int(const int *vector, int length) - - /************************************************************************** - * - * vcs_max_int: - * - * returns the maximum integer in a list. - ***************************************************************************/ -{ - int i, retn; - if (vector == NULL || length <= 0) return 0; - retn = vector[0]; - for (i = 1; i < length; i++) { - retn = MAX( retn, vector[i]); - } - return retn; -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -static void printSev(int severity) -{ - switch (severity) { - case 1: - plogf(" VCS NOTE : "); break; - case 2: - plogf(" VCS WARNING : "); break; - case 3: - plogf(" VCS ERROR : "); break; - case 4: - plogf(" VCS FATAL ERROR : "); break; - } -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -int vcsUtil_err_check(VCS_ERR_STRUCT &vcsE, char *string1, int ival) - - /************************************************************************** - * - * vcs_err_check: - * - * This routine checks the error flag, prints a message, and then - * resets the error counters. - * - * Input - * severity: Affects what happens in the routine. - * 0 = Ignore warning, don't print anything - * 1 = Note - * 2 = Warning - * 3 = Error -> Probably fatal - * 4 = Immediate Fatal Error - * ival = Another integer input that means different things - * depending on the error condition. Frequently, it will - * point to a species or reaction which is the culprit. - * - * Return - * Returns the error flag value - ***************************************************************************/ -{ - int flag = vcsE.Flag, doPrint, severity; - /* - * Do a fast exit if there is no error encountered + * zeroes a double vector */ - if (flag == VCS_SUCCESS) return flag; - switch (flag) { - case VCS_FAILED_CONVERGENCE: - severity = 1; - break; - case VCS_THERMO_OUTOFRANGE: - severity = 2; - break; - case VCS_NOMEMORY: - case VCS_PUB_BAD: - severity = 3; - break; - case VCS_SHOULDNT_BE_HERE: - severity = 4; - break; - } - doPrint = (vcsE.PrintLevel <= severity); - if (doPrint) { + void vcs_vdzero(std::vector &vvv, int len) { + if (len < 0) { + std::fill(vvv.begin(), vvv.end(), 0.0); + } else { + std::fill_n(vvv.begin(), len, 0.0); + } + } +#endif + + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + +#ifndef USE_MEMSET + /* + * vcs_vizero + * + * zeroes a double vector + */ + void vcs_vizero(std::vector &vvv, int len) { + if (len < 0) { + std::fill(vvv.begin(), vvv.end(), 0.0); + } else { + std::fill_n(vvv.begin(), len, 0.0); + } + } +#endif + + + +#ifndef USE_MEMSET + /* + * vcs_vdcopy + * + * copies a vector of doubles to another vector of doubles + * + * @param vec_to Vector to be copied to + * @param vec_from Vector to be copied from + * @param length Length of the copy + */ + void vcs_vdcopy(std::vector &vec_to, + const std::vector & vec_from, int length) { + std::copy(vec_from.begin(), vec_from.begin() + length, vec_to.begin()); + } +#endif + + +#ifndef USE_MEMSET + /* + * vcs_vicopy + * + * copies a vector to another vector + * + * @param vec_to Vector to be copied to + * @param vec_from Vector to be copied from + * @param length Length of the copy + */ + void vcs_vicopy(std::vector &vec_to, + const std::vector & vec_from, int length) { + std::copy(vec_from.begin(), vec_from.begin() + length, vec_to.begin()); + } +#endif + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int vcs_amax(const double *x, int j, int n) + + /************************************************************************** + * + * vcs_amax: + * + * Finds the location of the maximum component in a double vector + * INPUT + * x(*) - Vector to search + * j <= i < n : i is the range of indecises to search in X(*) + * + * RETURN + * return index of the greatest value on X(*) searched + ***************************************************************************/ + { + int i; + int largest = j; + double big = x[j]; + for (i = j + 1; i < n; ++i) { + if (x[i] > big) { + largest = i; + big = x[i]; + } + } + return largest; + } /* vcs_amax() **************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + int vcs_max_int(const int *vector, int length) + + /************************************************************************** + * + * vcs_max_int: + * + * returns the maximum integer in a list. + ***************************************************************************/ + { + int i, retn; + if (vector == NULL || length <= 0) return 0; + retn = vector[0]; + for (i = 1; i < length; i++) { + retn = MAX( retn, vector[i]); + } + return retn; + } + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + + static void printSev(int severity) { + switch (severity) { + case 1: + plogf(" VCS NOTE : "); break; + case 2: + plogf(" VCS WARNING : "); break; + case 3: + plogf(" VCS ERROR : "); break; + case 4: + plogf(" VCS FATAL ERROR : "); break; + } + } + + // Swap values in a std vector string + /* + * Switches the value of vecStrings[i1] with vecStrings[i2] + * + * @param vecStrings Vector of integers + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_stsw(std::vector & vstr, int i1, int i2) { + std::string tmp(vstr[i2]); + vstr[i2] = vstr[i1]; + vstr[i1] = tmp; + } + + // Swap values in vector of doubles + /* + * Switches the value of x[i1] with x[i2] + * + * @param x Vector of doubles + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_dsw(double x[], int i1, int i2) { + double t = x[i1]; + x[i1] = x[i2]; + x[i2] = t; + } + + // Swap values in an integer array + /* + * Switches the value of x[i1] with x[i2] + * + * @param x Vector of integers + * @param i1 first index + * @param i2 second index + */ + void vcsUtil_isw(int x[], int i1, int i2) { + int t = x[i1]; + x[i1] = x[i2]; + x[i2] = t; + } + + // Invert an n x n matrix and solve m rhs's + /* + * Solve a square matrix with multiple right hand sides + * + * \f[ + * C X + B = 0; + * \f] + * + * This routine uses Gauss elimination and is optimized for the solution + * of lots of rhs's. A crude form of row pivoting is used here. + * The matrix C is destroyed. + * + * @return Routine returns an integer representing success: + * - 1 : Matrix is singluar + * - 0 : solution is OK + * The solution x[] is returned in the matrix b. + * + * @param c Matrix to be inverted. c is in fortran format, i.e., rows + * are the inner loop. Row numbers equal to idem. + * c[i+j*idem] = c_i_j = Matrix to be inverted: i = row number + * j = column number + * @param idem number of row dimensions in c + * @param n Number of rows and columns in c + * @param b Multiple RHS. Note, b is actually the negative of + * most formulations. Row numbers equal to idem. + * b[i+j*idem] = b_i_j = vectors of rhs's: i = row number + * j = column number + * (each column is a new rhs) + * @param m number of rhs's + */ + int vcsUtil_mlequ(double *c, int idem, int n, double *b, int m) { + int i, j, k, l; + double R; + if (n > idem || n <= 0) { + plogf("vcsUtil_mlequ ERROR: badly dimensioned matrix: %d %d\n", n, idem); + return 1; + } + + /* + * Loop over the rows + * -> At the end of each loop, the only nonzero entry in the column + * will be on the diagonal. We can therfore just invert the + * diagonal at the end of the program to solve the equation system. + */ + for (i = 0; i < n; ++i) { + if (c[i + i * idem] == 0.0) { + /* + * Do a simple form of row pivoting to find a non-zero pivot + */ + for (k = i + 1; k < n; ++k) { + if (c[k + i * idem] != 0.0) goto FOUND_PIVOT; + } + plogf("vcsUtil_mlequ ERROR: Encountered a zero column: %d\n", i); + return 1; + FOUND_PIVOT: ; + for (j = 0; j < n; ++j) c[i + j * idem] += c[k + j * idem]; + for (j = 0; j < m; ++j) b[i + j * idem] += b[k + j * idem]; + } + + for (l = 0; l < n; ++l) { + if (l != i && c[l + i * idem] != 0.0) { + R = c[l + i * idem] / c[i + i * idem]; + c[l + i * idem] = 0.0; + for (j = i+1; j < n; ++j) c[l + j * idem] -= c[i + j * idem] * R; + for (j = 0; j < m; ++j) b[l + j * idem] -= b[i + j * idem] * R; + } + } + } + /* + * The negative in the last expression is due to the form of B upon + * input + */ + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + b[i + j * idem] = -b[i + j * idem] / c[i + i*idem]; + } + } + return 0; + } + + // Returns the value of the gas constant in the units specified by a parameter + /* + * @param mu_units Specifies the units. + * - VCS_UNITS_KCALMOL: kcal gmol-1 K-1 + * - VCS_UNITS_UNITLESS: 1.0 K-1 + * - VCS_UNITS_KJMOL: kJ gmol-1 K-1 + * - VCS_UNITS_KELVIN: 1.0 K-1 + * - VCS_UNITS_MKS: joules kmol-1 K-1 = kg m2 s-2 kmol-1 K-1 + */ + double vcsUtil_gasConstant(int mu_units) { + double r; + switch (mu_units) { + case VCS_UNITS_KCALMOL: + r = 0.008314472/4.184; + break; + case VCS_UNITS_UNITLESS: + r = 1.0; + break; + case VCS_UNITS_KJMOL: + r = 0.008314472; + break; + case VCS_UNITS_KELVIN: + r = 1.0; + break; + case VCS_UNITS_MKS: + /* joules / kg-mol K = kg m2 / s2 kg-mol K */ + r = 8.314472E3; + break; + default: + plogf("vcs_gasConstant error: uknown units: %d\n", + mu_units); + exit(-1); + } + return r; + } + + int vcsUtil_err_check(VCS_ERR_STRUCT &vcsE, char *string1, int ival) + + /************************************************************************** + * + * vcs_err_check: + * + * This routine checks the error flag, prints a message, and then + * resets the error counters. + * + * Input + * severity: Affects what happens in the routine. + * 0 = Ignore warning, don't print anything + * 1 = Note + * 2 = Warning + * 3 = Error -> Probably fatal + * 4 = Immediate Fatal Error + * ival = Another integer input that means different things + * depending on the error condition. Frequently, it will + * point to a species or reaction which is the culprit. + * + * Return + * Returns the error flag value + ***************************************************************************/ + { + int flag = vcsE.Flag, doPrint, severity; + /* + * Do a fast exit if there is no error encountered + */ + if (flag == VCS_SUCCESS) return flag; + switch (flag) { + case VCS_FAILED_CONVERGENCE: + severity = 1; + break; + case VCS_THERMO_OUTOFRANGE: + severity = 2; + break; + case VCS_NOMEMORY: + case VCS_PUB_BAD: + severity = 3; + break; + case VCS_SHOULDNT_BE_HERE: + severity = 4; + break; + } + doPrint = (vcsE.PrintLevel <= severity); + if (doPrint) { printSev(severity); if (string1 != NULL) plogf("%s ", string1); - } - switch (flag) { - case VCS_NOMEMORY: - if (doPrint) { - plogf("Out of Memory"); - } - break; - case VCS_FAILED_CONVERGENCE: - if (doPrint) { - plogf("Failed Convergence"); - } - break; - case VCS_SHOULDNT_BE_HERE: - if (doPrint) { - plogf("Shouldn't be here, internal vcsc error"); - } - break; - case VCS_PUB_BAD: - if (doPrint) { - plogf("Public data structure is corrupt"); - } - break; - case VCS_THERMO_OUTOFRANGE: - if (doPrint) { - plogf("Thermo Data out of Range"); - if (vcsE.Species1 >= 0) plogf(", Species = %d", vcsE.Species1); - if (ival >= 0) plogf(", Species = %d", ival); - if (vcsE.Value1 != VCS_ERR_NOVALUE) - plogf(", TKelvin = %g", vcsE.Value1); - if (vcsE.Value1 != VCS_ERR_NOVALUE) - plogf(", Tlimit = %g", vcsE.Value2); - } - break; - default: - if (doPrint) { - plogf("Unknown Error Condition = %d ??", flag); - } - break; - } + } + switch (flag) { + case VCS_NOMEMORY: + if (doPrint) { + plogf("Out of Memory"); + } + break; + case VCS_FAILED_CONVERGENCE: + if (doPrint) { + plogf("Failed Convergence"); + } + break; + case VCS_SHOULDNT_BE_HERE: + if (doPrint) { + plogf("Shouldn't be here, internal vcsc error"); + } + break; + case VCS_PUB_BAD: + if (doPrint) { + plogf("Public data structure is corrupt"); + } + break; + case VCS_THERMO_OUTOFRANGE: + if (doPrint) { + plogf("Thermo Data out of Range"); + if (vcsE.Species1 >= 0) plogf(", Species = %d", vcsE.Species1); + if (ival >= 0) plogf(", Species = %d", ival); + if (vcsE.Value1 != VCS_ERR_NOVALUE) + plogf(", TKelvin = %g", vcsE.Value1); + if (vcsE.Value1 != VCS_ERR_NOVALUE) + plogf(", Tlimit = %g", vcsE.Value2); + } + break; + default: + if (doPrint) { + plogf("Unknown Error Condition = %d ??", flag); + } + break; + } - if (doPrint) { + if (doPrint) { plogf("\n"); if (vcsE.Mess[0] != '\0') { printSev(severity); plogf(" %s\n", vcsE.Mess); } fflush(stdout); - } - if (severity > 3) exit(-1); - vcsUtil_err_reset(vcsE); - return flag; -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void vcsUtil_err_reset (VCS_ERR_STRUCT &vcsE) - - /************************************************************************** - * - * vcs_err_reset: - * - * Sets the error handler back to default conditions. - ***************************************************************************/ -{ - vcsE.Flag = VCS_SUCCESS; - vcsE.Species1 = -1; - vcsE.Species2 = -1; - vcsE.Value1 = VCS_ERR_NOVALUE; - vcsE.Value2 = VCS_ERR_NOVALUE; - vcsE.Mess[0] = '\0'; - vcsE.Mess[119] = '\0'; -} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ - -void vcs_print_line(const char *string, int num) - - /************************************************************************** - * - * vcs_print_char: - * - * Print a line consisting of a multiple of the same string - * - ***************************************************************************/ -{ - if (string) { - for (int j = 0; j < num; j++) plogf("%s", string); + } + if (severity > 3) exit(-1); + vcsUtil_err_reset(vcsE); + return flag; } - plogf("\n"); -} + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -/***************************************************************************/ -/************************************************************************ **/ -/************************************************************************ **/ + void vcsUtil_err_reset (VCS_ERR_STRUCT &vcsE) + + /************************************************************************** + * + * vcs_err_reset: + * + * Sets the error handler back to default conditions. + ***************************************************************************/ + { + vcsE.Flag = VCS_SUCCESS; + vcsE.Species1 = -1; + vcsE.Species2 = -1; + vcsE.Value1 = VCS_ERR_NOVALUE; + vcsE.Value2 = VCS_ERR_NOVALUE; + vcsE.Mess[0] = '\0'; + vcsE.Mess[119] = '\0'; + } + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -void vcs_print_stringTrunc(const char *str, int space, int alignment) - - /*********************************************************************** - * vcs_print_stringTrunc(): - * - * Print a string within a given space limit. This routine - * limits the amount of the string that will be printed to a - * maximum of "space" characters. - * - * str = String -> must be null terminated. - * space = space limit for the printing. - * alignment = 0 centered - * 1 right aligned - * 2 left aligned - ***********************************************************************/ -{ - int i, ls=0, rs=0; - int len = strlen(str); - if ((len) >= space) { - for (i = 0; i < space; i++) { - plogf("%c", str[i]); + void vcs_print_line(const char *string, int num) + + /************************************************************************** + * + * vcs_print_char: + * + * Print a line consisting of a multiple of the same string + * + ***************************************************************************/ + { + if (string) { + for (int j = 0; j < num; j++) plogf("%s", string); } - } else { - if (alignment == 1) { - ls = space - len; - } else if (alignment == 2) { - rs = space - len; + plogf("\n"); + } + + /***************************************************************************/ + /************************************************************************ **/ + /************************************************************************ **/ + + void vcs_print_stringTrunc(const char *str, int space, int alignment) + + /*********************************************************************** + * vcs_print_stringTrunc(): + * + * Print a string within a given space limit. This routine + * limits the amount of the string that will be printed to a + * maximum of "space" characters. + * + * str = String -> must be null terminated. + * space = space limit for the printing. + * alignment = 0 centered + * 1 right aligned + * 2 left aligned + ***********************************************************************/ + { + int i, ls=0, rs=0; + int len = strlen(str); + if ((len) >= space) { + for (i = 0; i < space; i++) { + plogf("%c", str[i]); + } } else { - ls = (space - len) / 2; - rs = space - len - ls; - } - if (ls != 0) { - for (i = 0; i < ls; i++) plogf(" "); - } - plogf("%s", str); - if (rs != 0) { - for (i = 0; i < rs; i++) plogf(" "); - } - } -} + if (alignment == 1) { + ls = space - len; + } else if (alignment == 2) { + rs = space - len; + } else { + ls = (space - len) / 2; + rs = space - len - ls; + } + if (ls != 0) { + for (i = 0; i < ls; i++) plogf(" "); + } + plogf("%s", str); + if (rs != 0) { + for (i = 0; i < rs; i++) plogf(" "); + } + } + } -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ + /*****************************************************************************/ -bool vcs_doubleEqual(double d1, double d2) + bool vcs_doubleEqual(double d1, double d2) /************************************************************************* * vcs_doubleEqual() @@ -429,17 +583,13 @@ bool vcs_doubleEqual(double d1, double d2) * roundoff error. Currently it's set to check for 10 digits of * accuracy. *************************************************************************/ -{ + { double denom = fabs(d1) + fabs(d2) + 1.0; double fac = fabs(d1 - d2) / denom; if (fac > 1.0E-10) { return false; } return true; -} - -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ + } }